linux 2.6源代码情景分析笔记之中断与异常4

IDT的初步初始化
在实模式时,idt被初始化并由bios例程使用。一旦linux接管,idt就被移到ram的另一个区域,并进行第二次初始化,因为linux没有利用任何bios例程。
IDT存放在idt_table表中,有256个表项。6字节的idt_descr变量指定了idt的大小和它的地址,只有当内核用lidt汇编指令初始化idtr寄存器时才用到这个变量。
在内核初始化过程中,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

紧接着初始化,内核将在idt中进行第二遍初始化,用有意义的陷阱和中断处理程序替换这个空处理程序。一旦这个过程完成,对控制单元产生的每个不同的异常,idt都有一个专门的陷阱或者系统门,而对于可编程中断控制器确认的每一个irq,idt都将包含一个专门的中断门。

cpu产生的大部分异常都由linux解释为出错的条件。当其中一个异常发生时,内核就向引起异常的进程放送一个信号向它通知一个反常条件。
异常处理程序有一个标准的结构,由三部分组成:
1.在内核堆栈中保存大多数寄存器的内容(用汇编语言实现)
2.用高级的c函数处理异常。
3.通过ret_from_exception()函数从异常处理程序退出。

必须对idt进行适当的初始化,使得每个被确认的异常都有一个异常处理函数。trap_init()函数的工作是将一些最终值插入到idt的非屏蔽中断以及异常表项中。

void __init trap_init(void)
{
#ifdef CONFIG_EISA
        void __iomem *p = ioremap(0x0FFFD9, 4);
        if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
                EISA_bus = 1;
        }
        iounmap(p);
#endif

#ifdef CONFIG_X86_LOCAL_APIC
        init_apic_mappings();
#endif

        set_trap_gate(0,&divide_error);(故障)信号SIGFPE。当一个程序试图执行整数被0除操作时
        set_intr_gate(1,&debug);(陷阱或者故障)信号SIGTRAP。产生于:设置eflags的TF标志时;一条指令或操作数的地址落在一个活动debug寄存器的范围之内。
        set_intr_gate(2,&nmi);NONE
        set_system_intr_gate(3, &int3); /* int3-5 can be called from all */(陷阱)信号SIGTRAP。由int3(断点)指令(通常由debugger插入)引起。
        set_system_gate(4,&overflow);(陷阱)信号SIGSEGV。当eflags的OF(overflow)标志被设置时,into(检查溢出)指令被执行。
        set_system_gate(5,&bounds);(故障)信号SIGSEGV。对于有效地址范围之外的操作数,bound(检查地址边界)指令被执行。
        set_trap_gate(6,&invalid_op);(故障)信号SIGILL.cpu执行单元检测到一个无效的操作码(决定执行操作的机器指令部分)
        set_trap_gate(7,&device_not_available);(故障)NONE。随着cr0的ts标志被设置,escape,mmx,xmm指令被执行。
        set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);(异常中止)NONE。正常情况下,当cpu正试图为前一个异常调用处理程序时,同时又检查到一个异常,两个异常能被串行地处理。
        set_trap_gate(9,&coprocessor_segment_overrun);(异常终止)信号SIGFPE。因外部的数学协处理器引起的问题。(仅用于80386微处理器)
        set_trap_gate(10,&invalid_TSS);(故障)信号SIGSEGV。cpu试图让一个上下文切换到无效的tss的进程。
        set_trap_gate(11,&segment_not_present);(故障)信号SIGBUS。引用一个不存在的内存段(段描述符的segment-present标志被清零)
        set_trap_gate(12,&stack_segment);(故障)信号SIGBUS.试图超过栈界限的指令,或者由ss标识的段不在内存。
        set_trap_gate(13,&general_protection);(故障)信号SIGSEGV。违反了80x86保护模式下的保护规则之一。
        set_intr_gate(14,&page_fault);(故障)信号SIGSEGV.寻址的页不在内存,相应的页表项为空,或者违反了一种分页保护机制。
        set_trap_gate(15,&spurious_interrupt_bug);NONE intel保留。
        set_trap_gate(16,&coprocessor_error);(故障)信号SIGFPE.集成到cpu芯片中的浮点单元用信号通知一个错误情形,如数字溢出,或被0除。
        set_trap_gate(17,&alignment_check);(故障)信号SIGSEGV.操作数的地址没有被正确第对齐(例如:一个长整数的地址不是4的倍数)
#ifdef CONFIG_X86_MCE
        set_trap_gate(18,&machine_check);(异常中止)NONE。机器检查机制检测到一个cpu错误或者总线错误。
#endif
        set_trap_gate(19,&simd_coprocessor_error);(故障)信号SIGFPE.集成到cpu芯片中的sse或者sse2单元对浮点操作用信号通知一个错误情形。

        set_system_gate(SYSCALL_VECTOR,&system_call);
        /*
         * Should be a barrier for any external CPU state.
         */
        cpu_init();

        trap_init_hook();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值