summaryrefslogtreecommitdiff
path: root/kernel/old/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/old/vm.c')
-rw-r--r--kernel/old/vm.c722
1 files changed, 201 insertions, 521 deletions
diff --git a/kernel/old/vm.c b/kernel/old/vm.c
index 814ff12..749bed3 100644
--- a/kernel/old/vm.c
+++ b/kernel/old/vm.c
@@ -6,7 +6,7 @@
** @brief Kernel VM support
*/
-#define KERNEL_SRC
+#define KERNEL_SRC
#include <common.h>
@@ -37,244 +37,70 @@ pde_t *kpdir;
** @param vector Interrupt vector number
** @param code Error code pushed onto the stack
*/
-static void vm_isr(int vector, int code)
-{
+static void vm_isr( int vector, int code ) {
+
// get whatever information we can from the fault
pfec_t fault;
- fault.u = (uint32_t)code;
+ fault.u = (uint32_t) code;
uint32_t addr = r_cr2();
// report what we found
- sprint(b256,
- "** page fault @ 0x%08x %cP %c %cM %cRSV %c %cPK %cSS %cHLAT %cSGZ",
- addr, fault.s.p ? ' ' : '!', fault.s.w ? 'W' : 'R',
- fault.s.us ? 'U' : 'S', fault.s.rsvd ? ' ' : '!',
- fault.s.id ? 'I' : 'D', fault.s.pk ? ' ' : '!',
- fault.s.ss ? ' ' : '!', fault.s.hlat ? ' ' : '!',
- fault.s.sgz ? ' ' : '!');
+ sprint( b256,
+ "** page fault @ 0x%08x %cP %c %cM %cRSV %c %cPK %cSS %cHLAT %cSGZ",
+ addr,
+ fault.s.p ? ' ' : '!',
+ fault.s.w ? 'W' : 'R',
+ fault.s.us ? 'U' : 'S',
+ fault.s.rsvd ? ' ' : '!',
+ fault.s.id ? 'I' : 'D',
+ fault.s.pk ? ' ' : '!',
+ fault.s.ss ? ' ' : '!',
+ fault.s.hlat ? ' ' : '!',
+ fault.s.sgz ? ' ' : '!'
+ );
// and give up
- PANIC(0, b256);
+ PANIC( 0, b256 );
}
/**
-** Name: ptcount
-**
-** Count the number of each type of entry in a page table.
-** Returns a 32-bit result containing two 16-bit counts:
+** Name: uva2kva
**
-** Upper half Lower half
-** PDIR: # of 4MB entries # of 'present' entries
-** PMT: zero # of 'present' entries
-**
-** The number of "not present" can be calculated from these.
+** Convert a user VA into a kernel address. Works for all addresses -
+** if the address is a page address, the PERMS(va) value will be 0;
+** otherwise, it is the offset into the page.
**
-** @param pt Pointer to the page table
-** @param dir Is it a page directory (vs. a page table)?
+** @param pdir Pointer to the page directory to examine
+** @param va Virtual address to check
*/
ATTR_UNUSED
-static uint32_t ptcount(pte_t *ptr, bool_t dir)
-{
- uint16_t n_np = 0, n_p = 0, n_lg = 0;
-
- for (int i = 0; i < N_PTE; ++i) {
- pde_t entry = *ptr++;
- if (!IS_PRESENT(entry)) {
- ++n_np;
- continue;
- }
- if (dir && IS_LARGE(entry)) {
- ++n_lg;
- } else {
- ++n_p;
- }
- }
-
- // n_lg will be 0 for PMTs
- return (n_lg << 16) | n_p;
-}
-
-// decode a PDE
-static void pde_prt(uint32_t level, uint32_t i, uint32_t entry, bool_t all)
-{
- if (!IS_PRESENT(entry) && !all) {
- return;
- }
-
- // indent
- for (int n = 0; n <= level; ++n)
- cio_puts(" ");
-
- // line header
- cio_printf("[%03x] %08x", i, entry);
+static void *uva2kva( pde_t *pdir, void *va ) {
- // perms
- if (IS_LARGE(entry)) { // PS is 1
- if ((entry & PDE_PAT) != 0)
- cio_puts(" PAT");
- if ((entry & PDE_G) != 0)
- cio_puts(" G");
- cio_puts(" PS");
- if ((entry & PDE_D) != 0)
- cio_puts(" D");
+ // find the PMT entry for this address
+ pte_t *pte = vm_getpte( pdir, va, false );
+ if( pte == NULL ) {
+ return NULL;
}
- if ((entry & PDE_A) != 0)
- cio_puts(" A");
- if ((entry & PDE_PCD) != 0)
- cio_puts(" CD");
- if ((entry & PDE_PWT) != 0)
- cio_puts(" WT");
- if ((entry & PDE_US) != 0)
- cio_puts(" U");
- if ((entry & PDE_RW) != 0)
- cio_puts(" W");
- // frame address
- cio_printf(" P --> %s %08x\n", IS_LARGE(entry) ? "Pg" : "PT",
- PDE_ADDR(entry));
-}
+ // get the entry
+ pte_t entry = *pte;
-// decode a PTE
-static void pte_prt(uint32_t level, uint32_t i, uint32_t entry, bool_t all)
-{
- if (!IS_PRESENT(entry) && !all) {
- return;
+ // is this a valid address for the user?
+ if( IS_PRESENT(entry) ) {
+ return NULL;
}
- // indent
- for (int n = 0; n <= level; ++n)
- cio_puts(" ");
-
- // line header
- cio_printf("[%03x] %08x", i, entry);
-
- // perms
- if ((entry & PTE_G) != 0)
- cio_puts(" G");
- if ((entry & PTE_PAT) != 0)
- cio_puts(" PAT");
- if ((entry & PTE_D) != 0)
- cio_puts(" D");
- if ((entry & PTE_A) != 0)
- cio_puts(" A");
- if ((entry & PTE_PCD) != 0)
- cio_puts(" CD");
- if ((entry & PTE_PWT) != 0)
- cio_puts(" WT");
- if ((entry & PTE_US) != 0)
- cio_puts(" U");
- if ((entry & PTE_RW) != 0)
- cio_puts(" W");
-
- cio_printf(" P --> Pg %08x\n", PTE_ADDR(entry));
-}
-
-/**
-** Name: ptdump
-**
-** Recursive helper for table hierarchy dump.
-**
-** @param level Current hierarchy level
-** @param pt Page table to display
-** @param dir Is it a page directory (vs. a page table)?
-** @param mode How to display the entries
-*/
-ATTR_UNUSED
-static void ptdump(uint_t level, void *pt, bool_t dir, enum vmmode_e mode)
-{
- pte_t *ptr = (pte_t *)pt;
-
- // indent two spaces per level
- for (int n = 0; n < level; ++n)
- cio_puts(" ");
-
- cio_printf("%s at 0x%08x:", dir ? "PDir" : "PTbl", (uint32_t)pt);
- uint32_t nums = ptcount(ptr, dir);
- if (dir) {
- cio_printf(" 4MB=%u", (nums >> 16));
+ // is this a system-only page?
+ if( IS_SYSTEM(entry) ) {
+ return NULL;
}
- cio_printf(" P=%u !P=%u\n", nums & 0xffff,
- N_PTE - ((nums >> 16) + (nums & 0xffff)));
- for (uint32_t i = 0; i < (uint32_t)N_PTE; ++i) {
- pte_t entry = *ptr++;
+ // get the physical address
+ uint32_t frame = PTE_ADDR(*pte) | PERMS(va);
- // only process this entry if it's not empty
- if (entry) {
- if (dir) {
- // this is a PDIR entry; could be either a 4MB
- // page, or a PMT pointer
- if (mode > Simple) {
- pde_prt(level, i, entry, false);
- if (!IS_LARGE(entry) && mode > OneLevel) {
- ptdump(level + 1, (void *)P2V(PTE_ADDR(entry)), false,
- mode);
- }
- }
- } else {
- // just a PMT entry
- if (mode > Simple) {
- pte_prt(level, i, entry, false);
- }
- }
- }
- }
+ return (void *) P2V(frame);
}
-/**
-** Name: pmt_dump
-**
-** Dump the non-zero entries of a page table or directory
-**
-** @param pt The page table
-** @param dir Is this a page directory?
-** @param start First entry to process
-** @param num Number of entries to process
-*/
-ATTR_UNUSED
-static void pmt_dump(pte_t *pt, bool_t dir, uint32_t start, uint32_t num)
-{
- cio_printf("\n\nP%c dump", dir ? 'D' : 'T');
- cio_printf(" of %08x", (uint32_t)pt);
- cio_printf(" [%03x] through [%03x]\n", start, start + num - 1);
-
- uint_t n = 0;
- uint_t z = 0;
-
- for (uint_t i = 0; i < num; ++i) {
- pte_t entry = pt[start + i];
- // four entries per line
- if (n && ((n & 0x3) == 0)) {
- cio_putchar('\n');
- }
- if (IS_PRESENT(entry)) {
- cio_printf(" %03x", start + i);
- if (IS_LARGE(entry)) {
- cio_printf(" 8 %05x", GET_4MFRAME(entry) << 10);
- } else {
- cio_printf(" 4 %05x", GET_4KFRAME(entry));
- }
- ++n;
- } else {
- ++z;
- }
- // pause after every four lines of output
- if (n && ((n & 0xf) == 0)) {
- delay(DELAY_2_SEC);
- }
- }
-
- // partial line?
- if ((n & 0x3) != 0) {
- cio_putchar('\n');
- }
-
- if (z > 0) {
- cio_printf(" %u entries were !P\n", z);
- }
-
- delay(DELAY_2_SEC);
-}
/*
** PUBLIC FUNCTIONS
@@ -285,83 +111,21 @@ static void pmt_dump(pte_t *pt, bool_t dir, uint32_t start, uint32_t num)
**
** Description: Initialize the VM module
*/
-void vm_init(void)
-{
+void vm_init( void ) {
+
#if TRACING_INIT
- cio_puts(" VM");
+ cio_puts( " VM" );
#endif
// set up the kernel's 4K-page directory
kpdir = vm_mkkvm();
- assert(kpdir != NULL);
-
-#if TRACING_VM
- cio_printf("vm_init: kpdir %08x, adding user pages\n", kpdir);
-#endif
-
- // add the entries for the user address space
- for (uint32_t addr = 0; addr < NUM_4MB; addr += SZ_PAGE) {
- int stat = vm_map(kpdir, (void *)addr, addr, SZ_PAGE, PTE_US | PTE_RW);
- if (stat != SUCCESS) {
- cio_printf("vm_init, map %08x->%08x failed, status %d\n", addr,
- addr, stat);
- PANIC(0, "vm_init user range map failed");
- }
-#if TRACING_VM
- cio_putchar('.');
-#endif
- }
-#if TRACING_VM
- cio_puts(" done\n");
-#endif
+ assert( kpdir != NULL );
// switch to it
vm_set_kvm();
-#if TRACING_VM
- cio_puts("vm_init: running on new kpdir\n");
-#endif
-
// install the page fault handler
- install_isr(VEC_PAGE_FAULT, vm_isr);
-}
-
-/**
-** Name: vm_uva2kva
-**
-** Convert a user VA into a kernel address. Works for all addresses -
-** if the address is a page address, the low-order nine bits will be
-** zeroes; otherwise, they are the offset into the page, which is
-** unchanged between the address spaces.
-**
-** @param pdir Pointer to the page directory to examine
-** @param va Virtual address to check
-*/
-void *vm_uva2kva(pde_t *pdir, void *va)
-{
- // find the PMT entry for this address
- pte_t *pte = vm_getpte(pdir, va, false);
- if (pte == NULL) {
- return NULL;
- }
-
- // get the entry
- pte_t entry = *pte;
-
- // is this a valid address for the user?
- if (!IS_PRESENT(entry)) {
- return NULL;
- }
-
- // is this a system-only page?
- if (IS_SYSTEM(entry)) {
- return NULL;
- }
-
- // get the physical address
- uint32_t frame = PTE_ADDR(*pte) | PERMS(va);
-
- return (void *)P2V(frame);
+ install_isr( VEC_PAGE_FAULT, vm_isr );
}
/**
@@ -373,11 +137,10 @@ void *vm_uva2kva(pde_t *pdir, void *va)
**
** @return a pointer to the new, duplicate page, or NULL
*/
-void *vm_pagedup(void *old)
-{
- void *new = (void *)km_page_alloc();
- if (new != NULL) {
- blkmov(new, old, SZ_PAGE);
+void *vm_pagedup( void *old ) {
+ void *new = (void *) km_page_alloc();
+ if( new != NULL ) {
+ blkmov( new, old, SZ_PAGE );
}
return new;
}
@@ -387,54 +150,58 @@ void *vm_pagedup(void *old)
**
** Duplicate a page directory entry
**
-** @param entry The entry to be duplicated
+** @param dst Pointer to where the duplicate should go
+** @param curr Pointer to the entry to be duplicated
**
-** @return the new entry, or -1 on error
+** @return true on success, else false
*/
-pde_t vm_pdedup(pde_t entry)
-{
+bool_t vm_pdedup( pde_t *dst, pde_t *curr ) {
+
+ assert1( curr != NULL );
+ assert1( dst != NULL );
+
#if TRACING_VM
- cio_printf("vm_pdedup curr %08x\n", (uint32_t)entry);
+ cio_printf( "vm_pdedup dst %08x curr %08x\n",
+ (uint32_t) dst, (uint32_t) curr );
#endif
+ pde_t entry = *curr;
// simplest case
- if (!IS_PRESENT(entry)) {
- return 0;
- }
-
- // is this a large page?
- if (IS_LARGE(entry)) {
- // just copy it
- return entry;
+ if( !IS_PRESENT(entry) ) {
+ *dst = 0;
+ return true;
}
- // OK, we have a 4KB entry; allocate a page table for it
- pte_t *tblva = (pte_t *)km_page_alloc();
- if (tblva == NULL) {
- return (uint32_t)-1;
+ // OK, we have an entry; allocate a page table for it
+ pte_t *newtbl = (pte_t *) km_page_alloc();
+ if( newtbl == NULL ) {
+ return false;
}
- // make sure the entries are all initially 'not present'
- memclr(tblva, SZ_PAGE);
+ // we could clear the new table, but we'll be assigning to
+ // each entry anyway, so we'll save the execution time
- // VA of the page table for this directory entry
- pte_t *old = (pte_t *)P2V(PDE_ADDR(entry));
+ // address of the page table for this directory entry
+ pte_t *old = (pte_t *) PDE_ADDR(entry);
- // pointer to the first PTE in the new table (already a VA)
- pte_t *new = tblva;
+ // pointer to the first PTE in the new table
+ pte_t *new = newtbl;
- for (int i = 0; i < N_PTE; ++i) {
- // only need to copy 'present' entries
- if (IS_PRESENT(*old)) {
+ for( int i = 0 ; i < N_PTE; ++i ) {
+ if( !IS_PRESENT(*old) ) {
+ *new = 0;
+ } else {
*new = *old;
}
++old;
++new;
}
- // replace the page table address
- // (PA of page table, lower 12 bits from '*curr')
- return (pde_t)(V2P(PTE_ADDR(tblva)) | PERMS(entry));
+ // replace the page table address
+ // upper 22 bits from 'newtbl', lower 12 from '*curr'
+ *dst = (pde_t) ( PTE_ADDR(newtbl) | PERMS(entry) );
+
+ return true;
}
/**
@@ -452,37 +219,38 @@ pde_t vm_pdedup(pde_t entry)
** @return A pointer to the page table entry for this VA, or NULL if
** there isn't one and we're not allocating
*/
-pte_t *vm_getpte(pde_t *pdir, const void *va, bool_t alloc)
-{
- pte_t *ptbl;
+pte_t *vm_getpte( pde_t *pdir, const void *va, bool_t alloc ) {
+ pte_t *ptab;
// sanity check
- assert1(pdir != NULL);
+ assert1( pdir != NULL );
// get the PDIR entry for this virtual address
- pde_t *pde_ptr = &pdir[PDIX(va)];
+ pde_t *pde = &pdir[ PDIX(va) ];
// is it already set up?
- if (IS_PRESENT(*pde_ptr)) {
+ if( IS_PRESENT(*pde) ) {
+
// yes!
- ptbl = (pte_t *)P2V(PTE_ADDR(*pde_ptr));
+ ptab = (pte_t*)P2V(PTE_ADDR(*pde));
} else {
+
// no - should we create it?
- if (!alloc) {
+ if( !alloc ) {
// nope, so just return
return NULL;
}
// yes - try to allocate a page table
- ptbl = (pte_t *)km_page_alloc();
- if (ptbl == NULL) {
- WARNING("can't allocate page table");
+ ptab = (pte_t *) km_page_alloc();
+ if( ptab == NULL ) {
+ WARNING( "can't allocate page table" );
return NULL;
}
// who knows what was left in this page....
- memclr(ptbl, SZ_PAGE);
+ memclr( ptab, SZ_PAGE );
// add this to the page directory
//
@@ -491,54 +259,46 @@ pte_t *vm_getpte(pde_t *pdir, const void *va, bool_t alloc)
// entries, if necessary.
//
// NOTE: the allocator is serving us virtual page addresses,
- // so we must convert them to physical addresses for the
- // table entries
- *pde_ptr = V2P(ptbl) | PDE_P | PDE_RW | PDE_US;
+ // so we must convert them to physical addresses
+ *pde = ((uint32_t) V2P(ptab)) | PDE_P | PDE_RW;
}
- // finally, return a pointer to the entry in the page table for this VA
- return &ptbl[PTIX(va)];
+ // finally, return a pointer to the entry in the
+ // page table for this VA
+ return &ptab[ PTIX(va) ];
}
// Set up kernel part of a page table.
-pde_t *vm_mkkvm(void)
+pde_t *vm_mkkvm( void )
{
mapping_t *k;
// allocate the page directory
pde_t *pdir = km_page_alloc();
- if (pdir == NULL) {
+ if( pdir == NULL ) {
return NULL;
}
-#if 0 && TRACING_VM
- cio_puts( "\nEntering vm_mkkvm\n" );
- pmt_dump( pdir, true, 0, N_PDE );
-#endif
// clear it out to disable all the entries
- memclr(pdir, SZ_PAGE);
+ memclr( pdir, SZ_PAGE );
- if (P2V(PHYS_TOP) > DEV_BASE) {
- cio_printf("PHYS_TOP (%08x -> %08x) > DEV_BASE(%08x)\n", PHYS_TOP,
- P2V(PHYS_TOP), DEV_BASE);
- PANIC(0, "PHYS_TOP too large");
+ if( P2V(PHYS_TOP) > DEV_BASE ) {
+ cio_printf( "PHYS_TOP (%08x -> %08x) > DEV_BASE(%08x)\n",
+ PHYS_TOP, P2V(PHYS_TOP), DEV_BASE );
+ PANIC( 0, "PHYS_TOP too large" );
}
// map in all the page ranges
k = kmap;
- for (int i = 0; i < n_kmap; ++i, ++k) {
- int stat = vm_map(pdir, ((void *)k->va_start), k->pa_start,
- k->pa_end - k->pa_start, k->perm);
- if (stat != SUCCESS) {
- vm_free(pdir);
+ for( int i = 0; i < n_kmap; ++i, ++k ) {
+ int stat = vm_map( pdir, ((void *)k->va_start),
+ k->pa_end - k->pa_start,
+ k->pa_start, k->perm );
+ if( stat != SUCCESS ) {
+ vm_free( pdir );
return 0;
}
}
-#if 0 && TRACING_VM
- cio_puts( "\nvm_mkkvm() final PD:\n" );
- pmt_dump( pdir, true, 0, 16 );
- pmt_dump( pdir, true, 0x200, 16 );
-#endif
return pdir;
}
@@ -549,37 +309,32 @@ pde_t *vm_mkkvm(void)
**
** @return a pointer to the new page directory, or NULL
*/
-pde_t *vm_mkuvm(void)
-{
+pde_t *vm_mkuvm( void ) {
+
// allocate the directory
- pde_t *new = (pde_t *)km_page_alloc();
- if (new == NULL) {
+ pde_t *new = (pde_t *) km_page_alloc();
+ if( new == NULL ) {
return NULL;
}
- // iterate through the 'system' portions of the kernel
- // page directory
- int i = PDIX(KERN_BASE);
- pde_t *curr = &kpdir[i];
- pde_t *dst = &new[i];
- while (i < N_PDE) {
- if (*curr != 0) {
+ // iterate through the kernel page directory
+ pde_t *curr = kpdir;
+ pde_t *dst = new;
+ for( int i = 0; i < N_PDE; ++i ) {
+
+ if( *curr != 0 ) {
// found an active one - duplicate it
- pde_t entry = vm_pdedup(*curr);
- if (entry == (uint32_t)-1) {
+ if( !vm_pdedup(dst,curr) ) {
return NULL;
}
- *dst = entry;
- } else {
- *dst = 0;
}
++curr;
++dst;
- ++i;
}
return new;
+
}
/**
@@ -587,15 +342,8 @@ pde_t *vm_mkuvm(void)
**
** Switch the page table register to the kernel's page directory.
*/
-void vm_set_kvm(void)
-{
-#if TRACING_VM
- cio_puts("Entering vm_set_kvm()\n");
-#endif
- w_cr3(V2P(kpdir)); // switch to the kernel page table
-#if TRACING_VM
- cio_puts("Exiting vm_set_kvm()\n");
-#endif
+void vm_set_kvm( void ) {
+ w_cr3( V2P(kpdir) ); // switch to the kernel page table
}
/**
@@ -605,18 +353,11 @@ void vm_set_kvm(void)
**
** @param p PCB of the process we're switching to
*/
-void vm_set_uvm(pcb_t *p)
-{
-#if TRACING_VM
- cio_puts("Entering vm_set_uvm()\n");
-#endif
- assert(p != NULL);
- assert(p->pdir != NULL);
+void vm_set_uvm( pcb_t *p ) {
+ assert( p != NULL );
+ assert( p->pdir != NULL );
- w_cr3(V2P(p->pdir)); // switch to process's address space
-#if TRACING_VM
- cio_puts("Entering vm_set_uvm()\n");
-#endif
+ w_cr3( V2P(p->pdir) ); // switch to process's address space
}
/**
@@ -635,35 +376,36 @@ void vm_set_uvm(pcb_t *p)
**
** @return status of the allocation attempt
*/
-int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
- char *data, uint32_t bytes)
-{
+int vm_add( pde_t *pdir, bool_t wr, bool_t sys,
+ void *va, uint32_t size, char *data, uint32_t bytes ) {
+
// how many pages do we need?
- uint32_t npages = ((size & MOD4K_BITS) ? PGUP(size) : size) >> MOD4K_SHIFT;
+ uint_t npages = ((size & MOD4K_BITS) ? PGUP(size) : size) >> MOD4K_SHIFT;
// permission set for the PTEs
- uint32_t entrybase = PTE_P;
- if (wr) {
+ uint_t entrybase = PTE_P;
+ if( wr ) {
entrybase |= PTE_RW;
}
- if (!sys) {
+ if( sys ) {
entrybase |= PTE_US;
}
#if TRACING_VM
- cio_printf("vm_add: pdir %08x, %s, va %08x size %u (%u pgs)\n",
- (uint32_t)pdir, wr ? "W" : "!W", (uint32_t)va, size, npages);
- cio_printf(" from %08x, %u bytes, perms %08x\n", (uint32_t)data,
- bytes, entrybase);
+ cio_printf( "vm_add: pdir %08x, %s, va %08x (%u, %u pgs)\n",
+ (uint32_t) pdir, wr ? "W" : "!W", (uint32_t) va, size );
+ cio_printf( " from %08x, %u bytes, perms %08x\n",
+ (uint32_t) data, bytes, entrybase );
#endif
// iterate through the pages
- for (int i = 0; i < npages; ++i) {
+ for( int i = 0; i < npages; ++i ) {
+
// figure out where this page will go in the hierarchy
- pte_t *pte = vm_getpte(pdir, va, true);
- if (pte == NULL) {
- // if i > 0, this isn't the first frame - is
+ pte_t *pte = vm_getpte( pdir, va, true );
+ if( pte == NULL ) {
+ // TODO if i > 0, this isn't the first frame - is
// there anything to do about other frames?
// POSSIBLE MEMORY LEAK?
return E_NO_MEMORY;
@@ -671,27 +413,27 @@ int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
// allocate the frame
void *page = km_page_alloc();
- if (page == NULL) {
- // same question here
+ if( page == NULL ) {
+ // TODO same question here
return E_NO_MEMORY;
}
// clear it all out
- memclr(page, SZ_PAGE);
+ memclr( page, SZ_PAGE );
// create the PTE for this frame
- uint32_t entry = (uint32_t)(V2P(PTE_ADDR(page)) | entrybase);
+ uint32_t entry = (uint32_t) (PTE_ADDR(page) | entrybase);
*pte = entry;
// copy data if we need to
- if (data != NULL && bytes > 0) {
+ if( data != NULL && bytes > 0 ) {
// how much to copy
- uint32_t num = bytes > SZ_PAGE ? SZ_PAGE : bytes;
+ uint_t num = bytes > SZ_PAGE ? SZ_PAGE : bytes;
// do it!
- memmove((void *)page, (void *)data, num);
+ memcpy( (void *)page, (void *)data, num );
// adjust all the pointers
- data += num; // where to continue
- bytes -= num; // what's left to copy
+ data += num; // where to continue
+ bytes -= num; // what's left to copy
}
// bump the virtual address
@@ -699,6 +441,7 @@ int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
}
return SUCCESS;
+
}
/**
@@ -711,43 +454,36 @@ int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
**
** @param pdir Pointer to the page directory
*/
-void vm_free(pde_t *pdir)
-{
-#if TRACING_VM
- cio_printf("vm_free(%08x)\n", (uint32_t)pdir);
-#endif
+void vm_free( pde_t *pdir ) {
// do we have anything to do?
- if (pdir == NULL) {
+ if( pdir == NULL ) {
return;
}
// iterate through the page directory entries, freeing the
// PMTS and the frames they point to
pde_t *curr = pdir;
- int nf = 0;
- int nt = 0;
+ for( int i = 0; i < N_PDE; ++i ) {
- for (int i = 0; i < N_PDE; ++i) {
// the entry itself
pde_t entry = *curr;
// does this entry point to anything useful?
- if (IS_PRESENT(entry)) {
+ if( IS_PRESENT(entry) ) {
+
// yes - large pages make us unhappy
- assert(!IS_LARGE(entry));
+ assert( !IS_LARGE(entry) );
// get the PMT pointer
- pte_t *pmt = (pte_t *)P2V(PTE_ADDR(entry));
+ pte_t *pmt = (pte_t *) PTE_ADDR(entry);
// walk the PMT
- for (int j = 0; j < N_PTE; ++j) {
- pte_t tmp = *pmt;
+ for( int j = 0; j < N_PTE; ++j ) {
// does this entry point to a frame?
- if (IS_PRESENT(tmp)) {
+ if( IS_PRESENT(*pmt) ) {
// yes - free the frame
- km_page_free((void *)P2V(PTE_ADDR(tmp)));
- ++nf;
+ km_page_free( (void *) PTE_ADDR(*pmt) );
// mark it so we don't get surprised
*pmt = 0;
}
@@ -755,8 +491,7 @@ void vm_free(pde_t *pdir)
++pmt;
}
// now, free the PMT itself
- km_page_free((void *)P2V(PDE_ADDR(entry)));
- ++nt;
+ km_page_free( (void *) PDE_ADDR(entry) );
*curr = 0;
}
@@ -765,12 +500,7 @@ void vm_free(pde_t *pdir)
}
// finally, free the PDIR itself
- km_page_free((void *)pdir);
- ++nt;
-
-#if TRACING_VM
- cio_printf("vm_free: %d pages, %d tables\n", nf, nt);
-#endif
+ km_page_free( (void *) pdir );
}
/*
@@ -782,74 +512,47 @@ void vm_free(pde_t *pdir)
**
** @param pdir Page directory for this address space
** @param va The starting virtual address
-** @param pa The starting physical address
** @param size Length of the range to be mapped
+** @param pa The starting physical address
** @param perm Permission bits for the PTEs
**
** @return the status of the mapping attempt
*/
-int vm_map(pde_t *pdir, void *va, uint32_t pa, uint32_t size, int perm)
-{
+int vm_map( pde_t *pdir, void *va, uint_t size, uint_t pa, int perm ) {
+
// round the VA down to its page boundary
- char *addr = (char *)PGDOWN((uint32_t)va);
+ char *addr = (char*)PGDOWN((uint_t)va);
// round the end of the range down to its page boundary
- char *last = (char *)PGDOWN(((uint32_t)va) + size - 1);
+ char *last = (char*)PGDOWN(((uint_t)va) + size - 1);
-#if TRACING_VM
- cio_printf("vm_map pdir %08x va %08x pa %08x size %08x perm %03x\n",
- (uint32_t)pdir, (uint32_t)va, pa, size, perm);
-#endif
+ while( addr < last ) {
- while (addr <= last) {
// get a pointer to the PTE for the current VA
- pte_t *pte = vm_getpte(pdir, addr, true);
- if (pte == NULL) {
+ pte_t *pte = vm_getpte( pdir, addr, true );
+ if( pte == NULL ) {
// couldn't find it
return E_NO_PTE;
}
-#if 0 && TRACING_VM
- cio_printf( " addr %08x pa %08x last %08x pte %08x *pte %08x\n",
- (uint32_t) addr, pa, (uint32_t) last, (uint32_t) pte, *pte
- );
-#endif
-
- // create the new entry for the page table
- pde_t newpte = pa | perm | PTE_P;
// if this entry has already been mapped, we're in trouble
- if (IS_PRESENT(*pte)) {
- if (*pte != newpte) {
-#if TRACING_VM
- cio_printf(
- "vm_map: va %08x pa %08x pte %08x *pte %08x entry %08x\n",
- (uint32_t)va, pa, (uint32_t)pte, (uint32_t)*pte, newpte);
- cio_printf(" addr %08x PDIX 0x%x PTIX 0x%x\n", (uint32_t)addr,
- PDIX(addr), PTIX(addr));
-
- // dump the directory
- pmt_dump(pdir, true, PDIX(addr), 4);
+ if( IS_PRESENT(*pte) ) {
+ cio_printf( "vm_map(%08x,%08x,%u,%08x,%03x)\n",
+ (uint32_t) pdir, (uint32_t) va, size, pa, perm );
+ cio_printf( " addr %08x last %08x pte %08x *pte %08x\n",
+ (uint32_t) addr, (uint32_t) last,
+ (uint32_t) pte, *pte );
- // find the relevant PDE entry
- uint32_t ix = PDIX(va);
- pde_t entry = pdir[ix];
- if (!IS_LARGE(entry)) {
- // round the PMT index down
- uint32_t ix2 = PTIX(va) & MOD4_MASK;
- // dump the PMT for the relevant directory entry
- pmt_dump((void *)P2V(PDE_ADDR(entry)), false, ix2, 4);
- }
-#endif
- PANIC(0, "mapping an already-mapped address");
- }
+ PANIC( 0, "mapping an already-mapped address" );
}
// ok, set the PTE as requested
- *pte = newpte;
+ *pte = pa | perm | PTE_P;
// nope - move to the next page
addr += SZ_PAGE;
pa += SZ_PAGE;
+
}
return SUCCESS;
}
@@ -866,48 +569,48 @@ int vm_map(pde_t *pdir, void *va, uint32_t pa, uint32_t size, int perm)
** now have two sets of page tables that refer to the same physical
** frames in memory.
**
-** @param new New page directory
** @param old Existing page directory
+** @param new New page directory
**
** @return status of the duplication attempt
*/
-int vm_uvmdup(pde_t *new, pde_t *old)
-{
- if (old == NULL || new == NULL) {
+int vm_uvmdup( pde_t *old, pde_t *new ) {
+
+ if( old == NULL || new == NULL ) {
return E_BAD_PARAM;
}
-#if TRACING_VM
- cio_printf("vmdup: old %08x new %08x\n", (uint32_t)old, (uint32_t)new);
-#endif
-
// we only want to deal with the "user" half of the address space
- for (int i = 0; i < (N_PDE >> 1); ++i) {
+ for( int i = 0; i < (N_PDE >> 1); ++i ) {
+
// the entry to copy
pde_t entry = *old;
// is this entry in use?
- if (IS_PRESENT(entry)) {
+ if( IS_PRESENT(entry) ) {
+
// yes. if it points to a 4MB page, we just copy it;
// otherwise, we must duplicate the next level PMT
- if (!IS_LARGE(entry)) {
+ if( !IS_LARGE(entry) ) {
+
// it's a 4KB page, so we need to duplicate the PMT
- pte_t *newpt =
- (pte_t *)vm_pagedup((void *)P2V(PTE_ADDR(entry)));
- if (newpt == NULL) {
+ pte_t *newpt = (pte_t *) vm_pagedup( (void *)PTE_ADDR(entry) );
+ if( newpt == NULL ) {
return E_NO_MEMORY;
}
uint32_t perms = PERMS(entry);
// create the new PDE entry by replacing the frame #
- entry = ((uint32_t)V2P(PTE_ADDR(newpt))) | perms;
+ entry = ((uint32_t) newpt) | perms;
}
} else {
+
// not present, so create an empty entry
entry = 0;
+
}
// send it on its way
@@ -920,26 +623,3 @@ int vm_uvmdup(pde_t *new, pde_t *old)
return SUCCESS;
}
-
-/**
-** Name: vm_print
-**
-** Print out a paging hierarchy.
-**
-** @param pt Page table to display
-** @param dir Is it a page directory (vs. a page table)?
-** @param mode How to display the entries
-*/
-void vm_print(void *pt, bool_t dir, enum vmmode_e mode)
-{
- cio_puts("\nVM hierarchy");
- if (pt == NULL) {
- cio_puts(" (NULL pointer)\n");
- return;
- }
-
- cio_printf(", starting at 0x%08x (%s):\n", (uint32_t)pt,
- dir ? "PDIR" : "PMT");
-
- ptdump(1, pt, dir, mode);
-}