fix(vkernel/intr): ISR 用户返回同时接受 CS=0x2B(sysretq 选择子),修“用户态一被中断就 cli;hlt 假死”

- 现象:日志尾部只有 "B 2B 23",随后整机假死(QEMU 窗口消失、没有 dump)

- 根因:isr\num\()_ret_user 硬编码校验 CS==0x1B;但 app 只要发过一次 syscall,返回走 sysretq 后 CS 就是 STAR[63:48]=0x1B 算出的 0x2B(SS=0x23)→ 之后任何用户态中断/异常(例如定时器抢占)都被判“坏 CS/SS” → 走 cli;hlt 死循环,既假死又掩盖真实异常现场

- 现在同时接受 0x1B 与 0x2B(SS 仍须 0x23);注释里记录 GDT/STAR 隐患:0x2B 当前指向 GDT 第 5 项,而那里是 TSS(QEMU 不校验 SYSRET 目标描述符类型才没暴露),根治需把用户代码段挪到第 5 项
This commit is contained in:
TermiNexus committed 2026-10-14 19:04:07 +08:00
1 parent c232c0c0d5
commit 79e9dfd5a4
1 file changed
+12 -2
+12 -2
View File
@@ -189,10 +189,20 @@ isr\num\()_ret_user:
mov al, 0x4E # 'N' marker = NT was set (now cleared)
out dx, al
1:
cmp r9, 0x1B
jne 8f
# 用户态 CS 必须同时接受两个值(本内核两条入口路径给的不一样):
# 0x1B — drop_to_user_mode 首次 iretq 进用户态时压的 CS(= USER_CODE_SEG 0x18 | RPL3)
# 0x2B — syscall 返回走 sysretq:STAR[63:48]=0x1B ⇒ 硬件算 CS=+16=0x2B、SS=+8=0x23
# 原来只认 0x1B:app 只要发过一次 syscall,之后任何用户态**中断/异常**(例如定时器抢占)
# 都被判“坏 CS/SS”,打印 "B 2B 23" 后 cli;hlt 死机 —— 既假死,又掩盖真正的用户态异常现场。
# (另注:0x2B 指向 GDT 第 5 项,见 gdt.vp —— 那里目前放的是 TSS,属于 GDT/STAR 布局的
# 隐患,QEMU 不校验 SYSRET 的目标描述符类型才没暴露;要根治需把用户代码段挪到第 5 项。)
cmp r11, 0x23
jne 8f
cmp r9, 0x1B
je 6f
cmp r9, 0x2B
jne 8f
6:
push r11 # SS
push rax # RSP
push r10 # RFLAGS