Linux内核2:中断代码分析
总体来说,中断相关的汇编代码有两个,asm.s,systemcall.s ,其中定义了中断发生前的相关参数入栈,调用的C函数入口地址入栈,中断发生后的恢复。而各种中断的C函数代码分布在不同的C文件中。如下表所示。
中断前处理,调用,中断后恢复 | 执行中断函数的C文件 | |
---|---|---|
硬中断的处理 | asm.s | trap.c |
软件及系统调用的处理 | system_call.s | fork.c signal.c exit.c sys.c |
比如,asm.s中包含了各种错误的中断相关汇编代码。其中具体实现又调用了c的代码,使用了各种do函数,这些do函数在traps.c文件中有定义
1 | /* |
比如divide_error除法错误的中断,就调用了do_divide_error函数,这个在traps.c中定义如下
1 | void do_divide_error(long esp, long error_code) |
其中又调用了die函数
1 | static void die(char * str,long esp_ptr,long nr) |
die函数在traps.c中定义,入口参数有三个:一个字符串,一个栈顶指针(ESP为8086体系中的栈顶指针),一个(段号,在哪里出错的段号)
die函数的具体内容:首先,3:10打印一些入栈的参数。然后,11:21打印栈里的一些内容,get_seg_long函数是从段里取一个4字节的整数。do_exit帮忙退出。
整体来说,die函数就是打印一些栈的信息,错误号(中断号),可以当成一个print函数
在traps.c中基本都是背调用的中断的函数,最后有一个trap_init函数,比较特殊
1 | void trap_init(void) |
这个函数是整个中断的初始化函数,主要由两个函数组成,set_trap_gate和set_system_gate。这两个函数主要是权限不同,set_trap_gate优先级为0,只能由用户程序产生,set_system_gate优先级为3,能被所有的程序产生,用户与系统都可以调用
1 |
大部分中断函数只进行了打印,而没有真正的实现
在中断发生的时候,操作系统做了什么?
每一个进程,操作系统会分配一些内存,由代码段,数据段(程序的全局变量等),TSS段程序状态段(状态码),栈(临时运行,调用的参数)。
上面提到的asm.s里面的入栈,出栈,就是这个栈。比如CPU通用寄存器的数据,函数入口地址等临时放到了栈里。
但是system_call.s的调用中断函数的过程和asm不同,asm是把函数的入口地址放到了寄存器中,而system_call是放到了sys_call_table中,所有的系统调用C函数放到了这里面
1 | /* |
eax中放的是系统调用的操作码,sys_call_table在sys.h中,里面放了所有的系统调用
1 | fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read, |