linux 2.6源代码情景分析笔记之中断与异常3

来源:互联网 发布:服装设计网络班 编辑:程序博客网 时间:2024/06/05 23:26

初始化中断描述符表

内核启用中断以前,必须把idt表的初始地址装到idtr寄存器,并初始化表中的每一项。这项工作是在初始化系统时完成。
int指令允许用户态进程发出一个中断信号,其值可以是0-255的任意一个向量。因此。为了防止用户通过int指令模拟非法的中断和异常,idt的初始化必须非常小心。这可以通过把中断或者陷阱门描述符的dpl字段设置成0来实现。如果进程试图发出其中的一个中断信号,控制单元将检查出cpl的数值与dpl的字段有冲突,并且产生一个general protection异常。

intel提供了三种类型的中断描述符:任务门,中断门,以及陷阱门描述符。linux使用与inetl不同的细目分类和术语:
中断门(interrupt gate)所有linux中断处理程序都通过中断门激活,全部限制在内核态。
系统门(system gate)用户态的进程可以访问一个intel陷阱门dpl字段为3.通过系统门来激活三个linux异常处理程序,向量是4,5,128.在用户态下,可以发布into,bound,int $0x80三条汇编语言指令。
系统中断门(system interrtup gate)能够被用户态进程访问的intel中断门(门的dpl字段为3)。与向量3相关的异常处理程序是由系统门中断门激活的,在用户态下,可以使用汇编语言指令int3.
陷阱门(trap gate)用户态的进程不能访问一个intel陷阱门(门的dpl字段为0)。大部分linux异常处理程序都通过陷阱门来激活。
任务门(task gate)不能被用户态进程访问的intel任务门(门的dpl字段为0)。linux对“double fault”异常处理程序是由任务门激活的。

下列体系结构相关的函数用来在idt中插入门。

在idt的第n个表项中插入一个中断门。门中的段选择符设置成内核代码的段选择符,偏移量设置为中断处理程序的地址addr,dpl字段设置为0.
void set_intr_gate(unsigned int n, void *addr)
{
        _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
}
在idt的第n个表项中插入一个陷阱门。门中的段选择符设置成为内核代码的段选择符,偏移量设置为异常处理程序的地址addr,dpl字段设置为3.
static void __init set_system_gate(unsigned int n, void *addr)
{
        _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
}
在idt的第n个表项插入一个中断门。门中的段选择符设置成内核代码的段选择符,偏移量设置为异常处理程序的地址addr,dpl字段设置为3.
static inline void set_system_intr_gate(unsigned int n, void *addr)
{
        _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS);
}
与上一个类似,不过将dpl字段设置为0.
static void __init set_trap_gate(unsigned int n, void *addr)
{
        _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
}
在idt的第n个表项中插入一个中断门。门中的段选择符中存放一个tss的全局描述符表的指针,该tss中包含要被激活的函数。偏移量设置为0,而dpl字段设置为0.
static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
{
        _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
}

#define _set_gate(gate_addr,type,dpl,addr,seg) /
do { /
  int __d0, __d1; /
  __asm__ __volatile__ ("movw %%dx,%%ax/n/t" /
        "movw %4,%%dx/n/t" /
        "movl %%eax,%0/n/t" /
        "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)

原创粉丝点击