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 

 

 

posted @ 2014-06-18 15:27  乾卦  阅读(444)  评论(0编辑  收藏  举报