系統初始化的時候,定義和初始化了中斷向量表。並初始化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,÷_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,¶llel_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