diff --git a/VKernel/Kernel/sched/process.vp b/VKernel/Kernel/sched/process.vp index a215532..123baff 100644 --- a/VKernel/Kernel/sched/process.vp +++ b/VKernel/Kernel/sched/process.vp @@ -240,15 +240,16 @@ def drop_to_user_mode(entry: rawptr, user_rsp: uint64, kern_rsp: uint64): # syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu # syscall/ISR return does swapgs to restore GS_BASE = 0 # GS state is restored in isrCommonhandler before _yield() if needed. + # [FIX] Normalize GS to the user convention (GS_BASE = 0) before returning to ring 3. + # This thread may have been switched in from ANOTHER thread's user-mode timer interrupt: + # that path never runs the ISR exit swapgs, so GS_BASE is still the kernel view (pointing + # at the per-cpu struct). Running user code in that state makes the app's first syscall + # swapgs the wrong way; the kernel-stack lookup then reads garbage from linear address 8, + # the stack pointer becomes garbage, and even the page-fault frame cannot be pushed + # => triple fault with zero output (not even the ISR entry probe can fire). + # Swapgs only when GS_BASE != 0 (idempotent; same idiom as the handler's GS restore). __asm__(f"""cli mov rsp, {asminp(kern_rsp, ASM_DESCR.REG_ANY)} - # 【FIX】进用户态前必须把 GS 归一化到用户约定(GS_BASE=0): - # 本线程可能是**从别人的用户态定时器 ISR 里被切换过来的**(timer 路径不走 - # isrCommonhandler 的 GS 恢复,且线程切换后 ISR 出口的 swapgs 永远不会执行), - # 此时 GS_BASE 仍 = _per_cpu(内核视角)。带着这个状态跑用户代码 ⇒ app 第一条 - # syscall 再 swapgs 就反了 ⇒ mov rsp, gs:[0x8] 读到地址 0x8 的垃圾 ⇒ rsp 变 - # 垃圾 ⇒ push 时 #PF 连异常帧都压不进去 ⇒ 三重故障(QEMU 直接消失、零输出, - # 连 ISR 入口探针都照不到)。这里按 GS_BASE 是否为 0 决定是否 swapgs(幂等)。 mov ecx, 0xC0000101 rdmsr shl rdx, 32