我们好像忘了很重要的东西:
(1)set_intr_gate
/*
* This needs to use 'idt_table' rather than 'idt', and
* thus use the _nonmapped_ version of the IDT, as the
* Pentium F0 0F bugfix can have resulted in the mapped
* IDT being write-protected.
*/
staticinlinevoidset_intr_gate(unsignedintn,void*addr)
{
BUG_ON((unsigned)n > 0xFF);
_set_gate(n, GATE_INTERRUPT, addr, 0, 0, __KERNEL_CS);//设置中断门
}
(2)set_system_intr_gate
/*
* This routine sets up an interrupt gate at directory privilege level 3.
*/
staticinlinevoidset_system_intr_gate(unsignedintn,void*addr)
{
BUG_ON((unsigned)n > 0xFF);
_set_gate(n, GATE_INTERRUPT, addr, 0x3, 0, __KERNEL_CS);//设置中断门
}
(3)set_task_gate
staticinlinevoidset_task_gate(unsignedintn, unsignedintgdt_entry)
{
BUG_ON((unsigned)n > 0xFF);
_set_gate(n, GATE_TASK, (void*)0, 0, 0, (gdt_entry<<3));//设置任务门
}
(4)set_system_trap_gate
staticinlinevoidset_system_trap_gate(unsignedintn,void*addr)
{
BUG_ON((unsigned)n > 0xFF);
_set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);//设置陷阱门
}
我们观察一下这几个函数,都是调用_set_gate,区别在于第二个和第四个参数。第二个参数对应于中断门或陷阱门格式中的D标志位加上类型位段;第四个参数对应于DPL。下面,我们来看一下_set_gate函数:
staticinlinevoid_set_gate(intgate, unsigned type,void*addr,
unsigned dpl, unsigned ist, unsigned seg)
{
gate_desc s;
pack_gate(&s, type, (unsignedlong)addr, dpl, ist, seg);
/*
* does not need to be atomic because it is only done once at
* setup time
*/
write_idt_entry(idt_table, gate, &s);
}
其第一个操作pack_gate():
staticinlinevoidpack_gate(gate_desc *gate, unsignedchartype,
unsignedlongbase, unsigned dpl, unsigned flags,
unsignedshortseg)
{
gate->a = (seg <
gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl <
}
而wirte_idt_entry():
#define write_idt_entry(dt, entry, g) native_write_idt_entry(dt, entry, g)
staticinlinevoidnative_write_idt_entry(gate_desc *idt,intentry,constgate_desc *gate)
{
memcpy(&idt[entry], gate,sizeof(*gate));
}
trap_init()中设置了一些为CPU保留专用的IDT表项以及系统调用所用的陷阱门以后,就进入init_IRQ()设置大量用于外设的通用中断门了:void__init init_IRQ(void)
{
inti;
/*
* We probably need a better place for this, but it works for
* now ...
*/
x86_add_irq_domains();
/*
* On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
* If these IRQ's are handled by legacy interrupt-controllers like PIC,
* then this configuration will likely be static after the boot. If
* these IRQ's are handled by more mordern controllers like IO-APIC,
* then this vector space can be freed and re-used dynamically as the
* irq's migrate etc.
*/
for(i = 0; i nr_legacy_irqs; i++)
per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;
x86_init.irqs.intr_init();
}
这段内容在《情景分析》中有精彩的解释,但是我没有在3.0.4中找到合适的代码,不过想来应该是变化不大的,特别是基本的原理应该变化不大,因此就不费时讲解了。
本文详细解析了Linux内核中中断门(set_intr_gate)、系统中断门(set_system_intr_gate)、任务门(set_task_gate)及陷阱门(set_system_trap_gate)的设置过程。通过分析_set_gate函数及其内部实现细节,介绍了不同门类型之间的区别。
1386

被折叠的 条评论
为什么被折叠?



