中斷描述符表

來源:互聯網
上載者:User

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

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

int指令允許使用者態進程發出一個中斷訊號,其值可以是0-255的任意一個向量。因此,為了防止使用者通過int指令類比非法的中斷和異常,IDT的初始化必須非常小心。這可以通過把中斷或陷阱門描述符的DPL欄位設定成0來實現。如果進程試圖發出其中的一個中斷訊號,控制單元將會發現CPL的值與DPL欄位有衝突,並且產生一個"General protection”異常。

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

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

1 中斷門、陷阱門及系統門

我們先回憶一下前一篇博文的“中斷描述符表”,Intel提供了三種類型的中斷描述符:任務門、中斷門及陷阱門描述符。Linux使用與Intel稍有不同的細目分類和術語,把它們如下進行分五類:

中斷門(interrupt gate):使用者態的進程不能訪問Intel中斷門(門的DPL欄位為0)。所有的Linux中斷處理常式都通過中斷門啟用,並全部限制在核心態。

系統門(system gate):使用者態的進程可以訪問Intel陷阱門(門的DPL欄位為3)。通過系統門來啟用三個Linux例外處理常式,它們的向量是4,5及128,因此,在使用者態下,發行就緒into、bound及int $0x80三條組合語言指令。

系統中斷門(system interrupt gate):能夠被使用者態進程訪問的Intel中斷門(門的DPL欄位為3)。與向量3相關的例外處理常式是由系統中斷門啟用的,因此,在使用者態可以使用組合語言指令int3。

陷阱門(trap gate):使用者態的進程不能訪問的一個Intel陷阱門(門的DPL欄位為0)。大部分Linux例外處理常式都通過陷阱門來啟用。

任務門(task gate):不能被使用者態進程訪問的Intel任務門(門的DPL欄位為0)。Linux對“Double fault”異常的處理常式是由任務門啟用的。

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

set_intr_gate(n,addr)

在IDT的第n個表項插入一個中斷門。門中的段選擇符設定成核心代碼的段選擇符,位移量設定為中斷處理常式的地址addr,DPL欄位設定為0。

set_system_gate(n,addr)

在IDT的第n個表項插入一個陷阱門。門中的段選擇符設定成核心代碼的段選擇符,位移量設定為例外處理常式的地址addr,DPL欄位設定為3。

set_system_intr_gate(n,addr)

在IDT的第n個表項插入一個中斷門。門中的段選擇符設定成核心代碼的段選擇符,位移量設定為例外處理常式的地址addr,DPL欄位設定為3。

set_trap_gate(n,addr)

與前一個函數類似,只不過DPL的欄位設定成0。

set_task_gate(n,gdt)

在IDT的第n個表項中插入一個中斷門。門中的段選擇符中存放一個TSS的通用描述元表的指標,該TSS中包含要被啟用的函數。位移量設定為0,而DPL欄位設定為3。

2 IDT的初步初始化

當電腦還運行在實模式時,IDT就被初始化並由BIOS常式使用。然而,一旦Linux接管,IDT就被移到RAM主存的另一個地區,並進行第二次初始化,因為Linux沒有利用任何BIOS的常式。

在原始碼中,IDT存放在idt_table表中,有256個表項。6位元組的idt_descr變數指定了IDT的大小和它的地址,只有當核心用lidt彙編指令初始化idtr寄存器時才用到這個變數(回憶一下,idtr寄存器存放的是IDT的基址)。

在核心初始化過程中,setup_idt()組合語言函數用同一個中斷門(即指向ignore_int()中斷處理常式)來填充所有這256個idt_table表項:
    setup_idt:
        lea ignore_int, %edx
        movl $(_ _KERNEL_CS << 16), %eax
        movw %dx, %ax       /* selector = 0x0010 = cs */
        movw $0x8e00, %dx   /* interrupt gate, dpl=0, present */
        lea idt_table, %edi
        mov $256, %ecx
    rp_sidt:
        movl %eax, (%edi)
        movl %edx, 4(%edi)
        addl $8, %edi
        dec %ecx
        jne rp_sidt
        ret

用組合語言寫成的ignore_int()中斷處理常式,可以看作一個空的處理常式,它執行下列動作:

1. 在棧中儲存一些寄存器的內容。
2. 調用printk()函數列印“Unknown interrupt”系統訊息。
3. 從棧恢複寄存器的內容。
4. 執行iret指令以恢複被中斷的程式。

ignore_int()處理常式應該從不被執行。如果在控制台或記錄檔中出現的“Unknown interrupt”訊息,則標誌著要麼是出現了一個硬體的問題(一個I/O裝置正在產生沒有預料到的中斷),要麼就是出現了一個核心的問題(一個中斷或異常未被適當地處理)。

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

好了,現在有了對中斷硬體環境的瞭解,以及在得到一個空的IDT的表以後,接下來的博文中,將分別針對異常和中斷來詳細地說明這個工作是如何完成的。隨後將分別為中斷和異常舉一個執行個體,一個是進程調度的“心臟”——時鐘中斷,一個是虛擬儲存的核心內容——缺頁異常。敬請期待!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.