内核代码理解起来还是太困难了,需要对体系结构有很强的了解才行,这周作业就简单写一下吧。
系统调用经过了如下的流程
1) 初始化
首先,在内核初始化时,前几周已经讲到了通过start_kernel进行全局的初始化工作。
start_kernel中会调用trap_init来进行中断相关的初始化工作。
-
setup_log_buf(0);
-
pidhash_init();
-
vfs_caches_init_early();
-
sort_main_extable();
-
trap_init();
-
mm_init();
trap_init源码如下所示,
-
void __init trap_init(void)
-
{
-
int i;
-
-
#ifdef CONFIG_EISA
-
void __iomem *p = early_ioremap(0x0FFFD9, 4);
-
-
if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
-
EISA_bus = 1;
-
early_iounmap(p, 4);
-
#endif
-
-
set_intr_gate(X86_TRAP_DE, ÷_error);
-
set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK);
-
/* int4 can be called from all */
-
set_system_intr_gate(X86_TRAP_OF, &overflow);
-
set_intr_gate(X86_TRAP_BR, &bounds);
-
set_intr_gate(X86_TRAP_UD, &invalid_op);
-
set_intr_gate(X86_TRAP_NM, &device_not_available);
-
#ifdef CONFIG_X86_32
-
set_task_gate(X86_TRAP_DF, GDT_ENTRY_DOUBLEFAULT_TSS);
-
#else
-
set_intr_gate_ist(X86_TRAP_DF, &double_fault, DOUBLEFAULT_STACK);
-
#endif
-
set_intr_gate(X86_TRAP_OLD_MF, &coprocessor_segment_overrun);
-
set_intr_gate(X86_TRAP_TS, &invalid_TSS);
-
set_intr_gate(X86_TRAP_NP, &segment_not_present);
-
set_intr_gate_ist(X86_TRAP_SS, &stack_segment, STACKFAULT_STACK);
-
set_intr_gate(X86_TRAP_GP, &general_protection);
-
set_intr_gate(X86_TRAP_SPURIOUS, &spurious_interrupt_bug);
-
set_intr_gate(X86_TRAP_MF, &coprocessor_error);
-
set_intr_gate(X86_TRAP_AC, &alignment_check);
-
#ifdef CONFIG_X86_MCE
-
set_intr_gate_ist(X86_TRAP_MC, &machine_check, MCE_STACK);
-
#endif
-
set_intr_gate(X86_TRAP_XF, &simd_coprocessor_error);
-
-
/* Reserve all the builtin and the syscall vector: */
-
for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
-
set_bit(i, used_vectors);
-
-
#ifdef CONFIG_IA32_EMULATION
-
set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
-
set_bit(IA32_SYSCALL_VECTOR, used_vectors);
-
#endif
-
-
#ifdef CONFIG_X86_32
-
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
-
set_bit(SYSCALL_VECTOR, used_vectors);
-
#endif
-
-
/*
-
* Should be a barrier for any external CPU state:
-
*/
-
cpu_init();
-
-
x86_init.irqs.trap_init();
-
}
可以看到,trap_init中主要对中断门进行了初始化工作。 对于X86结构来说,中断向量表中1-32与0x80分配给内部中断,内部中断又分为“异常” “陷阱” (?),具体分配情况如代码所示,
-
/* Interrupts/Exceptions */
-
enum {
-
X86_TRAP_DE = 0, /* 0, Divide-by-zero */
-
X86_TRAP_DB, /* 1, Debug */
-
X86_TRAP_NMI, /* 2, Non-maskable Interrupt */
-
X86_TRAP_BP, /* 3, Breakpoint */
-
X86_TRAP_OF, /* 4, Overflow */
-
X86_TRAP_BR, /* 5, Bound Range Exceeded */
-
X86_TRAP_UD, /* 6, Invalid Opcode */
-
X86_TRAP_NM, /* 7, Device Not Available */
-
X86_TRAP_DF, /* 8, Double Fault */
-
X86_TRAP_OLD_MF, /* 9, Coprocessor Segment Overrun */
-
X86_TRAP_TS, /* 10, Invalid TSS */
-
X86_TRAP_NP, /* 11, Segment Not Present */
-
X86_TRAP_SS, /* 12, Stack Segment Fault */
-
X86_TRAP_GP, /* 13, General Protection Fault */
-
X86_TRAP_PF, /* 14, Page Fault */
-
X86_TRAP_SPURIOUS, /* 15, Spurious Interrupt */
-
X86_TRAP_MF, /* 16, x87 Floating-Point Exception */
-
X86_TRAP_AC, /* 17, Alignment Check */
-
X86_TRAP_MC, /* 18, Machine Check */
-
X86_TRAP_XF, /* 19, SIMD Floating-Point Exception */
-
X86_TRAP_IRET = 32, /* 32, IRET Exception */
-
};
举一例来说, set_intr_gate(X86_TRAP_PF, &page_fault);
就是将page_fault这个函数,注册给缺页异常。 当系统内产生缺页异常时,则调用page_fault。
当然,在Trap_init中,我们关注的是 set_system_trap_gate
(SYSCALL_VECTOR
, &system_call
);
对比一下,setset_intr_gate与set_system_trap_gate的实现,发现他们最终都是操作了IDT(Interrupt Descriptor Table--中断描述表),来完成的中断服务程序函数与中断号的绑定。
set_intr_gate
set_intr_gate_ist
set_system_intr_gate ---> _set_gate ---> pack_gate / write_idt_entry
-
static inline void pack_gate(gate_desc *gate, unsigned char type,
-
unsigned long base, unsigned dpl, unsigned flags,
-
unsigned short seg)
-
{
-
gate->a = (seg << 16) | (base & 0xffff);
-
gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8);
-
}
-
-
static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate)
-
{
-
memcpy(&idt[entry], gate, sizeof(*gate));
-
}
关于IDT的结构,如下
-
/* 8 byte segment descriptor */
-
struct desc_struct {
-
union {
-
struct {
-
unsigned int a;
-
unsigned int b;
-
};
-
struct {
-
u16 limit0;
-
u16 base0;
-
unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
-
unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
-
};
-
};
-
}
base就是中断服务程序isr的地址。
(逐项分析一下idt的内容,比较一下异同)
顺便提一句,另外还有听着相似的gdt,ldt两个概念,分别是
GDT:Global Descriptor Table --全局描述表
LDT:Local Descriptor Table --局部描述表
后续,在评论中会补充一下这两个表的含义。
=====
分析 system_call
未完成
阅读(657) | 评论(0) | 转发(0) |