asm.s
是Linux内核的一部分,主要负责处理各种类型的硬件异常和中断。
-
_divide_error
处理除法错误中断。当CPU执行除法指令时遇到除数为零的情况,会触发这个中断。此函数首先保存当前的寄存器状态,然后调用_do_divide_error函数来处理具体的错误。处理完毕后,它恢复寄存器的状态并返回中断前的上下文。 -
_debug
处理调试中断。当运行调试指令如INT 3时,会触发此中断。它通过跳转到_do_int3函数来处理这个中断,_do_int3通常用于调试目的。 -
_nmi
处理非屏蔽中断(NMI)。NMI是一种不能被处理器屏蔽的中断,常用于系统监控或错误检测。它同样通过跳转到_do_nmi函数来处理中断。 -
_int3
处理中断3。这通常与调试有关,类似于_debug,但通过直接跳转到_do_int3函数来处理。 -
_overflow
处理溢出中断。当算术运算的结果超出寄存器能表示的范围时,会触发此中断。它通过调用_do_overflow函数来处理。 -
_bounds
处理边界检查中断。当访问数组越界时,会触发此中断。它通过调用_do_bounds函数来处理。 -
_invalid_op
处理无效操作码中断。当遇到CPU不认识的操作码时,会触发此中断。它通过调用_do_invalid_op函数来处理。 -
_coprocessor_segment_overrun
处理协处理器段越界中断。当协处理器访问超出其权限的内存时,会触发此中断。它通过调用_do_coprocessor_segment_overrun函数来处理。 -
_reserved
处理保留中断。当遇到未定义的中断类型时,会触发此中断。它通过调用_do_reserved函数来处理。 -
_irq13
处理IRQ13中断。IRQ13通常用于键盘中断,但在这个上下文中,它似乎用于处理协处理器错误。它首先清除中断信号,然后跳转到_coprocessor_error函数进行处理。 -
_double_fault
处理双重故障中断。当处理器在处理一个中断时又遇到另一个中断,而这个新的中断无法处理时,会触发此中断。它保存所有寄存器的状态,设置错误代码,然后调用_do_double_fault函数来处理。 -
_invalid_TSS
处理无效任务状态段(TSS)中断。当尝试切换到一个无效的TSS时,会触发此中断。它通过调用_do_invalid_TSS函数来处理。 -
_segment_not_present
处理段不存在中断。当尝试访问一个不存在的段时,会触发此中断。它通过调用_do_segment_not_present函数来处理。 -
_stack_segment
处理栈段中断。当栈段出现错误时,会触发此中断。它通过调用_do_stack_segment函数来处理。 -
_general_protection
处理通用保护中断。当发生任何违反保护机制的行为时,如访问受限内存,会触发此中断。它通过调用_do_general_protection函数来处理。
每个处理函数都会保存当前的寄存器状态,调用相应的处理函数,然后恢复寄存器状态并返回中断前的上下文。这种设计确保了在处理中断时系统的稳定性和安全性。
asm.s
源码
/*
* 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.
*/
.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
_divide_error:
pushl $_do_divide_error
no_error_code:
xchgl %eax,(%esp)
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
pushl $0 # "error code"
lea 44(%esp),%edx
pushl %edx
movl $0x10,%edx
mov %dx,%ds
mov %dx,%es
mov %dx,%fs
call *%eax
addl $8,%esp
pop %fs
pop %es
pop %ds
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %eax
iret
_debug:
pushl $_do_int3 # _do_debug
jmp no_error_code
_nmi:
pushl $_do_nmi
jmp no_error_code
_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
_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
_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