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,÷_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();
}
linux 2.6源代码情景分析笔记之中断与异常4
最新推荐文章于 2024-07-06 16:00:29 发布