linux初始化代码陷阱门初始化:
trap_init主要功能对异常陷阱程序做初始化,其实就是设置中断描述符表(IDT:interrupt Description Table)。IDT和GDT差不多每个IDT都是由一个8个字节组成。最多0.11内核中支持256个描述符,对于第n个描述符获取地址大概可以这样计算 add(n) = add(IDT)+8*(n-1)得到。
一:IDT中存放着三种描述符:
中断门,陷阱门,任务门。
中断门的模型:
31 16 15 13 12 8 5 4 0
过程入口偏移31..16 p DPL 01110类型 000 |
段选择符 过程入口偏移15…0 |
过程入口偏移31..16 p DPL 01111类型 000 |
段选择符 过程入口偏移15…0 |
二:工作过程
响应一个异常或者中断的向量会作为IDT表索引,如果所以指向中断门或陷阱门则处理器会使用与call类似的操作处理中断或者异常过程。任务会进行任务切换操作。首先会根据中断向量号找到对应描述符,根据描述符中的段选择符找到GDT全局或者LDT局部描述符表中的段描述符,找段基地址属性等,由段地址+对应中断描述符中的偏移找到具体的处理代码点执行处理。
中断向量 |
选择符 属性 偏移量
|
段基址 属性 限长 |
异常处理过程 |
三:具体初始化工作
void trap_init(void)包含有set_trap_gate陷阱门设置, set_system_gate系统陷阱门配置两种陷阱门做配置。
陷阱门和系统陷阱门差别就是特权及前者为0,后者为3用户态,后者用于单步调试,溢出出错等处理。
gate_addr:是描述符地址其占用的8个字节将被书写进描述符内容,描述符内容在最前面所示。
Type:是描述符的类型中断门是0x0E就是前面红色里面的东西
Dpl: 权限特权标志,比如陷阱门是0,系统陷阱门是3在图中有dpl表示的。
Addr:偏移地址,找到段后,需要使用这个地址来找到具体的地址。
#define _set_gate(gate_addr,type,dpl,addr) /
"__asm__ ("movw %%dx,%%ax/n/t" /
//edx放的是addr偏移,eax初始为0x00080000上面意思是
//eax = eax&0xFFFF00+addr&0x00FFFF,0008是段描述符
"movw %0,%%dx/n/t" /
//%0中放着0x8000[P位]+(dpl<<13)+(type<<8))组成陷阱门属性将被
//放入陷阱门描述符高32中的第16位
"movl %%eax,%1/n/t" /
//此刻eax中内容是描述符需要的第32位: 段选择符+偏移15-0
"movl %%edx,%2" /
//此刻edx内容为描述符需要的高32位: 偏移31-16+属性
: /
: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), / //%0
"o" (*((char *) (gate_addr))), / //%1
"o" (*(4+(char *) (gate_addr))), / //%2
"d" ((char *) (addr)),"a" (0x00080000)) //edx
后面的对于陷阱门设置主要改变参数调用_set_gate宏来实现没有其他可以解释的地方。
#define set_intr_gate(n,addr) /
_set_gate(&idt[n],14,0,addr)
//这里就是type不同中断门区别与陷阱门的地方
#define set_trap_gate(n,addr) /
_set_gate(&idt[n],15,0,addr)
//这里就是权限不同陷阱门区别与系统陷阱门的地方
#define set_system_gate(n,addr) /
_set_gate(&idt[n],15,3,addr)