中断处理有三个阶段
进入阶段:栈保存(带出错码的中断、不带出错码的中断)
处理阶段:中断处理
退出阶段:恢复栈
80×86中有特权级的概念,不同的特权级有不同的栈,所以中断发生时要保存中断前的栈地址。
查看intel使用手册
interrupt.s源代码文件(参考linux 0.11源代码)
.global divide_error,debug_exception,nmi,breakpoint,overflow,bound,invalid_opcode
.global coprocessor_not_available,double_fault,coprocessor_segment_overrun,invalid_tss
.global segment_not_present,stack_exception,protection_exception,page_fault
.global intel_reserved,coprecessor_error,default_isr,timer
.include "kernel.inc"
divide_error:
pushl $do_divide_error
no_error_code:
xchgl %eax, (%esp) # &function-> %eax, 原%eax放到栈中
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
pushl $0 # 填充错误码,作为中断处理函数的参数
lea 52(%esp), %edx #当前堆栈地址加上52后,放到edx中
pushl %edx #压edx入栈,这样中断处理函数就能获取到被压入栈的寄存器的值
movl $DATA_SEL, %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
invalid_tss:
pushl $do_invalid_tss
error_code:
xchgl %eax, 4(%esp) # error code -> %eax, 原eax放到栈中
xchgl %ebx, (%esp) # &function -> %ebx,原ebx放到栈中
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
pushl %ds
pushl %es
pushl %fs
pushl %eax # 压入错误码,作为中断处理函数的参数
lea 52(%esp), %eax # 当前堆栈地址加上52后,放到eax中
pushl %eax # 压eax入栈,这样中断处理函数就能获取到被压入栈的寄存器的值
movl $DATA_SEL, %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
debug_exception:
pushl $do_debug_exception
jmp no_error_code
nmi:
pushl $do_nmi
jmp no_error_code
breakpoint:
pushl $do_breakpoint
jmp no_error_code
overflow:
pushl $do_overflow
jmp no_error_code
bound:
pushl $do_bound
jmp no_error_code
invalid_opcode:
pushl $do_invalid_opcode
jmp no_error_code
coprocessor_not_available:
pushl $do_coprocessor_not_available
jmp no_error_code
coprocessor_segment_overrun:
pushl $do_coprocessor_segment_overrun
jmp no_error_code
intel_reserved:
pushl $do_intel_reserved
jmp no_error_code
coprecessor_error:
pushl $do_coprocessor_error
jmp no_error_code
timer:
pushl $do_timer
jmp no_error_code
double_fault:
pushl $do_double_fault
jmp error_code
invaild_tss:
pushl $do_invalid_tss
jmp error_code
segment_not_present:
pushl $do_segment_not_present
jmp error_code
stack_exception:
pushl $do_stack_exception
jmp error_code
protection_exception:
pushl $do_protection_exception
jmp error_code
page_fault:
pushl $do_page_fault
jmp error_code
default_isr:
pushl $do_default_isr
jmp no_error_code
interrupt.h源代码文件
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_
//在中断处理函数中,每个寄存器在栈中的下标
#define OLD_SS_REG 2
#define OLD_ESP_REG 1
#define OLD_EFLAGS_REG 0
#define OLD_CS_REG -1
#define OLD_EIP_REG -2
#define EAX_REG -3
#define EBX_REG -4
#define ECX_REG -5
#define EDX_REG -6
#define EDI_REG -7
#define ESI_REG -8
#define EBP_REG -9
#define DS_REG -10
#define ES_REG -11
#define FS_REG -12
extern void default_isr(void); //该函数定义在idt.c文件中
extern void divide_error(void);
extern void debug_exception(void);
extern void nmi(void);
extern void breakpoint(void);
extern void overflow(void);
extern void bound(void);
extern void invalid_opcode(void);
extern void coprocessor_not_available(void);
extern void double_fault(void);
extern void coprocessor_segment_overrun(void);
extern void invalid_tss(void);
extern void segment_not_present(void);
extern void stack_exception(void);
extern void protection_exception(void);
extern void page_fault(void);
extern void intel_reserved(void);
extern void coprecessor_error(void);
extern void timer(void);
extern void sys_call(void);
#endif