summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/offsets.h2
-rw-r--r--kernel/kernel.c26
-rw-r--r--kernel/procs.c33
-rw-r--r--kernel/user.c146
-rw-r--r--kernel/vm.c127
5 files changed, 163 insertions, 171 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;
+
+ // convert that address to a kernel VA
+ uint32_t *kvptr = (uint32_t *)vm_uva2kva(pcb->pdir, (void *)uvptr);
+
+ /*
+ ** 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;
- // user VA for the first byte following that page
- uint32_t *uv_ptr = (uint32_t *)(USER_STACK_P2 + SZ_PAGE);
+ 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]);
- // 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;
+ // remember the user address where this string went
+ uv_argv[i] = (char *)uvstrptr;
- // 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;
+ // adjust both string addresses
+ kvstrptr += strlengths[i];
+ uvstrptr += strlengths[i];
+ }
/*
- ** Next, we need to copy over the data. Start by determining where
+ ** 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);
+ cio_printf("[%03x] %08x", i, entry);
+
// perms
- if ((entry & PDE_G) != 0)
+ if ((entry & PTE_G) != 0)
cio_puts(" G");
- if ((entry & PDE_PAT) != 0)
+ if ((entry & PTE_PAT) != 0)
cio_puts(" PAT");
- if ((entry & PDE_D) != 0)
+ if ((entry & PTE_D) != 0)
cio_puts(" D");
- if ((entry & PDE_A) != 0)
+ if ((entry & PTE_A) != 0)
cio_puts(" A");
- if ((entry & PDE_PCD) != 0)
+ if ((entry & PTE_PCD) != 0)
cio_puts(" CD");
- if ((entry & PDE_PWT) != 0)
+ if ((entry & PTE_PWT) != 0)
cio_puts(" WT");
- if ((entry & PDE_US) != 0)
+ if ((entry & PTE_US) != 0)
cio_puts(" U");
- if ((entry & PDE_RW) != 0)
+ if ((entry & PTE_RW) != 0)
cio_puts(" W");
- cio_puts((entry & PDE_P) != 0 ? " P" : "!P");
- cio_printf(" --> Pg %08x", PTE_ADDR(entry));
+ 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);
}