Linux 0.11中断机制解读

Linux 0.11中断机制解读

在bios启动的时候首先使用的是bios自带的中断服务函数,int 0x13和int 0x19。

在setup.s里面关中断:将EFLAGS置为0。setup将head.s和内核代码搬运到0x0000开始的地址处,覆盖了原BIOS的中断函数部分,废除了BIOS的中断函数机制。故事就从这里开始。

与中断相关的标志位:iF 中断许可(第 9 位)

Eflags

中断服务函数挂接

外部中断、软件中断和异常是通过中断描述符表(IDT)处理的。 IDT 中包含访问中断和异常处理程序的门描述符的集合。像 GDT 一样,IDT 不是一个段, IDT 的线性基地址包含在 IDT 寄存器中(IDTR)。

异常处理类中断服务函数

trap_init();函数把中断异常处理服务程序与IDT进行挂接

将异常处理函数插入IDT的表项是由set_trap_gate()和set_system_gate()函数来完成的

1
2
3
4
5
6
7
8
9
void trap_init(void)
{
int i;
//这里是在维护中断描述符表的内容,idt的架子在head.s里面给了
set_trap_gate(0,&divide_error);//这里的0,1,2...是中断描述符表项//除零错误
set_trap_gate(1,&debug);//单步调试//两个参数:表的索引+中断服务函数
set_trap_gate(2,&nmi);//不可屏蔽中断
...
}
1
2
3
#define set_trap_gate(n,addr) \
_set_gate(&idt[n],15,0,addr)!0对应dpl,15对应类型(查手册):1111
//idt是中断描述符表的起始地址。idt[n]是中断描 述符表中中断号n对应项的偏移值。中断描述符的类型是15,特权级是0.意思是只能由内核处理,如果dpl特权级别=3则可以由3特权级(用户)来处理与陷阱门不同,系统陷阱门的特权级是3,即系统陷阱门设置的中断处理过程能够被所有进程调用(如单步调试、溢出出错和超出边界出错等)
参数对应图
1
2
3
4
5
6
7
8
9
10
11
#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
"movw %0,%%dx\n\t" \//%0对应i
"movl %%eax,%1\n\t" \//%1对应第二行的o,将eax寄存器的值放到idt表项里面,即&idt【0】,也就是gate_addr
"movl %%edx,%2" \//%2对应第三行的 放到gateaddr的后四个字节
: \
: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ //i:立即数
"o" (*((char *) (gate_addr))), \ //中断描述符前四个字节地址,o是偏移的意思
"o" (*(4+(char *) (gate_addr))), \//中断描述符后四个字节地址
"d" ((char *) (addr)),"a" (0x00080000))//d对应edx,a对应eax,这说明了为啥edx是&divide0地址

这里面的偏移地址,就是段偏移再加上gdt里面的段基址就得到了真正的线性地址 这里本来edx里面有着完整的中断服务程序段偏移地址:"d" ((char *) (addr)),为了配合中断描述符,强行把低字部分给了eax(movw %%dx,%%ax\n\t)。 注意,前两条汇编这部分代码一直是在对寄存器进行操作,还没有放到内存里面,后面再添到&idt[0]里面

解释图

中断描述符

中断描述符
1
"i" ((short) (0x8000+(dpl<<13)+(type<<8)))

movw %%dx,%%ax\n\t将edx的低字赋值给eax,也就是&divide_error的低字,使得中断服务程序偏移地址符合上述中断描述符

系统描述符:,这里的1111即_set_gate(gate_addr,type,dpl,addr)里面的type,属于系统描述符,从下面这张表中可以看出这里15是32位的陷阱门。

例如这个输入的是14就是32位中断门

1
2
#define set_intr_gate(n,addr) \
_set_gate(&idt[n],14,0,addr)
系统段和门描述符

IDT的变迁

LDT的变迁

系统调用

system_call路径:

系统调用