设置完IDT以后,还需要再次设置GDT。在setup.S中已经设置过一次全局描述符表,为什么在head.S中还要重新设置呢?这是因为setup中使用的GDT位于setup所处的那一段内存,也就是0x90200的位置,但是内核真正运行起来以后的GDT应该位于内核数据结构中,所以进入head.S以后就需要重新设置。但这并不难,只需要和setup中的GDT保持一致就可以了。
与IDT一样,GDT也包含256个元素,每个元素是一个全局描述符,它的大小是8B。GDT的前5项可以手动编辑后硬编码进去,后面的251项则使用fill伪指令进行填充。设置GDT的代码如下所示:
1 ...
2 call setup_idt
3 call setup_gdt
4 ...
5
6 setup_gdt:
7 lgdt gdt_descr
8 ret
9 ...
10
11 .align 4
12 .word 0
13 idt_descr:
14 .word 256 *8-1
15 .long idt
16
17 .align 4
18 .word 0
19 gdt_descr:
20 .word 256 *8-1
21 .long gdt
22
23 .align 8
24 idt:
25 .fill 256,8,0
26
27 gdt:
28 .quad 0x0000000000000000
29 .quad 0x00c09a0000000fff
30 .quad 0x00c0920000000fff
31 .quad 0x00c0f20b8000ffff
32 .quad 0x0000000000000000
33 .fill 251,8,0
GDT的第一项(第28行)是为CPU准备的保留项,不会被使用。第二项(第29行)是全局代码段,它的段基址为0,段长度为16MB。第三项是全局数据段,它的段基址也是0,段长度也是16MB。大家可以对照图2-2,自己计算全局描述符各个段的读写属性。同时,这里也保留了段基址为0xb8000的一个数据段,它的基址指向显存。这个描述符与setup中的GDT的第4项是一样的,使用这个描述符是为了方便地访问显存,因为不用每次都计算基地址。所以这里不妨称这一项为视频段选择子。