进程0设置LDT和TSS描述符

进程0设置LDT和TSS描述符

Content #

代码路径:include/asm/system.h

#define _set_tssldt_desc(n,addr,type) \
__asm__ ("movw $104,%1\n\t" \            //将104,即1101000存入描述符的第1、2字节
          "movw %%ax,%2\n\t" \           //将tss或ldt基地址的低16位存入描述符的第
                                          //3、4字节
          "rorl $16,%%eax\n\t" \         //循环右移16位,即高、低字互换
          "movb %%al,%3\n\t" \           //将互换完的第1字节,即地址的第3字节存入第5字节
          "movb $" type ",%4\n\t" \      //将0x89或0x82存入第6字节
          "movb $0x00,%5\n\t" \          //将0x00存入第7字节
          "movb %%ah,%6\n\t" \   //将互换完的第2字节,即地址的第4字节存入第8字节
          "rorl $16,%%eax" \      //复原eax
          ::"a" (addr), "m" (*(n)), "m" (*(n + 2)), "m" (*(n + 4)), \
          "m" (*(n + 5)), "m" (*(n + 6)), "m" (*(n + 7)) \
    //"m" (*(n))是gdt第n项描述符的地址开始的内存单元
    //"m" (*(n + 2)) 是gdt第n项描述符的地址向上第3字节开始的内存单元
    //其余依此类推
    )
//n:gdt的项值,addr:tss或ldt的地址,0x89对应tss,0x82对应ldt
#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82")

movw $104,%1是将104赋给了段限长15:0的部分;粒度G为0,说明限长就是104字节,而TSS除去struct i387_struct i387后长度正好是104字节。LDT是3×8 =24 字节,所以104字节限长够用。(取两者的最大值,LDT有部分浪费。)

TSS的类型是0x89,即二进制的10001001,可以看出movb $" type “,%4在给type 赋值1001的同时,顺便将P、DPL、S字段都赋值好了。同理,movb $0x00,%5在给段限长19:16部分赋值0000的同时,顺便将G、D/B、保留、AVL字段都赋值好了。

From #

Linux内核设计的艺术

任务状态段TSS的格式 序号占位符 进程0中GDT、LDT、TSS关系示意图