在深入理解linux内核课程结束之际,我觉得对中断过程的理解,太浅薄。于是又重新将孟宁老师的系统中断部分再一次的听讲了一遍,并希望能够从中理解更多有关中断的处理过程。
系统中断
在课程中,老师以系统中断为例子讲解。这里我也从系统中断开篇。
当应用程序在应用层调用系统调用时,比如调用了read函数,那么经过库函数sys_call,将会通过int 0x80进入到内核中。此时会发生什么呢?
首先,因为是中断过程,硬件会保存部分现场。硬件保存的内容包括哪些呢?
- 用户态栈的栈顶值
- 当时的状态字
- 当时的cs:eip的值
保存的位置在栈中保存。保存到了用户的栈上。
如果保存到了用户的栈上,那么此时sp的值到底还是不是指向栈顶的位置呢?也许是,也许不是。
特别值得提出的是,对sp的保存,也保存到了栈中,这是如何完成的呢?在扩展中进一步的分析。
理解与扩展
通过上述的硬件保存的值,我们可以知道保存了栈顶值,从而可以推测出在内核态中栈顶值将会是另外一个,也就说,内核中仍然有一个栈,是和用户态中的栈不是一起的。
保存了状态值。这个状态是在eflag寄存器的值。看来这个寄存器的值对硬件是十分重要的。虽然在软件编程的过程中,我们不需要涉及到,但是他的值可能会影响很多程序的走向。保存eflag的值,接下来更换新的eflag的时候,将会指示当前程序的模式是内核模式了。
保存eip的值,当我们返回时将会继续执行应用程序,只要把他弹出来即可。这里进一步的分析。cs:eip的值,在应用层指向了用户空间的代码段。那么保存之后,将会指向内核的代码段中的语句。cs:eip的值更新后,将会自动的指向内核空间。cs:eip的值肯定会被更新到0xC000 000之上的位置中。
刚才我们看到int 0x80保存这些值到栈中,如何保存的呢? 老师在课程中讲到是硬件完成的。硬件是如何完成的呢?不知道。这需要查芯片手册估计才能明确。
另外,int 0x80保存了sp的值到栈中,但是没有保存bp的值。是不需要保存吗?显然不是,因为用户空间的栈和内核空间的栈是两个部分。现在推论不是硬件保存的,而是软件保存的,在后文中应该可以看到。此处存疑。
软件保存现场
我们的硬件保存现场之后,在进入中断处理函数中,第一件事情是,SAVE_ALL做的事情。又继续保存现场。
那么为什么这里还需要保存现场呢?
原因是在硬件保存现场中,保存的寄存器的值还不够,还要进一步的保存。
在代码中我们找到了SAVE_ALL的调用之处:
代码位置:
arch/x86/kernel/entry.s
# system call handler stub
ENTRY(system_call)
RING0_INT_F