From 79e9dfd5a490033b020452c33c0e1342901c1dce Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 14 Oct 2026 19:04:07 +0800 Subject: [PATCH] =?UTF-8?q?fix(vkernel/intr):=20ISR=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=90=8C=E6=97=B6=E6=8E=A5=E5=8F=97=20CS=3D0?= =?UTF-8?q?x2B=EF=BC=88sysretq=20=E9=80=89=E6=8B=A9=E5=AD=90=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E2=80=9C=E7=94=A8=E6=88=B7=E6=80=81=E4=B8=80?= =?UTF-8?q?=E8=A2=AB=E4=B8=AD=E6=96=AD=E5=B0=B1=20cli;hlt=20=E5=81=87?= =?UTF-8?q?=E6=AD=BB=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 现象:日志尾部只有 "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 项 --- VKernel/Kernel/intr/isr.s | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/VKernel/Kernel/intr/isr.s b/VKernel/Kernel/intr/isr.s index c4b5420..8284d3d 100644 --- a/VKernel/Kernel/intr/isr.s +++ b/VKernel/Kernel/intr/isr.s @@ -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