Content #
#define _set_gate(gate_addr,type,dpl,addr) \
__asm__("movw %%dx,%%ax\n\t" \ //将edx的低字赋值给eax的低字
"movw %0,%%dx\n\t" \ //%0对应第二个冒号后的第1行的"i"
"movl %%eax,%1\n\t" \ //%1对应第二个冒号后的第2行的"o"
"movl %%edx,%2" \ //%2对应第二个冒号后的第3行的"o"
: \ //这个冒号后面是输出,下面冒号后面是输入
: "i" ((short) (0x8000 + (dpl<<13) + (type<<8))), \ //立即数
"o" (*((char *) (gate_addr))), \ //中断描述符前4个字节的地址
"o" (*(4 + (char *) (gate_addr))), \ //中断描述符后4个字节的地址
"d" ((char *) (addr)),"a" (0x00080000)) //"d"对应edx,"a"对应eax
set_trap_gate定义如下:
#define set_trap_gate(n,addr) _set_gate(&idt[n],15,0,addr)
因此:
set_trap_gate(0,÷_error)<=> _set_gate(&idt[n],15,0,addr)
可以看出,n是0;gate_addr是&idt[0],也就是idt的第一项中断描述符的地址; type是15;dpl(描述符特权级)是0;addr是中断服务程序divide_error(void)的入口地址.
“movw %%dx,%%ax\n\t”是把edx的低字赋值给eax的低字; edx是(char *)(addr),也就是÷_error; eax的值是0x00080000,8应该看成1000,这样eax的值就是 0x00080000 +((char *)(addr)的低字),其中的0x0008是段选择符,
“movw %0,%%dx\n\t”是把(short)(0x8000 +(dpl<<13)+(type<<8))赋值给dx。别忘了,edx是(char *)(addr),也就是÷_error。
set_system_gate(n,addr)与set_trap_gate(n,addr)用的_set_gate(gate_addr,type,dpl,addr)是一样的;差别是set_trap_gate的
dpl是0,而set_system_gate的dpl是3。dpl为0的意思是只能由内核处理,dpl为
3的意思是系统调用可以由3特权级(也就是用户特权级)调用。

From #
Linux内核设计的艺术