中断描述符表IDT的预初始化

中断描述符表IDT的预初始化

   当计算机运行在实模式时,IDT被初始化并由BIOS使用。然而,一旦真正进入了Linux内核,IDT就被移到内存的另一个区域,并进行进入实模式的初步初始化。

 1.中断描述表寄存器IDTR的初始化

     用汇编指令LIDT对中断向量表寄存器IDTR进行初始化,其代码在arch/i386/boot/setup.S中:

 

lidt    idt_48                  # load idt with 0,0

    idt_48:

        .word   0                 # idt limit = 0

        .word   0, 0               # idt base = 0L

  2.把IDT表的起始地址装入IDTR

   用汇编指令LIDT装入IDT的大小和它的地址(在arch/i386/kernel/head.S中):

 

#define IDT_ENTRIES     256

.globl SYMBOL_NAME(idt)

 

lidt idt_descr

idt_descr:

       .word IDT_ENTRIES*8-1          # idt contains 256 entries

SYMBOL_NAME(idt):

        .long SYMBOL_NAME(idt_table)

    其中idt为一个全局变量,内核对这个变量的引用就可以获得IDT表的地址。表的长度为256´8=2048字节。

3.用setup_idt()函数填充idt_table表中的256个表项。

   我们首先要看一下idt_table的定义(在arch/i386/kernel/traps.c中):

 

   structdesc_struct idt_table[256] __attribute__((__section__(".data.idt")))= { {0, 0}, };

 

   desc_struct结构定义为:

 

   struct desc_struct {

    unsignedlong a,b   }

 

   对idt_table变量还定义了其属性(__attribute__),__section__是汇编中的“节”,指定了idt_table的起始地址存放在数据节的idt变量中,如上面第2条所述。

 

  在对idt_table表进行填充时,使用了一个空的中断处理程序ignore_int()。因为现在处于初始化阶段,还没有任何中断处理程序,因此用这个空的中断处理程序填充每个表项。ignore_int()是一段汇编程序(在head.S中):

 

ignore_int:

        cld           #方向标志清0,表示串指令自动增长它们的索引寄存器(esi和edi)

        pushl %eax

        pushl %ecx

        pushl %edx

        pushl %es

        pushl %ds

        movl $(__KERNEL_DS),%eax

        movl %eax,%ds

        movl %eax,%es

        pushl $int_msg

        call SYMBOL_NAME(printk)

        popl %eax

        popl %ds

        popl %es

        popl %edx

        popl %ecx

        popl %eax

        iret

int_msg:

       .asciz"Unknown interrupt\n"

       ALIGN

 

该中断处理程序模仿一般的中断处理程序,执行如下操作:

·     在栈中保存一些寄存器的值

·     调用printk()函数打印“Unknown interrupt”系统信息

·     从栈中恢复寄存器的内容

·     执行iret指令以恢复被中断的程序。

 

实际上,ignore_int()处理程序应该从不执行。如果在控制台或日志文件中出现了“Unknown interrupt”消息,说明要么是出现了一个硬件问题(一个I/O设备正在产生没有预料到的中断),要么就是出现了一个内核问题(一个中断或异常未被恰当地处理)。

 

 最后,我们来看setup_idt()函数如何对IDT表进行填充:

 

 /*

  *  setup_idt

  *

  *  sets up a idtwith 256 entries pointing to

  *  ignore_int,interrupt gates. It doesn't actually load

  *  idt - that canbe done only after paging has been enabled

  *  and the kernelmoved to PAGE_OFFSET. Interrupts

  *  are enabledelsewhere, when we can be relatively

  *  sureeverything is ok.

  */

setup_idt:

        lea ignore_int,%edx   /*计算ignore_int地址的偏移量,并将其装入%edx*/

        movl $(__KERNEL_CS << 16),%eax  /* selector = 0x0010 = cs */

        movw %dx,%ax           

        movw $0x8E00,%dx        /*interrupt gate - dpl=0, present */

 

        lea SYMBOL_NAME(idt_table),%edi

        mov $256,%ecx

rp_sidt:

        movl %eax,(%edi)

        movl %edx,4(%edi)

        addl $8,%edi

        dec %ecx

        jne rp_sidt

        ret

 

    这段程序的理解要对照门描述符的格式。8个字节的门描述符放在两个32位寄存器eax和edx,如图3.5所示,从rp_sidt开始的那段程序是循环填充256个表项。

           32                  16 15                               0

        eax

 

                                  

图  门描述符存放在两个32位的寄存器

 


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值