Linux系统 setup.s文件如何初始化 全局描述符表GDT 请给出源码并注释
时间: 2024-02-12 07:08:03 浏览: 38
首先,需要了解一下全局描述符表(Global Descriptor Table,GDT)是什么。GDT是在操作系统启动时由CPU初始化的一个数据结构,用于管理内存段的访问权限。操作系统可以通过修改GDT来控制内存的访问权限和保护。
在Linux系统中,GDT的初始化是在setup.s文件中完成的。下面是setup.s文件中初始化GDT的代码和注释:
```
/*
* 初始化GDT
*/
init_gdt:
lgdt gdtr /* 加载GDT寄存器 */
/* GDT表项0:空描述符 */
gdt_null:
.word 0, 0
.byte 0, 0, 0, 0
/* GDT表项1:内核代码段描述符 */
gdt_code:
.word 0xffff, 0 /* 段界限 */
.byte 0, 0, 0x9a, 0xcf /* 基地址为0,代码段可读可执行,DPL为0,系统段,粒度为4KB */
/* GDT表项2:内核数据段描述符 */
gdt_data:
.word 0xffff, 0 /* 段界限 */
.byte 0, 0, 0x92, 0xcf /* 基地址为0,数据段可读可写,DPL为0,系统段,粒度为4KB */
/* GDT表项3:用户代码段描述符 */
gdt_user_code:
.word 0xffff, 0 /* 段界限 */
.byte 0, 0, 0x9a, 0xcf /* 基地址为0,代码段可读可执行,DPL为3,用户段,粒度为4KB */
/* GDT表项4:用户数据段描述符 */
gdt_user_data:
.word 0xffff, 0 /* 段界限 */
.byte 0, 0, 0x92, 0xcf /* 基地址为0,数据段可读可写,DPL为3,用户段,粒度为4KB */
/* GDT表项5:TSS描述符 */
gdt_tss:
.word 0x67, 0 /* 段界限 */
.byte 0, 0, 0x89, 0x40 /* 基地址为tss_entry,DPL为0,系统段,粒度为1B */
.word 0 /* tss_entry的低16位 */
.byte 0 /* tss_entry的第24位 */
.byte 0x00 /* tss_entry的第32位 */
.word 0 /* tss_entry的高16位 */
/* GDT表项6:LDT描述符 */
gdt_ldt:
.word 0, 0 /* 段界限 */
.byte 0, 0, 0x82, 0x40 /* 基地址为ldt,DPL为0,系统段,粒度为1B */
/* GDT表项7:TSS段 */
gdt_tss_entry:
.word 0, 0 /* 填充 */
.word 0x10, 0 /* ss0 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
/* GDT表项8:LDT段 */
gdt_ldt_entry:
.word 0, 0 /* 填充 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
/* GDT表项9:TSS段 */
gdt_tss2_entry:
.word 0, 0 /* 填充 */
.word 0x10, 0 /* ss0 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
/* GDT表项10:LDT段 */
gdt_ldt2_entry:
.word 0, 0 /* 填充 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
/* GDT表项11:TSS段 */
gdt_tss3_entry:
.word 0, 0 /* 填充 */
.word 0x10, 0 /* ss0 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
/* GDT表项12:LDT段 */
gdt_ldt3_entry:
.word 0, 0 /* 填充 */
.byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 填充 */
.fill 16 * 8 - (. - init_gdt) /* 填充到16字节 */
/* GDT表 */
gdt:
.word 16 * 8 - 1 /* GDT表长度 */
.long gdt /* GDT表地址 */
/* GDT寄存器 */
gdtr:
.word 16 * 8 - 1 /* GDT表长度 */
.long gdt /* GDT表地址 */
```
上述代码中,首先使用`lgdt`指令将GDT表的长度和地址加载到GDT寄存器中。然后,定义了一些GDT表项,包括空描述符、内核代码段描述符、内核数据段描述符、用户代码段描述符、用户数据段描述符、TSS描述符和LDT描述符。其中,每个GDT表项包括段界限、基地址、段属性等信息。
最后,定义了一个GDT表数组`gdt`,将GDT表长度和地址存储在`gdtr`寄存器中,完成了GDT的初始化。
需要注意的是,上述代码只是一个简化的示例,实际的GDT表项可能更加复杂,具体的实现方式也可能因操作系统的不同而有所差异。