From 9945ad6119248d297f003a3b9515e6677f2c9378 Mon Sep 17 00:00:00 2001
From: Freya Murphy <freya@freyacat.org>
Date: Tue, 1 Apr 2025 12:32:51 -0400
Subject: [PATCH] track changes

---
 include/offsets.h |   2 -
 kernel/kernel.c   |  26 ++++----
 kernel/procs.c    |  33 ++--------
 kernel/user.c     | 150 ++++++++++++++++++++++------------------------
 kernel/vm.c       | 147 +++++++++++++++++++++++++--------------------
 5 files changed, 175 insertions(+), 183 deletions(-)

diff --git a/include/offsets.h b/include/offsets.h
index c0cc029..bf19776 100644
--- a/include/offsets.h
+++ b/include/offsets.h
@@ -3,8 +3,6 @@
 **
 ** GENERATED AUTOMATICALLY - DO NOT EDIT
 **
-** Creation date: Mon Mar 31 11:38:04 2025
-**
 ** This header file contains C Preprocessor macros which expand
 ** into the byte offsets needed to reach fields within structs
 ** used in the baseline system.  Should those struct declarations
diff --git a/kernel/kernel.c b/kernel/kernel.c
index 44a8eee..ce2e9dd 100644
--- a/kernel/kernel.c
+++ b/kernel/kernel.c
@@ -163,7 +163,7 @@ static void kreport(bool_t dtrace)
 	}
 #endif /* TRACE > 0 */
 
-	cio_puts("\n-------------------------------\n");
+	cio_putchar('\n');
 }
 
 #if defined(CONSOLE_STATS)
@@ -304,10 +304,10 @@ int main(void)
 	user_init(); // user code handling
 
 	cio_puts("\nModule initialization complete.\n");
-	cio_puts("-------------------------------\n");
 
 	// report our configuration options
 	kreport(true);
+	cio_puts("-------------------------------\n");
 
 	delay(DELAY_2_SEC);
 
@@ -378,21 +378,23 @@ int main(void)
 
 	sio_enable(SIO_RX);
 
+#if 0
 	// produce a "system state" report
-	cio_puts("System status: Queues ");
-	pcb_queue_dump("R", ready, true);
-	pcb_queue_dump("W", waiting, true);
-	pcb_queue_dump("S", sleeping, true);
-	pcb_queue_dump("Z", zombie, true);
-	pcb_queue_dump("I", sioread, true);
+	cio_puts( "System status: Queues " );
+	pcb_queue_dump( "R", ready, true );
+	pcb_queue_dump( "W", waiting, true );
+	pcb_queue_dump( "S", sleeping, true );
+	pcb_queue_dump( "Z", zombie, true );
+	pcb_queue_dump( "I", sioread, true );
 	ptable_dump_counts();
-	pcb_dump("Current: ", current, true);
+	pcb_dump( "Current: ", current, true );
 
-	delay(DELAY_3_SEC);
+	delay( DELAY_3_SEC );
 
-	vm_print(current->pdir, true, TwoLevel);
+	vm_print( current->pdir, true, TwoLevel );
 
-	delay(DELAY_3_SEC);
+	delay( DELAY_3_SEC );
+#endif
 
 	return 0;
 }
diff --git a/kernel/procs.c b/kernel/procs.c
index 20e6784..82c4c98 100644
--- a/kernel/procs.c
+++ b/kernel/procs.c
@@ -963,16 +963,8 @@ void pcb_dump(const char *msg, register pcb_t *pcb, bool_t all)
 		return;
 	}
 
-	cio_printf(" %d", pcb->pid);
-
-	cio_printf(" %s", pcb->state >= N_STATES ? "???" : state_str[pcb->state]);
-#if 0
-	if( pcb->state >= N_STATES ) {
-		cio_puts( " ????" );
-	} else {
-		cio_printf( " %s", state_str[pcb->state] );
-	}
-#endif
+	cio_printf(" %d %s", pcb->pid,
+			   pcb->state >= N_STATES ? "???" : state_str[pcb->state]);
 
 	if (!all) {
 		// just printing IDs and states on one line
@@ -982,13 +974,6 @@ void pcb_dump(const char *msg, register pcb_t *pcb, bool_t all)
 	// now, the rest of the contents
 	cio_printf(" %s",
 			   pcb->priority >= N_PRIOS ? "???" : prio_str[pcb->priority]);
-#if 0
-	if( pcb->priority >= N_PRIOS ) {
-		cio_puts( " ???" );
-	} else {
-		cio_printf( " %s", prio_str[pcb->priority] );
-	}
-#endif
 
 	cio_printf(" ticks %u xit %d wake %08x\n", pcb->ticks, pcb->exit_status,
 			   pcb->wakeup);
@@ -1007,8 +992,6 @@ void pcb_dump(const char *msg, register pcb_t *pcb, bool_t all)
 /**
 ** pcb_queue_dump(msg,queue,contents)
 **
-** Dump the contents of the specified queue to the console
-**
 ** @param msg[in]       Optional message to print
 ** @param queue[in]     The queue to dump
 ** @param contents[in]  Also dump (some) contents?
@@ -1124,16 +1107,10 @@ void ptable_dump_counts(void)
 
 	cio_printf("Ptable: %u ***", unknown);
 	for (n = 0; n < N_STATES; ++n) {
-		cio_printf(" %u %s", nstate[n],
-				   state_str[n] != NULL ? state_str[n] : "???");
-#if 0
-		cio_printf( " %u ", nstate[n] );
-		if( state_str[n][0] != '\0' ) {
-			cio_puts( state_str[n] );
-		} else {
-			cio_puts( "???" );
+		if (nstate[n]) {
+			cio_printf(" %u %s", nstate[n],
+					   state_str[n] != NULL ? state_str[n] : "???");
 		}
-#endif
 	}
 	cio_putchar('\n');
 }
diff --git a/kernel/user.c b/kernel/user.c
index 0e5e186..5759534 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -510,45 +510,72 @@ static context_t *stack_setup(pcb_t *pcb, uint32_t entry, const char **args,
 	** Stack alignment rules for the SysV ABI i386 supplement dictate that
 	** the 'argc' parameter must be at an address that is a multiple of 16;
 	** see below for more information.
+	**
+	** Ultimately, this is what the bottom end of the stack will look like:
+	**
+	**         kvavptr
+	** kvacptr   |
+	**     |     |
+	**     v     v
+	**    argc  argv  av[0] av[1] etc  NULL       str0   str1    etc.
+	**   [....][....][....][....] ... [0000] ... [......0......0.........]
+	**           |    ^ |    |                    ^      ^
+	**           |    | |    |                    |      |
+	**           ------ |    ---------------------|-------
+	**                  ---------------------------
 	*/
 
 	/*
-	** Find the user stack. The PDE entry for user address space points
-	** to a page table for the first 4MB of the address space, but the
-	** "pointer" there a physical frame address.
+	** We need to find the last page of the user stack. Find the page
+	** table for the 4MB user address space. The physical address of its
+	** frame is in the first page directory entry. Extract that from the
+	** entry and convert it into a virtual address for the kernel to use.
 	*/
 	pde_t *kv_userpt = (pde_t *)P2V(PTE_ADDR(pcb->pdir[USER_PDE]));
 	assert(kv_userpt != NULL);
 
 	/*
 	** The final entries in that PMT are for the pages of the user stack.
-	** Grab the address of the frame for the last one.  (Again, we need
-	** to convert it to a virtual address we can use.)
+	** Grab the physical address of the frame for the last one.  (Again,
+	** we need to convert it to a virtual address we can use.)
 	*/
 
 	// the PMT entry for that page
 	pte_t pmt_entry = kv_userpt[USER_STK_LAST_PTE];
 	assert(IS_PRESENT(pmt_entry));
 
-	// kernel VA for the first byte following that page
-	uint8_t *kv_ptr = (uint8_t *)P2V(PTE_ADDR(pmt_entry) + SZ_PAGE);
-	assert(kv_ptr != NULL);
+	// user VA for the first byte of that page
+	uint32_t *uvptr = (uint32_t *)USER_STACK_P2;
 
-	// user VA for the first byte following that page
-	uint32_t *uv_ptr = (uint32_t *)(USER_STACK_P2 + SZ_PAGE);
-
-	// Pointers to where the arg strings should be filled in.
-	uint32_t kv_strings = ((uint32_t)kv_ptr) - argbytes;
-	uint32_t uv_strings = ((uint32_t)uv_ptr) - argbytes;
-
-	// back the pointers up to the nearest word boundary; because we're
-	// moving toward location 0, the nearest word boundary is just the
-	// next smaller address whose low-order two bits are zeroes
-	kv_strings &= MOD4_MASK;
-	uv_strings &= MOD4_MASK;
+	// convert that address to a kernel VA
+	uint32_t *kvptr = (uint32_t *)vm_uva2kva(pcb->pdir, (void *)uvptr);
 
 	/*
-	** Next, we need to copy over the data. Start by determining where
+	** Move these pointers to where the string area will begin. We
+	** will then back up to the next lower multiple-of-four address.
+	*/
+
+	uint32_t uvstrptr = ((uint32_t)uvptr) + SZ_PAGE - argbytes;
+	uvstrptr &= MOD4_MASK;
+
+	uint32_t kvstrptr = ((uint32_t)kvptr) + SZ_PAGE - argbytes;
+	kvstrptr &= MOD4_MASK;
+
+	// Copy over the argv strings, remembering where each string begins
+	for (int i = 0; i < argc; ++i) {
+		// copy the string using kernel addresses
+		strcpy((char *)kvstrptr, kv_args[i]);
+
+		// remember the user address where this string went
+		uv_argv[i] = (char *)uvstrptr;
+
+		// adjust both string addresses
+		kvstrptr += strlengths[i];
+		uvstrptr += strlengths[i];
+	}
+
+	/*
+	** Next, we need to copy over the other data. Start by determining
 	** where 'argc' should go.
 	**
 	** Stack alignment is controlled by the SysV ABI i386 supplement,
@@ -564,68 +591,37 @@ static context_t *stack_setup(pcb_t *pcb, uint32_t entry, const char **args,
 	** Isn't technical documentation fun?  Ultimately, this means that
 	** the first parameter to main() should be on the stack at an address
 	** that is a multiple of 16. In our case, that is 'argc'.
-	**
+	*/
+
+	/*
 	** The space needed for argc, argv, and the argv array itself is
 	** argc + 3 words (argc+1 for the argv entries, plus one word each
-	** for argc and argv).  We back up that much from 'strings'.
+	** for argc and argv).  We back up that much from the string area.
 	*/
 
 	int nwords = argc + 3;
-	uint32_t *kv_acptr = ((uint32_t *)kv_strings) - nwords;
-	uint32_t *uv_acptr = ((uint32_t *)uv_strings) - nwords;
+	uint32_t *kvacptr = ((uint32_t *)kvstrptr) - nwords;
+	uint32_t *uvacptr = ((uint32_t *)uvstrptr) - nwords;
 
 	// back these up to multiple-of-16 addresses for stack alignment
-	kv_acptr = (uint32_t *)(((uint32_t)kv_acptr) & MOD16_MASK);
-	uv_acptr = (uint32_t *)(((uint32_t)uv_acptr) & MOD16_MASK);
-
-	// the argv location
-	uint32_t *kv_avptr = kv_acptr + 1;
-
-	// the user address for the first argv entry
-	uint32_t *uv_avptr = uv_acptr + 2;
-
-	// Copy over the argv strings.
-	for (int i = 0; i < argc; ++i) {
-		// copy the string using kernel addresses
-		strcpy((char *)kv_strings, kv_args[i]);
-
-		// remember the user address where this string went
-		uv_argv[i] = (char *)uv_strings;
-
-		// adjust both string addresses
-		kv_strings += strlengths[i];
-		uv_strings += strlengths[i];
-	}
-
-	/*
-	** Next, we copy in argc, argv, and the pointers. The stack will
-	** look something like this:
-	**
-	**         kv_avptr
-	** kv_acptr  |
-	**     |     |
-	**     v     v
-	**    argc  argv  av[0] av[1] etc  NULL       str0   str1    etc.
-	**   [....][....][....][....] ... [0000] ... [......0......0.........]
-	**           |    ^ |    |                    ^      ^
-	**           |    | |    |                    |      |
-	**           ------ |    ---------------------|-------
-	**                  ---------------------------
-	*/
+	kvacptr = (uint32_t *)(((uint32_t)kvacptr) & MOD16_MASK);
+	uvacptr = (uint32_t *)(((uint32_t)uvacptr) & MOD16_MASK);
 
 	// copy in 'argc'
-	*kv_acptr = argc;
+	*kvacptr = argc;
 
-	// copy in 'argv'
-	*kv_avptr++ = (uint32_t)uv_avptr;
+	// 'argv' immediately follows 'argc', and 'argv[0]' immediately
+	// follows 'argv'
+	uint32_t *kvavptr = kvacptr + 2;
+	*(kvavptr - 1) = (uint32_t)kvavptr;
 
 	// now, the argv entries themselves
 	for (int i = 0; i < argc; ++i) {
-		*kv_avptr++ = (uint32_t)uv_argv[i];
+		*kvavptr++ = (uint32_t)uv_argv[i];
 	}
 
 	// and the trailing NULL
-	*kv_avptr = NULL;
+	*kvavptr = NULL;
 
 	/*
 	** Almost done!
@@ -641,8 +637,8 @@ static context_t *stack_setup(pcb_t *pcb, uint32_t entry, const char **args,
 
 	// Locate the context save area on the stack by backup up one
 	// "context" from where the argc value is saved
-	context_t *kv_ctx = ((context_t *)kv_acptr) - 1;
-	uint32_t uv_ctx = (uint32_t)(((context_t *)uv_acptr) - 1);
+	context_t *kvctx = ((context_t *)kvacptr) - 1;
+	uint32_t uvctx = (uint32_t)(((context_t *)uvacptr) - 1);
 
 	/*
 	** We cleared the entire stack earlier, so all the context
@@ -655,18 +651,18 @@ static context_t *stack_setup(pcb_t *pcb, uint32_t entry, const char **args,
 	** where it winds up.
 	*/
 
-	kv_ctx->eflags = DEFAULT_EFLAGS; // IF enabled, IOPL 0
-	kv_ctx->eip = entry; // initial EIP
-	kv_ctx->cs = GDT_CODE; // segment registers
-	kv_ctx->ss = GDT_STACK;
-	kv_ctx->ds = kv_ctx->es = kv_ctx->fs = kv_ctx->gs = GDT_DATA;
+	kvctx->eflags = DEFAULT_EFLAGS; // IF enabled, IOPL 0
+	kvctx->eip = entry; // initial EIP
+	kvctx->cs = GDT_CODE; // segment registers
+	kvctx->ss = GDT_STACK;
+	kvctx->ds = kvctx->es = kvctx->fs = kvctx->gs = GDT_DATA;
 
 	/*
-	** Return the new context pointer to the caller.  It will be our
-	** caller's responsibility to schedule this process.
+	** Return the new context pointer to the caller as a user
+	** space virtual address.
 	*/
 
-	return ((context_t *)uv_ctx);
+	return ((context_t *)uvctx);
 }
 
 /*
diff --git a/kernel/vm.c b/kernel/vm.c
index a700bcb..814ff12 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -95,13 +95,19 @@ static uint32_t ptcount(pte_t *ptr, bool_t dir)
 }
 
 // decode a PDE
-static void pde_prt(uint32_t level, uint32_t i, uint32_t entry)
+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("[%08x] %08x", i, entry);
+	cio_printf("[%03x] %08x", i, entry);
+
 	// perms
 	if (IS_LARGE(entry)) { // PS is 1
 		if ((entry & PDE_PAT) != 0)
@@ -122,43 +128,49 @@ static void pde_prt(uint32_t level, uint32_t i, uint32_t entry)
 		cio_puts(" U");
 	if ((entry & PDE_RW) != 0)
 		cio_puts(" W");
-	cio_puts((entry & PDE_P) != 0 ? " P" : "!P");
 
-	cio_printf(" --> %s %08x", IS_LARGE(entry) ? "Pg" : "PT", PDE_ADDR(entry));
+	// frame address
+	cio_printf(" P --> %s %08x\n", IS_LARGE(entry) ? "Pg" : "PT",
+			   PDE_ADDR(entry));
 }
 
 // decode a PTE
-static void pte_prt(uint32_t level, uint32_t i, uint32_t entry)
+static void pte_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("[%08x] %08x", i, entry);
-	// perms
-	if ((entry & PDE_G) != 0)
-		cio_puts(" G");
-	if ((entry & PDE_PAT) != 0)
-		cio_puts(" PAT");
-	if ((entry & PDE_D) != 0)
-		cio_puts(" D");
-	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");
-	cio_puts((entry & PDE_P) != 0 ? " P" : "!P");
 
-	cio_printf(" --> Pg %08x", PTE_ADDR(entry));
+	// 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:	pdump
+** Name:	ptdump
 **
 ** Recursive helper for table hierarchy dump.
 **
@@ -168,40 +180,44 @@ static void pte_prt(uint32_t level, uint32_t i, uint32_t entry)
 ** @param mode   How to display the entries
 */
 ATTR_UNUSED
-static void pdump(uint_t level, void *pt, bool_t dir, enum vmmode_e mode)
+static void ptdump(uint_t level, void *pt, bool_t dir, enum vmmode_e mode)
 {
 	pte_t *ptr = (pte_t *)pt;
 
-	cio_printf("? at 0x%08x:", dir ? "PDir" : "PTbl", (uint32_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(" %u 4MB", (nums >> 16));
+		cio_printf(" 4MB=%u", (nums >> 16));
 	}
-	cio_printf(" %u P %u !P\n", nums & 0xffff,
+	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;
-		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);
-				cio_putchar('\n');
-				if (!IS_LARGE(entry)) {
-					pdump(level + 1, (void *)*ptr, false, mode);
+		pte_t entry = *ptr++;
+
+		// 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);
 				}
 			}
-		} else {
-			// just a PMT entry
-			if (mode > Simple) {
-				pte_prt(level, i, entry);
-				cio_putchar('\n');
-			}
 		}
-
-		// move to the next entry
-		++ptr;
 	}
 }
 
@@ -285,7 +301,7 @@ void vm_init(void)
 
 	// 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_RW);
+		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);
@@ -315,8 +331,8 @@ void vm_init(void)
 **
 ** 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 is the offset into the page, which is
-** unchanged within the address spaces.
+** 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
@@ -333,7 +349,7 @@ void *vm_uva2kva(pde_t *pdir, void *va)
 	pte_t entry = *pte;
 
 	// is this a valid address for the user?
-	if (IS_PRESENT(entry)) {
+	if (!IS_PRESENT(entry)) {
 		return NULL;
 	}
 
@@ -477,7 +493,7 @@ pte_t *vm_getpte(pde_t *pdir, const void *va, bool_t alloc)
 		// 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_ptr = V2P(ptbl) | PDE_P | PDE_RW | PDE_US;
 	}
 
 	// finally, return a pointer to the entry in the page table for this VA
@@ -630,7 +646,7 @@ int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
 	if (wr) {
 		entrybase |= PTE_RW;
 	}
-	if (sys) {
+	if (!sys) {
 		entrybase |= PTE_US;
 	}
 
@@ -664,7 +680,7 @@ int vm_add(pde_t *pdir, bool_t wr, bool_t sys, void *va, uint32_t size,
 		memclr(page, SZ_PAGE);
 
 		// create the PTE for this frame
-		uint32_t entry = (uint32_t)(PTE_ADDR(V2P(page)) | entrybase);
+		uint32_t entry = (uint32_t)(V2P(PTE_ADDR(page)) | entrybase);
 		*pte = entry;
 
 		// copy data if we need to
@@ -711,6 +727,7 @@ void vm_free(pde_t *pdir)
 	pde_t *curr = pdir;
 	int nf = 0;
 	int nt = 0;
+
 	for (int i = 0; i < N_PDE; ++i) {
 		// the entry itself
 		pde_t entry = *curr;
@@ -721,14 +738,15 @@ void vm_free(pde_t *pdir)
 			assert(!IS_LARGE(entry));
 
 			// get the PMT pointer
-			pte_t *pmt = (pte_t *)PTE_ADDR(entry);
+			pte_t *pmt = (pte_t *)P2V(PTE_ADDR(entry));
 
 			// walk the PMT
 			for (int j = 0; j < N_PTE; ++j) {
+				pte_t tmp = *pmt;
 				// does this entry point to a frame?
-				if (IS_PRESENT(*pmt)) {
+				if (IS_PRESENT(tmp)) {
 					// yes - free the frame
-					km_page_free((void *)PTE_ADDR(*pmt));
+					km_page_free((void *)P2V(PTE_ADDR(tmp)));
 					++nf;
 					// mark it so we don't get surprised
 					*pmt = 0;
@@ -737,7 +755,7 @@ void vm_free(pde_t *pdir)
 				++pmt;
 			}
 			// now, free the PMT itself
-			km_page_free((void *)PDE_ADDR(entry));
+			km_page_free((void *)P2V(PDE_ADDR(entry)));
 			++nt;
 			*curr = 0;
 		}
@@ -875,7 +893,8 @@ int vm_uvmdup(pde_t *new, pde_t *old)
 
 			if (!IS_LARGE(entry)) {
 				// it's a 4KB page, so we need to duplicate the PMT
-				pte_t *newpt = (pte_t *)vm_pagedup((void *)PTE_ADDR(entry));
+				pte_t *newpt =
+					(pte_t *)vm_pagedup((void *)P2V(PTE_ADDR(entry)));
 				if (newpt == NULL) {
 					return E_NO_MEMORY;
 				}
@@ -883,7 +902,7 @@ int vm_uvmdup(pde_t *new, pde_t *old)
 				uint32_t perms = PERMS(entry);
 
 				// create the new PDE entry by replacing the frame #
-				entry = ((uint32_t)newpt) | perms;
+				entry = ((uint32_t)V2P(PTE_ADDR(newpt))) | perms;
 			}
 
 		} else {
@@ -919,8 +938,8 @@ void vm_print(void *pt, bool_t dir, enum vmmode_e mode)
 		return;
 	}
 
-	cio_printf("Starting at 0x%08x (%s):\n", (uint32_t)pt,
+	cio_printf(", starting at 0x%08x (%s):\n", (uint32_t)pt,
 			   dir ? "PDIR" : "PMT");
 
-	pdump(0, pt, dir, mode);
+	ptdump(1, pt, dir, mode);
 }