中断编程实践

实践内容

预备工作

  • 8259A初始化,读写IMR寄存器,发送EOI控制字,等

实践一

  • 自定义软中断的实现 (内部中断处理)

实践二

  • 时钟中断的响应及处理 (外部中断处理)

预备工作

编写延迟函数 (Delay)

编写8259A初始化函数 (Init8259A)

编写8259A中断屏蔽寄存器读写函数 (ReadIMR;WriteIMR)

编写8259A中断结束符写入函数 (WriteEOI)

Init8259A

 读写IMR寄存器

使用OCW1设置IMR的目标值

写入对应端口 (0x21或0xA1)

汇编小贴士

汇编语言支持预处理语句 (如:%include)

与c语言中的情况类似,汇编预处理语句常用于文本替换

示例:语句重复 (%rep)

inc.asm新增的一些常量定义

; PIC-8259A Ports 
MASTER_ICW1_PORT                        equ     0x20
MASTER_ICW2_PORT                        equ     0x21
MASTER_ICW3_PORT                        equ     0x21
MASTER_ICW4_PORT                        equ     0x21
MASTER_OCW1_PORT                        equ     0x21
MASTER_OCW2_PORT                        equ     0x20
MASTER_OCW3_PORT                        equ     0x20

SLAVE_ICW1_PORT                         equ     0xA0
SLAVE_ICW2_PORT                         equ     0xA1
SLAVE_ICW3_PORT                         equ     0xA1
SLAVE_ICW4_PORT                         equ     0xA1
SLAVE_OCW1_PORT                         equ     0xA1
SLAVE_OCW2_PORT                         equ     0xA0
SLAVE_OCW3_PORT                         equ     0xA0

MASTER_EOI_PORT                         equ     0x20
MASTER_IMR_PORT                         equ     0x21
MASTER_IRR_PORT                         equ     0x20
MASTER_ISR_PORT                         equ     0x20

SLAVE_EOI_PORT                          equ     0xA0
SLAVE_IMR_PORT                          equ     0xA1
SLAVE_IRR_PORT                          equ     0xA0
SLAVE_ISR_PORT                          equ     0xA0

预备工作

%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector  equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

TopOfStack16	equ    0x7c00

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	; initalize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt
    cli 
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0


; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString
	
	call Init8259A
	
	mov ax, 0xFF
	mov dx, MASTER_IMR_PORT
	call WriteIMR
	
	mov ax, 0xFF
	mov dx, SLAVE_IMR_PORT
	call WriteIMR

	jmp $

;
;
Delay:
    %rep 5
    nop
    %endrep
    
    ret
    
;
;
Init8259A:
    push ax
    
    ; Master
    ; ICW1
    mov al, 00010001B
    out MASTER_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x20
    out MASTER_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000100B
    out MASTER_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00010001B
    out MASTER_ICW4_PORT, al
    call Delay
    
    ; Slave
    ; ICW1
    mov al, 00010001B
    out SLAVE_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x28
    out SLAVE_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000010B
    out SLAVE_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00000001B
    out SLAVE_ICW4_PORT, al
    call Delay
    
    pop ax
    
    ret

;al  --> IMR register value
;dx  --> 8259A port
WriteIMR:
    out dx, al
    call Delay
    
    ret
    
; dx  --> 8259A port
; return:
;    al  --> IMR register value
ReadIMR:
    in al, dx
    call Delay
    
    ret

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1

153行-200行,我们定义了初始化8259A的函数;202-217行,我们定义了读写8259A中断屏蔽寄存器的函数。

实践一

自定义保护模式下的软中断 (0x80)

0x80中断使用后,在屏幕上打印字符串

示例

 实现思路

 注意事项

x86处理器一共支持256个中断类型,因此,中断描述表中需要有256个描述符与之对应。

中断描述符表

内部中断实现

%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector  equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

[section .idt]
align 32
[bits 32]
IDT_ENTRY:
; IDT definition
;                           Selector,           Offset,            DCount,           Attribut
%rep 128
             Gate        Code32Selector,     DefaultHandler,          0,             DA_386IGate
%endrep
Int0x80 :    Gate        Code32Selector,     Int0x80Handler,          0,             DA_386IGate
%rep 127
             Gate        Code32Selector,     DefaultHandler,          0,             DA_386IGate
%endrep
; IDT end

IdtLen      equ     $ - IDT_ENTRY
IdtPtr:
        dw  IdtLen - 1
        dd  0

TopOfStack16	equ    0x7c00

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$
	
	INT_0X80            db    "int 0x80", 0
	INT_0X80_Offset     equ   INT_0X80 - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	; initialize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax
	
	; initialize IDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, IDT_ENTRY
	mov dword [IdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt and load IDT
    cli 
    
    lidt [IdtPtr]
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0


; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString
	
	call Init8259A
	
	mov ax, 0xFF
	mov dx, MASTER_IMR_PORT
	call WriteIMR
	
	mov ax, 0xFF
	mov dx, SLAVE_IMR_PORT
	call WriteIMR

    mov ebp, INT_0X80_Offset
    mov bx, 0x0c
    mov dh, 14
    mov dl, 32
    int 0x80

	jmp $

;
;
Delay:
    %rep 5
    nop
    %endrep
    
    ret
    
;
;
Init8259A:
    push ax
    
    ; Master
    ; ICW1
    mov al, 00010001B
    out MASTER_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x20
    out MASTER_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000100B
    out MASTER_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00010001B
    out MASTER_ICW4_PORT, al
    call Delay
    
    ; Slave
    ; ICW1
    mov al, 00010001B
    out SLAVE_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x28
    out SLAVE_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000010B
    out SLAVE_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00000001B
    out SLAVE_ICW4_PORT, al
    call Delay
    
    pop ax
    
    ret

;al  --> IMR register value
;dx  --> 8259A port
WriteIMR:
    out dx, al
    call Delay
    
    ret
    
; dx  --> 8259A port
; return:
;    al  --> IMR register value
ReadIMR:
    in al, dx
    call Delay
    
    ret

DefaultHandlerFunc:

    iret
    
DefaultHandler      equ     DefaultHandlerFunc - $$

Int0x80HandlerFunc:
    call PrintString
    
    iret
    
Int0x80Handler      equ     Int0x80HandlerFunc - $$

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1

 257行-261行,我们定义了默认的中断函数,注意:在中断函数里需要iret指令返回。

263行-266行,我们定义了字符串打印的中断函数。

29行-42行,我们定义了中断描述符表,由于中断描述符表中需要给出256个中断描述符,而我们只需要用到128(0x80)号中断,所以我们需要填补其他的中断描述符,用%rep来填补。

94行-99行,我们初始化了IDT结构体的中断描述符表的起始地址,107行,我们将中断描述符表加载进内存中。

172行-176行,我们调用了0x80号我们自己定义的中断来调用字符串打印函数,这和BIOS提供的0x10号中断的功能是一样的。

 我们成功的通过了0x80号中断打印了"int 0x80"这个字符串。

实践二

处理外部时钟中断 (主8259A-IR0引脚上的中断请求)

接受到时钟中断后,在屏幕上循环打印0-9

实现思路

注意事项

由于8259A初始化为手动结束中断的方式,因此,外部中断服务程序中需要手动发送结束控制字。

发送中断结束命令字

时钟中断处理

%include "inc.asm"

org 0x9000

jmp ENTRY_SEGMENT

[section .gdt]
; GDT definition
;                                 段基址,       段界限,       段属性
GDT_ENTRY		: Descriptor		0, 			    0,		      0
CODE32_DESC		: Descriptor		0, 	   Code32SegLen - 1,  DA_32 + DA_C
VIDEO_DESC	    : Descriptor     0xb8000,       0x7fff,       DA_32 + DA_DRWA
DATA32_DESC		: Descriptor	    0,     Data32SegLen - 1,  DA_32 + DA_DRW
STACK32_DESC	: Descriptor        0,      TopOfStack32,     DA_32 + DA_DRW
; GDT end  

GdtLen	  equ	   $ - GDT_ENTRY
GdtPtr:    
		dw	GdtLen - 1
		dd	0

; GDT Selector
Code32Selector	equ    (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector	equ    (0x0002 << 3) + SA_TIG + SA_RPL0
Data32Selector  equ    (0x0003 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ    (0x0004 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]

[section .idt]
align 32
[bits 32]
IDT_ENTRY:
; IDT definition
;                           Selector,           Offset,            DCount,           Attribut
%rep 32
             Gate        Code32Selector,     DefaultHandler,          0,             DA_386IGate
%endrep
Int0x20 :    Gate        Code32Selector,     TimerHandler,            0,             DA_386IGate
%rep 95
             Gate        Code32Selector,     DefaultHandler,          0,             DA_386IGate
%endrep
Int0x80 :    Gate        Code32Selector,     Int0x80Handler,          0,             DA_386IGate
%rep 127
             Gate        Code32Selector,     DefaultHandler,          0,             DA_386IGate
%endrep
; IDT end

IdtLen      equ     $ - IDT_ENTRY
IdtPtr:
        dw  IdtLen - 1
        dd  0

TopOfStack16	equ    0x7c00

[section .dat]
[bits 32]
DATA32_SEGMENT:
	DTOS		        db    "D.T.OS!", 0
	DTOS_Offset	        equ	  DTOS - $$ 

	HELLOWORLD		    db    "Hello, World!", 0
	HELLOWORLD_Offset   equ   HELLOWORLD - $$
	
	INT_0X80            db    "int 0x80", 0
	INT_0X80_Offset     equ   INT_0X80 - $$

Data32SegLen	equ   $ - DATA32_SEGMENT

[section .s16]
[bits 16]
ENTRY_SEGMENT:
	mov ax, cs
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov sp, TopOfStack16

	; initialize GDT for 32 bits code segment
	mov esi, CODE32_SEGMENT
	mov edi, CODE32_DESC
	call InitDescItem

	mov esi, DATA32_SEGMENT
	mov edi, DATA32_DESC
	call InitDescItem

	mov esi, STACK32_SEGMENT
	mov edi, STACK32_DESC
	call InitDescItem

	; initialize GDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, GDT_ENTRY
	mov dword [GdtPtr + 2], eax
	
	; initialize IDT pointer struct
	mov eax, 0
	mov ax, ds
	shl eax, 4
	add eax, IDT_ENTRY
	mov dword [IdtPtr + 2], eax

	; 1. load GDT
    lgdt [GdtPtr]
    
    ; 2. close interrupt and load IDT
    cli 
    
    lidt [IdtPtr]
    
    ; 3. open A20
    in al, 0x92
    or al, 00000010b
    out 0x92, al
    
    ; 4. enter protect mode
    mov eax, cr0
    or eax, 0x01
    mov cr0, eax
    
    ; 5. jump to 32 bits code
    jmp dword Code32Selector : 0


; esi    --> code segment labelBACK_ENTRY_SEGMENT
; edi    --> descriptor label
InitDescItem:
	push eax

	mov eax, 0
	mov ax, cs
	shl eax, 4
	add eax, esi
	mov word [edi + 2], ax
	shr eax, 16
	mov byte [edi + 4], al
	mov byte [edi + 7], ah
	
	pop eax

	ret

[section .s32]
[bits 32]
CODE32_SEGMENT:
	mov ax, VideoSelector
	mov gs, ax

	mov ax, Stack32Selector
	mov ss, ax

	mov eax, TopOfStack32
	mov esp, eax

	mov ax, Data32Selector
	mov ds, ax

	mov ebp, DTOS_Offset
	mov bx, 0x0c
	mov dh, 13
	mov dl, 33
	call PrintString
	
	call Init8259A
	
	mov ax, 0xFF
	mov dx, MASTER_IMR_PORT
	call WriteIMR
	
	mov ax, 0xFF
	mov dx, SLAVE_IMR_PORT
	call WriteIMR

    mov ebp, INT_0X80_Offset
    mov bx, 0x0C
    mov dh, 14
    mov dl, 32
    int 0x80
    
    sti
    call EnableTimer

	jmp $

;
;
EnableTimer:
    push ax
    push dx
    
    mov ah, 0x0C
    mov al, '0'
    mov [gs : ((15 * 80 + 32) * 2)], ax
    
    mov dx, MASTER_IMR_PORT
    call ReadIMR
    and ax, 0xFE
    call WriteIMR
    
    pop ax
    pop dx
    
    ret

;
;
Delay:
    %rep 5
    nop
    %endrep
    
    ret
    
;
;
Init8259A:
    push ax
    
    ; Master
    ; ICW1
    mov al, 00010001B
    out MASTER_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x20
    out MASTER_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000100B
    out MASTER_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00010001B
    out MASTER_ICW4_PORT, al
    call Delay
    
    ; Slave
    ; ICW1
    mov al, 00010001B
    out SLAVE_ICW1_PORT, al
    call Delay
    
    ; ICW2
    mov al, 0x28
    out SLAVE_ICW2_PORT, al
    call Delay
    
    ; ICW3
    mov al, 00000010B
    out SLAVE_ICW3_PORT, al
    call Delay
    
    ; ICW4
    mov al, 00000001B
    out SLAVE_ICW4_PORT, al
    call Delay
    
    pop ax
    
    ret

;al  --> IMR register value
;dx  --> 8259A port
WriteIMR:
    out dx, al
    call Delay
    
    ret
    
; dx  --> 8259A port
; return:
;    al  --> IMR register value
ReadIMR:
    in al, dx
    call Delay
    
    ret

; 
; dx  --> 8259A port
WriteEOI:
    push ax
    
    mov al, 0x20
    out dx, al
    call Delay
    
    pop ax
    
    ret

DefaultHandlerFunc:

    iret
    
DefaultHandler      equ     DefaultHandlerFunc - $$

Int0x80HandlerFunc:
    call PrintString
    
    iret
    
Int0x80Handler      equ     Int0x80HandlerFunc - $$

TimerHandlerFunc:
    push ax
    push dx
    
    mov ax, [gs : ((15 * 80 + 32) * 2)]
    cmp al, '9'
    je throtate
    inc al
    jmp thshow

throtate:
    mov al, '0'
    
thshow:  
    mov [gs : ((15 * 80 + 32) * 2)], ax
    
    mov dx, MASTER_OCW2_PORT
    call WriteEOI

    pop ax
    pop dx
    
    iret

TimerHandler        equ     TimerHandlerFunc - $$

; ds:ebp    --> string address
; bx        --> attribute
; dx        --> dh : row, dl : col
PrintString:
	push ebp
	push cx
	push eax
	push dx
	push edi

print:
	mov cl, [ds:ebp]
	cmp cl, 0
	je end
	mov eax, 80
	mul dh
	add al, dl
	shl eax, 1
	mov edi, eax
	mov ah, bl
	mov al, cl
	mov [gs:edi], ax
	inc ebp
	inc dl
	jmp print
	
end:
	pop edi
	pop dx
	pop eax
	pop cx
	pop ebp

	ret

Code32SegLen	equ    $ - CODE32_SEGMENT


[section .gs]
[bits 32]
STACK32_SEGMENT:
	times 1024 * 4 db 0

Stack32SegLen	equ    $ - STACK32_SEGMENT
TopOfStack32    equ    Stack32SegLen - 1

310行-332行,定义了外部时钟中断的中断处理函数,这个函数的作用是在屏幕的15行32列,循环打印数字0-9;327行,手动发送结束控制字,因为此函数是外部中断函数,并且我们将8259A初始化为手动结束中断的方式,所以在外部中断函数调用结束时,需要手动清除对应的ISR标志位。

189行-205行,我们定义了使能外部时钟中断的函数,我们将IMR的第0位置0,表示8259A将IR0对应的中断放行,IR0所连接的就是时钟,这样8259A就可以把时钟对应的中断请求发送给处理器了!

第182行,我们打开了处理中断的总开关,由于进入保护模式前我们把中断开关关闭了,所以需要重新打开,打开这个开关后,处理器就可以接收到8259A发送过来的中断请求了。

第183我们调用了使能时钟的函数,处理器在接受到时钟中断后,在屏幕上循环打印0-9。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中断服务程序设计实验 2.7.1 实验目的 1、 熟悉中断的概念、中断响应过程、中断向量表以及系统是如何根据中断类型号在中断向量表中得到该中断对应的中断服务程序的入口地址等内容。 2、 掌握中断服务程序的设计方法。 2.7.2 实验预习要求 1、 复习中断的有关内容。 2、 复习中断服务程序设计方法。 3、 读懂“2.7.4 实验内容”中给出的源程序,以便上机调试。 4、 从“2.7.5 实验习题”中任选一道题目,编写源程序,以便上机调试。 2.7.3 中断服务程序设计方法简介 由2.6节中的中断向量表可以看出,PC中断系统中中断类型可分为三类: 磁盘操作系统DOS提供的中断服务程序,中断类型号从20H到2FH; 系统主板BIOS芯片提供的BIOS中断服务程序,包括系统内部中断中断类型号从00H到07H;系统8级外部中断中断类型号从08H到0FH,它们对应于接在可编程中断控制器8259A的8个中断请求输入端IR0IR7的8个外部中断,其中IR2(中断类型号0AH)为系统保留,用户可通过该引脚实现对用户所需的外部硬件中断的管理;设备驱动程序,中断类型号从10H到1FH等; 用户定义的中断中断类型号从60H到7FH、F1H到FFH。用户可根据实际需要将某些通用性强的子程序功能通过中断服务程序来实现。一旦设置好了这样的中断服务程序,在其他应用程序中就可以调用这些中断服务程序。 设计中断服务程序的步骤如下: 1、 选择一个中断类型号 如果采用硬件中断,则要使用硬件决定的中断类型号。在PC机系统中,使用了一片可编程中断控制器8259A来对外部硬件中断进行管理,具体内容参见教材264页“8259A应用举例”,可以看出IR2为系统保留,其中断类型号为0AH。若用户需要,可将用户所需的外部中断源发来的中断请求信号接到IR2,编写该中断所需的中断服务程序,并将该中断服务程序的入口地址写到中断向量表0AH4AH4+3四个单元中,这样,当接在IR2上的外部中断源发来中断请求信号时,系统就会根据得到的类型号(0AH)到中断向量表中找出其入口地址,并转去执行该中断服务程序。 如果采用软件中断,即利用执行int n指令的方式执行中断服务程序,则可从系统预留给用户的中断类型号60H7FH、F1HFFH中选择一个。 2、 将中断服务程序的入口地址置入中断向量表的相应的四个存储单元中 确定了中断类型号,还要把中断服务程序入口地址置入中断向量表,以保证在中断响应时CPU能自动转入与该类型号相对应的中断服务程序。下面介绍两种将中断服务程序入口地址置入中断向量表的方法。 (1) 直接装入法 用传送指令直接将中断服务程序首地址置入矢量表中。设中断类型号为60H(此类型号对应的矢量表地址为从00180H开始的四个连续存储单元)。 PUSH DS XOR AX,AX MOV DS,AX ;将数据段寄存器清零 MOV AX,OFFSET INT60 ;将中断服务程序INT60所在段内的偏移地址送AX MOV DS:[0180H],AX ;将中断服务程序偏移地址送中断向量表00180H和00181单元 MOV AX,SEG INT60 ;将中断服务程序INT60所在段的段地址送AX MOV DS:[0180H+2],AX ;将中断服务程序所在代码段的段地址送00182H和00183单元 POP DS (2) DOS系统功能调用法 功能号(AH)=25H; 入口参数:(AL)=中断类型号, (DS)=中断服务程序入口地址的段地址 (DX)=中断服务程序入口地址的偏移地址 下面程序段完成中断类型号为60H的入口地址置入。 PUSH DS ;保护DS MOV DX,OFFSET INT60 ;取服务程序偏移地址 MOV AX,SEG INT60 ;取服务程序段地址 MOV DS,AX MOV AH,25H ;送功能号 MOV AL,60H ;送中断类型号 INT 21H ;DOS功能调用 POP DS ;恢复DS 3、 使中断服务程序驻留内存,以便其他应用程序调用 实现这一步骤的必要性在于:一旦中断服务程序驻留内存后,一般程序员使用这一新增的中断调用就如同调用DOS或BIOS的中断子程序一样,只要了解其入口要求和返回参数就可调用。程序驻留在内存后,它占用的存储区就不会被其他软件覆盖。使程序驻留内存,要求该程序以 .COM形式运行,这种种结构的程序要求入口定位于100H,并且数据和代码均在同一个段内,这样,.COM程序就被定位于低地址区,DOS常在低地址区增加驻留程序,而 .EXE程序被定位于高地
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值