首页 > 解决方案 > 为什么这条 mov gs 指令会导致运行 Windows 7 操作系统的 VMWare Workstation 来宾出现故障?

问题描述

当我在 VMWare Workstation 虚拟机中运行的 Windows 7 x64 内核模式下运行以下汇编序列时:

xor eax, eax
mov ax, gs
mov gs, ax     ; this instruction

在此处输入图像描述

最后一条mov gs, ax指令立即导致该 VM 崩溃(或可能是错误检查),并显示以下弹出消息:

在此处输入图像描述

发生故障,导致虚拟 CPU 进入关闭状态。如果此故障发生在虚拟机之外,则会导致物理机重新启动。错误配置虚拟机、客户操作系统中的错误或 VMWare Workstation 中的问题可能会导致关闭状态。

重新加载gs寄存器是否会导致内核出现问题,还是虚拟化问题?

mov我在英特尔手册中没有看到关于该指令的任何异常。

PS。顺便说一句,将gs寄存器替换为fs不会导致此故障。


编辑:回答有关 GDT 中段描述符状态的问题。这里是:

0: kd> r gs
gs=002b
0: kd> dg 28
                                                    P Si Gr Pr Lo
Sel        Base              Limit          Type    l ze an es ng Flags
---- ----------------- ----------------- ---------- - -- -- -- -- --------
0028 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3

标签: assemblykernelvmwarevirtualizationwindows-kernel

解决方案


我不确定为什么此举mov gs,ax会导致 Windows 立即出现三倍故障,但很快就会导致它崩溃。在 64 位 Windows 内核中,GS 段用作访问当前 CPU 的处理器控制区域(PCR) 的指针。每个 CPU 都有不同的 GS 基值,指向不同的 PCR。您的mov ax,gs mov gs,ax序列实际上破坏了这一点,因为它将 GS 基的错误值加载到描述符缓存中。

GDT 实际上并不包含 GS 寄存器的正确基数。由于 GDT 只能保存 32 位地址,因此它实际上并不用于加载 GS 基址。相反,IA32_GS_BASE 和 IA32_KERNEL_GS_BASE MSR(后者与 SWAPGS 指令结合使用)用于为 GS 段设置 64 位基址。存储在 GS 寄存器中的选择器值只是一个虚拟值。

因此,您的mov gs,ax指令加载存储在 GDT 中的虚拟 32 位基值,而不是存储在 IA32_GS_BASE 中的 64 位值。这意味着 GS 段的基地址设置为 0,而不是当前 CPU 的 PCR 地址。在加载这个不正确的 GS 基础之后,Windows 内核尝试使用 GS 寄存器访问 PCR(使用类似指令mov rax, gs:[10])并最终读取可能未映射的内存,从而导致意外的内核页面错误和崩溃只是时间问题。


推荐阅读