xv6(4)
//main.c : tvinit() extern uint vectors[]; // in vectors.S: array of 256 entry pointers void tvinit(void) //初始化256个中断门,然后设置 T_SYSCALL 号为陷阱门 { int i; for(i = 0; i < 256; i++) SETGATE(idt[i], 0, SEG_KCODE<<3, vectors[i], 0); SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER); initlock(&tickslock, "time"); //初始化tickslock这个结构变量 } struct spinlock tickslock;
// vectors.S通过vectors.pl产生,编译才有 # generated by vectors.pl - do not edit # handlers .globl alltraps .globl vector0 vector0: pushl $0 pushl $0 jmp alltraps .globl vector1 vector1: pushl $0 pushl $1 jmp alltraps .globl vector2 vector2: pushl $0 pushl $2 jmp alltraps .globl vector3 vector3: pushl $0 pushl $3 jmp alltraps .globl vector4 vector4: pushl $0 pushl $4 jmp alltraps .globl vector5 vector5: pushl $0 pushl $5 jmp alltraps ... # vector table .data .globl vectors vectors: .long vector0 .long vector1 .long vector2 .long vector3 .long vector4 .long vector5 ...
那么这个alltraps是什么呢?
整个trapasm.S就是这个函数
作用:
1.保存现场
2.切换段寄存器
3.调用trap
# Call trap(tf), where tf=%esp pushl %esp call trap addl $4, %esp trapret:
4.恢复现场
下面看看trap:
// Layout of the trap frame built on the stack by the // hardware and by trapasm.S, and passed to trap(). struct trapframe { // registers as pushed by pusha uint edi; <- esp uint esi; uint ebp; uint oesp; // useless & ignored uint ebx; uint edx; uint ecx; uint eax; // rest of trap frame ushort gs; ushort padding1; ushort fs; ushort padding2; ushort es; ushort padding3; ushort ds; ushort padding4; uint trapno; // below here defined by x86 hardware uint err; uint eip; ushort cs; ushort padding5; uint eflags; // below here only when crossing rings, such as from user to kernel uint esp; ushort ss; ushort padding6; }; void trap(struct trapframe *tf) { //如果是自陷门 if(tf->trapno == T_SYSCALL){ if(proc->killed) exit(); proc->tf = tf; syscall(); if(proc->killed) exit(); return; } //如果是中断 switch(tf->trapno){ case T_IRQ0 + IRQ_TIMER: //定时器中断 if(cpu->id == 0){ acquire(&tickslock); ticks++; wakeup(&ticks); release(&tickslock); } lapiceoi(); break; //SATA primary case T_IRQ0 + IRQ_IDE: //#define IRQ_IDE 14 ideintr(); lapiceoi(); break; //SATA secondary case T_IRQ0 + IRQ_IDE+1: // Bochs generates spurious IDE1 interrupts. break; case T_IRQ0 + IRQ_KBD: //键盘 kbdintr(); lapiceoi(); break; case T_IRQ0 + IRQ_COM1: uartintr(); lapiceoi(); break; case T_IRQ0 + 7: case T_IRQ0 + IRQ_SPURIOUS: cprintf("cpu%d: spurious interrupt at %x:%x\n", cpu->id, tf->cs, tf->eip); lapiceoi(); break; //PAGEBREAK: 13 default: //其余中断 if(proc == 0 || (tf->cs&3) == 0){ // In kernel, it must be our mistake. cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n", tf->trapno, cpu->id, tf->eip, rcr2()); panic("trap"); } // In user space, assume process misbehaved. cprintf("pid %d %s: trap %d err %d on cpu %d " "eip 0x%x addr 0x%x--kill proc\n", proc->pid, proc->name, tf->trapno, tf->err, cpu->id, tf->eip, rcr2()); proc->killed = 1; } // Force process exit if it has been killed and is in user space. // (If it is still executing in the kernel, let it keep running // until it gets to the regular system call return.) if(proc && proc->killed && (tf->cs&3) == DPL_USER) exit(); // Force process to give up CPU on clock tick. // If interrupts were on while locks held, would need to check nlock. if(proc && proc->state == RUNNING && tf->trapno == T_IRQ0+IRQ_TIMER) yield(); // Check if the process has been killed since we yielded if(proc && proc->killed && (tf->cs&3) == DPL_USER) exit(); }
非R0下中断发生的栈:
tss->esp0: ss esp eflags cs eip err_code ┓ pushl $0 ┛ err_code ? pushl $中断号 pushl %ds pushl %es pushl %fs pushl %gs pushal <-esp 切换非cs的段寄存器 pushl %esp pushl trapretaddr