当我在VMWare Workstation虚拟机中运行的Windows 7 x64内核模式下运行以下程序集序列时:
xor eax, eax
mov ax, gs
mov gs, ax ; this instruction
最后一条mov gs, ax
指令立即导致虚拟机崩溃,并显示以下弹出消息:
发生故障,导致虚拟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
答案 0 :(得分:6)
我不确定mov gs,ax
的移动为什么会导致Windows立即出现三重故障,但是很快就会导致崩溃。在64位Windows内核中,GS段用作访问当前CPU的Processor Control Region(PCR)的指针。每个CPU都有不同的GS基值,指向不同的PCR。您的mov ax,gs
mov gs,ax
序列实际上打破了这一点,因为它将错误的GS base值加载到描述符缓存中。
GDT实际上没有包含GS寄存器的正确基数。由于GDT只能保存32位地址,因此实际上并未用于加载GS base。取而代之的是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]
这样的指令)并最终读取可能导致未预期内核的未映射内存,只是时间问题页面错误和崩溃。