轉載請标注:http://blog.csdn.net/zgh1988/article/details/7389329
下面我将分别以c和d為例,來講述單程序切換和多程序切換下的中斷處理程式
1、單程序環境下的中斷處理程式
2、多程序環境下的中斷處理程式
一、單程序環境下的中斷處理程式
在這裡我們隻考慮利用時鐘中斷來進行程序切換。
我們知道程序是運作在ring1環境下的,而中斷處理程式是運作在ring0環境下的,讓我們想象一下程序切換時的情形。一個程序正在兢兢業業地運作着,這時候時鐘中斷發生了,特權級從ring1跳到ring0,開始執行時鐘中斷處理程式,中斷處理程式這時調用程序排程子產品,指定下一個應用運作的程序,當中斷處理程式結束時,下一個程序準備就緒并開始運作,特權級又從ring0跳回到ring1。
下面我們從兩個方面來考慮程序切換過程中需要注意什麼?(假設此時運作的是程序A)
1、現場的儲存和恢複
進入中斷處理程式之後,首要任務就是儲存程序A的狀态資訊,以便于将來恢複程序A時使用。在本程式中,程序A的狀态資訊隻包含寄存器内容。由于是單程序環境下的中斷,是以在離開中斷處理程式之前,要恢複程序A的狀态資訊,離開中斷處理程式之後,就又傳回到程序A。
hwint00:
……
;儲存原寄存器的内容
pushad
push ds
push es
push fs
push gs
………
;恢複原寄存器的内容
pop gs
pop fs
pop es
pop ds
popad
……
iretd
2、堆棧的切換
中斷發生,特權級發生了變化,從ring1(程序A)----- ring0(中斷處理程式)-----ring1(程序A)。
首先考慮ring1----ring0,從低特權級(ring1)跳轉到高特權級(ring0),需要從TSS中擷取es0和esp0。進入到ring0(中斷處理程式)之後,我們需要将程序A的狀态資訊儲存到PCB(程序控制塊)中,是以在發生中斷處理程式之前,我們将TSS中esp0指向程序表。是以在restart函數中,我們看到:
restart:
mov esp, [p_proc_ready] ;将程序表首位址指派給esp
lldt [esp + P_LDT_SEL] ;加載PCB中的LDT
lea eax, [esp + P_STACKTOP] ;将eax指向PCB中的eax的位址
mov dword [tss + TSS3_S_SP0], eax ;将TSS中的esp0指向PCB中的eax的位址
;此時esp指向程序表首位址,連續出棧,依次彈出gs, fs, es, ds, edi
;esi, ebp, esp, ebx, edx, ecx, eax。
pop gs
pop fs
pop es
pop ds
popad
;此時esp指向eip
add esp, 4
iretd

結合圖形來分析程式。
我們知道,我們将esp0指向了資料結構PROCESS中STACK_FRAME的eax,是以在時鐘中斷發後,進入中斷處理程式,首先需要儲存程序狀态資訊,即通過一堆push指令來完成,剛好儲存到程序的PCB中。也就是PROCESS結構。
hwint00: ; Interrupt routine for irq 0 (the clock).
sub esp, 4
;儲存原寄存器的内容
pushad
push ds
push es
push fs
push gs
mov dx, ss
mov ds, dx
mov es, dx
;改變螢幕第0行,第0列的字元
;inc byte[gs:0]
;使主8259接受中斷
mov al, EOI
out INT_M_CTL, al
inc dword[k_reenter]
cmp dword[k_reenter], 0
jne .re_enter
;切換到核心棧
mov esp, StackTop
;打開中斷
sti
;調用disp_str函數,用來顯示“^”
push clock_int_msg
call disp_str
add esp, 4
;調用delay函數,實作中斷嵌套
;push 1
;call delay
;add esp, 4
;關閉中斷
cli
;離開核心棧
mov esp, [p_proc_ready]
lea eax, [esp + P_STACKTOP]
mov dword[tss + TSS3_S_SP0], eax
.re_enter:
dec dword[k_reenter]
;恢複原寄存器的内容
pop gs
pop fs
pop es
pop ds
popad
add esp, 4
iretd
在ring0中,我們需要調用程序排程子產品,或者顯示某些字元,需要使用堆棧,此時的esp指向的是程序表,是以如果對esp進行操作,相當于改變了程序表的内容。是以我們此時需要将esp儲存起來,然後将其指向另一塊堆棧(即核心棧)即:
mov esp, StackTop。
執行完排程子產品,或者顯示某些字元之後,我們需要離開核心棧,那麼此時我們需要将esp指向何處呢?我們知道,在離開中斷處理程式之前,我們需要恢複程序A的狀态資訊,是以要通過一堆pop指令來完成。于是我們必須将esp指派為指向程序表的起始位址。即:mov esp, [p_proc_ready]
這時候,我們還需要考慮一個問題,就是我們在離開中斷處理程式之前,應該還要完成一個任務,就是指派TSS中的esp0。是以我們使用
mov esp, [p_proc_ready]
lea eax, [esp + P_STACK_TOP]
mov dword[tss + TSS3_S_SP0], eax
這段代碼,與restart中指派esp0的一模一樣。
此時我們完成了ring0 --- ring1的跳轉。
二、多程序環境下的中斷處理程式
在多程序切換環境下,要求多個程序進行切換,是以每次在發生中斷處理程式之後,我們需要從程序表中取出下一個等待的程序,然後去執行該程序。是以,在多程序環境下的中斷處理程式隻比之前多了一個任務,那就是在離開中斷處理程式之前,将一個等待的程序取出。 下面是程式代碼:
hwint00: ; Interrupt routine for irq 0 (the clock).
sub esp, 4
;儲存原寄存器的内容
pushad
push ds
push es
push fs
push gs
mov dx, ss
mov ds, dx
mov es, dx
;使主8259接受中斷
mov al, EOI
out INT_M_CTL, al
inc dword[k_reenter]
cmp dword[k_reenter], 0
jne .re_enter
;切換到核心棧
mov esp, StackTop
;打開中斷
sti
;調用clock_handler函數,通過調整p_proc_ready的指向proc_table
;數組中不同的程序。
push 0
call clock_handler
add esp, 4
;關閉中斷
cli
;離開核心棧
mov esp, [p_proc_ready]
lldt [esp + P_LDT_SEL]
lea eax, [esp + P_STACKTOP]
mov dword[tss + TSS3_S_SP0], eax
.re_enter:
dec dword[k_reenter]
;恢複原寄存器的内容
pop gs
pop fs
pop es
pop ds
popad
add esp, 4
iretd
我們使用排程子產品,來完成了程序的排程,該程序排程簡單,就是依次運作程序表中的每一個程序。我們可以檢視clock_handler函數。它是這樣完成的:
PUBLIC void clock_handler(int irq)
{
disp_str("#");
p_proc_ready++;
if (p_proc_ready >= proc_table + NR_TASKS)
{
p_proc_ready = proc_table;
}
}
這樣之後,我們就完成了不同程序之間的切換。
全面剖析《自己動手寫作業系統》第六章--程序 http://blog.csdn.net/zgh1988/article/details/7371754
全面剖析《自己動手寫作業系統》第五章--makefile http://blog.csdn.net/zgh1988/article/details/7338380
全面剖析《自己動手寫作業系統》第五章---加載核心kernel.bin http://blog.csdn.net/zgh1988/article/details/7329941
全面剖析《自己動手寫作業系統》第五章---Red Hat 9.0 的安裝過程 http://blog.csdn.net/zgh1988/article/details/7315676
全面剖析《自己動手寫作業系統》第四章---FAT12檔案系統 http://blog.csdn.net/zgh1988/article/details/7284834
全面剖析《自己動手寫作業系統》第四章---加載Loader.bin http://blog.csdn.net/zgh1988/article/details/7291909
全面剖析《自己動手寫作業系統》第三章---進入保護模式 http://blog.csdn.net/zgh1988/article/details/7098981
全面剖析《自己動手寫作業系統》第三章---“實模式--保護模式--實模式” http://blog.csdn.net/zgh1988/article/details/7255804
全面剖析《自己動手寫作業系統》第三章---堆棧段的工作方式 http://blog.csdn.net/zgh1988/article/details/7256254
全面剖析《自己動手寫作業系統》第三章---特權級以及不同特權級代碼段之間的跳轉 http://blog.csdn.net/zgh1988/article/details/7262901
全面剖析《自己動手寫作業系統》第三章---分頁機制 http://blog.csdn.net/zgh1988/article/details/7270748
全面剖析《自己動手寫作業系統》第三章---中斷機制 http://blog.csdn.net/zgh1988/article/details/7276259
全面剖析《自己動手寫作業系統》第二章http://blog.csdn.net/zgh1988/article/details/7062065
全面剖析《自己動手寫作業系統》第一章http://blog.csdn.net/zgh1988/article/details/7060032
《自己動手寫作業系統》讀後感http://blog.csdn.net/zgh1988/article/details/7059936