ints.asm

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· 汇编 代码 · 共 628 行

ASM
628
字号
; -----------------------------------------------
; $Id: ints.asm,v 1.4 2003/12/13 08:07:47 epr Exp $
;
; Interrupts code
;
; Author       : E.. Prangsma
; -----------------------------------------------

    global Lsetup_idt

; -------------------------------------
; Stack for inthandler & irqhandler
; -------------------------------------

OLD_SS      equ 76
OLD_ESP     equ 72
OLD_EFLAGS  equ 68
OLD_CS      equ 64
OLD_EIP     equ 60
ERROR       equ 56
INTNO   	equ 52
HANDLER     equ 48 
OLD_EAX     equ 44
OLD_ECX     equ 40
OLD_EDX     equ 36
OLD_EBX     equ 32
;OLD_ESP     equ 28
OLD_EBP     equ 24
OLD_ESI     equ 20
OLD_EDI     equ 16
OLD_DS      equ 12
OLD_ES      equ 8
OLD_FS      equ 4
OLD_GS      equ 0

%macro int_entry 0
    pusha 
    push ds
    push es
    push fs
    push gs
    mov eax,KERNEL_DS
    mov ds,ax
    mov es,ax
    mov gs,ax
    ; Do not overwrite FS here, since it will always contain the current processor selector
    %if TRACE_INTERRUPTS
		inc byte [0xb8000+0*2]
	%endif
    cld
%endmacro

%macro int_exit 0
    mov eax,esp
    and dword [esp+OLD_EFLAGS],~F_NT ; Clear NT flag
    and byte [gdt_tss+5],~0x02       ; Clear busy bit in TSS descriptor
    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp,12 ; Remove HANDLER & INTNO & ERRORCODE 
    iret
%endmacro

; -------------------------
; Generic interrupt handler
; -------------------------
inthandler:
    int_entry
	mov eax,esp
	mov ebp,esp
	cmp dword [ebp+OLD_CS],USER_CS
	jne kernel_panic
	mov ebx,[esp+HANDLER]
	call ebx
	test dword [resume_int],0xFFFFFFFF
	jz inthandler_ret
	; Resume the interrupt (caused by an an IRQ)
	;jmp int_die
	mov ebp,esp
	mov eax,[resume_intno]
	mov [ebp+INTNO],eax
	mov eax,[resume_error]
	mov [ebp+ERROR],eax
	mov eax,[resume_handler]
	mov [ebp+HANDLER],eax
	mov dword [resume_int],0
	jmp irqhandler_resume
inthandler_ret:
    int_exit
    
resume_int: dd 0
resume_intno: dd 0
resume_error: dd 0
resume_handler: dd 0
    
kernel_panic:
	mov eax,kernel_panic_msg
	call sys_print_str
	jmp int_die
	
kernel_irq_panic:
	mov eax,kernel_irq_panic_msg
	call sys_print_str
	jmp int_die
	
kernel_panic_msg: db 'Kernel panic!',0xd,0xa,0
kernel_irq_panic_msg: db 'Kernel panic in IRQ!',0xd,0xa,0

; -----------------------------------------------
; Unhandled interrupt. Die
; -----------------------------------------------
; EAX contains a reference to the register structure

int_die:
	cli
	mov ebx,ebp
	call sys_print_intregs
	;ret
int_die_halt:
	cli
	mov eax,int_die_halt_msg
	call sys_print_str
	hlt

int_die_halt_msg: db 'Real panic: int_die_halt!',0

%macro idm_print_reg 2
	push eax
	mov eax,idm_%1
	call sys_print_str
	pop eax
	mov eax,%2
	call sys_print_eax
%endmacro

%macro idm_print_byte 2
	push eax
	mov eax,idm_%1
	call sys_print_str
	pop eax
	movzx eax,byte %2
	call sys_print_al
%endmacro

sys_print_intregs:
	idm_print_reg intno, [ebp+INTNO]
	idm_print_reg error, [ebp+ERROR]
	idm_print_reg cr2, cr2
	idm_print_reg cr3, cr3
	idm_print_reg eip, [ebp+OLD_EIP]
	idm_print_reg cs,  [ebp+OLD_CS]
	idm_print_reg eflags, [ebp+OLD_EFLAGS]
	idm_print_reg eax, [ebp+OLD_EAX]
	idm_print_reg ebx, [ebp+OLD_EBX]
	idm_print_reg ecx, [ebp+OLD_ECX]
	idm_print_reg edx, [ebp+OLD_EDX]
	idm_print_reg ebp, [ebp+OLD_EBP]
	idm_print_reg esp, [ebp+OLD_ESP]
	idm_print_reg edi, [ebp+OLD_EDI]
	idm_print_reg esi, [ebp+OLD_ESI]
	idm_print_reg ds,  [ebp+OLD_DS]
	idm_print_reg es,  [ebp+OLD_ES]
	idm_print_reg fs,  [ebp+OLD_FS]
	idm_print_reg gs,  [ebp+OLD_GS]
	mov ebx,[ebp+OLD_ESP]
	idm_print_reg stack0,  [ebx+0]
	idm_print_reg stack1,  [ebx+4]
	idm_print_reg stack1,  [ebx+8]
	idm_print_reg stack1,  [ebx+12]
	idm_print_reg stack1,  [ebx+16]
	idm_print_reg stack1,  [ebx+20]
	mov ebx,[ebp+OLD_EIP]
	idm_print_byte ip0,	   [ebx+0]
	idm_print_byte ip1,	   [ebx+1]
	idm_print_byte ip1,	   [ebx+2]
	idm_print_byte ip1,	   [ebx+3]
	idm_print_byte ip1,	   [ebx+4]
	idm_print_byte ip1,	   [ebx+5]
	idm_print_byte ip1,	   [ebx+6]
	idm_print_byte ip1,	   [ebx+7]
	idm_print_byte ip1,	   [ebx+8]
	idm_print_byte ip1,	   [ebx+9]
	idm_print_byte ip1,	   [ebx+10]
	idm_print_byte ip1,	   [ebx+11]
	idm_print_byte ip1,	   [ebx+12]
	idm_print_byte ip1,	   [ebx+13]
	idm_print_byte ip1,	   [ebx+14]
	idm_print_byte ip1,	   [ebx+15]
	ret

idm_intno:  db 0xd,0xa,'int  : ',0
idm_error:  db        ' Error: ',0
idm_cr2:    db        ' CR2  : ',0
idm_cr3:    db        ' CR3  : ',0
idm_eip:    db 0xd,0xa,'EIP  : ',0
idm_cs:     db        ' CS   : ',0
idm_eflags: db        ' FLAGS: ',0
idm_eax:    db 0xd,0xa,'EAX  : ',0
idm_ebx:    db        ' EBX  : ',0
idm_ecx:    db        ' ECX  : ',0
idm_edx:    db        ' EDX  : ',0
idm_ebp:    db 0xd,0xa,'EBP  : ',0
idm_esp:    db        ' ESP  : ',0
idm_edi:    db        ' EDI  : ',0
idm_esi:    db        ' ESI  : ',0
idm_ds:     db 0xd,0xa,'DS   : ',0
idm_es:     db        ' ES   : ',0
idm_fs:     db        ' FS   : ',0
idm_gs:     db        ' GS   : ',0
idm_stack0: db 0xd,0xa,'STACK: ',0
idm_stack1: db        0
idm_ip0:    db 0xd,0xa,'CODE : ',0
idm_ip1:    db        0

; -------------------
; Generic IRQ handler
; -------------------

irqhandler:
    int_entry
	mov eax,esp
	mov ebp,esp
	cmp dword [esp+OLD_CS],USER_CS
	jne irqhandler_suspend
irqhandler_resume:
	call dword [esp+HANDLER]
irqhandler_ret:
	%if TRACE_INTERRUPTS
		inc byte [0xb8000+79*2]
	%endif
	int_exit
irqhandler_suspend:
	;jmp int_die
	and dword [esp+OLD_EFLAGS],~F_IF
	mov eax,[esp+INTNO]
	mov dword [resume_intno],eax
	mov eax,[esp+ERROR]
	mov dword [resume_error],eax
	mov eax,[esp+HANDLER]
	mov dword [resume_handler],eax
	mov eax,1
	xchg dword [resume_int],eax
	; Test for resume overruns
	test eax,eax
	jz inthandler_ret ; No overrun, finish int handler
	mov eax,irq_resume_overrun_msg
	call sys_print_str
	jmp inthandler_ret

irq_suspend_msg: db 'IRQ suspend!',0
irq_resume_overrun_msg: db 'IRQ resume overrun!',0

; Int handler code for interrupts without error code
; Parameters <label> <int no>
%macro int_noerror 2
stub_%1:
	push dword 0   ; error code
	push dword %2  ; int no
	push dword %1  ; handler
	jmp inthandler
%endmacro

; Int handler code for interrupts with error code
; Parameters <label> <int no>
%macro int_error 2
stub_%1:
	push dword %2   ; int no
	push dword %1   ; handler
	jmp inthandler
%endmacro

int_noerror int_div, 0		; Division by zero
int_noerror int_debug, 1	; Debug
int_noerror int_nmi, 2		; Non maskable Interrupt
int_noerror int_bp, 3		; Breakpoint
int_noerror int_of, 4		; Overflow
int_noerror int_bc, 5		; Bounds check
int_noerror int_inv_oc, 6	; Invalid opcode
int_noerror int_copro_na, 7	; Coprocessor not available
int_error   int_df, 8		; Double fault
int_noerror int_copro_or, 9	; Coprocessor overrun
int_error   int_inv_tss, 10	; Invalid TSS
int_error   int_snp, 11		; Segment not present
int_error   int_sf, 12		; Stack fault
int_error   int_gpf, 13		; General protection fault
int_error   int_pf, 14		; Page fault
int_noerror int_copro_err, 16	; Coprocessor error
int_noerror int_stack_overflow,0x31	; Stack overflow trap

; IRQ handler code
; Parameters <irq no> <handler>
%macro int_irq 2
stub_irq%1:
	push dword 0  ; error code
	push dword %1 ; irq no
	push dword %2 ; handler
	jmp irqhandler
%endmacro

int_irq 0, timer_handler
int_irq 1, def_irq_handler
int_irq 2, def_irq_handler
int_irq 3, def_irq_handler
int_irq 4, def_irq_handler
int_irq 5, def_irq_handler
int_irq 6, def_irq_handler
int_irq 7, def_irq_handler
int_irq 8, def_irq_handler
int_irq 9, def_irq_handler
int_irq 10, def_irq_handler
int_irq 11, def_irq_handler
int_irq 12, def_irq_handler
int_irq 13, def_irq_handler
int_irq 14, def_irq_handler
int_irq 15, def_irq_handler

; intport <index> <offset> [<dpl>]
%macro intport 2-3 0
	mov eax,stub_%2
	mov edi,idtstart+((%1)*8)
	mov ebx,0x8e00 | (%3 << 13)
	call setup_idtentry
%endmacro

; trapport <index> <offset> [<dpl>]
%macro trapport 2-3 0
	mov eax,stub_%2
	mov edi,idtstart+((%1)*8)
	mov ebx,0x8f00 | (%3 << 13)
	call setup_idtentry
%endmacro

; Setup and IDT entry
; Parameters
;   EDI offset of IDT entry
;   EAX offset of handler
;   EBX type of IDT entry
;	0x8e00 = interrupt port (dpl=0)
;	0xee00 = interrupt port (dpl=3)
;	0x8f00 = trap port (dpl=0)
;	0xef00 = trap port (dpl=3)
setup_idtentry:
	mov word [edi+0],ax
	shr eax,16
	mov word [edi+2],KERNEL_CS
	mov word [edi+4],bx
	mov word [edi+6],ax
	ret

idt:
	dw idtend-idtstart
	dd idtstart

idtstart:
	times (0x40)*8 db 0
idtend:

Lsetup_idt:
    ; First disable NMI
	in al,0x70
	or al,0x80
	out 0x70,al

	intport 0, int_div		; Division by 0
	intport 1, int_debug    ; Debug exception
	intport 2, int_nmi		; NMI
	intport 3, int_bp		; Breakpoint
	intport 4, int_of		; Overflow
	intport 5, int_bc, 3	; Bounds check
	intport 6, int_inv_oc	; Invalid opcode
	intport 7, int_copro_na	; Coprocessor not available
	intport 8, int_df		; Double fault
	intport 9, int_copro_or	; Coprocessor overrun
	intport 10, int_inv_tss	; Invalid TSS
	intport 11, int_snp		; Segment not present
	intport 12, int_sf		; Stack exception
	intport 13, int_gpf		; General protected fault
	intport 14, int_pf		; Page fault
	intport 16, int_copro_err; Coprocessor error

	intport 0x20, irq0
	intport 0x21, irq1
	intport 0x22, irq2
	intport 0x23, irq3
	intport 0x24, irq4
	intport 0x25, irq5
	intport 0x26, irq6
	intport 0x27, irq7
	intport 0x28, irq8
	intport 0x29, irq9
	intport 0x2A, irq10
	intport 0x2B, irq11
	intport 0x2C, irq12
	intport 0x2D, irq13
	intport 0x2E, irq14
	intport 0x2F, irq15
	
	intport 0x30, yieldPointHandler, 3
	intport 0x31, int_stack_overflow, 3

	lidt [idt]

; Now we have to reprogram the interrupts :-(
; we put them right after the intel-reserved hardware interrupts, at
; int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
; messed this up with the original PC, and they haven't been able to
; rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
; which is used for the internal hardware interrupts as well. We just
; have to reprogram the 8259's, and it isn't fun.

	mov	al,0x11		; initialization sequence
	out	0x20,al		; send it to 8259A-1
	call	delay
	mov	al,0x20		; start of hardware int's (0x20)
	out	0x21,al
	call	delay
	mov	al,0x04		; 8259-1 is master
	out	0x21,al
	call	delay
	mov	al,0x01		; 8086 mode for both
	out	0x21,al
	call	delay

	mov	al,0x11		; initialization sequence
	out	0xA0,al		; and to 8259A-2
	call	delay
	mov	al,0x28		; start of hardware int's 2 (0x28)
	out	0xA1,al
	call	delay
	mov	al,0x02		; 8259-2 is slave
	out	0xA1,al
	call	delay
	mov	al,0x01		; 8086 mode for both
	out	0xA1,al
	call	delay

; Reprogram timer 0 to 1000 times/second
; Set timer count to 1.193.200/1.000 = 1193,2
	mov eax,0x36	; Command for 16-bit, mode 3, binary operation
	out 0x43,al
	call delay
	mov eax,1193
	out 0x40,al		; Load timer 0 count LSB
	call delay
	mov al,ah
	out 0x40,al		; Load timer 0 count MSB
	call delay

; Enable NMI
	in al,0x70
	and al,0x7F
	out 0x70,al

; Enable IRQ's
	xor eax,eax
	out 0x21,al
	out 0xA1,al
	
	ret

;
; Delay is needed after doing i/o
;
delay:
	jmp d1
d1:
	jmp d2
d2:
	ret

; -----------------------------------------------
; Specific interrupt handlers
; -----------------------------------------------

; ---------------------------
; Debug exception
; ---------------------------
int_debug:
	jmp int_die
    mov ebp,eax
    mov eax,dbg_msg1
    call sys_print_str
	mov eax,[ebp+OLD_EIP]
	call sys_print_eax
	mov eax,[ebp+OLD_EAX]
	call sys_print_eax
	mov eax,[ebp+OLD_EBX]
	call sys_print_eax
	mov eax,[ebp+OLD_ECX]
	call sys_print_eax
	mov eax,[ebp+OLD_EDX]
	call sys_print_eax
	mov eax,[ebp+OLD_ESP]
	call sys_print_eax
    mov eax,dbg_msg2
    call sys_print_str
	ret

dbg_msg1: db 'debug eip,eabcdx,sp=',0
dbg_msg2: db 0xd,0xa,0


; ---------------------------
; Breakpoint
; ---------------------------
int_bp:
    mov ebp,eax
    mov eax,bp_msg1
    call sys_print_str
	mov eax,[ebp+OLD_EIP]
	call sys_print_eax
	mov eax,[ebp+OLD_EAX]
	call sys_print_eax
    mov eax,bp_msg2
    call sys_print_str
	ret

bp_msg1: db 'breakpoint eip,eax=',0
bp_msg2: db 0xd,0xa,0

; ---------------------------
; General protected fault
; ---------------------------
int_gpf:
	mov eax,[ebp+OLD_EIP]
	cmp byte [eax],0xf4 ; Get the instruction that caused the GPF
	jne int_gpf_2
	; A hlt was called, do a hlt
int_gpf_hlt:
	inc dword [ebp+OLD_EIP] ; Return past the hlt instruction
	test dword [ebp+OLD_EFLAGS],F_IF
	jz int_gpf_1
	sti
int_gpf_1:
	hlt
	ret
int_gpf_2:
	jmp int_die

; ---------------------------
; Page fault
; ---------------------------
int_pf:
	cmp dword [ebp+OLD_CS],USER_CS
	jne int_pf_kernel
	mov eax,cr2
	test eax,0xFFFFF000 ; Error in first (null) page?
	jz int_pf_npe
	neg eax
	test eax,0xFFFFF000 ; Error in last (null) page?
	jz int_pf_npe
	mov eax,SoftByteCodes_EX_PAGEFAULT
	mov ebx,cr2
	;jmp int_die
	call int_system_exception
	ret
int_pf_npe:
	;jmp int_die
	mov eax,SoftByteCodes_EX_NULLPOINTER
	mov ebx,[ebp+OLD_EIP]
	call int_system_exception
	ret
	
int_pf_kernel:
	jmp int_die
	
; ---------------------------
; Double fault
; ---------------------------
int_df:
	cli
	mov eax,int_df_msg
	call sys_print_eax
	hlt
	
int_df_msg: db 'Real panic: Double fault! Halting...',0

; ---------------------------
; Division by 0
; ---------------------------
int_div:
	cmp dword [ebp+OLD_CS],USER_CS
	jne int_die
	mov eax,SoftByteCodes_EX_DIV0
	mov ebx,[ebp+OLD_EIP]
	call int_system_exception
	ret

; ---------------------------
; Bounds check
; ---------------------------
int_bc:
	cmp dword [ebp+OLD_CS],USER_CS
	jne int_die
	mov eax,SoftByteCodes_EX_INDEXOUTOFBOUNDS
	mov ebx,[ebp+OLD_EIP]
	; Determine index register number
	movzx ebx,byte [ebx+1]		; ModR/M
	shr ebx,3					; ModR/M.reg
	and ebx,0x07
	; Determine index
	neg ebx						; -(ModR/M.reg)
	mov ebx,[ebp+OLD_EAX+ebx*4]	; Gets reg value
	; Now throw the exception
	call int_system_exception
	ret

; ---------------------------
; NMI
; ---------------------------
int_nmi:
; Overflow
int_of:
; Invalid opcode
int_inv_oc:
; Invalid TSS
int_inv_tss:
; Segment not present
int_snp:
; Stack exception
int_sf:
int_copro_na:
int_copro_or:
int_copro_err:
	jmp int_die	
	

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?