在GDT中安装一个新的描述符

在GDT中安装一个新的描述符

Content #

  set_up_gdt_descriptor:              ;在GDT内安装一个新的描述符
                                      ;输入:EDX:EAX=描述符
                                      ;输出:CX=描述符的选择子
      push eax
      push ebx
      push edx

      push ds
      push es

      mov ebx,core_data_seg_sel          ;切换到核心数据段
      mov ds,ebx

      sgdt [pgdt]                        ;以便开始处理GDT

      mov ebx,mem_0_4_gb_seg_sel   ;整个0-4GB内存的段的选择子
      mov es,ebx                   ;让ES指向4GB内存段以操作全局描述符表

;计算描述符安装地址。
;1. 先得到描述符表的界限值,将它加1,得到描述符总字节数。
;2. 该总字节数即为新描述符在GDT内的偏移量。
;3. 用GDT的线性地址加上这个偏移量,就是用于安装新描述符的线性地址。
      movzx ebx,word [pgdt]              ;GDT界限
      inc bx                             ;GDT总字节数,也是下一个描述符偏移#
      add ebx,[pgdt+2]                   ;下一个描述符的线性地址
;访问ES指向的4GB内存段,将EDX:EAX中的64位段描述符写入EBX指向的偏移处
      mov [es:ebx],eax
      mov [es:ebx+4],edx

      add word [pgdt],8                  ;增加一个描述符的大小

      lgdt [pgdt]                        ;对GDT的更改生效
;根据GDT新界限值,来生成相应的段选择子。
;界限值会比GDT总字节数小1,因此界限除以8(丢掉余数7)后的商即为描述符索引号。
      mov ax,[pgdt]                      ;得到GDT界限值
      xor dx,dx
      mov bx,8
      div bx                             ;除以8,去掉余数
      mov cx,ax
      shl cx,3                           ;左移3次,留出TI位和RPL位

      pop es
      pop ds

      pop edx
      pop ebx
      pop eax

      retf

如果这是启动计算机以来,第一次在GDT 中安装描述符,两种写法会有区别。

在初始状态下,也就是计算机启动之后,这时还没有使用GDT,GDTR 寄存器中的基地址为0x00000000,界限为0xFFFF。

当GDTR 寄存器的界限部分是0xFFFF 时,表明GDT 中还没有描述符。因此,将此值加1,结果是0x10000,由于该寄存器的界限部分只有16 位,所以只能容纳16 位的结果,即0x0000,这就是第一个描述符在表内的偏移量。

同样的道理,因为EBX 寄存器中的内容是GDT 的界限值0x0000FFFF,如果执行的是指令 inc ebx 那么,EBX 寄存器中的内容将是0x00010000,以它作为第一个描述符的偏移量显然是不对的。

相反,如果执行的是指令是 inc bx 那么,因为BX 寄存器只有16 位,故,结果为0x0000,进位被丢弃(决不会影响 EBX 寄存器的高16 位)。此指令执行后,EBX 寄存器的内容是0x00000000。

From #

sgdt