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内核设计的艺术