xv6(6)

xv6运行第一个程序的过程:

int
main(void)
{
  kinit1(end, P2V(4*1024*1024)); // phys page allocator
  kvmalloc();      // kernel page table
  mpinit();        // collect info about this machine
  lapicinit();
  seginit();       // set up segments
  cprintf("\ncpu%d: starting xv6\n\n", cpu->id);
  picinit();       // interrupt controller
  ioapicinit();    // another interrupt controller
  consoleinit();   // I/O devices & their interrupts
  uartinit();      // serial port
  pinit();         // process table
  tvinit();        // trap vectors
  binit();         // buffer cache
  fileinit();      // file table
  iinit();         // inode cache
  ideinit();       // disk
  if(!ismp)
    timerinit();   // uniprocessor timer
  startothers();   // start other processors
  kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
  userinit();      // first user process
  // Finish setting up this processor in mpmain.
  mpmain();
}

后面倒数的两个函数是关键:

void
userinit(void)                        //初始化proc的部分成员
{
  struct proc *p;
  extern char _binary_initcode_start[], _binary_initcode_size[];
  
  p = allocproc();                    // 初始化kstack、tf等成员(初始化为申请的空间) trapret forkret
  initproc = p;
  if((p->pgdir = setupkvm()) == 0)    // 初始化pgdir成员
    panic("userinit: out of memory?");
  inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
  p->sz = PGSIZE;
  memset(p->tf, 0, sizeof(*p->tf));   // tf的成员初始化
  p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
  p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
  p->tf->es = p->tf->ds;
  p->tf->ss = p->tf->ds;
  p->tf->eflags = FL_IF;
  p->tf->esp = PGSIZE;                // 0x1000
  p->tf->eip = 0;                     // beginning of initcode.S

  safestrcpy(p->name, "initcode", sizeof(p->name));
  p->cwd = namei("/");

  p->state = RUNNABLE;
}
static void
mpmain(void)               //初始化idt 调用scheduler
{
  cprintf("cpu%d: starting\n", cpu->id);
  idtinit();               // load idt register
  xchg(&cpu->started, 1);  // tell startothers() we're up
  scheduler();             // start running processes
}
// proc.c
void
scheduler(void)
{
  struct proc *p;

  for(;;){
    // Enable interrupts on this processor.
    sti();

    // Loop over process table looking for process to run.
    acquire(&ptable.lock);
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
      if(p->state != RUNNABLE)
        continue;

      // Switch to chosen process.  It is the process's job
      // to release ptable.lock and then reacquire it
      // before jumping back to us.
      proc = p;
      switchuvm(p);
      p->state = RUNNING;
      swtch(&cpu->scheduler, proc->context); //从这里开始
      switchkvm();

      // Process is done running for now.
      // It should have changed its p->state before coming back.
      proc = 0;
    }
    release(&ptable.lock);

  }
}
  # swtch.S
.globl swtch
swtch:
  movl 4(%esp), %eax    # &cpu->scheduler
  movl 8(%esp), %edx    # proc->context

  # Save old callee-save registers
  pushl %ebp
  pushl %ebx
  pushl %esi
  pushl %edi

  # Switch stacks
  movl %esp, (%eax)     # eip --> [eax]
  movl %edx, %esp       # 切换栈

  # Load new callee-save registers
  popl %edi
  popl %esi
  popl %ebx
  popl %ebp
  ret                   # 弹出context->eip 即forkret
//proc.c
void
forkret(void)           #第一次在这里下断
{
  static int first = 1;
  // Still holding ptable.lock from scheduler.
  release(&ptable.lock);

  if (first) {
    // Some initialization functions must be run in the context
    // of a regular process (e.g., they call sleep), and thus cannot 
    // be run from main().
    first = 0;
    initlog();
  }
  
  // Return to "caller", actually trapret (see allocproc).
}
.globl trapret
trapret:
  popal
  popl %gs
  popl %fs
  popl %es
  popl %ds
  addl $0x8, %esp  # trapno and errcode
  iret                  # r0 --> r3  5个参数出栈
  # initcode.S         
  # exec(init, argv)
.globl start
start:                  # r3  注意此时的栈内容
  pushl $argv           
  pushl $init
  pushl $0  // where caller pc would be
  movl $SYS_exec, %eax
  int $T_SYSCALL        # 进入系统调用

# for(;;) exit();
exit:
  movl $SYS_exit, %eax
  int $T_SYSCALL
  jmp exit

# char init[] = "/init\0";
init:
  .string "/init\0"

# char *argv[] = { init, 0 };
.p2align 2
argv:
  .long init
  .long 0
# vectors.S通过vectors.pl产生,编译才有
# generated by vectors.pl - do not edit
# handlers
.globl alltraps
.globl vector0        # r0  注意此时的栈内容 脑中想象一下
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
...

 

 

posted @ 2014-06-21 15:53  乾卦  阅读(409)  评论(0)    收藏  举报