x86_64保护模式下加载GDT触发Qemu重启问题排查
解决x86_64保护模式下加载GDT触发三重故障的问题
核心问题:GDTR结构体顺序错误
你定义的Gdt结构体字段顺序完全颠倒了。x86架构中,lgdt指令加载的GDTR寄存器格式是先16位的GDT大小(字节数-1),再64位的GDT基地址,而你的代码把offset(基地址)放在了前面,size放在后面,导致lgdt加载了错误的GDT信息——相当于用基地址的低16位作为GDT大小,用错误的地址作为GDT基址,后续访问段寄存器时,段选择符对应的描述符要么不存在,要么属性无效,直接触发三重故障。
修正方案
调整Gdt结构体的字段顺序
把size放在前面,offset(基地址)放在后面,符合GDTR的规范:#[repr(C, packed)] pub struct Gdt { /// GDT的字节数 - 1 size: u16, offset: u64, }验证GDT描述符的有效性
确保你配置的GDT中:- 选择符
0x8对应的是可执行代码段描述符(P位=1,S位=1,类型位设置为可执行),权限DPL=0(内核级); - 选择符
0x10对应的是可读写数据段描述符(P位=1,S位=1,类型位设置为可读写),权限DPL=0; - 空描述符(第0项)必须保持全0,这是x86的硬性要求。
- 选择符
确认内联汇编的正确性
修正结构体后,原有的汇编逻辑(加载段寄存器、远返回刷新CS)是可行的,但要确保retf后执行的代码地址正确——rip + 2f的计算是对的,标号2:后的代码会在远返回后执行。
额外提示
- 即使TSS段为空,只要你没有加载TSS(
ltr指令),就不会影响当前流程,这部分确实不是问题根源; - 三重故障通常是连续触发两次保护模式故障导致的,核心原因都是GDT加载错误导致段访问无效,修正结构体顺序后大概率能解决问题。
内容的提问来源于stack exchange,提问作者Turambar
相关产品推荐
相关产品推荐

