文章目录
  1. 1. 环境
  2. 2. 门描述符
  3. 3. 门描述符类型
  4. 4. 设置门描述符

环境

CPU : x86 32bit
内核版本:2.6.18

门描述符

在保护模式下,中断向量表中的表项由8个字节组成(两个字节的段描述符,偏移量四字节来表示),其中的每个表项叫做一个门描述符(gate
descriptor)。
“门”的含义是当中断发生时必须先通过这些门,然后才能进入相应的处理程序。
门描述符的一般格式如下:

gate_1

门描述符类型

1.中断门(Interrupt gate)
其类型码为110,它包含一个中断或异常处理程序所在的段选择符和段内偏移。控制权通过中断门进入中断处理程序时,处理器清IF标志,即关中断,以避免嵌套中断的发生。
中断门中的DPL(Descriptor Privilege Level)为0,因此,用户态的进程不能访问Intel的中断门。所有的中断处理程序都由中断门激活,并全部限制在内核态。
设置中断门的代码如下:

//中断描述符表
struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
//描述符结构
struct desc_struct {
    unsigned long a,b;
};

void set_intr_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
}

2.陷阱门(Trap gate)
其类型码为111,与中断门类似,其唯一的区别是,控制权通过陷阱门进入处理程序时维持IF标志位不变,也就是说,不关中断。
其设置代码如下:

static void __init set_trap_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
}

3.任务门(Task gate)
IDT中的任务门描述符格式与GDT和LDT中的任务门格式相同,含有一个任务TSS段的选择符,该任务用于处理异常或中断,Linux用于处理Double fault。
其设置代码如下:

static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
{
    _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
}

4.系统门(System gate)
能够让用户态的进程访问Intel的陷阱门,门描述符的DPL为3。通过系统门来激活3个Linux异常处理程序,它们的向量是4、5及0x80,也就是说,在用户态下,可以使用into、bound
及int0x80三条汇编指令。

static void __init set_system_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
}

5.系统中断门 (System intterupt gate)
能够被用户态进程访问的Intel中断门,门的DPL为3.与向量3相关的异常处理程序是由系统中断门激活的,因此,在用户态可以使用汇编语言指令int3.

static inline void set_system_intr_gate(unsigned int n, void *addr)
{
,..._set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
} 

gate_2

设置门描述符

1.(seg<<16)段描述符放到eax寄存中.
2.((char *)(addr))段中偏移量(比如_system_call的地址)放到edx寄存中.
3.设置DPL和门类型码:(0x8000+(dpl<<13)+(type<<8))
4.(gate_addr)为中断描述符的低32位
5.(gate_addr+1)为中断描述符的高32位

#define _set_gate(gate_addr,type,dpl,addr,seg) \
do { \
  int __d0, __d1; \
  //把dx(edx的低16位)放到ax(eax的第16位中)
  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
    //设置DPL和门类型码并放到dx(edx的低16位)
    "movw %4,%%dx\n\t" \
    //把eax的内容放到门描述符的低32位上
    "movl %%eax,%0\n\t" \
    //把edx的内容放到门描述符的高32位上
    "movl %%edx,%1" \
    :"=m" (*((long *) (gate_addr))), \
     "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
    :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
     "3" ((char *) (addr)),"2" ((seg) << 16)); \
} while (0)