二、IDT初始化过程
当计算机还运行在实模式时,IDT被初始化并由BIOS使用。然而一旦linux接管,IDT就被移到RAM的另一个区域,并进行第二次初始化,因为linux没有利用任何BIOS例程。
1. 首先在head_32.S文件中会调用setup_once局部汇编初始化IDT,本文要讲的head_32.S函数定义在\arch\x86\kernel文件中。
__INIT
setup_once:
movl $idt_table,%edi
movl $early_idt_handlers,%eax
movl $NUM_EXCEPTION_VECTORS,%ecx
1:
movl %eax,(%edi)
movl %eax,4(%edi)
/* interrupt gate, dpl=0, present */
movl $(0x8E000000 + __KERNEL_CS),2(%edi)
addl $9,%eax
addl $8,%edi
loop 1b
movl $256 - NUM_EXCEPTION_VECTORS,%ecx
movl $ignore_int,%edx
movl $(__KERNEL_CS << 16),%eax
movw %dx,%ax
/* selector = 0x0010 = cs */
movw $0x8E00,%dx
/* interrupt gate - dpl=0, present */
2:
movl %eax,(%edi)
movl %edx,4(%edi)
addl $8,%edi
loop 2b
这段汇编将IDT表分为两部分初始化,前一部分0- 32(NUM_EXCEPTION_VECTORS)表项的偏移量的地址设为early_idt_handlers的地址,32-256的表项偏移量的地址设为ignore_int的地址。
2.第二次对IDT初始化是在start_kernel()函数中通过调用trap_init()函数对IDT进行最终初始化。调用set_trap_gate()将其初始化为陷阱门,调用set_intr_gate()将其初始化为中断门,调用set_system_gate()将其初始化为访问特权级为3的陷阱门,调用set_task_gate()将其初始化为任务门,调用set_system_intr_gate()将其初始化为访问特权级为3的中断门。 |