diff --git a/defs.h b/defs.h index d6d68ad..2bf5005 100644 --- a/defs.h +++ b/defs.h @@ -155,23 +155,22 @@ void uartputc(int); // vm.c #define PGROUNDUP(sz) ((sz+PGSIZE-1) & ~(PGSIZE-1)) +extern pde_t *kpgdir; void pminit(void); void ksegment(void); void kvmalloc(void); -void loadkvm(void); void vminit(void); void jkstack(); void printstack(void); -void printpgdir(uint*); -uint* setupkvm(void); // XXX need pde_t* -char* uva2ka(uint*, char*); -int allocuvm(uint*, char*, uint); // XXX need pde_t* -void freevm(uint*); -void inituvm(uint*, char*, char*, uint); -int loaduvm(uint*, char*, struct inode *ip, uint, uint); -uint* copyuvm(uint*,uint); +void printpgdir(pde_t *); +pde_t* setupkvm(void); +char* uva2ka(pde_t*, char*); +int allocuvm(pde_t*, char*, uint); +void freevm(pde_t*); +void inituvm(pde_t*, char*, char*, uint); +int loaduvm(pde_t*, char*, struct inode *ip, uint, uint); +pde_t* copyuvm(pde_t*,uint); void loadvm(struct proc*); // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) - diff --git a/mmu.h b/mmu.h index 76d5ce7..378ae22 100644 --- a/mmu.h +++ b/mmu.h @@ -148,7 +148,6 @@ struct segdesc { #define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF) typedef uint pte_t; -typedef uint pde_t; // Control Register flags #define CR0_PE 0x00000001 // Protection Enable diff --git a/proc.c b/proc.c index 3e28200..c1faec6 100644 --- a/proc.c +++ b/proc.c @@ -242,7 +242,7 @@ sched(void) panic("sched running"); if(readeflags()&FL_IF) panic("sched interruptible"); - loadkvm(); // Switch to the kernel page table + lcr3(PADDR(kpgdir)); // Switch to the kernel page table intena = cpu->intena; swtch(&proc->context, cpu->scheduler); cpu->intena = intena; diff --git a/types.h b/types.h index 1c19789..e4adf64 100644 --- a/types.h +++ b/types.h @@ -1,3 +1,4 @@ typedef unsigned int uint; typedef unsigned short ushort; typedef unsigned char uchar; +typedef uint pde_t; diff --git a/vm.c b/vm.c index f24d510..8064ca2 100644 --- a/vm.c +++ b/vm.c @@ -6,13 +6,33 @@ #include "proc.h" #include "elf.h" -static uint kerntext; // linear/physical address of start of kernel text -static uint kerntsz; +// The mappings from logical to linear are one to one (i.e., +// segmentation doesn't do anything). +// The mapping from linear to physical are one to one for the kernel. +// The mappings for the kernel include all of physical memory (until +// PHYSTOP), including the I/O hole, and the top of physical address +// space, where additional devices are located. +// The kernel itself is linked to be at 1MB, and its physical memory +// is also at 1MB. +// Physical memory for user programs is allocated from physical memory +// between kernend and the end of physical memory (PHYSTOP). +// The virtual address space of each user program includes the kernel +// (which is inaccessible in user mode). The user program addresses +// range from 0 till 640KB (USERTOP), which where the I/O hole starts +// (both in physical memory and in the kernel's virtual address +// space). + +#define PHYSTOP 0x300000 +#define USERTOP 0xA0000 + +static uint kerntext; // Linker start kernel at 1MB +static uint kerntsz; static uint kerndata; static uint kerndsz; static uint kernend; static uint freesz; -static pde_t *kpgdir; + +pde_t *kpgdir; // One kernel page table for scheduler procs void printstack() @@ -140,13 +160,14 @@ loadvm(struct proc *p) lcr3(PADDR(p->pgdir)); // switch to new address space popcli(); - // Conservatively flush other processor's TLBs (XXX lazy--just 2 cpus) + // Conservatively flush other processor's TLBs + // XXX lazy--just 2 cpus, but xv6 doesn't need shootdown anyway. if (cpu->id == 0) lapic_tlbflush(1); else lapic_tlbflush(0); } -// Setup kernel part of page table. Linear adresses map one-to-one on -// physical addresses. +// Setup kernel part of a page table. Linear adresses map one-to-one +// on physical addresses. pde_t* setupkvm(void) { @@ -157,7 +178,7 @@ setupkvm(void) return 0; memset(pgdir, 0, PGSIZE); // Map IO space from 640K to 1Mbyte - if (!mappages(pgdir, (void *)0xA0000, 0x60000, 0xA0000, PTE_W, 0)) + if (!mappages(pgdir, (void *)USERTOP, 0x60000, USERTOP, PTE_W, 0)) return 0; // Map kernel text from kern text addr read-only if (!mappages(pgdir, (void *) kerntext, kerntsz, kerntext, 0, 0)) @@ -190,7 +211,7 @@ allocuvm(pde_t *pgdir, char *addr, uint sz) char *mem; n = PGROUNDUP(sz); - if (addr + n >= 0xA0000) + if (addr + n >= USERTOP) return 0; for (i = 0; i < n; i += PGSIZE) { if (!(mem = kalloc(PGSIZE))) { // XXX cleanup what we did? @@ -217,7 +238,7 @@ freevm(pde_t *pgdir) if (pgtab[j] != 0) { uint pa = PTE_ADDR(pgtab[j]); uint va = PGADDR(i, j, 0); - if (va >= 0xA0000) // done with user part? + if (va >= USERTOP) // done with user part? break; kfree((void *) pa, PGSIZE); pgtab[j] = 0; @@ -305,12 +326,12 @@ pminit(void) kerndata = ph[1].va; kerntsz = kerndata - kerntext; kerndsz = kernend - kerndata; - freesz = 0x300000 - kernend; // XXX no more than 3 Mbyte of phys mem + freesz = PHYSTOP - kernend; cprintf("kerntext@0x%x(sz=0x%x), kerndata@0x%x(sz=0x%x), kernend 0x%x freesz = 0x%x\n", kerntext, kerntsz, kerndata, kerndsz, kernend, freesz); - kinit((char *)kernend, freesz); // XXX should be called once on bootcpu + kinit((char *)kernend, freesz); } // Jump to mainc on a properly-allocated kernel stack @@ -331,20 +352,13 @@ kvmalloc(void) kpgdir = setupkvm(); } -// Switch to the kernel page table (used by the scheduler) -void -loadkvm(void) -{ - lcr3(PADDR(kpgdir)); -} - +// Turn on paging. void vminit(void) { uint cr0; - loadkvm(); - // Turn on paging. + lcr3(PADDR(kpgdir)); cr0 = rcr0(); cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP; cr0 &= ~(CR0_TS|CR0_EM);