#include "types.h" #include "param.h" #include "memlayout.h" #include "riscv.h" #include "spinlock.h" #include "proc.h" #include "defs.h" struct proc proc[NPROC]; struct proc *initproc; // helps ensure that wakeups of wait()ing // parents are not lost. helps obey the // memory model when using p->parent. // must be acquired before any p->lock. struct spinlock wait_lock; struct proc *allocproc(void); // a user program that calls exec("/init") // assembled from ../user/initcode.S // od -t xC ../user/initcode uchar initcode[] = { 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02, 0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02, 0x93, 0x08, 0x70, 0x00, 0x73, 0x00, 0x00, 0x00, 0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00, 0xef, 0xf0, 0x9f, 0xff, 0x2f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Set up first user process. void userinit(void) { struct proc *p; p = allocproc(); initproc = p; // allocate one user page and copy initcode's instructions // and data into it. uvmfirst(p->pagetable, initcode, sizeof(initcode)); p->sz = PGSIZE; // prepare for the very first "return" from kernel to user. p->trapframe->epc = 0; // user program counter p->trapframe->sp = PGSIZE; // user stack pointer p->cwd = namei("/"); p->state = RUNNABLE; release(&p->lock); } // A fork child's very first scheduling by scheduler() // will swtch to forkret. void forkret(void) { static int first = 1; // Still holding p->lock from scheduler. release(&myproc()->lock); if (first) { // File system initialization must be run in the context of a // regular process (e.g., because it calls sleep), and thus cannot // be run from main(). first = 0; fsinit(ROOTDEV); } usertrapret(); }