3.3.1 在内核中保存寄存器的值

   所有异常处理程序被调用的方式比较相似,因此,我们用handler_name来表示一个通用的异常处理程序的名字(实际名字都出现在表3.1中)。进入异常处理程序的汇编指令在arch/I386/kernel/entry.S中:

 

handler_name:

    pushl $0  /* only for some exceptions */

    pushl $do_handler_name

jmp error_code

 

例如: overflow

                pushl $0

                pushl $ do_overflow

                jmp error_code

 

    当异常发生时,如果控制单元没有自动地把一个硬件错误代码插入到中,相应的汇编语言片段会包含一条pushl $0指令,在中垫上一个空值,如果错误码已经被压入堆栈,则没有这条指令。然后,把异常处理函数的地址压进中;函数的名字由异常处理程序名与do_前缀组成。

    标号为error_code的汇编语言片段对所有的异常处理程序都是相同的,除了“设备不可用”这一个异常。这段代码为实际上是为异常处理程序的调用和返回进行相关的操作,代码如下:

 

 

 

 

 

   error_code:

         pushl %ds

         pushl %eax

         xorl %eax,%eax

         pushl %ebp               

         pushl %edi              C函数可能用到的寄存器都保存在

         pushl %esi                  

         pushl %edx

         decl %eax            eax = -1            

         pushl %ecx

         pushl %ebx

         cld                   eflags的方向标志,以确保ediesi寄存器的值自动增加

         movl %es,%ecx

         movl ORIG_EAX(%esp), %esi       # get the error code, ORIG_EAX= 0x24

         movl ES(%esp), %edi              # get the function address, ES = 0x20

         movl %eax, ORIG_EAX(%esp)      #把中的这个位置-1

         movl %ecx, ES(%esp)

         movl %esp,%edx

         pushl %esi                      # push the error code

         pushl %edx                     # push the pt_regs pointer

         movl $(__KERNEL_DS),%edx

         movl %edx,%ds           #把内核数据段选择符装入ds寄存器

         movl %edx,%es

         GET_CURRENT(%ebx)     ebx中存放当前进程task_struct结构的地址

         call *%edi                           #调用这个异常处理程序

         addl $8,%esp

        jmp ret_from_exception

如图3.6给出从用户进程进入异常处理程序时内核堆栈的示意图:

 

 

 

 

 

 

 

 

 

 

 

                                  +0x38     用户SS    

                                      +0x34     用户ESP      用户堆栈指针

                                      +0x30            EFLAGS

                                      +0x2C  用户空间的CS

                                      +0x28            EIP         返回到用户态的地址

                                      +0x24     错误码或0

                                      +0x20      函数地址

                                      +0x1C       DS

                                      +0x18      EAX    

                                      +0x14           EBP

                                      +0x10           EDI

                                      +0XC            ESI

                                      +8          EDX

                                      +4          ECX

内核堆栈指针ESP                    0           EBX

 

                    a 进入异常处理程序时内核堆栈示意图

 

                              

 

 

 +0x38     用户SS    

                                      +0x34     用户ESP

                                      +0x30           EFLAGS

                                      +0x2C   用户空间的CS

                                      +0x28           EIP

                                      +0x24   -1           

                                      +0x20    ES         

                                      +0x1C    DS

                                      +0x18           EAX      

                                      +0x14           EBP

                                      +0x10     EDI

                                      +0XC           ESI

                                      +8         EDX

                                      +4         ECX

                                          0         EBX

                                                       错误码

内核堆栈指针ESP                                  ESP

 

b     异常处理程序被调用后堆栈的示意图

                  3.6 进入异常后内核堆栈的变化