// | Page Directory | Page Table | Offset within Page |
// | Index | Index | |
// +----------------+----------------+---------------------+
-// \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
-// \----------- PPN(la) -----------/
-//
-// The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown.
-// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la),
-// use PGADDR(PDX(la), PTX(la), PGOFF(la)).
-
-// page number field of address
-#define PPN(la) (((uint) (la)) >> PTXSHIFT)
-#define VPN(la) PPN(la) // used to index into vpt[]
+// \--- PDX(la) --/ \--- PTX(la) --/
// page directory index
#define PDX(la) ((((uint) (la)) >> PDXSHIFT) & 0x3FF)
-#define VPD(la) PDX(la) // used to index into vpd[]
// page table index
#define PTX(la) ((((uint) (la)) >> PTXSHIFT) & 0x3FF)
-// offset in page
-#define PGOFF(la) (((uint) (la)) & 0xFFF)
-
// construct linear address from indexes and offset
#define PGADDR(d, t, o) ((uint) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
-// mapping from physical addresses to virtual addresses is the identity one
-// (really linear addresses, but we map linear to physical also directly)
+// turn a kernel linear address into a physical address.
+// all of the kernel data structures have linear and
+// physical addresses that are equal.
#define PADDR(a) ((uint) a)
// Page directory and page table constants.
#define PGSIZE 4096 // bytes mapped by a page
#define PGSHIFT 12 // log2(PGSIZE)
-#define PTSIZE (PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry
-#define PTSHIFT 22 // log2(PTSIZE)
-
#define PTXSHIFT 12 // offset of PTX in a linear address
#define PDXSHIFT 22 // offset of PDX in a linear address
#define PTE_PS 0x080 // Page Size
#define PTE_MBZ 0x180 // Bits must be zero
-// The PTE_AVAIL bits aren't used by the kernel or interpreted by the
-// hardware, so user processes are allowed to set them arbitrarily.
-#define PTE_AVAIL 0xE00 // Available for software use
-
-// Only flags in PTE_USER may be used in system calls.
-#define PTE_USER (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
-
// Address in page table or page directory entry
#define PTE_ADDR(pte) ((uint) (pte) & ~0xFFF)
static uint freesz;
pde_t *kpgdir; // One kernel page table for scheduler procs
-void
-printpgdir(pde_t *pgdir)
-{
- uint i;
- uint j;
-
- cprintf("printpgdir 0x%x\n", pgdir);
- for (i = 0; i < NPDENTRIES; i++) {
- if (pgdir[i] != 0 && i < 100) {
- cprintf("pgdir %d, v=0x%x\n", i, pgdir[i]);
- pte_t *pgtab = (pte_t*) PTE_ADDR(pgdir[i]);
- for (j = 0; j < NPTENTRIES; j++) {
- if (pgtab[j] != 0)
- cprintf("pgtab %d, v=0x%x, addr=0x%x\n", j, PGADDR(i, j, 0),
- PTE_ADDR(pgtab[j]));
- }
- }
- }
- cprintf("printpgdir done\n", pgdir);
-}
-
// return the address of the PTE in page table pgdir
// that corresponds to linear address va. if create!=0,
// create any required page table pages.
}
// create PTEs for linear addresses starting at la that refer to
-// physical addresses starting at pa.
+// physical addresses starting at pa. la and size might not
+// be page-aligned.
static int
mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
{
- uint i;
- pte_t *pte;
-
- for (i = 0; i < size; i += PGSIZE) {
- if (!(pte = walkpgdir(pgdir, (void*)(la + i), 1)))
+ char *first = PGROUNDDOWN(la);
+ char *last = PGROUNDDOWN(la + size - 1);
+ char *a = first;
+ while(1){
+ pte_t *pte = walkpgdir(pgdir, a, 1);
+ if(pte == 0)
return 0;
if(*pte & PTE_P)
panic("remap");
- *pte = (pa + i) | perm | PTE_P;
+ *pte = pa | perm | PTE_P;
+ if(a == last)
+ break;
+ a += PGSIZE;
+ pa += PGSIZE;
}
return 1;
}
// Map IO space from 640K to 1Mbyte
if (!mappages(pgdir, (void *)USERTOP, 0x60000, USERTOP, PTE_W))
return 0;
- // Map kernel text from kern text addr read-only
+ // Map kernel text read-only
if (!mappages(pgdir, (void *) kerntext, kerntsz, kerntext, 0))
return 0;
- // Map kernel data form kern data addr R/W
+ // Map kernel data read/write
if (!mappages(pgdir, (void *) kerndata, kerndsz, kerndata, PTE_W))
return 0;
// Map dynamically-allocated memory read/write (kernel stacks, user mem)
{
if (addr + sz >= (char*)USERTOP)
return 0;
- char *start = PGROUNDDOWN(addr);
+ char *first = PGROUNDDOWN(addr);
char *last = PGROUNDDOWN(addr + sz - 1);
char *a;
- for(a = start; a <= last; a += PGSIZE){
+ for(a = first; a <= last; a += PGSIZE){
pte_t *pte = walkpgdir(pgdir, a, 0);
if(pte == 0 || (*pte & PTE_P) == 0){
char *mem = kalloc(PGSIZE);
return 1;
}
+// free a page table and all the physical memory pages
+// in the user part.
void
freevm(pde_t *pgdir)
{
if (pgtab[j] != 0) {
uint pa = PTE_ADDR(pgtab[j]);
uint va = PGADDR(i, j, 0);
- if (va >= USERTOP) // done with user part?
- break;
- kfree((void *) pa, PGSIZE);
+ if (va < USERTOP) // user memory
+ kfree((void *) pa, PGSIZE);
pgtab[j] = 0;
}
}
kernend = ((uint)end + PGSIZE) & ~(PGSIZE-1);
kerntext = ph[0].va;
kerndata = ph[1].va;
- kerntsz = kerndata - kerntext;
- kerndsz = kernend - kerndata;
+ kerntsz = ph[0].memsz;
+ kerndsz = ph[1].memsz;
freesz = PHYSTOP - kernend;
cprintf("kerntext@0x%x(sz=0x%x), kerndata@0x%x(sz=0x%x), kernend 0x%x freesz = 0x%x\n",