2011-07-31 39 views
10

我正在編寫一個小的操作系統,它將在用戶模式下執行一些代碼(特權級別3)。從該用戶級別的代碼中,我想調用一個打印消息的操作系統的中斷。現在我並不關心我的中斷處理程序如何接受參數或類似的東西,我真的只想讓一箇中斷處理程序通知我(用戶)代碼已經執行。使用iret切換到用戶模式

我的問題是:如何在用戶模式下運行代碼?我有一個函數用代碼段和數據段(都具有用戶模式特權)設置本地描述符表。我不明白的是我應該如何將這些段加載到cs,ssds。我成功加載了我的LDT,但我不知道如何實際使用它。我聽說我應該使用iret,但我不明白如何。

我的另一個問題是我的中斷處理程序應該如何工作。比方說,我爲矢量編號0x40安裝一箇中斷處理程序,我要打印「hello,user mode!」。我知道如何設置一箇中斷處理程序,但我不完全理解從用戶模式進入內核中斷處理程序時上下文將如何切換。我知道cs寄存器必須更改,因爲我的例程將從我的IDT條目中指定的代碼段運行。我也明白,堆棧選擇器可能也會改變,但我不能確定這一點。

有人請向我解釋當中斷門被調用時會發生什麼樣的上下文變化?

回答

20

進入環3可以使用iret完成,因爲它的工作方式已被記錄。當收到一箇中斷時,處理器推:

  1. 堆棧段和指針(SS:ESP),作爲4個字
  2. EFLAGS
  3. 返回代碼段和指令指針(CS:EIP),如4個字
  4. 錯誤代碼,如果需要的話。

iret通過撤消步驟1-3(如果需要,ISR負責撤消步驟4)。我們可以通過將所需信息推入堆棧併發出iret指令來使用這一事實進入第3環。確保你的代碼和堆棧段中有正確的CPL(每個低兩位應該被設置)。但iret不會更改任何數據段,因此您需要手動更改它們。您使用mov指令來做到這一點,但是在執行此操作和切換環之間,您將無法讀取堆棧之外的數據。

cli 
mov ax, Ring3_DS 
mov ds, eax 
push dword Ring3_SS 
push dword Ring3_ESP 
pushfd 
or dword [esp], 0x200 // Set IF in EFLAGS so that interrupts will be reenabled in user mode 
push dword Ring3_CS 
push dword Ring3_EIP 
iret 

如果您想要一個完整的工作示例,請參閱this tutorial


當發出中斷,處理器讀取您的IDT獲得的ISR正確的代碼段和指令指針。然後它會查看您的TSS以查找新的堆棧段和指針。它適當地更改ssesp,然後將舊值推入新堆棧。它確實而不是更改任何數據段寄存器。如果您需要訪問ISR中的內存,則必須手動執行此操作。

+1

好的,你回答了我的問題和更多!我現在理解的是,我需要一個包含我的內核堆棧的TSS,謝謝你的幫助。 –

+0

我登錄只是爲了upvote這!謝謝!對於那裏的其他人,我也推薦osdev和Intel ISA手冊。他們真的清除了一切。 – Sid

+0

你是什麼意思IRET不改變數據段?你在談論通用寄存器中的值嗎? –

1

你也可以做一個retf。遠程返回到權限較低的代碼段會導致新的ss和sp從特權棧中彈出。

只要確保遠程調用和中斷的irets的返回值很高。它們之間的唯一區別是堆棧中存在標誌,但明智的是不要混淆它們。

另外,不要忘記,異常有時會在堆棧上推送錯誤代碼。