27 Commits
Author SHA1 Message Date
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 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
TermiNexus e1d31c3dc9 diag(explorer,fb0): vblank 返回等待迭代数并打点;脏行合并为一段渲染
排查'仍闪烁':① FB_WAIT_VBLANK 改为返回等待消耗的迭代数(到上限 = 超时 = 当前没有 VGA 回扫信号),explorer 首次调用打印一次 —— 用来判定垂直回扫同步是否真的生效;② render() 原来按连续脏行分段、每段各渲染一次,同一帧的多次写屏会跨越多个扫描周期,现在把脏行合并成一段连续范围一次性渲染,缩小撕裂窗口。
2026-10-16 21:55:36 +08:00
TermiNexus e41701e201 feat(fb0): 新增 FB_WAIT_VBLANK ioctl,合成前等垂直回扫
explorer 直接写 framebuffer 会与显示器扫描并发,造成撕裂/闪烁;而它在 Ring3 没有 IO 端口权限,不能像历史内核桌面那样自己 inb 0x3DA。所以在 /dev/fb0 上加 FB_WAIT_VBLANK(0x4601)由内核代等垂直回扫(带超时,无 VGA 时序时不死等),vpsdk 暴露 fb_wait_vblank(),desk_server.render() 写屏前调用一次。
2026-10-16 21:37:58 +08:00
TermiNexus 89c37cea22 fix(mouse): Y 增量取反成屏幕方向,修正上下移动反向
PS/2 协议的 Y 轴正方向是向上,而屏幕坐标 Y 向下为正,内核出口少了一次取反 —— 现场表现为鼠标上下移动反向。在 devfs 的 mouse_device.read 里统一转换成屏幕方向(消费方直接累加即可),与历史 desktop.vp 中 pkt_dy 的用法保持一致。只改内核,explorer 的 ELF 无需重编。
2026-10-16 21:33:31 +08:00
TermiNexus 6eb000d01d fix(mouse): 鼠标设备改返回相对位移,光标位置归 explorer 累积
现场:鼠标一有输入,光标立刻跳到左上角。根因:devfs 的 mouse_device.read 在 size>=9 时填的是 mouse.get_x()/get_y(),而 mouse_x/mouse_y 这两个静态量从未被更新(irq_handler 只把解码后的包入队 packets[]),恒为 0;explorer 拿到 (0,0) 就照抄成光标位置。改法:内核只给出 PS/2 包里的相对位移 dx/dy(uint8 原始字节手工做有符号扩展,不依赖 int8 转换语义),光标位置作为 explorer 自己的状态累积并做边界钳制 —— 内核不知道屏幕几何,钳制本来就该在图形壳这一层。
2026-10-16 21:23:05 +08:00
TermiNexus 48017a3d66 chore(devfs): 清理定位期临时探针,directory_count/file_count 恢复 static
main.vp:删除 devfs 注册结果回读([main] devfs reg / files[k] / find_in_dir / serial0(before fb/desk) fd)、fb0 注册后回读([main] fb0 reg)、desk 共享区地址比对([main] desk shm)、serial0 查找结果([main] devfs serial0 fd)共 6 组诊断打印,去掉不再使用的局部量。保留 _CheckFrameLocals 系列(fail-fast 断言,不是探针)。devfs.vp:删除 framebuffer_device.ioctl 内的两条 [fb0] ioctl 诊断打印与随之无用的 import viperlib;directory_count/file_count 恢复 static(跨模块读取点已随探针删除)。fat32_types.vp 的 winread FAIL / dir read failed 保留为正式错误上报(错误必须立即可见),未改动。
2026-10-16 20:45:40 +08:00
TermiNexus 4d0f29d533 fix(devfs): create_file 缺对象时直接失败,不再自建栈实例节点
把 files[] 改成指针数组后,else 分支的 new_file: devfs_file* = devfs_file() 暴露为栈实例逃逸,编译器以 LifetimeError 拦截(stack address escapes)。改为缺对象一律 return -1:设备节点必须由调用方以长寿命实例(模块级/堆)提供,不静默造占位对象。现有调用点(devfs_register_serial0/serial1/keyboard/mouse/fb0/desk)全部传对象,行为不变。
2026-10-16 20:34:02 +08:00
TermiNexus 441ea0c883 fix(devfs): files[] 改存指针,避免设备对象按值切片丢掉派生字段
现场:main.vp 探针读模块级 fb0_file 得 w=1360 h=768 pitch=5440(注册正确),而 explorer 侧 [fb0] ioctl 的 self 读得 w=0 h=0 pitch=0 fmt=0。IR 证据(devfs 编译单元 .text.ll 的 create_file):files[file_count] = *file_ptr 被生成成 llvm.load/llvm.store 整个 devfs_file 结构体(88 字节基类布局),派生字段 fb_phys/fb_size/fb_w/fb_h/fb_pitch/fb_format 从未被写入,保持 __init__ 的 memset 0;vptr 一并拷过去所以虚调用仍能进 framebuffer_device.ioctl,但读到的派生字段全是 0。这是对象切片而非编译器缺陷。

改法:files 由 [MAX_DEVICE_FILES]devfs_file 改为 devfs_file* 指针数组,create_file 只登记指针(设备对象由 devfs_register_* 以模块级实例持有,生命周期贯穿内核运行期);find_in_dir/list_in_dir 相应去掉取址;__init__ 的 memset 长度改为指针数组真实大小 8*MAX_DEVICE_FILES(原来按 devfs_file.__sizeof__() 清会越界清掉后面全局量)。顺带修好同样依赖派生字段的 /dev/desk(shm_device.shm_phys/shm_size)。
2026-10-16 20:32:12 +08:00
TermiNexus 35fc8b8ea8 chore(devfs): 临时探针 - fb0 ioctl 打印收到的 request/arg 与写入回读,定位 explorer fb 信息全 0
现场:explorer 打印 [explorer] fb 0x0 pitch=0 fmt=0 size=<垃圾> phys=0x130b90 —— 6 个字段里 3 个为 0、其余是残留,判定「这次 ioctl 没有真正写入用户缓冲」而非写错地址。两种可能:(a) syscall 派发把 request 传成别的值 ⇒ ioctl 直接 return -1;(b) 写入落在用户 VA 之外的地址空间。本探针在内核侧打印 fd/req/arg 与写入后回读的 w/h/pitch/fmt:若 req 不是 0x4600 ⇒ (a);若 req 正确且回读正常而 app 仍是残留 ⇒ (b)。app 侧应同时检查 ioctl 返回值(非 0 时绝不能用未写入的 info),下一步一并改。
2026-10-16 20:17:50 +08:00
TermiNexus 14011b1f2d fix(devfs): find_child/list_subdirs 的 dirp 漏了指针星号,导致 devfs_open 返回 -1
现场:devfs_register_* 之后 files[] 计数与名字全对、find_in_dir 正常,但 files[k].parent_dir 被写成 0x7d218(内核启动栈区 0x60000-0x80000),devfs_open(/dev/serial0) 一律 -1,用户态 app 因此建窗失败、起来就退。根因:devfs_directory.find_child 里 dirp 标注为值类型 devfs_directory 却赋 &directories[d](指针),list_subdirs 同样是这个 typo;编译器按值类型处理该变量,dirp.parent/dirp.name 读错位数据,return dirp 返回的是栈上残留值(0x7d218),偶然残留槽恰为 &directories[n] 时又看似正常(keyboard 的 0x135018 即此巧合),故表现为时对时错、多数错。改为 devfs_directory*(同文件其余 6 处 &directories[]/&files[] 本就带星号)。
2026-10-16 20:14:39 +08:00
TermiNexus 745c0e0b83 fix(devfs): directory_count/file_count 去掉 static,允许跨模块读取用于诊断
编译器报 NameError: drivers.devfs.devfs.directory_count is a static symbol, cross-module use is forbidden(static 仅定义模块内可见)。这两个只是注册计数,改为普通模块级变量即可让 main.vp 的临时探针读取;文件内原有的 global directory_count, file_count 声明语义不变。
2026-10-16 20:01:10 +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 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 0919a058a8 fix(vkernel): 预留内核 .bss 与栈区,修堆 arena 覆盖未预留内核内存
根因:bootloader 只按 kernel 文件大小 AllocatePages(.bss 不占文件),于是 .bss
尾部(ticks/_perf_* 等全局量)与主线程栈区(0x60000~0x80000)在 memmap 里仍是
EfiConventionalMemory,被内核 mm 的堆 arena 当作空闲内存占用 → 内核全局量被写坏、
堆元数据被反向破坏,最终桌面线程栈上的 va_list 被改坏,vsnprintf 读 %d 变参时
#GP(rip=0x130d45, err=0x0)。

- linker.ld: .bss 末尾加 LONG(0) 强制 PROGBITS,使 kernel.bin 的 FileSize 涵盖
  .bss,bootloader 的 PagesNeeded 得以预留整块内核镜像(含 .bss)
- mm.init: 新增 KernelAddr/KernelEnd,挑 arena 时把与内核镜像 [kernel_PhysAddr,
  __bss_end) 重叠的 region 起点抬到镜像末端(不整段丢弃)
- main.vp: 取 __bss_end 并传入 mm.init
- boot.c: ExitBootServices 前用 AllocatePages(AllocateAddress, EfiLoaderData)
  占位内核栈区 0x60000~0x80000,使其在 memmap 中标记已用

另含在途整理:多处补显式收窄转换(uint8()/uint16() 等)、kbd_svc 构造改为
kbd_svc.__init__() 等。
2026-10-14 12:54:43 +08:00
TermiNexus 5b4bab59cc chore(ViperOS): 合并落库内核侧在途改动并移除 vpsdk wiki 拷贝
VKernel / vpsdk / Apps / Libs 共 30 个源文件:内核与 SDK 侧的新语法适配及编译修正(含 bootinfo.vp / main.vp 位宽改 uint64、gfx.vp 前向引用改指针、devfs.vp 指针解引用赋值、elf.vp 跨模块函数取值等)。删除 vpsdk/wiki/*.md(14 文件,约 -8100 行):与仓库根 wiki 重复的拷贝,统一以根 wiki 为唯一来源。
2026-10-07 19:04:33 +08:00
TermiNexus dcb7c5c2c0 chore(ViperOS): 落库内核侧进行中的改动(26 文件,+1573/-1805)
内容由用户产出,本次仅代为提交、未做任何语义修改;含 static 修饰符前置迁移等(新增 static 前缀 16 行)。提交消息为中性描述——如需更精确的说明请 amend。
2026-09-28 15:24:52 +08:00
TermiNexus 5f5a119f06 fix(vkernel): schedule_int_transfer 的 toggle 形参改为值传递
schedule_int_transfer 第 6 形参原为 toggle_ptr: uint8*,却直接转发给 _td_set_token 的值形参 toggle: uint8,命中指针隐式转整数禁令(uhci.vp:160 CastError)。改为 toggle: uint8 值传递,四个调用点去掉取地址,buf 仍以 & 传。同时纳入工作区既有的指针语法迁移:t.CPtr 改 X*、c.Addr 改 &、c.Set(c.Deref(...)) 改 *p = v。
2026-09-27 15:05:37 +08:00
TermiNexus 2a54e2bafb 清理了 t.CVoid 2026-09-16 16:07:04 +08:00
TermiNexus a518f75b24 chore(vkernel): 重置基线 — 纳入 TPV codegen 修复配合的内核侧调整与既有工作区内容
- devfs.vp: string.split 传 PATH_BUFFER_SIZE(配合 split 新增容量参数)

- fat32_types.vp: lfn_extract 越界钳制(base+i > MAX_LFN 返回 -1)

- sheet.vp: gfx.Renderer 实参修正为 (fb, zb, w, h)(原单参导致 w/h=0 渲染空操作)

- 同批包含 VKernel 其余既有移植改动与 vpsdk/Apps/Libs 工作区内容
2026-09-11 14:27:01 +08:00
TermiNexus cd1cc915c5 修正了build.py,重置基线 2026-09-11 10:34:34 +08:00
TermiNexus c6a4063015 revert: devfs find 恢复 for i in result(编译器已实现 NULL 终止遍历语义) 2026-08-30 08:37:39 +08:00
TermiNexus 3b522927bb fix(kernel): devfs find 改 range(token) 遍历,修复全量遍历未初始化栈数组致 strcmp NULL 崩溃 2026-08-30 08:30:30 +08:00
TermiNexus 333adb090f fix(kernel): devfs last_slash/file_name 改用裸 str,修复 i8* 赋给 i8** 导致设备注册空名 2026-08-30 07:43:55 +08:00
TermiNexus 25d2628cd4 fix(fat32,devfs): c.Set 坏模式静默不写——lfn_extract/lfn_set_char 从未写入 LFN 缓冲,dir_find 长文件名匹配永远失败;devfs 键盘/鼠标 buffer 未写入;改 c.Set(c.Deref(ptr),val) 与下标赋值,并补 sfn 超 8 字符生成 ~1 短名;elf bad magic 加 hex dump 诊断 2026-08-27 00:32:54 +08:00
TermiNexus 20e7289c61 将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名 2026-07-30 16:34:26 +08:00