Commit Graph
184 Commits
Author SHA1 Message Date
TermiNexus 2481336dec chore(main): 临时加 devfs serial0 查找结果探针,定位“用户态写串口无输出/设备查找失败”
症状:三个 app 启动即 [syscall] exit called(create_window 失败 ⇒ is_active(-1) 为 0 ⇒ mainloop 立即返回)、explorer 的 [explorer] start 一行都没有、内核自己的 devfs 冒烟输出([serial0] open/write)也全缺 ⇒ 三条都指向 devfs_open 查不到设备。探针:[main] devfs serial0 fd=N(<0 即 lookup 失败,serial0_open 不会被调、也就不会有 [serial0] open 打印)。定位后删除。
2026-10-16 19:38:25 +08:00
TermiNexus d6d07b25ee feat(s5): 删除 TELL/SIZE 私有 syscall —— 用 lseek 的 SEEK_CUR/SEEK_END 表达
内核:SEEK 补真正的 whence(0=SET 1=CUR 2=END,END 时 offset 为距末尾的距离,offset>size 返回 -1);删除 TELL/SIZE 的枚举项、派发分支与 TELL/fsize 函数(fat32.tell/size 仍留给 SEEK 内部用)。

SDK:vpsdk/fs.vp 的 seek() 增加 whence 参数(默认 0,调用方不变);tell() 改为 lseek(fd,0,SEEK_CUR);fsize() 改为三次 lseek 往返(记住位置 → 跳末尾取大小 → 复位),不改变最终位置。

私有段只剩 5 项:OPENDIR/READDIR/CLOSEDIR(openat+getdents64)与 LOAD_SO/SO_CALL1(动态库加载下沉)。
2026-10-16 19:33:46 +08:00
TermiNexus 1fc1fab1e1 feat(explorer): S3f —— 补用户态字体渲染:窗口标题文字 + 任务栏底板
字体表直接复用 vpsdk/vpui.vp 的 font(8x16 点阵、MSB 优先、row = font[ci][fy]),不另抄第二份;新增 draw_char/draw_str。

合成器:① 窗口标题栏画上该窗口的 title(标题在建窗时随 CREATE 消息内联进槽位,set_title 走 REQ_TITLE 更新);② 屏幕底部 28px 任务栏底板 + "ViperOS" 标签,绘制次序为 背景 → 任务栏 → 窗口(窗口可盖住任务栏,与旧内核桌面同序)。

仍未做:任务栏时钟(用户态暂无时间源,需要 /dev/rtc 之类)、窗口侧边框与样式区分、最小化、拖边缩放、崩溃进程的窗口回收。
2026-10-16 19:28:08 +08:00
TermiNexus d96362186f fix(explorer): push_event/push_event_pid 补齐第 6 个参数 d,修 llvm.call 操作数个数错
现象:f4160f3611036a68.ll 报 llvm.call 传了 7 个操作数、被调方期望 6。根因是我这边实参个数不一致:签名是 (self,win,etype,a,b,c)(self+5=6),而鼠标三处调用按"再带一个 buttons"写了 6 个实参(self+6=7)。DeskMsg 本来就有 a..d 四个载荷位,window.vp 也早已用 _evt.d 当 button,所以正确修法是把签名补上 d:push_event/push_event_pid 各加一个 d 参数,并把原先少传的 KEY/CLOSE/CREATED 三处补齐。

说明:这不是编译器实现问题 —— 编译器(LLVM verifier)报得准确;只是实参个数这类错误没在前端拦住、漏到了 LLVM 层,属于前端检查的缺口,可另案记录。
2026-10-16 19:24:09 +08:00
TermiNexus c4305301fc fix(vpsdk): 恢复 window.vp 对 vpsdk.stdlib 的 import(app 裸名 malloc 的链接来源)
现象:ld.lld 报 undefined symbol: malloc,引用来自 Apps/HelloWorld 的 _start(4 处)。根因:malloc 是 vpsdk/stdlib.vp 的 CExport 裸名,app 侧那些裸名调用要靠 window.vp 的 import vpsdk.stdlib 把 stdlib 拉进链接图;S3d 重写 window.vp 时把它当未使用删掉了 ⇒ stdlib 不再进图 ⇒ malloc 无人定义。

同时删除 main.vp 里上一轮加的两处说明注释(按用户要求不保留)。
2026-10-16 19:20:26 +08:00
TermiNexus d96b632226 chore(main): 删掉内核身份下调 slog.so log_info 的启动冒烟调用
S4 之后 log_info 走 open(/dev/serial0)+write 两个 syscall,而该调用点在 devfs_init/devfs_register_serial0 之前 ⇒ 那条日志必然丢失。直接删除这个早期验证用的冒烟调用(动态库路径仍被 HelloWorld 的 dynlib.load_so/so_call1 与内核 LOAD_SO/SO_CALL1 覆盖)。同步更新上方的自启动说明注释。
2026-10-16 19:19:00 +08:00
TermiNexus 5e1cd04478 feat(s4): 删除 SERIAL_PUTS 私有 syscall,用户态改走 /dev/serial0
内核:删掉 SERIAL_PUTS 的枚举项/派发分支/处理函数(内核自身的 serial.puts 是直接驱动调用,不受影响)。SDK:vpsdk/devfs.vp 新增 serial_puts()(惰性 open /dev/serial0 一次 + write),syscall.vp 删掉该成员。

调用点全部切到 devfs.serial_puts:vpsdk/stdio.vp 的 printf、vpsdk/vpui.vp 的 _serial_puts、Apps/Terminal 的 _sdbg、Apps/Explorer 的 _dbg、Libs/SerialLogger 的 log_info/log_warn(.so 同样走设备节点)。顺带清掉因此失效的 import(vpui 的 _syscall、Terminal 的 _syscall、Explorer 的 syscall)。

至此私有段只剩 7 项:TELL/SIZE/OPENDIR/READDIR/CLOSEDIR(可由 lseek/fstat/openat+getdents64 表达)与 LOAD_SO/SO_CALL1(动态库加载待下沉用户层)。
2026-10-16 19:17:39 +08:00
TermiNexus c5e107e361 fix(vpsdk): 修正 desk_open/desk_map 的模块前缀(链接 undefined symbol 根因)
现象:ld.lld 报 undefined symbol aeb1805c34e518f8.desk_map / desk_open,引用来自 window.vp 的对象(_attach/_connect)。根因:我在 window.vp 与 Explorer/main.vp 里把这两个函数挂到了 devfs. 前缀上,而它们的定义在 vpsdk/desk.vp(devfs.vp 里只有底层 shm_map)。编译器按名解析到 desk.vp 的声明并发出带 desk 前缀的符号,但调用点的前缀不一致 ⇒ 链接期解析不到。

同时清掉 window.vp 里已不再使用的 import(devfs/stdlib/syscall —— get_winbuf 改用共享区后 stdlib.malloc 与 syscall 都已无引用)。
2026-10-16 19:14:57 +08:00
TermiNexus 13eee8e8ea feat(s3e)!: 内核 UI 层整体下沉用户态 —— 删 11 个 UI syscall + services/desktop.vp
内核 intr/syscall.vp:删除 WAIT_WINDOW/CREATE_WINDOW/DRAW_TEXT/GET_WINBUF/WIN_FLUSH/POLL_EVENT/SET_CURSOR/SET_TITLE/SET_GEOMETRY/SET_RESIZABLE/GET_WIN_SIZE 的枚举项、派发分支与对应函数;去掉 services.desktop 依赖;EXIT 不再拆窗口(内核已不持有窗口语义)。

删除 VKernel/Kernel/services/desktop.vp(~2900 行内核桌面/合成/输入分发);main.vp 不再启动 desktop 线程,只保留一次 fb 局部量一致性校验。剩余 syscall = Linux 对齐段 + 8 个待 devfs 化的私有项(SERIAL_PUTS/TELL/SIZE/OPENDIR/READDIR/CLOSEDIR/LOAD_SO/SO_CALL1)。

SDK:yield_cpu() 从 WAIT_WINDOW(0,2) 改为 Linux 对齐的 sched_yield(内核同样是 try_reschedule);syscall.vp 同步删掉 11 个 UI 成员。

explorer:关闭按钮改为先通知 CLOSE 再把槽位 used=0 —— window.vp 的 is_active() 见 used==0 返回 0,app 的 while is_active() 自然退出;像素缓冲不复用(bump 分配)⇒ 无别名风险。至此输入只剩 explorer 一家在读(内核桌面已删),两个合成器之争结束。
2026-10-16 19:11:44 +08:00
TermiNexus a45b9808b0 feat(s3d): vpsdk/window.vp 改走 /dev/desk 共享协议(对外 API 一字未改)
window.vp 重写:不再走内核 UI syscall,全部经共享区与用户态 explorer 通信。对外函数名/签名/常量/InputEvent 全部保持原样 ⇒ vpui.vp 与四个 app 零改动。

数据面:get_winbuf 直接返回共享 arena 里本窗口那块像素缓冲的线性地址(app 就地画),flush 只压一条 FLUSH 请求 ⇒ 全程零像素拷贝(旧实现是 app 私有缓冲 + 整块拷给内核)。控制面:请求环 + 按 pid 分的事件环;is_active/get_win_size 直接读共享槽(零 syscall)。create_window 压 CREATE(标题内联在消息里)并等 CREATED 答复拿 win_id。

协议补齐:DeskMsg 增内联 title(CREATE/TITLE 用,ring_push/pop 同步搬运);事件环按 pid 分(不能按 win_id——建窗答复送不到;也不能单环——单消费者结构多 app 会互抢);新增 DESK_MOUSE_PRESS/RELEASE/HOVER 语义常量。

合成器:关闭按钮改为置 active=0(app 的 while is_active() 自然退出)并通知一次 CLOSE;点击只投给窗口**内容区**(标题栏用于拖动)、松手投 RELEASE、移动投 HOVER,坐标均换算成窗口内坐标;拖动改为只在标题栏生效;RESIZE 重新从 arena 切片并更新内容尺寸(与 vpui 的 bh = h - TITLE_H - 2 对齐)。
2026-10-16 19:08:18 +08:00
TermiNexus bb82c2fe75 fix(desk)!: 事件环改为单环+按 pid 过滤,并补 getpid(S3d 前置)
缺陷:原设计把事件环按 win_id 索引,但建窗答复 CREATED 必须在 app 知道 win_id 之前送达 —— 按 win_id 索引物理上不可能送达。改为**单一事件环**,每条事件带目标 pid,由 app 用自己的 pid 过滤(与内核旧接口 poll_event(buf, caller_pid) 同口径)。

DeskMsg 增 pid 字段(ring_push/ring_pop 同步搬运,漏搬则事件全被当成 pid=0);desk_evt_ring_off() 去掉 win_id 参数;desk_format 只初始化一个事件环;服务端 push_event 从窗口槽取 pid、建窗答复走新增的 push_event_pid(此时槽里还没有 pid)。

新增 GETPID(Linux 号 39,此前是"留空"项,现在真正实现):内核 GETPID() 返回 process.current(),SDK 侧 process.get_pid()。app 需要它才能过滤自己的窗口事件。
2026-10-16 18:58:43 +08:00
TermiNexus 1633769534 feat(explorer): S3c —— explorer 窗口服务端与合成器(请求环 + 输入 + 逐行合成)
Apps/Explorer/desk_server.vp(新增):窗口槽分配(含 arena 像素缓冲切分与底色预清)、Z 序与焦点、逐脏行合成(背景整行 memcpy → 各窗口按 Z 序只重画落在该行的那一段 → 光标)、请求处理(CREATE/DESTROY/MOVE/RESIZE/FLUSH/ACTIVATE)、事件投递(CREATED/CLOSE/KEY)、输入轮询(读 /dev/input/keyboard 的 ASCII 与 /dev/input/mouse 的按键+x/y,做命中测试、点击聚焦、标题栏右侧关闭按钮发 CLOSE、按住拖动移窗)。

main.vp:fb/desk/输入三者就绪后交给 DeskServer.serve() 主循环;去掉 S2 的渐变条演示(像素通路已由 fb 映射日志与合成器本身证明)。desk.vp:删掉写错且无人使用 的 DESK_MSG_SIZE 常量。

注意:本切片尚未实现标题文字(需用户态字体表)、任务栏、最小化/缩放、窗口侧边框与样式;且此过渡态下内核 desktop 与 explorer 同时在画屏幕,会互相覆盖 —— S3d(app 改走协议)与 S3e(删内核 UI)收口。
2026-10-16 18:56:30 +08:00
TermiNexus 30708d3250 feat(desk): S3 底座 —— /dev/desk 共享内存通道 + 用户态协议模块
内核 devfs 新增 shm_device(/dev/desk):同一物理区间映射给所有打开者;main.vp 启动时 mm.malloc 出 DESK_SHM_SIZE(8MB) 并登记,分配失败只打日志跳过(explorer 的 open 会明确失败,不静默兜底)。内核只负责"分配 + 共享映射",区间内布局完全不参与。

vpsdk/desk.vp(新增协议模块):共享区固定布局(DeskHeader / WinSlot / 请求环 / 每窗口事件环 / 像素 arena)、单生产者单消费者环形队列(head/tail,跨进程无锁、全程指针直读写)、explorer 用的 desk_format/desk_arena_alloc 与 app 用的 desk_ready。请求/事件类型常量齐备(CREATE/DESTROY/MOVE/RESIZE/TITLE/FLUSH/ACTIVATE 与 CREATED/CLOSE/KEY/MOUSE/RESIZE)。

vpsdk/devfs.vp 增 DEV_DESK 与 shm_map();Explorer 启动即 open+mmap /dev/desk、desk_format 初始化并打印头信息,验证 IPC 底座可用。
2026-10-16 18:53:27 +08:00
TermiNexus 6bd2390e08 feat(explorer): S2 —— 新增图形壳应用 explorer 骨架,用户态经 devfs+mmap 直接写屏
Apps/Explorer:复制标准 app 骨架(main.vp / linker.ld / project.vpj,链接地址 0x400000)。启动流程:open /dev/fb0 → ioctl(FB_GET_INFO) 打几何 → mmap 拿到线性地址 → 等约 2 秒(等内核桌面首屏全量重绘过去)→ 画一条渐变横条验证像素真上屏 → open /dev/input/keyboard|mouse 验证输入设备可达 → 常驻不退出。

vpsdk/devfs.vp(新增 SDK 设备层):设备路径常量(与内核注册名逐字一致)、FB_GET_INFO 与 FbInfo 镜像(packed,与内核同布局)、fb_open/fb_get_info/fb_map/kbd_open/mouse_open。

build.py:把 Explorer 加进 required_apps 清单与完整构建分支;内核 main.vp 在四个 app 之后 spawn /APPS/explorer.elf。内核 desktop 与 explorer 并存属迁移中间态,S3 会把窗口合成整体交出去。
2026-10-16 18:43:13 +08:00
TermiNexus 7d5380148b feat(mmap): S1c —— MMAP 改 Linux 六参形态并支持映射 /dev/fb0
内核 MMAP(addr,length,prot,flags,fd,offset):fd=-1 + MAP_ANONYMOUS 走匿名映射(分配物理页、清零后映射到本进程新 VA,对齐 Linux"匿名必为零"语义);fd 是带 mmap_info 的 devfs 设备(当前仅 /dev/fb0)则把 [phys+offset, phys+offset+len) 按页映射进调用者地址空间(PTE_USER|WRITE)。addr/MAP_FIXED 暂未实现,一律由内核挑 VA 并返回真实起始地址。新增 PROT_*/MAP_*/MMAP_FD_ANON 常量。

参数次序与 Linux mmap 完全一致(rdi/rsi/rdx/r10/r8/r9),syscall_entry 的搬运顺序本就是这个约定,SDK 侧 vpsdk/syscall.vp 加 mmap() 助手走 _syscall6。stdlib.malloc 随之改为匿名映射调用(fd=-1、MAP_PRIVATE|MAP_ANONYMOUS、PROT_READ|PROT_WRITE),行为与原 MMAP(size) 一致且多一层清零。
2026-10-16 18:40:14 +08:00
TermiNexus f4c653958e feat(devfs): S1 —— 暴露 /dev/fb0 并让用户态可达 /dev/*(含 ioctl)
devfs:新增 /dev/fb0(framebuffer_device),提供 ioctl(FB_GET_INFO) 回填几何/格式/物理区间,并新增 devfs_file.mmap_info 虚方法(默认不可映射)把物理区间交给内核 mmap 用;main.vp 在 devfs_init 后登记它。输入设备(/dev/input/keyboard、/dev/input/mouse)此前已存在,本轮起从用户态可达。

用户态可达性:Process 增 fd_kind[](0=FAT32 fileobj*,1=devfs_fd+1),OPEN 对 "/dev/" 前缀改走 devfs,READ/WRITE/CLOSE 按 kind 分派;Process.exit 只对 kind=0 调 fat32.close(把 devfs fd 当 fileobj* 会跑飞)。fd 种类常量放在 process.vp 供 syscall.vp 引用,避免 process 反向 import devfs(devfs→keyboard/mouse→intr.idt→sched→process 会成环)。

新增 IOCTL syscall(Linux 号 16,本轮开始实现):只放给 devfs 设备,SDK 侧 vpsdk/fs.vp 加 ioctl() 助手。
2026-10-16 18:38:21 +08:00
TermiNexus ca72ddbbf7 refactor(syscall): 调用号改用 enum 并全面对齐 Linux x86-64 ABI
内核 intr/syscall.vp 与 vpsdk/syscall.vp 各一份 1..34 的 define 表改为同名 enum Syscall。编号口径:与 Linux 同名同号;Linux 有而我们未实现的留空不占号(12 brk / 39 getpid / 84 rmdir / 217 getdents64 / 257 openat … 需要时按号补)。

15 个语义重合的调用直接用 Linux 号:READ 0 / WRITE 1 / OPEN 2 / CLOSE 3 / STAT 4 / SEEK 8 / MMAP 9 / MUNMAP 11 / YIELD 24 / THREAD_CREATE 56(≈clone) / SPAWN 59(≈execve) / THREAD_EXIT 60(exit) / MKDIR 83 / REMOVE 87 / EXIT 231(exit_group)。

其余 19 个(UI 11 个 + SERIAL_PUTS/TELL/SIZE/OPENDIR/READDIR/CLOSEDIR/LOAD_SO/SO_CALL1)暂放 0x1000 起的**临时私有段**,每条带迁移标注:私有能力最终不占 syscall 号、改走 devfs 设备文件;UI 11 个待用户态 explorer(图形壳)接管 framebuffer 与输入后删除。

内核派发链改 n == int(Syscall.X)(n 是 int/i64、成员是 i32,显式 int() 规避未证实的混合宽度比较);SDK 全部调用点统一为 syscall.Syscall.X;stdlib 的 SYSCALL_MMAP 别名并入 Syscall.MMAP;Terminal 里硬编码的 uint64(18) 改为常量。
2026-10-16 18:32:33 +08:00
TermiNexus 4e1be2be88 fix(intr): 修正 isr80 的调用号/arg4 压栈顺序(int 0x80 一直把 arg4 当调用号)
栈向下增长,先压的落在高地址,而要的布局是 [S+0]=调用号(rax)、[S+8]=arg4(r10),所以必须先 push r10 后 push rax;原实现反了 ⇒ mov rax,[rsp+40] 取到 arg4 当调用号、mov r8,[rsp+168] 取到调用号当 arg4 ⇒ syscall_handler 收到错误的 n。

现场(探针实测):用户线程出口跳板 mov eax,34(THREAD_EXIT); int 0x80; jmp $ —— int 0x80 带着错的 n 进 syscall_handler,不匹配任何分支返回 0,iretq 回用户态落到 jmp $ 死转。该线程永不再 yield ⇒ needs_reschedule 无人消费 ⇒ 全系统停止切换:探针显示 cur 冻结在 5、t5 恒为 RUNNING,intr_cs=2B intr_rip=0x7FFFFFDE0007(正是跳板页偏移 7 的 jmp $)rsp=0x7FFFFFDE0000 ⇒ 桌面线程(tid 6)饿死,[perf]/[chk] 永不再打印。

这条路径此前无任何调用者(vpsdk 全走 syscall 指令),所以从未暴露。同时移除定位用的临时探针(timer.vp 心跳/调度器快照、isr.s 的 _intr_*)。
2026-10-16 18:07:57 +08:00
TermiNexus c29c1953df chore(intr): 探针补记被中断代码的 RIP/CS/RSP,用于定位卡死线程停在哪条指令
isr.s: ISR_NOERR/ISR_ERR 的 _frame_ready 里把 r8(RIP)/r9(CS)/rax(RSP) 写进新增的 _intr_rip/_intr_cs/_intr_rsp(只读这三个寄存器,不影响随后压栈)。timer.vp: 心跳行追加 3 个 hex32 字段。定时器 1kHz,所以这三个值几乎总是最后一次定时中断打断的现场:intr_cs=2B 表示该线程卡在用户态 intr_rip 处,=08 表示卡在内核。
2026-10-16 17:58:51 +08:00
TermiNexus 2784b327c7 chore(timer): 临时加 IRQ0 心跳+调度器快照探针,定位「app 退出后 [perf] 停摆」
每 1000 tick 直接写 COM1 一行 [t] <ticks> <current_tid> <thread_count> <各线程 state>,自带 LSR 超时、不依赖 serial 驱动、绝不挂住 ISR。用来区分三种可能:A) 探针也停 = IRQ0/EOI 死了;B) 探针继续但 cur 恒定且该线程 st=RUNNING = 该线程死循环且不再调用带 try_reschedule 的 syscall,needs_reschedule 无人消费;C) cur 在变 = 调度器活着,问题在桌面线程自身。定位后必须删除。
2026-10-16 17:40:51 +08:00
TermiNexus f34fe8a378 fix(sched): 用户线程出口改为跳板页,消除「线程函数 return 即 #PF」
alloc_user_thread 原来在用户栈顶下一格写哨兵返回地址 0:线程函数一旦 return,ret 就把 0 弹进 rip,Ring3 在 VA 0 取指。VA 0 在内核 identity map 里是存在但 supervisor-only 的页,于是现场固定为 rip=0x0 cr2=0x0 err=0x15 (P=1 保护违例 | U=1 用户态 | I/D=1 取指) rsp=线程栈 vtop,日志以 exc in tid=N, terminating 收场 —— 一次正常的线程结束被报成异常崩溃。

实测:Scene3D 渲染线程(唯一的 THREAD_CREATE,其栈顶 vtop 恰为 0x7FFFFFDE0000)在窗口被 taskbar 徽标关闭后 while root.winfo_exists() 退出并 return,日志即 serial.log 489-493 行那三行。

改为一页只含 mov eax,34(THREAD_EXIT); int 0x80; jmp $ 的出口跳板,映射在 [vtop, vtop+0x1000)(线程栈顶之上、栈向下增长永不到达的 64KB 间隙),栈顶哨兵改写成它的 VA。线程函数 return → 跳板 → THREAD_EXIT syscall → 内核干净回收本线程。free_user_thread 同步解映射该页并交还物理页,UserThreadCtx 增 tramp 字段记录。
2026-10-16 17:02:31 +08:00
TermiNexus 3ee35ad586 fix(sched): exit_current_thread 先标记 THREAD_DONE 再回收资源,堵住已退线程被再调度的窗口
原顺序是 free_user_thread 在前、state=THREAD_DONE 在后:在已释放用户栈/上下文但 state 仍为 RUNNING 的窗口里,若发生一次再调度(定时器 IRQ → try_reschedule → _yield 仅按 state 过滤),本线程会被再次选中并带着失效上下文回用户态,在已回收的栈上取指 0(现场 [0E] rip=0x0 err=0x15 cr2=0x0 rsp=0x7fffffde0000,紧跟 [syscall] exit called)。_yield 的选择逻辑(THREAD_READY/RUNNING 才可选)本身已正确,故只需把死亡标记提前。
2026-10-16 16:47:00 +08:00
TermiNexus 424233dcea chore(build): QEMU/OVMF 改为 code 只读 + 独立可写 vars 副本 2026-10-16 16:40:41 +08:00
TermiNexus cc96d00f1a refactor(vesafb): gfx.vp 的 Vec3/Mat4 改为值语义(去指针参数) 2026-10-16 16:40:41 +08:00
TermiNexus 0886252a08 feat(vpsdk): window/syscall/process/stdio/fs/dynlib 适配 + apps 同步调整 2026-10-16 16:40:41 +08:00
TermiNexus 06d24ae1aa chore(kernel): 恢复最小异常现场 dump;EXIT 增加不返回硬保护
isr.s:ISR_ERR 两条入口写 _fault_rip/_fault_err/_fault_rsp;idt.vp:带错误码向量打印 rip/err/rsp(#PF 追加 cr2),返回槽三连仅在出错 RSP 落在内核栈范围时读取(用户栈下方页未映射,读 [rsp-8] 会触发次生 #PF)。syscall.vp:EXIT 在 exit_current_thread 之后禁止返回(返回会一路 ret 回 app 的 _start 末尾、弹到 0 取指,现场 [0E] rip=0x0 err=0x15)。
2026-10-16 16:29:04 +08:00
TermiNexus f8b37564da refactor(vpui): 引入 tkinter 式类层次 Misc/Wm/BaseWidget/Widget,新增容器控件 Frame
层次:Misc(mixin:master/tk + winfo_master/toplevel + bind/unbind) ├─ Tk(Wm, Misc) └─ BaseWidget(Misc) └─ Widget(BaseWidget) ← Label/Button/Entry/Scrollbar/FBCanvas/Text/Frame 全部继承 Widget。约束按 Test/MultiInheritTest 的布局模型:父类字段展平进子类、非首基类必须无字段(故 Wm 无字段)、基类方法内不做 self.<虚拟> 自我分派(多继承非最左基类的虚表索引会整体后移)。控件 master 由 Widget* 改为 Misc*(Tk* 成为合法上转型),原先 8 处 Tk*(self.master) 裸转改为 self.tk;事件派发统一走 BaseWidget.dispatch_event(先跑 bind 回调再 handle_event)。中文。
2026-10-16 16:29:04 +08:00
TermiNexus 7b58758603 fix(vpsdk): 修正 malloc 块头越界写(ptr-hdr_size → ptr),修复全部 app 启动即 #PF
块头原写在 mmap 映射区起点之前 8 字节;第一次 malloc 时 mmap 返回用户堆起点 0x20000000,写 0x1ffffff8 落在映射区外 ⇒ #PF(err=0x7 用户态写、cr2=0x1ffffff8),四个 app 启动瞬间全部崩在同一个 stdlib.malloc 上。改为把块头写在映射区起始处 ptr,返回 ptr+hdr_size 不变,free/calloc/realloc 的 ptr-hdr_size 反查仍然正确。
2026-10-16 16:29:04 +08:00
TermiNexus 3a497e38ec fix(usb): 控制传输短读判失败+描述符链完整性校验;CCB 读改写屏蔽 IRQ1;清理已验证探针
uhci.control_transfer:除错误位外再比对 DATA TD 的 Actual Length(bit10:0)。短读时错误位可能全 0(QEMU/硬件不把短包当错误),只查错误位会漏 —— 现场是 USB 鼠标的 25 字节配置描述符只落下前 9 字节 ⇒ 接口解析为 0 ⇒ [usb_mse] no USB mouse found。

usb._parse_config 改为返回实际走完的偏移,enumerate_port 要求恰好走完 total_len,否则重读、仍不完整即报错返回(fail-fast,不带着半截描述符继续);同时删除两条探针。

keyboard.init/mouse.init 读-改-写 CCB 全程 pic.setMask(1):读 CCB 的 0x20 会把 CCB 值放进 0x60 输出缓冲并拉高 IRQ1,IRQ1 handler 会把它当扫描码抢走(现场 sc=0x47),使回读拿到残留值。改为只在校验失败时打印错误,去掉全部 [kbd] 探针。

清理已验证调试输出:idt 的 IRQ1 handler 探针及其计数器、desktop 的 [dbg] back_fb/row_buf/bg_row_buf、main 的 [DBG] LAPIC/idt32/swint/pic_isr 与 [DB] BootInfo 转储、timer 的 [PIT] 与自旋打印及随之无用的 import。
2026-10-16 15:26:35 +08:00
TermiNexus 82e951ee84 fix(desktop): 建窗与置脏标记加关键区,消除并发导致的共槽/同 z_order
create() 由各 App 线程经 syscall 并发调用(开机多 App 同时建窗最易命中),但 _win_count/_next_z 的读-改-写无互斥:抢占后读到同一 _win_count ⇒ 两个 App 共用同一 AppWindow 槽,标题/坐标/z_order/fb 互相覆盖;读到同一 _next_z ⇒ z_order 相同,渲染排序退化成槽位下标顺序 —— 均表现为更下方窗口的 title 突然显示到最上方。

改为:关键区①只原子分配槽位,结构体填充留在区外(避免长时间关中断);关键区②把 active/z_order/焦点一次性发布(渲染线程只在 active==1 后读该槽)。_bring_to_front 的 _next_z 自增同加关键区;_mark_rows_dirty/_mark_all_dirty/_clear_dirty_flags 同加关键区,避免与 App 线程并发时丢置脏标记(丢标记会让该行永不重绘,旧合成滞留在屏幕上)。
2026-10-16 15:20:49 +08:00
TermiNexus 1b2f6853fc fix(usb): uhci 控制传输逐 TD 校验并暴露错误位,补描述符落盘探针
- _wait_for_complete 原先只查 status TD 的 bit21|bit22,DATA 阶段的 CRC/超时(bit18)、bitstuff(bit17)、babble(bit20) 会被当成成功 ⇒ GET_DESCRIPTOR 拿到零字节缓冲区仍返回 0,最终表现为 [usb] device class=00 proto=00 ep=0、usb_kbd 找不到键盘(现场)。改为对齐 Linux usb-uhci.h:新增 TD_CTRL_ERR_MASK/NAK_MASK 与 _td_error(),control_transfer 收尾逐个校验 setup/data/status 三个 TD,失败时打印三个状态字。

- usb.vp 增加两条探针:[usb] devdesc blen/btype/maxpkt0 与 [usb] cfgdesc total/b0/t0/iface/proto/ep,用于区分数据未落盘与解析未命中。
2026-10-16 15:15:58 +08:00
TermiNexus 89907682ec fix(keyboard): init() 对齐 mouse 写法 - 去掉 0xAD/0xAE 键盘接口禁用序列(CCB 回写失败会停在禁用态),并补 pic.clearMask(1) 2026-10-16 14:14:51 +08:00
TermiNexus d37eac32fe fix(keyboard): init() 改为幂等(避免重复初始化禁用键盘接口);按键时打印扫描码/字符到串口便于验证 2026-10-16 14:12:50 +08:00
TermiNexus befed3904a fix(Gargantua): setup_camera 改用 V3 值语义(消除旧版 &_g_cam 指针残留),移除定位用调试输出 2026-10-16 14:12:50 +08:00
TermiNexus d9b39e99a5 chore(debug): Scene3D 每帧持续打印 time 与两个 sinf 采样值位模式 - 抓曲线变平时刻 2026-10-15 20:02:19 +08:00
TermiNexus d31f887290 chore(scene3d): 移除 [s3d] 时间探针 - 已确认回绕常量(-12.566371/+12.566371)正确、时间正常 2026-10-15 19:58:45 +08:00
TermiNexus cceefa4e2e revert(scene3d): PI 还原为 define - app 侧 workaround 撤销,float 字面量折叠由 ViperC 侧修复 2026-10-15 18:22:48 +08:00
TermiNexus aec563e33a fix(scene3d): PI 改为运行期 float 变量 - 消除 float 字面量被折叠成 double 致波形算术提升为 double(SIN 波形塌平) 2026-10-15 18:21:10 +08:00
TermiNexus 2803aff04c chore(debug): Scene3D 时间探针改为按 time 跨整数打印(与帧计数解耦) - 确保能可靠观测渲染循环是否在推进 2026-10-15 17:46:14 +08:00
TermiNexus e066c529f2 fix(scene3d): 深度缓冲初值 1.0->2.0 (NDC z in [-1,1], 初值须大于上界,否则远表面被永久剔平);撤掉 R/U/Y 阶段探针 2026-10-15 17:42:13 +08:00
TermiNexus 03dcd16f8b chore(debug): Scene3D 渲染线程加阶段探针(R/U/Y 每帧标记) - 定位冻结卡在 Render/update/yield 哪一步 2026-10-15 17:39:17 +08:00
TermiNexus 30620a2d0c chore(debug): Scene3D 临时探针打印 _time_val 位模式 - 区分时间退化与被内存写坏/几何深度剔除 2026-10-15 17:28:56 +08:00
TermiNexus abd13260af fix(scene3d): 时间相位回绕 4pi - 避免 float32 相位精度随运行退化致 SIN 波形塌平与热力图失色 2026-10-15 17:25:24 +08:00
TermiNexus 0d0dba476f fix(vkernel): 键盘无法输入 - 键盘/鼠标共享 0x60 统一为单一消费者(IRQ1 ISR→buffer→desktop 轮询),IRQ1 只收键盘字节 2026-10-15 17:24:17 +08:00
TermiNexus 6e78a08797 fix(vpsdk/vpui): 回调按闭包 ABI 调用(rdi=env, call [closure]) - 修点击 Submit 跳到堆上执行致用户态缺页 2026-10-15 17:17:42 +08:00
TermiNexus 0ee5ec5dcc fix(vkernel/ide): PIO 命令块寄存器连写补 io_wait + 读完核 ERR - 修读盘读错扇区(根目录扇区读回 ELF 头致 app spawn 失败) 2026-10-15 17:14:12 +08:00
TermiNexus 2eea065a67 chore(debug): fat32 dir_find/win_read 加取证探针 - 请求8.3短名 vs 磁盘目录项、读盘失败扇区、win_dirty 写盘痕迹 2026-10-15 17:08:58 +08:00
TermiNexus 152c4c5683 feat(vkernel/vpsdk): 用户线程生命周期 - THREAD_EXIT 显式退出;异常终止时回收用户栈并释放槽位;返回哨兵可辨识 2026-10-15 16:50:58 +08:00
TermiNexus 29e1bc6e34 chore(debug): 移除定位用的 MMAP/get_winbuf/redraw 临时探针(线程模型修复后 PF 与卡死均已消失) 2026-10-15 16:48:19 +08:00
TermiNexus a7faeed21b fix(vkernel): THREAD_CREATE 改用户态线程 - 独立用户栈与内核栈经 drop_to_user_mode 进 Ring3;调度器按线程切 TSS.RSP0/gs[8];同步 _thread_entry 硬编码偏移并加 fail-fast 自检 2026-10-15 16:45:09 +08:00