linux0.11中断处理源码初探

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/THEANARKH/article/details/89050261

系统初始化的时候,定义和初始化了中断向量表。并初始化8259的工作方式。

// 加载idt的基地址和限长到idt寄存器
lidt idt_descr
// 定义
idt_descr:
	.word 256*8-1		# idt contains 256 entries
	.long _id
// 初始化
_idt:	.fill 256,8,0

所以idt的内容是一个单位是8字节,长度是256的数组。linux0.11分为中断、系统、陷阱门。系统在启动的时候设置idt。


void trap_init(void)
{
	int i;

	set_trap_gate(0,&divide_error);
	set_trap_gate(1,&debug);
	set_trap_gate(2,&nmi);
	set_system_gate(3,&int3);	/* int3-5 can be called from all */
	set_system_gate(4,&overflow);
	set_system_gate(5,&bounds);
	set_trap_gate(6,&invalid_op);
	set_trap_gate(7,&device_not_available);
	set_trap_gate(8,&double_fault);
	set_trap_gate(9,&coprocessor_segment_overrun);
	set_trap_gate(10,&invalid_TSS);
	set_trap_gate(11,&segment_not_present);
	set_trap_gate(12,&stack_segment);
	set_trap_gate(13,&general_protection);
	// 缺页和写保护异常处理函数
	set_trap_gate(14,&page_fault);
	set_trap_gate(15,&reserved);
	set_trap_gate(16,&coprocessor_error);
	for (i=17;i<48;i++)
		set_trap_gate(i,&reserved);
	set_trap_gate(45,&irq13);
	// 允许8259接收中断
	outb_p(inb_p(0x21)&0xfb,0x21);
	outb(inb_p(0xA1)&0xdf,0xA1);
	set_trap_gate(39,&parallel_interrupt);
}


#define _set_gate(gate_addr,type,dpl,addr) \
// 把dx即处理函数地址的低16位赋值给ax,不影响eax的高16位
__asm__ ("movw %%dx,%%ax\n\t" \
	/*
		设置idt描述符的第三个字节的内容,左移位数是字段对应的位置偏移,
		相加后赋值给dx,共16位,edx的高16位保存了处理函数的高16位地址
	*/
	"movw %0,%%dx\n\t" \
	// 把eax即0x000080000 + 处理函数的地址赋值给idt描述符的前两个字节
	"movl %%eax,%1\n\t" \
	// 把edx的内容写入idt描述符的第5-8个字节
	"movl %%edx,%2" \
	: \
	: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
	// o表示使用内存地址并可以加偏移量
	"o" (*((char *) (gate_addr))), \
	// 指向保存选择子的首地址
	"o" (*(4+(char *) (gate_addr))), \
	// edx等于addr,eax等于0x00080000
	"d" ((char *) (addr)),"a" (0x00080000))

#define set_intr_gate(n,addr) \
	_set_gate(&idt[n],14,0,addr)

#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)

其中idt描述符格式是,这个版本貌似还没有任务门。
在这里插入图片描述
还有一些是键盘,软盘等也设置中断。下面看一个异常处理程度。就是缺页或写保护异常的时候触发的


.globl _page_fault

_page_fault:
	// 交换两个寄存器的值,esp指向的位置保存了错误码
	xchgl %eax,(%esp)
	// 压栈寄存器
	pushl %ecx
	pushl %edx
	push %ds
	push %es
	push %fs
	// 内核数据段描述符
	movl $0x10,%edx
	mov %dx,%ds
	mov %dx,%es
	mov %dx,%fs
	// 如果是缺页异常,cr2保存了引起缺页的线性地址
	movl %cr2,%edx
	// 线性地址(有的话)和错误码入参
	pushl %edx
	pushl %eax
	// 1和eax与,结果放到ZF中
	testl $1,%eax
	// zf=0则跳转,即0是写异常,1是缺页异常
	jne 1f
	call _do_no_page
	jmp 2f
1:	call _do_wp_page
// 出栈,返回中断,会重新异常指令
2:	addl $8,%esp
	pop %fs
	pop %es
	pop %ds
	popl %edx
	popl %ecx
	popl %eax
	iret

缺页或写保护异常的时候,系统会把错误码和线性地址告诉处理程序。具体的处理可以见内存管理分析那篇文件。

猜你喜欢

转载自blog.csdn.net/THEANARKH/article/details/89050261