登 录
/* * linux/kernel/traps.c *traps.c实现了asm.s 中断处理中调用的c函数。另外几个硬件中断处理程序在文件system_ call.s和mm/pages.s中实现。 * (C) 1991 Linus Torvalds */ /* * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'asm.s'. Currently mostly a debugging-aid, will be extended * to mainly kill the offending process (probably by giving it a signal, * but possibly by killing it outright if necessary). */ /*在程序asm.s中保存了一些状态后,本程序用来处理硬件陷阱和故障。目前仅仅用来作测试的。以后用来撒谎四遭破坏的进程(主要是通过发送一个信号,但有时也必须杀死)。*/ #include <string.h> //字符串头文件,主要定义了一些有关字符串操作的嵌入函数 #include <linux/head.h>//head头文件,定义了段描述符的简单结构,和几个选择符常量。 #include <linux/sched.h> //调度文件头文件,定义了债任务结构task——struct、初始任务0的数据。 #include <linux/kernel.h> //内核头文件。含有一些内核常用函数的原型定义。 #include <asm/system.h> //系统头文件。定义了设置或修改描述符/中断门等的嵌入式汇编宏。 #include <asm/segment.h> //段操作头文件。定义了有关寄存器操作的嵌入式汇编函数。 #include <asm/io.h> //输入输出头文件。定义了硬件端口输入输出宏汇编语句。 //以下语句定义了三个嵌入式汇编宏语句语句函数。取段seg中的地址addr处的一个字节。 //用圆括号括住的组合语句(花括号中的语句),可以作为表达式使用,其中最后的_res是其输出值。 #define get_seg_byte(seg,addr) ({ / register char __res; / __asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" / :"=a" (__res):"0" (seg),"m" (*(addr))); / __res;}) //取段seg中地址addr处的一个长字(4字节) #define get_seg_long(seg,addr) ({ / register unsigned long __res; / __asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" / :"=a" (__res):"0" (seg),"m" (*(addr))); / __res;}) //取fs段寄存器的值(选择符) #define _fs() ({ / register unsigned short __res; / __asm__("mov %%fs,%%ax":"=a" (__res):); / __res;}) //以下定义了一些函数的原型 int do_exit(long code);//程序退出处理(kernel/exit.c) void page_exception(void);//页异常,实际是page_fault(mm/page.s) //以下定义了一些中断处理程序的原型,代码在(kernel/asm.s或system_call.s)中。 void divide_error(void); void debug(void); void nmi(void); void int3(void); void overflow(void); void bounds(void); void invalid_op(void); void device_not_available(void); void double_fault(void); void coprocessor_segment_overrun(void); void invalid_TSS(void); void segment_not_present(void); void stack_segment(void); void general_protection(void); void page_fault(void); void coprocessor_error(void); void reserved(void); void parallel_interrupt(void); void irq13(void); //该程序用来打印出错中断的名称、出错号、调用程序的EIP、EFLAGS、ESP、fs段寄存器值、段的基址 //段的长度、进程号pid、任务号、10字节指令码。如果堆栈在用户段,则还可以打印16字节的堆栈内容。 static void die(char * str,long esp_ptr,long nr) { long * esp = (long *) esp_ptr; int i; printk("%s: %04x/n/r",str,nr&0xffff); printk("EIP:/t%04x:%p/nEFLAGS:/t%p/nESP:/t%04x:%p/n", esp[1],esp[0],esp[2],esp[4],esp[3]); printk("fs: %04x/n",_fs()); printk("base: %p, limit: %p/n",get_base(current->ldt[1]),get_limit(0x17)); if (esp[4] == 0x17) { printk("Stack: "); for (i=0;i<4;i++) printk("%p ",get_seg_long(0x17,i+(long *)esp[3])); printk("/n"); } str(i);//取当前运行任务的任务号(include/linux/sched.h) printk("Pid: %d, process nr: %d/n/r",current->pid,0xffff & i); for(i=0;i<10;i++) printk("%02x ",0xff & get_seg_byte(esp[1],(i+(char *)esp[0]))); printk("/n/r"); do_exit(11); /* play segment exception */ } //以下这些是以do开头的函数,对应中断处理程序调用的c函数。 void do_double_fault(long esp, long error_code) { die("double fault",esp,error_code); } void do_general_protection(long esp, long error_code) { die("general protection",esp,error_code); } void do_divide_error(long esp, long error_code) { die("divide error",esp,error_code); } void do_int3(long * esp, long error_code, long fs,long es,long ds, long ebp,long esi,long edi, long edx,long ecx,long ebx,long eax) { int tr; __asm__("str %%ax":"=a" (tr):"0" (0)); //取任务寄存器值-->tr printk("eax/t/tebx/t/tecx/t/tedx/n/r%8x/t%8x/t%8x/t%8x/n/r", eax,ebx,ecx,edx); printk("esi/t/tedi/t/tebp/t/tesp/n/r%8x/t%8x/t%8x/t%8x/n/r", esi,edi,ebp,(long) esp); printk("/n/rds/tes/tfs/ttr/n/r%4x/t%4x/t%4x/t%4x/n/r", ds,es,fs,tr); printk("EIP: %8x CS: %4x EFLAGS: %8x/n/r",esp[0],esp[1],esp[2]); } void do_nmi(long esp, long error_code) { die("nmi",esp,error_code); } void do_debug(long esp, long error_code) { die("debug",esp,error_code); } void do_overflow(long esp, long error_code) { die("overflow",esp,error_code); } void do_bounds(long esp, long error_code) { die("bounds",esp,error_code); } void do_invalid_op(long esp, long error_code) { die("invalid operand",esp,error_code); } void do_device_not_available(long esp, long error_code) { die("device not available",esp,error_code); } void do_coprocessor_segment_overrun(long esp, long error_code) { die("coprocessor segment overrun",esp,error_code); } void do_invalid_TSS(long esp,long error_code) { die("invalid TSS",esp,error_code); } void do_segment_not_present(long esp,long error_code) { die("segment not present",esp,error_code); } void do_stack_segment(long esp,long error_code) { die("stack segment",esp,error_code); } void do_coprocessor_error(long esp, long error_code) { if (last_task_used_math != current) return; die("coprocessor error",esp,error_code); } void do_reserved(long esp, long error_code) { die("reserved (15,17-47) error",esp,error_code); } //下面是异常(陷阱)中断称许初始化子程序。设置中断调用门(中断向量)。set_trap_gate()与 //set_system_gate()主要区别在于前者设置的特权级为0,后者为3。因此断点int3、溢出overflow //和边界出错中断bounds可由任何程序产生。这两个函数均是嵌入式汇编宏(include/asm/system.h) void trap_init(void) { int i; set_trap_gate(0,÷_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++) //将int17~48的陷阱门先均设置为reserverd。 set_trap_gate(i,&reserved); //以后各硬件初始化时会重新设置自己的陷阱门。 set_trap_gate(45,&irq13); //设置协处理器的陷阱门 outb_p(inb_p(0x21)&0xfb,0x21); //允许主8359A芯片的IRQ2中断请求。 outb(inb_p(0xA1)&0xdf,0xA1); //允许从8359A芯片的IRQ2中断请求。 set_trap_gate(39,¶llel_interrupt); //设置并行口的陷阱门。 }
抱歉!评论已关闭.