我正在编写一个简单的自制64位OS,并通过UEFI进行引导。这意味着当我的代码开始执行时,它已经处于long模式,并且启用了分页。
现在,退出UEFI引导服务后,我想用我自己的UEFI构建所有控制结构。
成功更改CR3(分页结构)的内容后,我使用成功加载了新的GDT lgdt。
问题在于,现在,要正确使用此新GDT,我需要将新值移至CS中。在网上,我找到了许多有关如何从32位切换到64位的方法的教程,但是从长模式到长模式几乎一无所获。
我想我应该跳个很远的距离,但是我没有用以下代码(AT&T语法)来做到这一点:
mov %rax, %cr3 # load paging structures (it works)
lgdt 6(%rcx) # load gdt (it works)
mov $100, %rsp # update stack pointer (it works)
# now what I tried unsuccessfully:
pushw $8 # new code segment selector
pushq fun # function to execute next
retfq # far return (pops address and code segment)
Run Code Online (Sandbox Code Playgroud)
没有适当的IDT,此代码使处的错误倍增retfq。
编辑:我检查了我的分页结构,并且我很确定它们不是问题的原因。实际上,在没有最后三个指令的情况下,代码可以正常运行。问题是我需要一种更新CS的方法,在我的代码中仍然引用UEFI构建的旧段。是retfq正确的方法吗?还是我应该使用其他哪条指令?
提前致谢。
我读到 LDT(本地描述符表)在 64 位体系结构中不存在,并且想知道如何模拟使用它的 32 位系统。
使用 初始化并将 GDT 加载到 GDTR 后lgdt,以后如何更新 GDT?
如果我使用sgdt命令获取基地址,然后更新或添加条目,然后使用 重新加载它,我是否正确lgdt?还有其他方法吗?
或者我是否遗漏了一些东西,并且 GDT 永远不会“意味着”在初始化和加载后进行更新?
在GDT 上的文章中, OSDev wiki 描述了用作 CS 描述符的 D 位的标志如下:
Sz:大小位。如果为0,则选择器定义 16 位保护模式。如果为1,则定义 32 位保护模式。您可以同时拥有 16 位和 32 位选择器。
另一个问题引用了 Intel 手册:代码段描述符中的 D 标志对 x86-64 指令有什么作用?它链接到Intel 64 和 IA-32 架构软件开发人员手册第 3 卷 [...]:系统编程指南中的“3.4.5 段描述符”部分 ,阅读:
D/B(默认操作大小/默认堆栈指针大小和/或上限)标志
根据段描述符是可执行代码段、向下扩展数据段还是堆栈段执行不同的功能。(对于 32 位代码和数据段,此标志应始终设置为 1,对于 16 位代码和数据段,应始终设置为 0。)
• 可执行代码段。该标志称为 D 标志,它表示段中指令引用的有效地址和操作数的默认长度。如果设置了标志,则假定为 32 位地址和 32 位或 8 位操作数;如果清楚,则假定为 16 位地址和 16 位或 8 位操作数。指令前缀 66H 可用于选择默认值以外的操作数大小,前缀 67H 可用于选择默认值以外的地址大小。
问题是,“D”代表什么?
在 bootasm.S
.p2align 2 # force 4 byte alignment
gdt:
SEG_NULLASM # null seg
SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg
gdtdesc:
.word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
.long gdt # address gdt
Run Code Online (Sandbox Code Playgroud)
这用于
lgdt gdtdesc
Run Code Online (Sandbox Code Playgroud)
gdtdesc 的第一个字不应该是 gdt 的字节大小吗?在这种情况下,它是3*8=24,它等于gdtdesc - gdt。为什么gdtdesc - gdt - 1在这里?
我浏览了网上有关全局描述符表的许多教程.但我找不到一个详细解释64位描述符中所有字段的站点.此外,我坚持使用GDT中的选择器概念.我知道选择器有一个索引,TI是GDT还是LDT字段.简单来说,选择器与GDT之间的关系是什么?如果可能请详细说明.
谢谢..
我知道GDT(全局描述符表)是如何实现的以及段寄存器和段描述符的使用。然而,如何/何时访问 GDT 条目呢?
是否可以通过基本 mov 指令访问,例如
mov [eax],ebx
Run Code Online (Sandbox Code Playgroud)
这是否隐式调用 ds 段寄存器,然后访问 GDT 段描述符,或者是否有其他方式访问 GDT 条目?