TermiNexus
|
395e5eefab
|
feat(terminal): 去掉提示符/光标/输入文字的颜色
Text 默认的 prompt/cursor 由绿色改为与普通文本一致的 0xCCCCCC,
输入文字也不再硬编码白色;终端整体保持单色。
|
2026-10-27 14:54:00 +08:00 |
|
TermiNexus
|
c379cadc38
|
feat(terminal): 日志与输入行之间留空行
- Text._exec_input 在本命令确实产生输出时追加一个空行,
提示符与最后一条日志之间保持一个空行;无输出的命令不补
- 用实际 line_count 判断,clear 后不会被误补空行
- Terminal 启动时的介绍日志后也插入一个空行
|
2026-10-27 14:52:09 +08:00 |
|
TermiNexus
|
99c8cea8ee
|
feat(window): 滚轮事件下传与 Terminal 滚动
- desk 协议新增 DESK_MOUSE_WHEEL;window 新增 EVENT_TYPE_WHEEL
- Explorer 汇总一批鼠标包的 wheel 增量,投给光标下的窗口
(窗口内坐标;任务栏区域不投递)
- InputEvent.button 承载滚轮有符号增量(uint8 编码,消费方按 int8 解码)
- vpui.Text 处理 WHEEL:每次滚动 3 行,按“输出行 + 输入行”总行数钳制,
并同步滚动条;输入行仍保持在可视区内
|
2026-10-27 14:50:04 +08:00 |
|
TermiNexus
|
5405a34a24
|
feat(input): PS/2 鼠标启用 IntelliMouse 滚轮
- init 发送 200/100/80 魔数并读取设备 ID;ID=3/4 时切到 4 字节包
- IRQ 的 4 字节模式解析第 4 字节低 4 位为有符号 Z 增量;
标准 3 字节模式 wheel 恒 0
- mouse_packet 增加 wheel:int8
- /dev/input/mouse 布局扩展:[9] = wheel(int8),read 返回 10;
调用方缓冲不足 10 字节时仍返回旧的 9 字节布局
|
2026-10-27 14:50:03 +08:00 |
|
TermiNexus
|
5e2598a992
|
feat(terminal): 输入行跟随输出并显示当前路径
- Text 不再把输入行固定在控件底部:输入行紧跟在最后一条输出之后,
输出增加时随之下移;超出可视区时 scroll_offset 保持输入行可见
- Text 增加 prompt 字段 / set_prompt;点击定位、光标、_exec_input、
滚动条计算都按实际 prompt 长度和总行数(输出行 + 输入行)计算
- Terminal 的提示符改为“归一化路径 + /> ”:
根目录是 "/> ",/apps 是 "/apps/> "
- cd 成功后更新提示符;裸 cd 仍打印当前路径
|
2026-10-27 14:41:35 +08:00 |
|
TermiNexus
|
ab18afd26e
|
feat(window): WIN7 关闭按钮红底改为圆形
WIN7 样式的关闭按钮仍保留 28×20 的命中区,但红色背景改为
区域内居中的 20×20 圆,圆心与 X 图标中心重合;
hover / 按下时的颜色变化规则不变。
|
2026-10-27 14:40:48 +08:00 |
|
TermiNexus
|
b94de46ce5
|
feat(window): 任务栏层级提升到窗口之上
- render_range 顺序改为:背景 → 窗口 → 任务栏 → 光标,
窗口拖到任务栏区域时会被任务栏盖住
- hit_test 在任务栏高度内直接返回 -1,避免窗口视觉上被任务栏
盖住后还能点到下面的窗口;任务栏图标仍由 _taskbar_icon_hit 处理
|
2026-10-27 14:35:38 +08:00 |
|
TermiNexus
|
b6ea47277c
|
fix(kernel): 用户异常终止不再提前 swapgs,避免拖垮整机
用户态 #PF 的终止路径直接从 ISR 调用 _yield,不经过 ISR 出口。
原实现在 _yield 前把 GS_BASE swap 回 0;但下一个被调度的线程如果是
从用户态 timer IRQ 或 syscall 挂起的,它的恢复路径会自己 swapgs 回 0。
提前 swap 会让它 swap 反,下一次系统调用用 gs:[8] 取内核栈时读到
线性地址 8,进而三重故障/整机卡死。
- 删除终止路径的 swapgs 块,保持 ISR 入口后的 GS 视图,与其他
timer/syscall 让出路径一致
- 先置 THREAD_DONE 再 free_user_thread,与
Scheduler.exit_current_thread 的次序一致,避免“资源已释放但
state 仍是 RUNNING”的再调度窗口
|
2026-10-27 14:30:16 +08:00 |
|
TermiNexus
|
f9e91a9d6e
|
fix(gargantua): 调整窗口大小时不再改画布源尺寸
现象:计算过程中拖动/缩放 Gargantua 窗口,tid=2 以
[0E] rip=0x413f2f cr2=0x46c000 退出。
原因:RESIZE 处理器把 FBCanvas 的源尺寸用
set_fb(fb, new_w, new_h) 改成窗口内容尺寸,但 _fb_mem 仍是固定的
160×90。窗口变大后 FBCanvas.draw 会按新的 _cw 逐行读取
self._fb[py*_cw+px],越过 _fb_mem 末尾(0x46c000)触发用户态缺页。
修复:RESIZE 时不再改画布源尺寸,只调用 root.redraw() 按新窗口
尺寸重绘;超过源尺寸的部分由 FBCanvas 现有的 min(_cw,self.w)
裁剪逻辑处理。
|
2026-10-27 14:23:35 +08:00 |
|
TermiNexus
|
845633773b
|
fix(window): 标题栏按钮保持方角,仅按窗口圆角裁剪
上一版把 WIN11 关闭按钮红底做了内收 + 按钮圆角,不符合预期:
窗口是全圆角,但按钮本身应当是方角,唯一需要丢弃的是与窗口
右上圆角重合的那部分像素。
- WIN11 关闭按钮红底恢复整块矩形,仅用 _window_round_keep 丢弃窗口圆角外像素
- WIN7/WINXP 按钮底色同样改为方角(r=0),仍做窗口轮廓裁剪
- 按钮命中区域保持不变(仍是完整方角矩形)
|
2026-10-27 13:25:41 +08:00 |
|
TermiNexus
|
8dc806e7e2
|
fix(window): WIN11 关闭按钮 hover 红底按圆角裁剪
WIN11 窗口是圆角样式,关闭按钮又紧贴右上角;此前 hover/按下直接
row_fill 整块矩形,红色会盖住窗口圆角外的区域。
- 新增 _window_round_keep:按窗口自身的圆角轮廓判断像素是否可画
- 新增 _close_fill_row:同时按“按钮圆角 + 窗口圆角”双重裁剪
- WIN11 关闭按钮红底向内收 2px、圆角 3px;WIN7/WINXP 也走窗口轮廓裁剪
- 移除不再使用的 _round_fill_row
|
2026-10-27 13:21:34 +08:00 |
|
TermiNexus
|
b9efc30d71
|
feat(window): 标题栏 hover、最大化图标、边缘缩放与控件光标
1) 标题栏按钮 hover:min/max 背景按 alpha 压暗,close 变红、图标变白;
按下态更深。新增 hover_btn_win/kind,仅在变化时重画标题栏。
2) 最大化图标改为单线方框(上边框不再两行加厚);最大化后显示
两个错位重叠方框作为“还原”。
3) 窗口边缘 5px 热区支持拖拽缩放:左/右 ↔、上/下 ↕、四角斜向;
缩放中实时更新几何与内容缓冲(按 1.5 倍扩容,避免 arena 抖动),
并向 app 发 RESIZE。
4) 新增 DESK_REQ_CURSOR / window.set_cursor_type 真正下发光标类型;
explorer 按窗口 cursor + 边缘热区选择箭头 / I 形 / 手指 / 缩放光标。
5) vpui.Tk 在 HOVER 时按最上层控件设置光标:Entry/Text → I 形,
Button → 手指;Entry 自己的光标请求移除,避免与集中逻辑冲突。
|
2026-10-27 13:14:42 +08:00 |
|
TermiNexus
|
6ecd891f64
|
fix(desk): 清空共享区槽表并按版本拒绝旧 app
现场:所有窗口消失、任务栏多出若干图标,点击后 explorer 以
[0E] rip=0x4061e8 cr2=0x1207e8fff 缺页退出。
原因:desk_format 只清 DeskHeader,没有清 0x100 起的 WinSlot 表。
DESK_SHM_SIZE 从 8MB 提到 32MB 后,mm.malloc 拿到的内存不再恰好全零
(混入 bootloader/固件遗留数据),随机 used/active 被当成窗口,
合成时按垃圾 fb_off 越界读像素。
- desk_format 先 memset 整个控制区(0x000000 ~ 0x200000)
- 分配槽位时整槽清零,避免复用残留
- DESK_VERSION 1 → 2,desk_ready 校验版本:
旧 app 按旧 WinSlot 偏移读写会写坏共享区,现在直接拒绝挂载
- render_window_rows 校验 fb_off 范围,坏槽位只跳过,不再拖崩合成器
|
2026-10-27 12:52:23 +08:00 |
|
TermiNexus
|
8e94458fc2
|
fix(window): 最大化窗口不绘制阴影
最大化后窗口底边正好贴住任务栏,阴影(下沿 14px)会盖在任务栏上。
最大化状态跳过阴影绘制。
|
2026-10-27 12:44:54 +08:00 |
|
TermiNexus
|
03a5738702
|
perf(window): 最小化窗口的 FLUSH 不再置脏
应用最小化后仍会继续绘制并发送 FLUSH;此前每条 FLUSH 都标脏窗口区域,
合成器于是每帧重画背景。最小化时直接忽略置脏即可。
|
2026-10-27 12:43:53 +08:00 |
|
TermiNexus
|
97ca7bbbdb
|
chore(build): viperc 路径集中为 VIPERC 常量并切换 vpcbuild3
- BuildKernel / BuildLibs / BuildApps 共用 VIPERC,去掉三处硬编码
- 指向 ViperC/__vpcbuild3__/output/viperc.exe
|
2026-10-27 12:43:19 +08:00 |
|
TermiNexus
|
632bc877df
|
feat(window): 鼠标捕获与窗口最小化/最大化
鼠标:
- 内容区按下后记录 capture_win,按住期间的移动仍投 HOVER、松开投 RELEASE
(即使光标移出窗口)。此前 btn_down != 0 时完全不发 HOVER,滚动条
拖动拿不到位置更新。
- 标题栏按钮按下态改为通用 btn_win/btn_kind,支持关闭/最小化/最大化。
窗口:
- WinSlot 新增 maximized、restore_*、fb_cap 字段
- 最小化:隐藏窗口并把焦点交给最高可见窗口;任务栏点击恢复,
再点一次已聚焦窗口则最小化
- 最大化:保存还原几何,铺满工作区(不含任务栏)并发送 RESIZE 事件;
再次点击还原;拖动最大化窗口会先还原
- 像素缓冲按 fb_cap 复用,仅在容量不足时从 arena 扩容,避免反复
最大化/还原耗尽 bump arena
- 1920x1080 最大化需要约 7.3MB 内容缓冲:DESK_SHM_SIZE 8MB → 32MB
|
2026-10-27 12:43:19 +08:00 |
|
TermiNexus
|
859197e5e9
|
feat(kbd): USB 键盘按住自动重复
USB HID 键盘只在状态变化时上报;a3c1d22 为避免 Enter 洪流加入整份报告去重后,
按住不放不再产生任何字符。
- 记录当前按住的非 CapsLock 键与下一次补发时刻
- 同一份报告重复到达(按键仍按住)时,按 500ms 首次延迟、33ms 间隔
重新走 _decode_press,注入与按下沿相同的 ASCII/ANSI 字节
- 松开或换键时更新/清除重复目标;CapsLock 本身不重复
|
2026-10-27 12:43:19 +08:00 |
|
TermiNexus
|
b8ca4826a9
|
chore(kernel): 移除帧缓冲参数的影子副本校验
fb/width/height/pitch 偶发被写坏的根因(页表/1GB 大页拆分时写坏内存)已修复,
不再需要 fail-fast 影子防御:
- 删除 _ShadowFb/_ShadowW/_ShadowH/_ShadowPitch 与 _SetFrameShadow、_CheckFrameLocals
- 删除 after_usb / after_vga / pre_devfs_fb0 / pre_explorer 四处校验调用
- devfs_register_fb0 恢复直接使用 __init__ 里的局部几何
(原先为规避局部量被写坏,改为从 BootInfo 重取)
|
2026-10-27 11:54:41 +08:00 |
|
TermiNexus
|
f43951c1f8
|
fix(fat32): 以 . / .. 结尾的路径会误开第一个子目录
dir_open_path 在 follow_path 返回后仍按“父目录中的最后一项”回读目录项。
当路径以 “.” 或 “..” 结尾时,follow_path 已经把 dp 打开成目标目录,
这段回读会把目标目录的第一个子项当成最终项再打开:
根目录 cd .. → full=/.. → follow_path 打开根 → 回读根的第一项 APP
→ 实际进入 /APP,于是 ls 显示的是 app 里的 helloworld.asm。
现在检测末尾的 “.” / “..”,与根路径一样直接返回已打开的 dp。
|
2026-10-26 23:10:38 +08:00 |
|
TermiNexus
|
329a60b123
|
feat(terminal): 裸 cd 显示当前路径并归一化 cwd
- 只输入 cd 时不再重置到根目录,改为打印当前路径(pwd 语义)
- 新增 _normalize_path:折叠重复分隔符、去掉 .、处理 ..,
根目录下 cd .. 仍为 /
- _cwd 保存归一化后的路径,pwd/ls 不再出现 /app/../.. 这类串,
也避免路径越 cd 越长
|
2026-10-26 23:09:19 +08:00 |
|
TermiNexus
|
338472e304
|
fix(vpui): Label 自然尺寸与 pack 交叉轴居中
Input Demo 的两个显示问题:
- Label 没有显式 w/h,构造后 w/h 恒为 0:pack 时按 0 尺寸计算,
PACK_BOTTOM 的标签被贴到内容区底边之外(字模被裁),且不占纵向空间,
后面的按钮与 Name: 标签重叠。新增 _fit_natural() 按文本最长行/行数
计算自然尺寸,__init__ 与 config() 时更新。
- pack 在未 fill 时原先一律贴左上,导致 Submit 按钮紧贴左边缘。
改为与 tkinter 默认 anchor=center 一致:TOP/BOTTOM 横向居中、
LEFT/RIGHT 纵向居中,沿 pack 方向仍保留 padx/pady。
- redraw 先刷新窗口尺寸再 _do_layout(),避免 resize 后布局滞后一帧。
|
2026-10-26 23:04:25 +08:00 |
|
TermiNexus
|
ad6f0f68a2
|
chore(boot): GOP 显示模式改用 22
同时精简 GOP 初始化处的冗余注释。bootx64.efi 为编译产物,已停止跟踪,
需要时用 build.py --bootloader 重编。
|
2026-10-26 22:41:52 +08:00 |
|
TermiNexus
|
ca448eee98
|
chore(build): 移除 VPUI64 动态库并调整构建入口
- 删除 Libs/VPUI64(linker.ld / project.vpj / vpui64.vp),同步 README
- viperc 路径改到 ViperC/__vpcbuild__/output
- 新增 --nokernel(显式 --kernel 优先,且与 --kernel-only 互斥)
- 未编内核时的提示改为「跳过内核编译」
|
2026-10-26 22:41:47 +08:00 |
|
TermiNexus
|
fa1a92b568
|
chore(terminal): 链接不再 --strip-all,保留符号
便于崩溃现场按地址反查函数,与内核保留符号的做法一致。
|
2026-10-26 22:41:39 +08:00 |
|
TermiNexus
|
bc089a0c69
|
feat(diag): 用户态窗口渲染链路临时打点
沿 Scene3D → FBCanvas → vpui.redraw → window.flush → explorer 合成器逐段打点,
用于定位窗口内容不上屏停在哪一环:
- Explorer:fb 哨兵像素回读、建窗槽位回读、首个 FLUSH、首帧 back/fb/任务栏像素、
每 240 帧统计槽位/最上层窗口矩形/中心像素/共享缓冲首像素
- vpui:首次 redraw(缓冲地址尺寸)、st1~st4 分段(malloc/铺底/控件/拷回)、
首次 flush、FBCanvas 首绘的源缓冲与像素
- Scene3D:主线程预渲染 3 帧(非清屏像素计数、三角形命中/调用数)、渲染线程
入口与每 60 轮采样;渲染线程参数类型改为 rawptr
以上均为临时诊断,定位完成后应移除。
|
2026-10-26 22:41:32 +08:00 |
|
TermiNexus
|
0c47d81767
|
feat(diag): 异常现场完整转储(裸串口通路 + 无错误码向量)
- isr.s:ISR_NOERR 也保存 RIP/CS/RFLAGS/RSP,_fault_err 用 -1 表示无错误码;
两类宏都补存 rbx/rbp/r12(用户态 #PF 时 r12 常为出错 store 的目标对象基址)
- idt.vp:新增不经驱动/缓冲的裸串口输出(asm.outb),打印 rip/rsp/cs/flags、
u 位、callee-saved、错误码;#UD 附带出错指令字节,#PF 附带 cr2
- 前 32 条异常打印完整现场,之后每次只补 '*',避免异常风暴刷爆串口
|
2026-10-26 22:41:14 +08:00 |
|
TermiNexus
|
8c31645c0f
|
fix(gfx): floorf/ceilf 参数显式收窄为 float
min/max 是 double 内建,结果直接传给 floorf/ceilf 时编译器禁止隐式
double->float,实际会把 f64 的低 32 位当 f32 传参,使三角形包围盒取值全错。
内核 vesafb 与 Scene3D 两处光栅化同步修正。
|
2026-10-26 22:41:09 +08:00 |
|
TermiNexus
|
624554df01
|
fix(sched): 通过 rdi 传递用户线程入口参数
用户线程入口的第一个形参在 rdi,但 drop_to_user_mode 这条路径从未设置过 rdi,
thread_create(fn, arg) 的 arg 在用户侧一直是垃圾值。iretq 只恢复
RIP/CS/RFLAGS/RSP/SS,因此在 iretq 前显式 mov rdi 即可。
|
2026-10-26 22:40:10 +08:00 |
|
TermiNexus
|
1ccacf8204
|
refactor(userspace): 清理 t/c 依赖与过时注释
Terminal、SerialLogger 不再 import t, c;dynlib 删除已失效的指针级数说明。
|
2026-10-26 22:40:07 +08:00 |
|
TermiNexus
|
3583f78efc
|
refactor(kernel): 适配 ViperC 新语法
- 去掉不再需要的 import t, c
- class → struct(纯数据聚合)
- t.CArray[T, N] → [N]T
- static 修饰符移到类型前
- @__attribute(packed) → @__attribute__(packed)
- UHCI 中断回调参数改用 callable[[], int]
- 同步 CPUID 注释中的旧类型名
|
2026-10-26 22:39:56 +08:00 |
|
TermiNexus
|
89dd08895a
|
chore(disk): 停止跟踪编译产物 bootx64.efi
disk/ 已在 .gitignore 中豁免;引导器由 build.py --bootloader 从 boot/boot.c 重编,不再纳入版本库。本地磁盘上的新产物保留。
|
2026-10-26 22:39:48 +08:00 |
|
TermiNexus
|
7b6c508b21
|
增加 disk 产物豁免
|
2026-10-26 22:31:46 +08:00 |
|
TermiNexus
|
e9d8024138
|
fix(sched): 压缩 _do_switch 注释,规避内联汇编 2047 字节静默截断
llc 报 <inline asm>:55:13 invalid operand + 孤立 mov 的真因:ViperC 的 _asm_append_cstr 只写入 ASM_TEXT_BUF_SIZE-1=2047 字节且静默丢弃后续内容。_do_switch 的 asm 模板(含 CRLF)为 2245 字节,第 2047 字节正好落在 mov [rsi + 40], rcx 的 mov 之后 ⇒ 生成的汇编串以孤立 mov 结尾,popfq/pop/ret 全部丢失。压缩块内 4 条中文注释(模板降到 1894 字节),指令与 clobber 未动。附:sha1_map 第 57 行 3e23dc8764e4a4dd:sched/sched.vp 与报错哈希一致;全仓 16 个含 asm 的 .vp、189 个模板中仅此一处超过 2047 字节。
|
2026-10-17 17:36:45 +08:00 |
|
TermiNexus
|
89385d1b42
|
fix(sched): 恢复立即数 store 的 qword ptr(去掉后操作数大小有歧义)
上一笔把 sched.vp 里所有 qword ptr 都去掉了,误伤 _thread_entry 构造初始栈帧的 8 条立即数 store:mov [rax - 64], 0x202 这类'内存←立即数'无法由另一侧推断大小,报 ambiguous operand size。寄存器配对的 mov(rcx/[rsi]、[rdx]/rcx 等)保持无 ptr 写法,立即数 store 恢复 qword ptr。
|
2026-10-17 17:21:20 +08:00 |
|
TermiNexus
|
937b51a0c5
|
fix(sched): 内联汇编去掉 qword ptr,操作数大小改由寄存器推断
llc 集成汇编器在 Intel 语法下对 mov rcx, qword ptr [rsi] 报 Expected 'PTR' or 'ptr' token(列号正落在 ptr 处),而生成的 .ll 文本本身是对的。改写为 mov rcx, [rsi] / mov [rdx], rcx / mov [rax], rsp 等形式:内存操作数大小可由另一侧寄存器(rcx/rsp)推断,语义完全等价。
|
2026-10-17 17:19:23 +08:00 |
|
TermiNexus
|
7d8a4ee6ff
|
fix(sched): 内联汇编改用 lea + 间接寻址,绕开 [rip + sym + 偏移] 不被集成汇编器接受
llc 集成汇编器对 mov qword ptr [rip + _isr_scratch + 8], rcx 这种'RIP 相对符号 + 常量偏移'的直接寻址报 invalid operand(把整条指令识别成缺源操作数)。改为先 lea rsi, [rip + _isr_scratch](lea 形式此前已验证可用),再按 [rsi + N] / [rdx + N] 访问,共 12 处(保存 6 + 恢复 6)。rsi/rdx 都在 _do_switch 的 push 列表内,切栈后写入会被随后的 pop 恢复,不影响新线程寄存器。
|
2026-10-17 17:17:28 +08:00 |
|
TermiNexus
|
645e4015ca
|
feat(sched): 线程切换保存/恢复 FPU/SSE(fxsave/fxrstor)
混合抢占后中断帧只保存通用寄存器,异步抢占可能落在 SSE 表达式中间,FP 密集 app(Gargantua/Scene3D)的 XMM 会被其它线程覆盖。① Thread 末尾内嵌 fpu_area[528] + fpu_ptr,用 (base+15)&~15 手工对齐出 512B FXSAVE 区(编译器类装饰器只认 packed,不认 aligned);Thread 由 64B 变为 600B,MAX_THREADS=16 ⇒ 线程表 9600B,Scheduler 约 9624B。② _do_switch:切 rsp 之前 fxsave [old],换栈后 fxrstor [new];仅用 RAX 取地址(其值已压栈),不改动 GPR 与中断状态。③ 新线程 FPU 默认镜像直接写内存(512B 清零、FCW=0x037F、MXCSR=0x1F80、MXCSR_MASK=0xFFFF),不执行 fninit 以免破坏创建者的实时 XMM。④ 内嵌于 Thread,随静态存储存活,无需额外回收。⑤ 协作式 yield 与抢占共用 _do_switch,因此两条路径都正确隔离 SSE。⑥ _thread_entry 的硬编码偏移同步为 +9600/×600,并加 fail-fast 校验(不符立即 FATAL,不静默跑飞)。
|
2026-10-17 17:15:14 +08:00 |
|
TermiNexus
|
f2d8e771c2
|
feat(sched): 协作 + 时间片抢占(IRQ0 返回用户态时切换)
原先 timer_tick 只置 needs_reschedule,唯一消费点是 SPAWN 阻塞循环,纯计算线程永不被切走。① 抢占点:isr32_handler 在 timer_handler(含 pic.eoi(0)/apic.eoi)返回之后、且 from_user != 0(ISR 入口读 CS 低两位)时调用 try_reschedule;栈切换仍在 _do_switch。只对 Ring3 返回路径生效,内核临界区/syscall 中途不切。② 中断帧保留在被切线程内核栈上,靠 rsp 切换自然保存/恢复,不拷贝、不在切换中途 iretq。③ 修正全局 _isr_scratch 跨线程覆盖:ISR_SAVE_CLOBBERED 把 rax/rcx/r8-r11 存在全局 scratch,抢占后跨线程会互相覆盖;_do_switch 现按 tid 保存/恢复(_isr_scratch_tbl[16*6])。④ ISR 走中断门 IF=0,_if_saved=0,切回后不 sti,由 iretq 用用户 RFLAGS 恢复;_yield_lock 防嵌套。⑤ 单核前提(_sched_ptr/tick_count 非 per-CPU)。⑥ yield_now 语义、SCHED_QUANTUM=10、Gargantua 分块均未改。已知缺口:中断帧未保存 XMM/MXCSR,FP 密集 app 在异步抢占下有 XMM 被覆盖风险,待补 fxsave/fxrstor。
|
2026-10-17 17:08:46 +08:00 |
|
TermiNexus
|
a3c1d221e6
|
fix(kbd,sched,scene3d): 键盘报告去重;用户线程 return 跳板修正;关窗时序
① Enter 洪流:usb_kbd._on_int_complete 的按下沿依赖 kbd_prev_keycodes,而状态提交在函数末尾第三趟循环;kbd_report 是常驻 DMA 缓冲,按键保持/NAK/重复完成都会让回调反复看到同一份报告 ⇒ 每次中断都注入一次 Enter,Terminal 刷出 [cmd] enter,explorer 被拖死。新增 kbd_prev_sig(modifier+6 keycode 的标量签名)整份报告去重;同一趟循环里先提交 prev 再判定;全 0 报告只更新状态;抽出 _rearm() 保证所有出口都重排中断 IN 且 DMA 读取先于重排。② explorer 限流:kb_pend[64] + _deliver_kb,单轮最多投递 64 字节,ring_push 返回 -1 时停在当前字节(不再当成功丢弃),pending 清空才补读;鼠标取包同样 64 包/轮上限。③ 关窗卡死根因:process.vp 的 _tramp_code 是 mov eax,34; int 0x80; jmp \$,而 Syscall.THREAD_EXIT=60 ⇒ 用户线程 return 后走 syscall 34(无匹配分支)返回 Ring3 在 jmp \$ 空转,空转不再产生 syscall,而内核只在 syscall 返回路径消费 needs_reschedule ⇒ 协作式调度彻底停摆,整机冻结。sched.create_user_thread 在跳板映射后把立即数低字节改为 60(幂等)。④ 次生:主线程先退会立即回收自己的用户栈,而 Scene3D 渲染线程还引用其栈上对象。Scene3D 渲染线程退出改为显式 process.thread_exit() 并置 _render_done;主线程 mainloop 返回后先 yield 等渲染线程退出(上限 10000 次)再 exit。⑤ window.flush 在槽位 used==0 时直接返回;vpui.Tk.redraw 入口判 win_id 与 is_active,窗口已回收时不碰 arena 不 flush。
|
2026-10-17 16:49:37 +08:00 |
|
TermiNexus
|
7e7204a09a
|
fix(mm,explorer): slab 页严格归属与分配位图;关闭按钮按下态与松手关闭
① [mm] BAD blk 的解码:site=2=free_block、reason=1=magic 失配;blk 实际是 slab_page+16(页在 0x1b56020),sz 是该页 free_head,而非块大小。被踩的是页头前 8~16 字节,最可能是无锁 buddy 在 usb.init(sched.enable 之后)与用户进程 MMAP 并发 malloc 时重复授予同一 8KB 块。② mm 加固:_slab_find_page 不再只看 magic,新增 _slab_page_owns(block_ptr 回指、指针在对象区内、按 obj_size 对齐、序号 < total_objs);slab_page 新增 alloc_bits,只有已分配对象可 free,重复释放/野指针被拒,避免 free_count 提前到 total_objs 把仍在用的页拆回 buddy;free_obj 拒绝已全空继续收对象;_create_page 失败路径清零 magic。③ hid_ascii 仅只读且已有边界检查,非本次堆损坏来源;usb_kbd 把 code >= 64 改为显式早返回。④ 关闭按钮:按下只置 close_down 并置脏(按钮画按下态:CLASSIC 40,40,70→20,20,45;WIN7/XP 红底 200,50,50→140,25,25;WIN10/11 补深灰底),松手且仍命中才发 CLOSE + used=0,移出则撤销按下态恢复;几何复用 _close_btn_* 同一套函数。
|
2026-10-17 16:23:44 +08:00 |
|
TermiNexus
|
bd1cd2f228
|
fix(explorer): 逐包跟踪按下/释放沿,修复单击需长按
批量取包后只保留最后一包的按键状态:快速点击的按下+释放落在同一批里,最终 btn=0,按下沿永远检测不到(表现为必须长按)。改为批次内维护 cur 并记录 saw_press(任一分包出现 0→1)。同时把释放与拖动从 elif 改为独立 if:同批内按下并松开时,按下分支之后必须立刻走释放,否则 btn_down 卡在 1,后续点击继续失效。
|
2026-10-17 15:52:32 +08:00 |
|
TermiNexus
|
eb953bb1d3
|
feat(keyboard): 接入 USB 键盘输入到 /dev/input/keyboard
现场证据:keyboard.init 的 0xF4 被 ACK,但按键时 [kbd] first IRQ1 从不出现;同时 [usb] device addr=1 class=03 proto=01 ep=1 说明真实按键来自 USB 键盘。usb_kbd 已通过 UHCI 中断回调收到报告并生成 kbd_buf 事件,但全仓无人消费(usb_kbd_thread 从未启动),所以 /dev/input/keyboard 永远读不到 USB 按键。① keyboard.vp 新增 inject_byte/inject_csi/inject_csi_tilde 三个公开注入函数,复用 _out_push/_emit_csi,不改 read_scancode/has_data/irq_handler 语义。② usb_kbd.vp 在 _on_int_complete 的按下沿(与上一帧 6 键码比较后新出现的键)按 boot protocol(枚举时已 SET_PROTOCOL(0):modifier+reserved+keycode[6])解码成 ASCII/ANSI,注入同一 out_buf:字母数字含 Shift/CapsLock、Enter\\n、Backspace\\b、方向键 ESC[A/B/C/D、Home/End ESC[H/F、Delete/PgUp/PgDn/Insert ESC[3~/5~/6~/2~,与 PS/2 路径一致;按住不重复、松开不产字节。③ 不新建线程、不启动 kbd_thread,USB 与 PS/2 共用同一队列,中断上下文内写入(IF=0)。④ 加一次性诊断 [usb_kbd] first key。
|
2026-10-17 15:43:48 +08:00 |
|
TermiNexus
|
d19d96dc70
|
build: 默认重编内核,--app 时才跳过
上一轮把默认改成不编内核,导致内核侧修复(键盘解码/诊断)没进产物,日志与代码对不上。恢复为:不带 --app 时默认编内核 + 库 + 全部应用;--app=a,b 视为只迭代应用(跳过内核),需要内核时显式加 --kernel。
|
2026-10-17 15:36:56 +08:00 |
|
TermiNexus
|
4195b05f75
|
diag(keyboard): IRQ1 首达与 0xF4 ACK 打点
键盘仍无字符。加两条一次性诊断:① irq_handler 首次触发打 [kbd] first IRQ1(判断中断是否送达);② init() 的 0xF4 扫描使能命令按 ACK 结果打 ok/not ACKed(判断命令是否送到键盘)。两者组合可区分'命令没送达'、'中断没到'、'解码丢字节'三种情况。
|
2026-10-17 15:33:55 +08:00 |
|
TermiNexus
|
0f235d0d0b
|
fix(keyboard): 移除 devfs 注册时的重复 keyboard.init()
键盘只收到一个残留字节(ch=50)后就没有数据,符合'数据上报被关掉'。keyboard.init() 被调了两次:devfs_register_keyboard() 与 services/keyboard.vp 的 start()。init() 会读-改-写 8042 CCB 并安装 IRQ1,二次读改写可能把键盘时钟/数据上报关掉。改为只在 service 层初始化一次。
|
2026-10-17 13:54:52 +08:00 |
|
TermiNexus
|
03e1137189
|
fix(keyboard): 去掉重复初始化,键盘只由 service 层 init 一次
现场:explorer 能 open /dev/input/keyboard,但按下键后 [explorer] kbd 一次都不出现 —— 内核侧没有数据。devfs_register_keyboard() 与 services/keyboard.start() 各调了一次 keyboard.init(),而 init 会读-改-写 8042 的 CCB(含数据上报/中断掩码位);第二次执行时设备状态已变,容易把上报关掉。现在初始化只保留 service 层那一次(它更晚、是最终状态);kbd_thread 并未被启动(kbd_svc.th 从未创建),不存在抢数据的问题。
|
2026-10-17 13:36:38 +08:00 |
|
TermiNexus
|
4003b0d286
|
diag(explorer): 首次键盘字节打点,区分内核无数据与事件未送达
键盘仍无输入:在 poll_input 的键盘分支加一次性打印(kn 字节数 + 首字节)。判读:没有该行 ⇒ 内核 keyboard 设备这一侧没数据;有该行但 Terminal 仍不显示 ⇒ explorer 投递或 vpui 路由问题。
|
2026-10-17 13:26:50 +08:00 |
|
TermiNexus
|
b405973e91
|
perf(gargantua): 渲染按 64 像素分块并每块让出 CPU
原实现一次连续算 4 行(640 像素,单像素最坏 100 步),长时间不让出,单核下输入/合成全卡。改为 64 像素一块,每块后 process.yield_cpu();每 4 行仍 root.redraw() 保持渐进刷新节奏;事件轮询从每 4 行一次提升到每 64 像素一次。单次占用降到约 1/10,逐像素结果不变(仅调度顺序变化)。
|
2026-10-17 13:20:22 +08:00 |
|
TermiNexus
|
850c4b8adc
|
fix(keyboard,explorer): 键盘解码单队列化消除读循环自旋;关窗清理悬垂状态
① 卡死/键盘无效:has_data() 把'原始待解码'与'已解码可读'混成一个计数,而 read_scancode() 只看已解码队列;一旦出现 has_data()>0 但本次取不到字节(断码/修饰键/E0 前缀),devfs 的读循环里 count 不前进而 has_data() 恒真 ⇒ asm.sti() 后无 yield 自旋,协作式调度下整机停死。改为解码下沉到 IRQ、只保留一个输出队列(has_data()==out_count,read_scancode() 返回 0 ⟺ 队列空),ANSI 序列整条原子入队;devfs 读循环以 read_scancode() 返回 0 为唯一终止条件。② 关窗:DESTROY 与关闭键路径清 drag_win,focus/_activate_from_taskbar 校验槽位存活;poll_requests 单轮最多处理一圈(head 已推进,剩余留到下轮,不丢消息也不自旋)。③ vpui:孤立 ESC 后紧跟的普通键不再被吞。
|
2026-10-17 13:20:22 +08:00 |
|