挂接中断服务程序(_set_gate)

挂接中断服务程序(_set_gate)

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,&divide_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),也就是&divide_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),也就是&divide_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内核设计的艺术