50 Commits
Author SHA1 Message Date
TermiNexus 6f856992da feat: Linux ABI P0-P6, BMIDE DMA, ImageSee, 4KiB page pool and Explorer hardening 2026-10-29 00:42:21 +08:00
TermiNexus 585d3a8215 feat(font): add Brotli/WOFF2 and TrueType text rendering
- vpsdk/brotli: Brotli decoder with the static dictionary
- vpsdk/fonttools: TTF/WOFF2 loading, cmap, glyf/composite glyphs and
  anti-aliased rasterization
- Apps/FontDemo: render 你好,世界 from a fixed font path
- autostart FontDemo and copy the Brotli dictionary into disk/libs
- build with the fixed ViperC compiler that zero-extends unsigned types
2026-10-27 20:26:05 +08:00
TermiNexus 7e0aa5c7af feat(acpi): power off via the ACPI FADT
Pass the firmware ACPI RSDP through boot_info so the kernel can locate
the FADT. Shutdown now writes the S5 sleep type to the PM1a/PM1b control
blocks advertised by the FADT instead of fixed QEMU/Bochs/VirtualBox
ports.

- boot: capture the ACPI 2.0/1.0 RSDP from the UEFI configuration table
- kernel: add platform/acpi; walk RSDP -> RSDT/XSDT -> FADT
- syscall: power_shutdown calls acpi.poweroff()
2026-10-27 17:05:05 +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 844fbff31c fix(kernel,explorer): 内核不再画屏消除残留;CREATE 打印 style 诊断
蓝色残留根因:main.vp 里 VGA_drv.Print 在 __init__ 尾部执行,而它晚于 app spawn —— explorer 已经把桌面画上去了,内核随后又往 framebuffer 打一行测试文本/清屏,于是永远盖在桌面上(整屏刷一次也救不了,因为之后又被画)。S3e 之后屏幕由 explorer 独占合成,直接删除内核侧 VGA 驱动创建与 Print。另:handle_request 的 CREATE 分支加一条诊断打印(style/w/h),用于确认 style 是否真的透传到 explorer —— 5 条日志,定位后撤。
2026-10-17 11:03:05 +08:00
TermiNexus 2dacfa85fb fix(input): 启用 PS/2 鼠标初始化,桌面鼠标通路恢复
main.vp 里 mouse.init() 一直被注释,而 services/mouse.vp 的 start() 只做 USB 鼠标初始化 ⇒ PS/2 鼠标的 IRQ12 从未注册、采样率与数据上报从未使能。表现是 explorer 能 open /dev/input/mouse(fd=3)却永远收不到事件,桌面有键盘无鼠标。恢复调用。
2026-10-16 20:51:01 +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 3c595527bc test(fb0): 注册后立刻回读设备对象字段的临时探针
区分两种真因:devfs_register_fb0 传参即为 0,还是注册正确后设备对象字段被踩成 0。_CheckFrameLocals 只校验 __init__ 的长寿命局部量,管不到设备对象里的字段,因此补一条紧跟注册之后的回读探针,与 explorer 侧 [fb0] ioctl 的 w/h 对读即可定位
2026-10-16 20:23:58 +08:00
TermiNexus 0fd1bf7567 fix(fb0): 几何登记为 0 + FbInfo 按值返回只回传一半 —— explorer 拿不到 framebuffer 几何
现场(serial.log 330-339):[fb0] ioctl fd=6 req=0x4600 arg=0x7fffffdffb78 w=0 h=0 ⇒ request 与 arg 传递都正常、写入回读也正常,真正的问题是设备对象里的 fb_w/fb_h/fb_pitch/fb_format/fb_phys/fb_size 全为 0;随后 explorer 以 pitch=0 调 mmap 失败退出。两个独立缺陷:① 内核侧——devfs_register_fb0 收到的是被清零的 width/height/pitch/fb_format/fb_size(main.vp 顶部注释记录的"__init__ 的 fb/width/height/pitch 局部量被偶发写坏"同类问题:这些长寿命局部量在 L121 之后、L304 之前被写坏,而 L366+ 的 _CheckFrameLocals 又不报,属时点相关),改为在调用点直接从 BootInfo 重取几何并补一条 _CheckFrameLocals(pre_devfs_fb0);② SDK 侧——fb_get_info 按值返回 32 字节 FbInfo,现场表现为只有前 16 字节有效、后 16 字节是调用方栈残留(size=1802724708 phys=0x130c30),改为出参 out + 返回 ioctl 返回码;③ explorer 侧改为判返回码与 pitch/size 非 0,失败即 _dbg 说明原因后 fail-fast 退出,不再带着 0 几何继续。
2026-10-16 20:20:36 +08:00
TermiNexus 9469ee8b4d chore(main): 临时探针 - 打印 devfs 注册计数/files[] 名字/直接 find_in_dir,三分 devfs_open=-1 的成因
devfs_open(/dev/serial0) 在仅注册 serial0/serial1/keyboard/mouse 之后就是 -1,且对象布局已由 MLIR 证明正确(vptr 在偏移 0、files[32] 按值数组、create_file 的路径切分与整份拷贝写法正确)。故加三条探针:注册后打印 directory_count/file_count、逐个打印 files[k].name/private_data/parent_dir、并用 files[0].parent_dir 直接调 find_in_dir(serial0)。判读:counts=0 或名字空 ⇒ 注册没落表;名字正常而 find_in_dir 返回 None ⇒ 名字比较路径坏;两者都正常而 devfs_open 仍 -1 ⇒ 封装层路径切分/返回值问题。
2026-10-16 19:59:47 +08:00
TermiNexus 887736d397 chore(main): 临时 bisect 探针 —— 在注册 fb0/desk 之前也查一次 devfs serial0
上一条探针已否掉重叠假设:desk shm=0xa781000(8MB)与 devfs_files=0x135140 / devfs_dirs=0x134cb0 相距极远,不重叠。本次再补一条 before 探针:若 “before fb/desk” 那行 fd>=0 而之后那行 fd=-1,即证明是本轮新增的 fb0/desk 注册把 devfs 表搞坏;若两行都 -1,则问题在更早(注册顺序/serial0 本身)。
2026-10-16 19:44:13 +08:00
TermiNexus 7f071b495a chore(main): 临时量出 desk 共享区与 devfs 注册表地址,验证 mm 是否把堆分到内核 .bss 上
MLIR 已排除编译器布局问题:devfs_file = (ptr, array<64xi8>, ptr, ptr)(vptr 在 0、基类字段在前)、framebuffer_device 在其后追加 6 个字段、files[32] 按值数组 —— 全对、无重叠。于是头号嫌疑转为:devfs_register_desk 里那块 8MB mm.malloc 与内核 .bss(devfs 的 directories/files/directory_count/file_count)重叠,把注册表踩掉 ⇒ devfs_open 查不到设备 ⇒ fd=-1(且 serial0_open 不会被调、无 [serial0] open: 打印)。本探针打印 desk shm 地址/size 与 devfs_files/devfs_dirs 地址,一眼可判重叠。定位后连同上一探针一并删除。
2026-10-16 19:42:30 +08:00
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 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 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 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 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 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 14e69f62f5 fix(vkernel): 不再 unmount 根文件系统,app 运行期才能读盘
- app 是 spawn 之后异步运行的,运行期仍要 fat32.open(load_so / 资产文件);原来在自动启动块后面立刻 fat32.unmount(),导致 app 第一次 LOAD_SO 就 "[so] failed to open file"

- 该 unmount 原本只为防“破坏性 FAT32 测试”改坏 disk.img,而那些测试已删除,留着只剩切断 app 文件访问的副作用

- 卸载能力保留给非根挂载点(U 盘/多分区),将来配挂载点表 + 引用计数
2026-10-14 18:42:24 +08:00
TermiNexus 077a150c92 feat(vkernel): 还原 elf 自启动(spawn 四个 app + slog.so 冒烟调用),改写为新语法
- 初版 6813947 的 main.py 在 FAT32 挂载后、破坏性测试前 spawn hello/terminal/gargantua/scene3d 并加载 slog.so 调 log_info;此前为排查内核概率性崩溃被 [DIAG]“app autostart disabled”禁用,现按要求还原

- 新语法改写:c.Addr(x) -> &x;t.CArray[t.CChar,N] -> [N]char;t.CInt -> int;t.CVoid|t.CPtr -> rawptr;c.Asm/c.AsmInp -> __asm__/asminp(调用符号用 intr/syscall.vp SO_CALL1 同款:rdi 传首参 + call 符号地址);字符串常量 -> const str

- 打印统一 [64]char + viperlib.snprintf + serial.puts(&buf),与同文件既有写法一致
2026-10-14 18:25:45 +08:00
TermiNexus a44f55574c fix(vkernel): 鼠标“飞”与刷屏性能 —— 帧缓冲改回写映射 + 鼠标驱动丢弃溢出包/细化分辨率
方案 A(帧缓冲映射):
- 去掉帧缓冲的 PTE_PCD,改为回写映射。原先非缓存映射下每次写屏直通设备,大块刷新极慢;
  QEMU 下回写显示正确(TCG 不模拟缓存不一致),真机严格正确应改 write-combining(PAT),
  已在代码注释里写明。
- 说明:“只刷脏行”本已是现状(_mark_rows_dirty 按区域标脏,全屏刷仅启动那一次)。

方案 C(鼠标驱动加固,drivers/input/mouse/mouse.vp):
- irq_handler 丢弃带 X/Y overflow 位(bit6/bit7)的包:此时设备给的是饱和值,直接采用
  会产生 ±127 级跳变,表现为光标“飞”。
- init 中在 0xF6(Set Defaults) 之后用 0xE8/0x03 把分辨率设为 8 counts/mm,避免默认最粗的
  4 counts/mm 造成每计数位移偏大。
2026-10-14 15:05:02 +08:00
TermiNexus c0c83cdc83 feat(vkernel): __init__ 帧参数加影子副本校验(fail-fast 抓偶发写坏源)
fb/width/height/pitch 局部量曾被偶发清零(→ desktop.start 拿到 fb=0 → 刷新把后备缓冲
写到物理 0 起、覆盖内核自身而卡死/崩宿主 QEMU)。USB/UHCI 路径已排查:TD 块走堆分配、
QH 在 free 前置 terminate、枚举缓冲均为堆分配且长度有钳制,未见明显越界零写。

故加常驻轻量校验(非临时探针,可长期保留):
- _SetFrameShadow:BootInfo 读取后保存影子
- _CheckFrameLocals:在 after_usb / after_vga / pre_desktop 三处比对,不一致即打印
  [FATAL](含期望值与实际值)并停机 —— 把“偶发写坏”变成可定位的现场,
  并明确是哪一个阶段之间被写坏。
2026-10-14 14:56:26 +08:00
TermiNexus b6cc64a5c9 chore(vkernel): 移除本轮排查加的全部临时诊断探针,并把 fb 为空改为 fail-fast
现象已定位清楚:fb=0 时刷新会把后备缓冲写到物理 0 起,覆盖 IVT/BDA + 低端内存 +
内核镜像自身(边跑边改坏自己正在执行的代码 → 卡死;宿主 QEMU abort 0x40000015)。
本轮实测 fb/pitch 正确时桌面渲染正常、[perf] 数值单调(.bss/中断那条线的修复生效)。

清理内容:
- main.vp:删除 _WhProbe 探针函数与 7 处调用、2 处 mm.DumpBuddy() 调用
- desktop.vp:删除 [rc] 阶段面包屑 7 处、[rc] preflush 转储、[dt] 每秒心跳、[dst] 入口探针
- mm.vp:删除已无调用点的 DumpBuddy()(保留 3 条 malloc 失败诊断——它们是错误信息,非调试噪音)

新增(fail-fast,替代静默兜底):
- desktop.start:fb_ptr == 0 时打印 FATAL 并停机,杜绝“刷新把内核自己写掉”这类灾难
- _render:脏行行界夹取保留(越界会静默写穿帧缓冲),但这是防破坏下限,非修复
2026-10-14 14:52:56 +08:00
TermiNexus d58833d3b5 diag(vkernel): 增加 post_vga / pre_start 探针,夹出 fb/pitch 被清零的位置
[rc] preflush 显示 fb=0x0(帧缓冲指针为 NULL),[dst] entry 显示 pitch=0:
刷新循环把 8MB 后备缓冲写到物理 0x0 起 —— 覆盖 IVT/BDA + 低端内存 + 内核镜像自身
(0x100000 起),边跑边覆盖正在执行的代码 → 卡死;QEMU 因客户机跑飞
abort(0x40000015 = STATUS_FATAL_APP_EXIT)。

VGA 文本(315-317 行)用同一组 fb/pitch 画出来是正常的,说明清零发生在
317 行之后、323 行 desktop.start 之前。故加两条探针把元凶夹死:
  _WhProbe("post_vga",  uint32(fb), pitch)   # 317 行后
  _WhProbe("pre_start", uint32(fb), pitch)   # 323 行前
若 post_vga 正常而 pre_start 为 0,元凶即这三条之一:
serial.puts("你好") / serial.puts("[main] starting desktop") / _WhProbe("pre_desktop")。
2026-10-14 14:47:53 +08:00
TermiNexus 38ccc9cdf6 diag(vkernel): main __init__ 插 width/height 探针,定位局部槽被清零的阶段
“[desktop] dirty_rows/back_fb malloc FAILED”的实质是 width/height 被随机清零:
malloc(0) 直接返回 NULL;伙伴系统经 DumpBuddy 实测健康(free≈160MB,order 3/5..12/15 有块)。
ISR 不保存 rax/rcx/r8-r11 的问题已修(0c63969),但现象仍在 → 主线程栈另有写坏源。

在 __init__ 的 5 个阶段打印 w/h(decl → pre_pg → post_mm → pre_usb → pre_desktop),
二分出被写坏的区间;定位到具体调用后,连探针一起移除。
2026-10-14 13:50:48 +08:00
TermiNexus 54e88ce957 feat(build): 额外链接带符号 kernel.elf;mm 增加 DumpBuddy 诊断
- build.py: 用同一批 .obj + 同一 linker.ld 再链一份
  VKernel/__vpcbuild__/output/kernel.elf(仅去掉 --oformat binary/--strip-all),
  段布局与 kernel.bin 一致 → 可把日志里的 rip 用 objdump/nm 映射回函数
- mm.vp: 新增 export DumpBuddy(),打印 arena start/end 与 total/used/free
  及各阶空闲链表首块(上限 8 个),定位分配失败是“链表空”还是“块指针坏”
- main.vp: mm.init 之后、desktop.start 之前各调一次 DumpBuddy(),
  用于排查“[desktop] dirty_rows malloc FAILED”
  (768B → ≤SLAB_THRESHOLD → slab size class 5(1024B) → _create_page 需 order≥1 伙伴块)
2026-10-14 13:27:40 +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 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 2a03330a9d fix(kernel): 分裂 2MB 大页使 .rodata 真正只读,加页表与格式串校验诊断并禁用 App 自动启动 2026-08-30 07:27:45 +08:00
TermiNexus 04ca2d4c5b fix(kernel): .rodata 映射只读 + CR0.WP=1,越界写立即 #PF 暴露写源
此前清 WP + 页表全可写,越界写 .rodata 字符串常量静默破坏(格式串 %lu 变 %lc、路径/符号名损坏连锁 → work=+/eyboard/terminal.elf 加载失败)。ProtectKernelRO 经 c.Asm 引用 __rodata_start/__rodata_end 清 PTE_WRITABLE,配合 CR0.WP 置位,越界写触发 #PF 打印 cr2/rip。
2026-08-29 17:34:41 +08:00
TermiNexus d0b512f159 debug(elf,main): 打印 read_len 与 spawn_elf 返回 pid 实际值——fat32.read 内部 br=64 但 load_elf 收到 <64、spawn ret pid=1 但 main 收到 0,定位跨模块返回值间歇性丢失 2026-08-27 01:08:37 +08:00
TermiNexus 61208676c6 fix(main): _start 加 stackrealign,修复变参函数 movaps #GP
根因链:_start 由 bootloader jmp 进入(rsp≡0 mod 16),编译器/llc 按 call
约定对齐函数帧(假设入口 rsp≡8 mod 16)→ 帧整体偏 8 → _start 内所有调用
rsp≡8 mod 16 → __init__ 的 float 变参调用(snprintf %.2f 保存 xmm)movaps
#GP(cr4.OSFXSR 已启用、地址 16 对齐仍 #GP 正是此因)。

加 t.attr.stackrealign 使 _start 序言动态重对齐栈,与入口约定无关。
2026-08-26 20:18:09 +08:00
TermiNexus 7b084803f5 fix(cpu): 启动早期启用 SSE/FPU,修复 movaps #GP
faulting RSP=0x7d760 16 对齐证明非栈对齐问题,movaps #GP(err=0) 真因是 CR4.OSFXSR 未置位(SSE 未启用)。OVMF 启动后 SSE 默认关闭,变参函数传 float/double 保存 xmm 寄存器时触发。新增 cpu.enable_sse(CR0 清 EM 置 MP + CR4 OSFXSR|OSXMMEXCPT + fninit),main.vp __init__ 开头调用。
2026-08-26 19:36:50 +08:00
TermiNexus 530c85d6a4 fix(main): 移除 BootInfo 局部重声明,修复 memmap 全 0
根因:BootInfo: t.CPtr = self.BootInfo(函数内注解重声明全局名)触发编译器
bug——局部 alloca 创建但从不写入(赋值落全局 @BootInfo),后续 BootInfo.X 读
未初始化局部 → 全 0 → mm.init 收 addr=0/size=0/desc=0 → 走 CMOS fallback →
读到 0xFF → size≈4GB → buddy 分配假内存 → 线程栈 4GB → #PF PANIC。

BootInfo 原始字节转储证实 bootloader 传参正确(mmap=0xde20d60 size=4800
desc=48 fb=0x80000000),纯内核读错。直接使用 global BootInfo 修复。

编译器 bug(注解局部重声明全局名赋值落全局)待 TransPyV 单独修复。
2026-08-26 19:26:50 +08:00
TermiNexus 87d4e359d8 debug(main): 转储 BootInfo 地址处原始 88 字节
BootInfo=0xde20d00 非 NULL 但字段全 0。转储该地址原始字节,区分内存确实全 0
(bootloader 写入未生效/重定位缺失)还是内核读错偏移(布局不匹配)。
2026-08-26 19:23:30 +08:00
TermiNexus 963e0ed53f debug(main): 打印 BootInfo 指针与 memmap 原始字段
mm.init 收到 addr=0 size=0 desc=0(全部为 0),可能是全局 BootInfo 为 NULL
(读物理 0-24 全 0)或 bootloader 传参异常。mm.init 前打印 BootInfo 指针
本身与 MemmapAddr/MemmapSize/MemmapDescSize/framebuffer_addr 原始值。
2026-08-26 19:17:58 +08:00
TermiNexus 3995cb9545 debug(timer): 门32读回+软int0x20+PIC ISR,一次性区分中断分发路径
LAPIC 配置已确认正常(base/ver/svr/lint0 全部读回正确)但硬件中断仍不达。
新增三段诊断:1) 读回 IDT 门 32 的 base/sel/type;2) 软件 int 0x20 验证
分发路径(门有效→H+返回,门无效→[GP] err=0x20);3) 读 PIC1 ISR 确认
PIT IRQ0 是否真正到达 PIC 并被响应。
2026-08-26 18:42:58 +08:00
TermiNexus ee329c313f fix(apic): early_init 改用 IA32_APIC_BASE EN 位判断,避免 cpuid 误判跳过 init
lint0 读回 0x0(QEMU 复位默认 0x10000)说明此前读的是 RAM,_lapic_base 为 0,
init() 很可能未执行。msr_read 已在前置流程验证可用,改按 MSR bit11 判断更可靠。
main.vp 增补综合诊断:打印 base/version/svr/lint0 重写读回/特性位,一次性区分
init 未执行、MMIO 映射失效、写不粘三种假设。
2026-08-26 18:39:07 +08:00
TermiNexus 9ff53aa1fa debug(apic): 读回 LINT0 与 APIC BASE MSR,验证 EXTINT 配置是否生效
PIT 正常(cnt=1109)但中断不送达。读回验证:
- lint0=0x700 → EXTINT 未屏蔽(正确);0x10700 → 被屏蔽;其它 → 写入失败
- apic_base_msr bit11 → APIC 使能状态
用后移除。
2026-08-26 18:32:21 +08:00
TermiNexus f675540c64 chore(boot): 移除全部中断排查诊断(int20 测试 + T/[T]/D 打印)
定时中断已确认恢复(APIC LINT0=EXTINT)。移除 int 0x20 软件触发测试与
isr32_handler 'T'、timer_handler '[T]'、isr_default 'D' 打印,回归干净
内核,定位 sti 后新出现的 #GP(疑似 int 0x20 测试触发)。
2026-08-26 18:19:41 +08:00
TermiNexus 3c163a5936 debug(boot): sti 后软件触发 int 0x20,二分定位中断不送达
APIC LINT0=EXTINT 已配置但仍无定时中断。加 int 0x20(向量 32)软件触发:
- 有 T → IDT gate 32 正常,问题在 PIT/PIC 硬件送达
- 无 T → IDT/lidt 问题
用后移除。
2026-08-26 18:16:09 +08:00
TermiNexus 9ec3627a5a fix(boot): 启用 apic.early_init,配置 LINT0=EXTINT 恢复 PIC 定时中断
QEMU/OVMF(UEFI)下本地 APIC 已启用,PIC 外部中断须经 LAPIC LINT0 送达
CPU。apic.init() 将 LINT0 配为 EXTINT(取消屏蔽);此前 early_init 被注释,
LINT0 保持未配置/屏蔽 → 定时器中断被 APIC 吞掉 → sti 后 timer_msleep 等
不到 ticks 永远挂死(serial.log 停在 "sti done",T/D 诊断均无输出)。
2026-08-26 18:14:29 +08:00
TermiNexus 49d074e487 通过插件的静态推导修复了一些错误 2026-07-30 17:28:27 +08:00
TermiNexus 20e7289c61 将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名 2026-07-30 16:34:26 +08:00