初始化中斷描述表

現在,我們知道了80x86微處理器在硬件級對中斷和異常做了些什麼,接下來,我們可以繼續描述如何初始化中斷描述表。

內核啓用中斷以前,必須把IDT表的初始地址裝到idtr寄存器,並初始化表中的每項。這項工作是在初始化系統時完成的。

int指令允許用戶態進程發出一箇中斷信號,其值可以是0~255的任意一個向量。因此,爲了防止用戶通過int指令模擬非法的中斷和異常,IDT的初始化必須非常小心。這可以通過把中斷或陷阱門描述符的DPL字段設置成0來實現。如果進程試圖發出其中的一箇中斷信號,控制單元將檢查出CPL的值與DPL字段有衝突,並且產生一個”Generalprotection”異常。

然而,在少數情況下,用戶態進程必須能發出一個編程異常。爲此,只要把中斷或陷阱門描述符的DPL字段設置成3,即特權級儘可能一樣高就足夠了。

現在,讓我們來看一下Linux是如何實現這種策略的。

中斷門、陷阱門及系統門

與在前面”中斷描述符表”中所提到的一樣,Intel提供了三種類型的中斷描述符:任務門、中斷門及陷阱門描述符。Linux使用與Intel稍有不同的細目分類和術語,把它們如下進行分類:

中斷門

用戶態的進程不能訪問的一個Intel中斷門。所有的Linux中斷處理程序都通過中斷門激活,並全部限制在內核態。

系統門

用戶態的進程可以訪問的一個Intel陷阱門。通過系統門來激活三個Linux異常處理程序,它們的向量是45128。因此,在用戶態下,可以發佈intoboundint$0x80三條彙編語言指令。

系統中斷門

能夠被用戶態進程訪問的Intel中斷門。與向量3相關的異常處理程序是由系統中斷門激活的,因此,在用戶態可以使用匯編語言指令int3

陷阱門

用戶態的進程不能訪問的一個Intel陷阱門。大部分Linux異常處理程序都通過陷阱門來激活。

任務門

不能被用戶態進程訪問的Intel任務門。Linux對”Doublefault”異常的處理程序是由任務門激活的。

下列體系結構相關的函數用來IDT中插入門:

set_intr_gate(n,addr)

IDT的第n個表項插入一箇中斷門。門中的段選擇符設置成內核代碼的段選擇符,偏移量設置成中斷處理程序的地址addrDPL字段設置成0

set_system_gate(n,addr)

IDT的每n個表項插入一個陷阱門。門中的段選擇符設置成內核代碼的段選擇符,偏移量設置成中斷處理程序的地址addrDPL字段設置成0

set_system_intr_gate(n,addr)

IDT的第n個表項插入一箇中斷門。門中的段選擇符設置成內核代碼的段選擇符,偏移量設置成中斷處理程序的地址addrDPL字段設置成0

set_trap_gate(n,addr)

與前一個函數類似,只不過DPL的字段設置成0

set_task_gate(n,gdt)

IDT的第n個表項插入一箇中斷門。門中的段選擇符存放一個TSS的全局描述符指針,該TSS中包含要被激活的函數,偏移量設置成0DPL字段設置成3


IDT的初步初始化

當計算機還運行在模式時,IDT被初始化並由BIOS例程使用。然而,一旦Linux接管,IDT就被移到RAM的另一個區域,並進行第二次初始化,因爲Linux沒有利用任何BIOS例程。

IDT存放在idt_table表中,有256個表項。6字節的idt_descr變量指定了IDT的大小和它的地址,只有當內核用lidt彙編指令初始化idtr寄存器時纔用到這個變量。

在內核初始化過程中,setup_idt()彙編函數用同一個斷門來填充所有這256idt_table表項。



用匯編語言寫成的ignore_int()中斷處理程序,可以看作一個空的處理程序,它執行下列動作:

  1. 在棧中保存一些寄存器的內容。

  2. 調用printk()函數打印”Unknowninterrupt”系統消息。

  3. 從棧恢復寄存器的內容。

  4. 執行iret指令以恢復被中斷的程序。

ignore_int()處理程序應該從不被執行,在控制檯或日誌文件中出現的”Unknowninterrupt”消息標誌着要麼是出現了一個硬件問題,要麼就是出現了一個內核的問題。

緊接着這個預初始化,內核將在IDT中進行第二遍初始化,用有意義的陷阱和斷處理程序替換這個空處理程序。一旦這個過程完成,對控制單元產生的每個不同的異常,IDT都有一個專門的陷阱或系統門,而對於可編程中斷控制器確認的每一個IRQIDT都將包含一個專門的中斷門。

在接下來的兩節中,將分別針對異常和中斷來詳細地說明這個工作是如何完成。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章