我正在阅读 Linux 内核代码。我对 Linux 中的 GDT(全局描述符表)有一些疑问。
我的问题是:
Where Linux Kernel Setup Large GDT?
I know that in pm.c [http://lxr.free-electrons.com/source/arch/x86/boot/pm.c#L123]
kernel call function setup_gdt() and it set up a small GDT with only three entries.
Then jumps to protected mode code.
Then where is the code to setup large GDT with 32 entries
( One specified in Understanding Linux Kernel https://books.google.co.in/books?id=h0lltXyJ8aIC&pg=PT59&lpg=PT59&dq=linux+kernel+file+gdt&source=bl&ots=gO0lH05fHX&sig=h4X1I6TP_P7JlEwzoCkQk3uztjw&hl=en&sa=X&ei=XFwPVM-WBbOBsQTtiIDIDw&redir_esc=y#v=onepage&q=linux%20kernel%20file%20gdt&f=false )
Kernel also defined constants for Large GDT set up in segment.h http://lxr.free-electrons.com/source/arch/x86/include/asm/segment.h#L46.
Run Code Online (Sandbox Code Playgroud)
为什么内核使用两步来设置 GDT?
如果我们使用 GRUB 作为引导加载程序,那么 …
flush_gdt:
lgdt [gdtr]
jmp 0x08:complete_flush
complete_flush:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
Run Code Online (Sandbox Code Playgroud)
我无法理解这段代码的作用.flush_gdt是一个标签好,然后lgdt [gdtr]将48-bit指针加载到gdtr寄存器中,然后从中加载jmp 0x08:complet_flush.
jmp指令有什么作用?然后我们为什么要将0x10移动到ax,然后移动到其他寄存器
我正在学习x86程序集,我正在尝试在NASM中制作玩具操作系统,但我不了解一些事情.
我做了一个成功启动内核的bootloader:
kernel.feo;0x2000;jmp 0x2000:0x0000.所以我的内核代码位于0x2000:0内存中.CS可能是因为使用远跳而设置得当.在这个内核代码中,我想进入32位保护模式,但我不确定GDT是如何工作的.当我在虚拟机上运行下面的代码时(QEMU),它不会做任何事情.
我想请你帮我进入32位保护模式!
也就是说,您有以下问题:
- 您认为代码是
0x7c00:0由于加载而导致的org 0,但可能并非如此.唯一保证的是物理地址.您应该使用远程跳转到您的入口点,以便CS正确设置.- 您出于某种原因进行设置
DS,0x2000以便您的代码根本找不到任何数据.您应该设置DS匹配CS,或在CS任何地方使用覆盖(不推荐).- 受保护的模式代码假设从零开始的段,这反过来意味着它预计
org 0x7c00当然与您的设置冲突.你应该切换到org 0x7c00和细分0.- VGA文本模式段
0xb8000不是0xb80000(少一个零).- 您没有
0x55 0xaa在引导扇区末尾的引导签名字节.
我在代码中更正了这些内容:
[org 0x0]被更正为[org 0x2000]并且段被设置为0;DS被纠正为0而不是0x2000,所以现在它匹配CS;0xb8000;但代码不适用于这些更正,它应该打印两个字符串,但它什么都不做! …
I want to use gdb to see my GDTR/LDTR/TTR and segment register
Run Code Online (Sandbox Code Playgroud)
不可见部分(x86)所以在gdb中我输入“p/x $gdtr”...等但结果是“$6 = Value can't be convert to integer”,在gdb中我输入“p/x $cs”唯一的结果是 CS,只是可见的部分
can anyone tell me how to view these value??
Run Code Online (Sandbox Code Playgroud)
感谢您的回答
我知道这两个表都包含段描述符,提供每个段的访问详细信息,包括基地址、类型、长度、访问权限等。
看这篇博客的区别如下:
1. GDT在系统中只有一个副本,而LDT可以有多个副本
2. GDT在执行过程中可能不会改变,任务切换时LDT经常发生变化
3. LDT的条目保存在GDT中。GDT 和 LDT 中的条目具有相同的结构。
系统在实际程序中如何以不同的方式使用这些结构?
我阅读了关于GDT(全局描述符表)的教程,该教程将GDT定义为"为内存的某些部分定义基本访问权限的那个".这意味着GDT用于记忆保护.
它是否执行除上述以外的任何其他任务?
是否必须在操作系统中实施GDT?
简而言之,如果有人能够以易于理解的方式详细阐述GDT,那将会更好.
谢谢
如果该位为零,那么存储器是逐字节寻址的?如果它是1,那么内存是通过4Kb寻址4Kb的?
因此,例如,如果将该位设置为0,并且我寻址了内存位置a000h,那么我将在该位置寻址该字节吗?如果我寻址下一个位置a001h,那将是内存中的下一个字节,对吗?
但是,如果该位为1,我是否要寻址4Kb块?
那么寻址a000h会给我一个4Kb的块,而给a001下一个4Kb的内存吗?
我正在经历x86的保护模式部分.我刚刚了解了GDT.之前,我已经研究过进入保护模式(即:使用所有32位地址线)必须启用A20门.那么,启用A20的代码必须是16位吗?最近,当我浏览wiki.osdev网站时,我发现启用A20的代码是用x86汇编编写的.X86汇编产生的32位操作码无法以16位模式加载吗?
请尽可能解释.谢谢.
我知道操作系统通过使用分段和特权级别来限制对内核代码和数据的访问。然而,用户可以更改段寄存器的值,如果以下代码执行成功,我们似乎可以访问内核数据:
mov eax, 0x10
mov es, ax #point selector to the item 2 in GDT with RPL 0, which is the data segment
les bx, [0]
Run Code Online (Sandbox Code Playgroud)
所以我想知道阻止此代码成功执行的机制是什么?
我主要用 C++ 制作操作系统,但对于引导加载程序,我使用的是 FASM。当我尝试设置 GDT 时,Qemu 会清除屏幕并在顶部重新打印“SeaBIOS”。它会一直循环下去,直到我关闭它。这是它的gif:

我尝试使用 -nographic 运行它,但它在 Windows 控制台中执行相同的操作。
哦,是的,操作系统/版本信息。
Windows:20H2
FASM:1.73.25
Qemu:5.1.0
这是我的代码:
gdt_start:
dd 0x00
dd 0x00
gdt_code:
dw 0xffff
dw 0x0
db 0x0
db 10011010b
db 11001111b
db 0x0
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
switch_to_pm:
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, …Run Code Online (Sandbox Code Playgroud) gdt ×10
x86 ×9
assembly ×8
kernel ×3
linux-kernel ×2
addressing ×1
bootloader ×1
fasm ×1
gdb ×1
nasm ×1
osdev ×1