//PAGEBREAK: 32 // hand-craft the first user process. We link initcode.S into the kernel // as a binary, the linker will generate __binary_initcode_start/_size void userinit(void) { struct proc *p; extern char _binary_initcode_start[], _binary_initcode_size[]; p = allocproc(); initproc = p; if((p->pgdir = kpt_alloc()) == NULL) { panic("userinit: out of memory?"); } inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size); p->sz = PTE_SZ; // craft the trapframe as if memset(p->tf, 0, sizeof(*p->tf)); p->tf->r14_svc = (uint)error_init; p->tf->spsr = spsr_usr (); p->tf->sp_usr = PTE_SZ; // set the user stack p->tf->lr_usr = 0; // set the user pc. The actual pc loaded into r15_usr is in // p->tf, the trapframe. p->tf->pc = 0; // beginning of initcode.S safestrcpy(p->name, "initcode", sizeof(p->name)); p->cwd = namei("/"); p->state = RUNNABLE; }
// Return the address of the PTE in page directory that corresponds to // virtual address va. If alloc!=0, create any required page table pages. static pte_t* walkpgdir (pgd_t *pgdbase, const void *va, int alloc) { pgd_t *pgd; pmd_t *pmdbase; pmd_t *pmd; pte_t *ptebase; pgd = &pgdbase[PGD_IDX((uint64)va)]; if(*pgd & (ENTRY_TABLE | ENTRY_VALID)) { pmdbase = (pmd_t*) p2v((*pgd) & PG_ADDR_MASK); } else { if (!alloc || (pmdbase = (pmd_t*) kpt_alloc()) == 0) { return 0; } memset(pmdbase, 0, PT_SZ); *pgd = v2p(pmdbase) | ENTRY_TABLE | ENTRY_VALID; } pmd = &pmdbase[PMD_IDX(va)]; if (*pmd & (ENTRY_TABLE | ENTRY_VALID)) { ptebase = (pte_t*) p2v((*pmd) & PG_ADDR_MASK); } else { if (!alloc || (ptebase = (pte_t*) kpt_alloc()) == 0) { return 0; } // Make sure all those PTE_P bits are zero. memset(ptebase, 0, PT_SZ); // The permissions here are overly generous, but they can // be further restricted by the permissions in the page table // entries, if necessary. *pmd = v2p(ptebase) | ENTRY_TABLE | ENTRY_VALID; } return &ptebase[PTE_IDX(va)]; }
// Given a parent process's page table, create a copy // of it for a child. pgd_t* copyuvm (pgd_t *pgdir, uint sz) { pgd_t *d; pte_t *pte; uint64 pa, i, ap; char *mem; // allocate a new first level page directory d = kpt_alloc(); if (d == NULL ) { return NULL ; } // copy the whole address space over (no COW) for (i = 0; i < sz; i += PTE_SZ) { if ((pte = walkpgdir(pgdir, (void *) i, 0)) == 0) { panic("copyuvm: pte should exist"); } if (!(*pte & (ENTRY_PAGE | ENTRY_VALID))) { panic("copyuvm: page not present"); } pa = PTE_ADDR (*pte); ap = PTE_AP (*pte); if ((mem = alloc_page()) == 0) { goto bad; } memmove(mem, (char*) p2v(pa), PTE_SZ); if (mappages(d, (void*) i, PTE_SZ, v2p(mem), ap) < 0) { goto bad; } } return d; bad: freevm(d); return 0; }