Process Creation

now let's talk about creating first process and its address space

Q: you'd expect there to be an array or something of pointers
   to the process's user memory. where is it? how does xv6
   know what memory a process is using?

ordinarily p->pgdir and phys mem contents created by fork()
  we will fake them for first process

ordinarily p->tf and p->context created by syscall/switch
  we will fake them for first process

main calls userinit

userinit sheet 22
  only called for first process
    other processes created by fork
  mimics fork+exec
    create a normal-looking process
    ordinary scheduler will run it
  needs to fill in all struct proc entries
allocproc sheet 22
  used by both fork and userinit
  kernel stack setup:
    trapframe w/ "saved user registers"
      for us, initial user registers
      eax, eip, esp, &c
    trapret !
    context w/ "saved kernel thread registers"
      for us, initial kernel thread registers
    assumes that execution will resume in a special
       assembly function called swtch (sheet 27) at line 2722,
       where there is code to pop the registers
       from stack and execute the return instruction
  Q: where will new kernel thread start executing?
  doesn't set up trapframe b/c ordinarily copied
    from parent by fork, which calls allocproc
  but fork and userinit both always start thread in forkret

trapframe sheet 06
context sheet 20

kernel stack diagram:
  top ->
                esp, ss
                eip, cs
                gs fs es ds
  p->tf ->      edi & 7 other registers
                eip = forkret
  p->context -> edi
  p->kstack ->  ...

Q: any guesses why there are *two* saved EIPs?

back to userinit
  we know setupkvm -- only fills in kernel mappings
  this is a new page table for the new process
    not using it yet, will switch when new kernel thread starts
  call inituvm w/ ptr to new process's user instructions

initcode.S sheet 77 : becomes _binary_initcode_start
  user program
  exec("/init", args)

init.c sheet 78 :
  initializes fds 0, 1, 2
  forks shell and waits for it to exit.
  if shell exits, init exits too.

inituvm sheet 18
  we know kalloc and mappages(pgdir, va, sz, pa)
  initcode is tiny, fits in one page
  diagram: new mapping

Q: new page is mapped at va=0; could inituvm call memmove(0, init, sz)?

back to userinit sheet 22
  tf->esp -- user stack at top of page
  tf->eip=0 -- first instruction at bottom of page

main calls scheduler() sheet 12

scheduler sheet 24
  no longer initialization: kernel now fully running
  whenever process gives up CPU -> scheduler
  so kernel runs scheduler a lot
  look for a process that wants to run, run it
  scheduler looks for RUNNABLE

switchuvm sheet 17
  tell h/w to use p->stack if re-enters kernel
    sys call or interrupt
  load %cr3

let's watch switch to new process's page table:
  (gdb) break switchuvm
  (gdb) x/5i 0
  0x0:    Cannot access memory at address 0x0
  next past load %cr3
  (gdb) x/5i 0
  same as initcode sheet 75
  but we are still in the kernel, in scheduler

back to scheduler sheet 24
  mark RUNNING so no other CPU runs it
  now switch to new process's kernel stack, registers, EIP
  swtch(place to save current ESP, previously saved ESP to switch to)

let's watch:
  (gdb) break swtch
  si until esp switch...
  (gdb) x/6x $esp
  si past esp switch
  (gdb) x/6x $esp
  after: 4 regs, forkret, trapret

step into forkret sheet 24
  just returns
  allocproc set up stack to have it return to trapret
  watch out:
    release and initlog cause interrupts
    so hack source to set first=0 and pushcli
    si for iret &c -- si leaves interrupts off
  next into trapret

look at trapframe sheet 06
  (gdb) x/19x $esp
  0x0 0x23 are eip:cs
  0x1000 0x2b are esp:ss

trapret sheet 29
  pops trapret registers from stack, mostly zero
  popal pops 8 general-purpose registers
  iret pops ESP, EIP, clears supervisor flag
  x/5x $esp
  now we are executing at address 0x0 in initcode sheet 75

what does initcode do?
  traps back into the kernel to make exec() system call