为什么这个 mov gs 指令会导致 VMWare Workstation guest 运行 Windows 7 OS 出现故障?
Why this mov gs instruction causes a fault in VMWare Workstation guest running Windows 7 OS?
当我在 VMWare Workstation 虚拟机中 运行 在 Windows 7 x64 运行ning 内核模式下执行以下汇编序列时:
xor eax, eax
mov ax, gs
mov gs, ax ; this instruction
最后的 mov gs, ax
指令立即导致 VM 崩溃(或可能是错误检查),并显示以下弹出消息:
A fault has occurred causing a virtual CPU to enter the shutdown
state. If this fault had occurred outside of a virtual machine, it
would have caused the physical machine to restart. The shutdown state
can be reached by incorrectly configuring the virtual machine, a bug
in the guest operating system, or a problem in 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
我不确定为什么移动 mov gs,ax
会导致 Windows 立即出现三重错误,但很快就会导致它崩溃。在 64 位 Windows 内核中,GS 段用作访问当前 CPU 的 Processor Control Region (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]
之类的指令)并最终读取可能未映射的内存只是时间问题导致意外的内核页面错误和崩溃。
当我在 VMWare Workstation 虚拟机中 运行 在 Windows 7 x64 运行ning 内核模式下执行以下汇编序列时:
xor eax, eax
mov ax, gs
mov gs, ax ; this instruction
最后的 mov gs, ax
指令立即导致 VM 崩溃(或可能是错误检查),并显示以下弹出消息:
A fault has occurred causing a virtual CPU to enter the shutdown state. If this fault had occurred outside of a virtual machine, it would have caused the physical machine to restart. The shutdown state can be reached by incorrectly configuring the virtual machine, a bug in the guest operating system, or a problem in 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
我不确定为什么移动 mov gs,ax
会导致 Windows 立即出现三重错误,但很快就会导致它崩溃。在 64 位 Windows 内核中,GS 段用作访问当前 CPU 的 Processor Control Region (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]
之类的指令)并最终读取可能未映射的内存只是时间问题导致意外的内核页面错误和崩溃。