grub 在加载linux内核之前已经进入保护段式映射模式
/* The code segment of the protected mode. */
#define CODE_SEGMENT 0x10 // 0b'000 10 000 => 01 => 2, 第2个段选择子
/* The data segment of the protected mode. */
#define DATA_SEGMENT 0x18 // 0b'000 11 000 => 11 => 3, 第3个段选择子
.byte 0xea // 跳到linux内核
VARIABLE(grub_relocator32_eip)
.long 0
.word CODE_SEGMENT
.byte 0xea
VARIABLE(grub_relocator32_eip)
.long 0
.word CODE_SEGMENT
/* GDT. Copied from loader/i386/linux.c. */
.p2align 4
LOCAL(gdt):
/* NULL. */
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 第0个描述符
/* Reserved. */
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // 第1个描述符
/* Code segment. */
.byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00 // 第2个描述符
/* Data segment. */
.byte 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00 // 第3个描述符
LOCAL(gdt_end):
VARIABLE(grub_relocator32_end)
进入linux内核之后
#define GDT_ENTRY_KERNEL_DS 3
#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)
.code32
ENTRY(startup_32)
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
* us to not reload segments
*/
testb $(1<<6), BP_loadflags(%esi)
jnz 1f
cli
movl $(__KERNEL_DS), %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
... ...
/*
* Prepare for entering 64 bit mode
*/
/* Load new GDT with the 64bit segments using 32bit descriptor */
leal gdt(%ebp), %eax
movl %eax, gdt+2(%ebp)
lgdt gdt(%ebp)
... ...
.data
gdt:
.word gdt_end - gdt // 第0个描述符
.long gdt
.word 0
.quad 0x0000000000000000 /* NULL descriptor */ // 第1个描述符
.quad 0x00af9a000000ffff /* __KERNEL_CS */ // 第2个描述符
.quad 0x00cf92000000ffff /* __KERNEL_DS */ // 第3个描述符
.quad 0x0080890000000000 /* TS descriptor */
.quad 0x0000000000000000 /* TS continued */
gdt_end: