中斷髮生時,操做系統會爲當前的任務創建一個快照,陷入內核,把CPU的控制權交給內核。內核趁這個機會作一些工做,好比調度執行其餘任務。這只是中斷的做用之一。操作系統
使用中斷有一套固定的流程,掌握它便可。流程大概以下:code
初始化工做是對主從8259A
的兩類端口賦值。這兩類端口是:ICW
和OCW
。內存
這是初始化命令字端口,一共有四個。io
ICW1
,設置是否級聯、是否向ICW4
寫入數據。ICW2
,設置主從8259A
的初始中斷向量號。注意,有一批中斷向量號已經在實模式下使用,設置初始中斷向量號應該避免覆蓋那批中斷向量號。ICW3
,主片使用位圖標識幾號引腳掛載從片。從片使用低3位識別主片發送的數據的接收方是不是本身。ICW4
,設置是否主動發送EOI
。不清楚這點。這是控制命令字端口。目前只須要操做一個。class
設置屏蔽哪些端口、放行哪些端口。1表示屏蔽,0表示放行。select
IDT
是中斷向量表。相似GDT
,也是內存中的一塊區域。但它內部包含的全是"門描述符"。循環
IDT
中的每一個門描述符的名稱是中斷向量號,選擇子是中斷向量號對應的處理中斷的代碼。語法
; Gate : offset,selector,attr,paramCount %macro Gate 4 dw %1 & 0FFFFh dw %2 & 0FFFFh dw ((%3 & 0FFh) << 8) | (%4 & 01Fh) db %1 >> 16 %endmacro [SECTION .idt] LABEL_IDT: %rep 128 Gate selector32, SpuriousHandler, attr, paramCount %endrep .080h: Gate selector32, UserIntHandler, attr, paramCount IDTLen equ $ - LABEL_IDT IDTPtr dw IDTLen - 1 dd 0
IDT
中,第一個元素是能夠用的,這與GDT
不一樣。程序
%rep 128 Gate selector32, offset, attr, paramCount %endrep
表示IDT
中有128個門描述符都指向相同的目標代碼段。從0算起,128個門描述符,緊接着的中斷向量號應該是128,正好是80h
。數據
_SpuriousHandler: SpuriousHandler equ _SpuriousHandler - $$ mov al, 'A' mov ah, 0Fh mov [gs:(80*20+20)*2], ax _UserIntHandler: UserIntHandler equ _UserIntHandler - $$ mov al, 'A' mov ah, 0Fh mov [gs:(80*20+20)*2], ax
上面的代碼和IDT
在同一代碼段code32。SpuriousHandler
、UserIntHandler
是code32內的兩個偏移量。
不能徹底理解這種寫法。不過,可暫且看成一種語法規則去記住就好了。之後有相似功能須要實現,就用這種寫法。
當中斷向量號是在0~127
(包括0和127)時,會執行中斷處理代碼SpuriousHandler
。
當中斷向量號是080h
時,會執行中斷處理代碼UserIntHandler
。
調用中斷的語句很簡單,以下:
int 00h int 01h int 10h int 80h
增長一箇中斷的流程:
IDT
中增長一個門描述符,提供目標代碼(中斷處理程序)的選擇子、偏移量等。時鐘中斷很特殊,不須要直接調用就能被調用。
編寫時鐘中斷的完整代碼以下:
; Gate : offset,selector,attr,paramCount %macro Gate 4 dw %1 & 0FFFFh dw %2 & 0FFFFh dw ((%3 & 0FFh) << 8) | (%4 & 01Fh) db %1 >> 16 %endmacro [SECTION .idt] LABEL_IDT: %rep 128 Gate selector32, SpuriousHandler, attr, paramCount %endrep .080h: Gate selector32, UserIntHandler, attr, paramCount .81h: Gate selector32, ClockIntHandler, attr, paramCount IDTLen equ $ - LABEL_IDT IDTPtr dw IDTLen - 1 dd 0 _SpuriousHandler: SpuriousHandler equ _SpuriousHandler - $$ mov al, 'A' mov ah, 0Fh mov [gs:(80*20+20)*2], ax _UserIntHandler: UserIntHandler equ _UserIntHandler - $$ mov al, 'A' mov ah, 0Fh mov [gs:(80*20+20)*2], ax _ClockIntHandler: ClockIntHandler equ _ClockIntHandler - $$ inc [gs:(80*20+20)*2] int 80h ;在死循環中,時鐘中斷會以必定的時間間隔發生。 jmp $
[gs:(80*20+20)*2]
這塊內存已經有數據了,inc [gs:(80*20+20)*2]
會增長這塊內存中的數據的值,效果是在屏幕上出現不斷變換的字母。