在长模式下更改 GDT 并更新 CS
Change GDT and update CS while in long mode
我正在编写一个简单的自制 64 位 OS,通过 UEFI 启动它。这意味着当我的代码开始执行时,它已经处于长模式,并启用了分页。
现在,退出 UEFI 引导服务后,我想用我自己的替换 UEFI 构建的所有控制结构。
成功更改CR3(分页结构)的内容后,我使用lgdt
成功加载了一个新的GDT。
现在的问题是,要正确使用这个新的 GDT,我需要将一个新值移动到 CS 中。我在网上找到了很多关于从 32 位切换到 64 位时如何做到这一点的教程,但几乎没有关于长模式到长模式的教程。
我想我应该使用远跳,但我没能用这段代码(AT&T 语法)做到这一点:
mov %rax, %cr3 # load paging structures (it works)
lgdt 6(%rcx) # load gdt (it works)
mov 0, %rsp # update stack pointer (it works)
# now what I tried unsuccessfully:
pushw # new code segment selector
pushq fun # function to execute next
retfq # far return (pops address and code segment)
没有任何 IDT,此代码在 retfq
.
出现三重故障
编辑:我检查了我的分页结构,我很确定它们不是问题的原因。事实上,代码在没有最后三个指令的情况下运行良好。问题是我需要一种更新 CS 的方法,在我的代码中它仍然指的是 UEFI 构建的旧段。 retfq
是这样做的正确方法吗?或者我应该使用哪个其他指令?
提前致谢。
看起来主要问题是一个简单的错字。在 at&t 语法中 pushq fun
和 pushq $fun
的意思非常不同,前者将内存中的 8 个字节压入地址 fun
而后者压入 fun
的地址(假设它适合转换为 32 位符号扩展立即数)。
也就是说,lretq
还希望选择器是一个完整的 8 字节 qword,所以 pushw
应该 pushq
。只要额外的 6 个字节可读,字大小的推送仍然有效,但它会使堆栈不平衡。如果您重新加载堆栈指针,这可能无关紧要。
避免上述所有陷阱的替代代码可能如下所示:
sub , %rsp
movq , 8(%rsp)
movabsq $fun, %rax
mov %rax, (%rsp)
lretq
我正在编写一个简单的自制 64 位 OS,通过 UEFI 启动它。这意味着当我的代码开始执行时,它已经处于长模式,并启用了分页。
现在,退出 UEFI 引导服务后,我想用我自己的替换 UEFI 构建的所有控制结构。
成功更改CR3(分页结构)的内容后,我使用lgdt
成功加载了一个新的GDT。
现在的问题是,要正确使用这个新的 GDT,我需要将一个新值移动到 CS 中。我在网上找到了很多关于从 32 位切换到 64 位时如何做到这一点的教程,但几乎没有关于长模式到长模式的教程。
我想我应该使用远跳,但我没能用这段代码(AT&T 语法)做到这一点:
mov %rax, %cr3 # load paging structures (it works)
lgdt 6(%rcx) # load gdt (it works)
mov 0, %rsp # update stack pointer (it works)
# now what I tried unsuccessfully:
pushw # new code segment selector
pushq fun # function to execute next
retfq # far return (pops address and code segment)
没有任何 IDT,此代码在 retfq
.
编辑:我检查了我的分页结构,我很确定它们不是问题的原因。事实上,代码在没有最后三个指令的情况下运行良好。问题是我需要一种更新 CS 的方法,在我的代码中它仍然指的是 UEFI 构建的旧段。 retfq
是这样做的正确方法吗?或者我应该使用哪个其他指令?
提前致谢。
看起来主要问题是一个简单的错字。在 at&t 语法中 pushq fun
和 pushq $fun
的意思非常不同,前者将内存中的 8 个字节压入地址 fun
而后者压入 fun
的地址(假设它适合转换为 32 位符号扩展立即数)。
也就是说,lretq
还希望选择器是一个完整的 8 字节 qword,所以 pushw
应该 pushq
。只要额外的 6 个字节可读,字大小的推送仍然有效,但它会使堆栈不平衡。如果您重新加载堆栈指针,这可能无关紧要。
避免上述所有陷阱的替代代码可能如下所示:
sub , %rsp
movq , 8(%rsp)
movabsq $fun, %rax
mov %rax, (%rsp)
lretq