fix(vkernel): 进用户态前归一化 GS_BASE,修线程从用户态定时器 ISR 切出后 GS 状态错乱导致的三重故障
根因:线程可能是在**别人的用户态定时器 ISR 里**被 _yield 切过来的(timer 路径不经 isrCommonhandler 的 GS 恢复,且切换后 ISR 出口的 swapgs 永不执行),此时 GS_BASE 仍 = _per_cpu。带着这个状态跑用户代码 ⇒ app 第一条 syscall 再 swapgs 就反了 ⇒ mov rsp,gs:[0x8] 读到地址 0x8 的垃圾 ⇒ rsp 变垃圾 ⇒ push 触发 #PF 时异常帧也压不进去 ⇒ 三重故障(QEMU 消失、零输出、ISR 入口探针都照不到)。现场:pid=1(Terminal) 正常、pid=2 起静默三崩。修复:drop_to_user_mode 在 iretq 前按 GS_BASE 是否为 0 决定是否 swapgs(幂等),保证用户代码一律以 GS_BASE=0 运行。
This commit is contained in:
1 parent
ee29ce37d1
commit
1f2faf0db8
1 file changed
+15
@@ -242,6 +242,21 @@ def drop_to_user_mode(entry: rawptr, user_rsp: uint64, kern_rsp: uint64):
|
||||
# GS state is restored in isrCommonhandler before _yield() if needed.
|
||||
__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
|
||||
or rax, rdx
|
||||
test rax, rax
|
||||
jz 1f
|
||||
swapgs
|
||||
1:
|
||||
mov rdx, {asminp(user_rsp, ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {asminp(entry, ASM_DESCR.REG_ANY)}
|
||||
mov r11, 0x202
|
||||
|
||||
Reference in new issue
Block a user