本文共 2069 字,大约阅读时间需要 6 分钟。
1.3.2 设置中断描述符表和全局描述符表
setup程序继续为保护模式做准备,此时要通过setup程序自身提供的数据信息对中断描述符表寄存器IDTR和全局描述符表寄存器GDTR进行初始化设置。
小贴士
GDT(Global Descriptor Table,全局描述符表):它是系统中唯一存放段寄存器内容(段描述符)的数组,配合程序进行保护模式下的段寻址。它在操作系统的进程切换中具有重要意义,可理解为所有进程的总目录表,其中存放着每一个任务(task)局部描述符表(LDT,Local Descriptor Table)地址和任务状态段(TSS,Task Structure Segment)地址,用于完成进程中各段的寻址、现场保护与现场恢复。
GDTR(Global Descriptor Table Register,GDT基地址寄存器):GDT可以存放在内存的任何位置,当程序通过段寄存器引用一个段描述符时,需要取得GDT的入口, GDTR所标识的即为此入口。在操作系统对GDT的初始化完成后,可以用LGDT(Load GDT)指令将GDT基地址加载至GDTR。
IDT(Interrupt Descriptor Table,中断描述符表):保存保护模式下所有中断服务程序的入口地址,类似于实模式下的中断向量表。
IDTR(Interrupt Descriptor Table Register,IDT基地址寄存器):IDT基地址寄存器,保存IDT的起始地址。
内核实现代码如下:
//代码路径:boot/setup.s lidt idt_48 lgdt gdt_48 gdt: .word 0,0,0,0 ! dummy .word 0x07FF ! 8Mb-limit=2047 (2048*4096=8Mb) .word 0x0000 ! base address=0 .word 0x9A00 ! code read/exec .word 0x00C0 ! granularity=4096, 386 .word 0x07FF ! 8Mb-limit=2047 (2048*4096=8Mb) .word 0x0000 ! base address=0 .word 0x9200 ! data read/write .word 0x00C0 ! granularity=4096, 386 idt_48: .word 0 ! idt limit=0 .word 0,0 ! idt base=0L gdt_48: .word 0x800 ! gdt limit=2048, 256 GDT entries .word 512+gdt,0x9 ! gdt base = 0X9xxxx
这些代码设置所需要的数据分别在idt_48和gdt_48所对应的标号处,它们与寄存器的对应方式如图1-18所示。
图1-18 设置GDTR和IDTR |
点评
32位的中断机制和16位的中断机制在原理上有比较大的差别,最明显的是16位的中断机制用的是中断向量表,中断向量表的起始位置在0x00000处,这个位置是固定的。32位的中断机制用的是中断描述符表IDT,位置是不固定的,可以由操作系统的设计者根据设计要求灵活安排,由IDTR寄存器来锁定其位置。
GDT表是保护模式下管理段描述符的数据结构,对操作系统自身的运行和管理,以及进程调度有重大意义,后面的章节会有详细讲解。
因为,此时此刻内核尚未真正运行起来,还没有进程,所以现在创建的GDT表的第一项为空,第二项为内核代码段描述符,第三项为内核数据段描述符,其余项皆为空。
IDT表虽然已经设置,实为一张空表,原因是目前已关中断,无须调用中断服务程序。此处反映的是数据“够用即得”的思想。
创建这两个表的过程可理解为是分两步进行的:
(1)在设计内核代码时,已经将两个表写好,并且把需要的数据也写好。
(2)将专用寄存器(IDTR和GDTR)指向表。
此处的数据区域是在内核源代码中设定和编译并直接加载至内存形成的一块数据区域。专用寄存器的指向由程序中的lidt指令和lgdt指令完成,具体操作见图1-18。
值得一提的是,在内存中做出数据的方法有两种:
(1)划分一块内存区域并初始化数据,“看住”这块内存区域,使之能被找到;
(2)由代码做出数据,如用push代码压栈,“做出”数据,此处采用的是第一种方法。
转载地址:http://rkxbn.baihongyu.com/