linux 0.11 内核学习 -- asm.s,机器难免出故障。

来源:互联网 发布:itunes windows xp版 编辑:程序博客网 时间:2024/06/05 13:35

/*

 *  linux/kernel/asm.s

 *

 *  (C) 1991  Linus Torvalds

 */

 

/*

 * asm.s contains the low-level code for most hardware faults.

 * page_exception is handled by the mm, so that isn't here. This

 * file also handles (hopefully) fpu-exceptions due to TS-bit, as

 * the fpu must be properly saved/resored. This hasn't been tested.

 */

 

/*

 * asm.asm处理的主要是和硬件相关的故障。注意的是页异常是有mm模块

 * 来实现管理的,所以在这里不需要处理。此外此程序来处理fpu的异常。

 *

 */

 

/*

 * 全局函数的定义,主要是引用的是traps.c文件中的函数声明。

 * 下面的代码主要是对intel的保留中断int0 -- int16的处理。

 */

.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op

.globl _double_fault,_coprocessor_segment_overrun

.globl _invalid_TSS,_segment_not_present,_stack_segment

.globl _general_protection,_coprocessor_error,_irq13,_reserved

 

# 一下的中断都是Intel得保留中断的处理程序。

#------------------------------------------------------------------------

# int0 -- 被0除所引发的中断。下面的$_do_divide_error是c函数编译之后

# 对应的模块的名称。

_divide_error:

pushl $_do_divide_error# 首先将函数入口地址压入堆栈。

no_error_code:# 标号相当于函数被下面程序调用。

xchgl %eax,(%esp)# xchgl指令的作用是交换寄存器。

# 在此的含义是将函数的地址存在

# eax中,将eax原来内容入栈。

pushl %ebx# 寄存器入栈

pushl %ecx

pushl %edx

pushl %edi

pushl %esi

pushl %ebp

push %ds

push %es

push %fs

 

####################################################

# 将出错码和中断返回地址入栈作为函数调用_do_divide_error

# 的参数。

pushl $0# "error code",出错码0入栈

lea 44(%esp),%edx# 取得中断返回地址

pushl %edx# 中断返回地址入栈

#####################################################

 

# 下面的代码重新设置寄存器。ds和es指向的是内核代码段

# fs指向的是用户数据段。

movl $0x10,%edx

mov %dx,%ds

mov %dx,%es

mov %dx,%fs

 

call *%eax# 调用函数,函数的地址在上面已经保存在eax。

 

addl $8,%esp# 将堆栈指针指向fs寄存器入栈处。

# 恢复现场。

pop %fs

pop %es

pop %ds

popl %ebp

popl %esi

popl %edi

popl %edx

popl %ecx

popl %ebx

popl %eax# 弹出原来eax内容

iret# 中断返回。

#-------------------------------------------------------------------------

 

#--------------------------------------------------------------------------

# 调试中断入口点

_debug:

pushl $_do_int3# _do_debug函数地址入栈

jmp no_error_code

#---------------------------------------------------------------------------

 

#---------------------------------------------------------------------------

# 非屏蔽中断调用入口点。

# 中断和异常是不相同的。中断是由定时器和io设备产生的。异常则是由程序的执行错误

# 导致的。每个中断和异常由0~255之间的一个数(8位)来标识,Intel称其为中断向量

# (vector)。非屏蔽中断的向量和异常的向量是固定的,可屏蔽中断的向量可以通过对

# 中断控制器的编程来改变

pushl $_do_nmi

jmp no_error_code

#---------------------------------------------------------------------------

# 通_debug。

_int3:

pushl $_do_int3

jmp no_error_code

#----------------------------------------------------------------------------

 

#-----------------------------------------------------------------------------

# 溢出错误处理程序。

_overflow:

pushl $_do_overflow

jmp no_error_code

#----------------------------------------------------------------------------

# 边界检查出错处理程序

_bounds:

pushl $_do_bounds

jmp no_error_code

#-----------------------------------------------------------------------------

 

#----------------------------------------------------------------------------

# 无效操作指令。

_invalid_op:

pushl $_do_invalid_op

jmp no_error_code

#---------------------------------------------------------------------------

 

#---------------------------------------------------------------------------

# 协处理器段超出异常。

_coprocessor_segment_overrun:

pushl $_do_coprocessor_segment_overrun

jmp no_error_code

#---------------------------------------------------------------------------

 

#---------------------------------------------------------------------------

# 保留。

_reserved:

pushl $_do_reserved

jmp no_error_code

#----------------------------------------------------------------------------

 

#-----------------------------------------------------------------------------

# 数学协处理器在完成计算之后使用下面的中断来通知cpu计算完成。使用irq13中断。

_irq13:

pushl %eax

xorb %al,%al

outb %al,$0xF0

movb $0x20,%al

outb %al,$0x20

jmp 1f

1:jmp 1f

1:outb %al,$0xA0

popl %eax

jmp _coprocessor_error

#-------------------------------------------------------------------------

 

#-------------------------------------------------------------------------

# 以下的中断调用会在中断返回地址之后将出错号压入堆栈,因此在返回时需要将

# 出错号弹出。

# int8 -- 双出错故障。

_double_fault:

pushl $_do_double_fault

error_code:

xchgl %eax,4(%esp)# error code <-> %eax

xchgl %ebx,(%esp)# &function <-> %ebx

pushl %ecx

pushl %edx

pushl %edi

pushl %esi

pushl %ebp

push %ds

push %es

push %fs

pushl %eax# error code

lea 44(%esp),%eax# offset

pushl %eax

movl $0x10,%eax

mov %ax,%ds

mov %ax,%es

mov %ax,%fs

call *%ebx

addl $8,%esp

pop %fs

pop %es

pop %ds

popl %ebp

popl %esi

popl %edi

popl %edx

popl %ecx

popl %ebx

popl %eax

iret

#-----------------------------------------------------------------------------

# 无效任务状态段。

_invalid_TSS:

pushl $_do_invalid_TSS

jmp error_code

#-----------------------------------------------------------------------------

# 段不存在。

_segment_not_present:

pushl $_do_segment_not_present

jmp error_code

#------------------------------------------------------------------------------

# 堆栈错误。

_stack_segment:

pushl $_do_stack_segment

jmp error_code

#------------------------------------------------------------------------------

# 一般性保护出错。

_general_protection:

pushl $_do_general_protection

jmp error_code

#----------------------------------------------------------------------------

#

# int7 -- 设备不存在。

# int14 -- 页错误。

# int16 -- 协处理器错误。

# int 0x20 -- 时钟中断。

# int 0x80 -- 系统调用。

 

参考《linux内核完全注释》和网上相关文章

原创粉丝点击