summaryrefslogtreecommitdiff
path: root/vm.c
diff options
context:
space:
mode:
authorRuss Cox <[email protected]>2011-02-19 21:17:55 -0500
committerRuss Cox <[email protected]>2011-02-19 21:17:55 -0500
commitcf4b1ad90bcaeeb0c8458098c87948f61d408f94 (patch)
treeb6385b1d72af5a3e634b94b318fb7e43644493af /vm.c
parent9c4fe7ba105c0430c90179fd1e93c3d439a8cbd5 (diff)
downloadxv6-labs-cf4b1ad90bcaeeb0c8458098c87948f61d408f94.tar.gz
xv6-labs-cf4b1ad90bcaeeb0c8458098c87948f61d408f94.tar.bz2
xv6-labs-cf4b1ad90bcaeeb0c8458098c87948f61d408f94.zip
xv6: formatting, cleanup, rev5 (take 2)
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c115
1 files changed, 54 insertions, 61 deletions
diff --git a/vm.c b/vm.c
index bfc0845..1fe64d2 100644
--- a/vm.c
+++ b/vm.c
@@ -6,8 +6,18 @@
#include "proc.h"
#include "elf.h"
+extern char data[]; // defined in data.S
+
static pde_t *kpgdir; // for use in scheduler()
+// Allocate one page table for the machine for the kernel address
+// space for scheduler processes.
+void
+kvmalloc(void)
+{
+ kpgdir = setupkvm();
+}
+
// Set up CPU's kernel segment descriptors.
// Run once at boot time on each CPU.
void
@@ -72,7 +82,6 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
a = PGROUNDDOWN(la);
last = PGROUNDDOWN(la + size - 1);
-
for(;;){
pte = walkpgdir(pgdir, a, 1);
if(pte == 0)
@@ -110,40 +119,32 @@ mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
// 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).
-
-// Allocate one page table for the machine for the kernel address
-// space for scheduler processes.
-void
-kvmalloc(void)
-{
- kpgdir = setupkvm();
-}
+static struct kmap {
+ void *p;
+ void *e;
+ int perm;
+} kmap[] = {
+ {(void*)USERTOP, (void*)0x100000, PTE_W}, // I/O space
+ {(void*)0x100000, data, 0 }, // kernel text, rodata
+ {data, (void*)PHYSTOP, PTE_W}, // kernel data, memory
+ {(void*)0xFE000000, 0, PTE_W}, // device mappings
+};
// Set up kernel part of a page table.
pde_t*
setupkvm(void)
{
- extern char etext[];
- char *rwstart;
pde_t *pgdir;
- uint rwlen;
-
- rwstart = PGROUNDDOWN(etext);
- rwlen = (uint)rwstart - 0x100000;
+ struct kmap *k;
- // Allocate page directory
if((pgdir = (pde_t*)kalloc()) == 0)
return 0;
memset(pgdir, 0, PGSIZE);
- if(// Map IO space from 640K to 1Mbyte
- mappages(pgdir, (void*)USERTOP, 0x60000, USERTOP, PTE_W) < 0 ||
- // Map kernel instructions
- mappages(pgdir, (void*)0x100000, rwlen, 0x100000, 0) < 0 ||
- // Map kernel data and free memory pool
- mappages(pgdir, rwstart, PHYSTOP-(uint)rwstart, (uint)rwstart, PTE_W) < 0 ||
- // Map devices such as ioapic, lapic, ...
- mappages(pgdir, (void*)0xFE000000, 0x2000000, 0xFE000000, PTE_W) < 0)
- return 0;
+ k = kmap;
+ for(k = kmap; k < &kmap[NELEM(kmap)]; k++)
+ if(mappages(pgdir, k->p, k->e - k->p, (uint)k->p, k->perm) < 0)
+ return 0;
+
return pgdir;
}
@@ -162,48 +163,27 @@ vmenable(void)
// Switch h/w page table register to the kernel-only page table,
// for when no process is running.
void
-switchkvm()
+switchkvm(void)
{
lcr3(PADDR(kpgdir)); // switch to the kernel page table
}
-// Switch h/w page table and TSS registers to point to process p.
+// Switch TSS and h/w page table to correspond to process p.
void
switchuvm(struct proc *p)
{
pushcli();
-
- // Setup TSS
cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0);
cpu->gdt[SEG_TSS].s = 0;
cpu->ts.ss0 = SEG_KDATA << 3;
cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;
ltr(SEG_TSS << 3);
-
if(p->pgdir == 0)
- panic("switchuvm: no pgdir\n");
-
+ panic("switchuvm: no pgdir");
lcr3(PADDR(p->pgdir)); // switch to new address space
popcli();
}
-// Return the physical address that a given user address
-// maps to. The result is also a kernel logical address,
-// since the kernel maps the physical memory allocated to user
-// processes directly.
-char*
-uva2ka(pde_t *pgdir, char *uva)
-{
- pte_t *pte;
-
- pte = walkpgdir(pgdir, uva, 0);
- if((*pte & PTE_P) == 0)
- return 0;
- if((*pte & PTE_U) == 0)
- return 0;
- return (char*)PTE_ADDR(*pte);
-}
-
// Load the initcode into address 0 of pgdir.
// sz must be less than a page.
void
@@ -228,10 +208,10 @@ loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
pte_t *pte;
if((uint)addr % PGSIZE != 0)
- panic("loaduvm: addr must be page aligned\n");
+ panic("loaduvm: addr must be page aligned");
for(i = 0; i < sz; i += PGSIZE){
if((pte = walkpgdir(pgdir, addr+i, 0)) == 0)
- panic("loaduvm: address should exist\n");
+ panic("loaduvm: address should exist");
pa = PTE_ADDR(*pte);
if(sz - i < PGSIZE)
n = sz - i;
@@ -243,10 +223,8 @@ loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
return 0;
}
-// Allocate memory to the process to bring its size from oldsz to
-// newsz. Allocates physical memory and page table entries. oldsz and
-// newsz need not be page-aligned, nor does newsz have to be larger
-// than oldsz. Returns the new process size or 0 on error.
+// Allocate page tables and physical memory to grow process from oldsz to
+// newsz, which need not be page aligned. Returns new size or 0 on error.
int
allocuvm(pde_t *pgdir, uint oldsz, uint newsz)
{
@@ -330,9 +308,9 @@ copyuvm(pde_t *pgdir, uint sz)
return 0;
for(i = 0; i < sz; i += PGSIZE){
if((pte = walkpgdir(pgdir, (void*)i, 0)) == 0)
- panic("copyuvm: pte should exist\n");
+ panic("copyuvm: pte should exist");
if(!(*pte & PTE_P))
- panic("copyuvm: page not present\n");
+ panic("copyuvm: page not present");
pa = PTE_ADDR(*pte);
if((mem = kalloc()) == 0)
goto bad;
@@ -347,16 +325,31 @@ bad:
return 0;
}
-// copy some data to user address va in page table pgdir.
-// most useful when pgdir is not the current page table.
+//PAGEBREAK!
+// Map user virtual address to kernel physical address.
+char*
+uva2ka(pde_t *pgdir, char *uva)
+{
+ pte_t *pte;
+
+ pte = walkpgdir(pgdir, uva, 0);
+ if((*pte & PTE_P) == 0)
+ return 0;
+ if((*pte & PTE_U) == 0)
+ return 0;
+ return (char*)PTE_ADDR(*pte);
+}
+
+// Copy len bytes from p to user address va in page table pgdir.
+// Most useful when pgdir is not the current page table.
// uva2ka ensures this only works for PTE_U pages.
int
-copyout(pde_t *pgdir, uint va, void *xbuf, uint len)
+copyout(pde_t *pgdir, uint va, void *p, uint len)
{
char *buf, *pa0;
uint n, va0;
- buf = (char*)xbuf;
+ buf = (char*)p;
while(len > 0){
va0 = (uint)PGROUNDDOWN(va);
pa0 = uva2ka(pgdir, (char*)va0);