linux0.11中斷處理源碼初探

系統初始化的時候,定義和初始化了中斷向量表。並初始化8259的工做方式。linux

// 加載idt的基地址和限長到idt寄存器
lidt idt_descr
// 定義
idt_descr:
    .word 256*8-1       # idt contains 256 entries
    .long _id
// 初始化
_idt:    .fill 256,8,0

因此idt的內容是一個單位是8字節,長度是256的數組。linux0.11分爲中斷、系統、陷阱門。系統在啓動的時候設置idt。編程

void trap_init(void)
{
    int i;

    set_trap_gate(0,&divide_error);
    set_trap_gate(1,&debug);
    set_trap_gate(2,&nmi);
    set_system_gate(3,&int3);   /* int3-5 can be called from all */
    set_system_gate(4,&overflow);
    set_system_gate(5,&bounds);
    set_trap_gate(6,&invalid_op);
    set_trap_gate(7,&device_not_available);
    set_trap_gate(8,&double_fault);
    set_trap_gate(9,&coprocessor_segment_overrun);
    set_trap_gate(10,&invalid_TSS);
    set_trap_gate(11,&segment_not_present);
    set_trap_gate(12,&stack_segment);
    set_trap_gate(13,&general_protection);
    // 缺頁和寫保護異常處理函數
    set_trap_gate(14,&page_fault);
    set_trap_gate(15,&reserved);
    set_trap_gate(16,&coprocessor_error);
    for (i=17;i<48;i++)
        set_trap_gate(i,&reserved);
    set_trap_gate(45,&irq13);
    // 容許8259接收中斷
    outb_p(inb_p(0x21)&0xfb,0x21);
    outb(inb_p(0xA1)&0xdf,0xA1);
    set_trap_gate(39,&parallel_interrupt);
}
#define _set_gate(gate_addr,type,dpl,addr) \
// 把dx即處理函數地址的低16位賦值給ax,不影響eax的高16位

__asm__ ("movw %%dx,%%ax\n\t" \
    /*
        設置idt描述符的第三個字節的內容,左移位數是字段對應的位置偏移,
        相加後賦值給dx,共16位,edx的高16位保存了處理函數的高16位地址
    */

    "movw %0,%%dx\n\t" \
    // 把eax即0x000080000 + 處理函數的地址賦值給idt描述符的前兩個字節
    "movl %%eax,%1\n\t" \
    // 把edx的內容寫入idt描述符的第5-8個字節
    "movl %%edx,%2" \
    : \
    : "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
    // o表示使用內存地址並能夠加偏移量
    "o" (*((char *) (gate_addr))), \
    // 指向保存選擇子的首地址
    "o" (*(4+(char *) (gate_addr))), \
    // edx等於addr,eax等於0x00080000
    "d" ((char *) (addr)),"a" (0x00080000))

#define set_intr_gate(n,addr) \
    _set_gate(&idt[n],14,0,addr)


#define set_trap_gate(n,addr) \
    _set_gate(&idt[n],15,0,addr)


#define set_system_gate(n,addr) \
    _set_gate(&idt[n],15,3,addr)

其中idt描述符格式是,這個版本貌似尚未任務門。
數組

在這裏插入圖片描述

還有一些是鍵盤,軟盤等也設置中斷。下面看一個異常處理程度。就是缺頁或寫保護異常的時候觸發的


.globl _page_fault

_page_fault:
    // 交換兩個寄存器的值,esp指向的位置保存了錯誤碼
    xchgl %eax,(%esp)
    // 壓棧寄存器
    pushl %ecx
    pushl %edx
    push %ds
    push %es
    push %fs
    // 內核數據段描述符
    movl $0x10,%edx
    mov %dx,%ds
    mov %dx,%es
    mov %dx,%fs
    // 若是是缺頁異常,cr2保存了引發缺頁的線性地址
    movl %cr2,%edx
    // 線性地址(有的話)和錯誤碼入參
    pushl %edx
    pushl %eax
    // 1和eax與,結果放到ZF中
    testl $1,%eax
    // zf=0則跳轉,即0是寫異常,1是缺頁異常
    jne 1f
    call _do_no_page
    jmp 2f
1:    call _do_wp_page
// 出棧,返回中斷,會從新異常指令
2:    addl $8,%esp
    pop %fs
    pop %es
    pop %ds
    popl %edx
    popl %ecx
    popl %eax
    iret

缺頁或寫保護異常的時候,系統會把錯誤碼和線性地址告訴處理程序。具體的處理能夠見內存管理分析那篇文件。微信


本文分享自微信公衆號 - 編程雜技(theanarkh)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。app

相關文章
相關標籤/搜索