diff --git a/kern/ansi.h b/kern/ansi.h index 970f9c6..8869cba 100644 --- a/kern/ansi.h +++ b/kern/ansi.h @@ -3,6 +3,22 @@ #include +#define ACOL_WRAP(s) "\33[" s "m" +#define ACOL_BLACK ACOL_WRAP("30") +#define ACOL_RED ACOL_WRAP("31") +#define ACOL_GREEN ACOL_WRAP("32") +#define ACOL_YELLOW ACOL_WRAP("33") +#define ACOL_BLUE ACOL_WRAP("34") +#define ACOL_MAGENTA ACOL_WRAP("35") +#define ACOL_CYAN ACOL_WRAP("36") +#define ACOL_WHITE ACOL_WRAP("37") +#define ACOL_CLEAR ACOL_WRAP("0") + +#define ACOL_TAG(c, s) "[" c s ACOL_CLEAR "] " +#define ACOL_NOTE(s) ACOL_TAG(ACOL_WHITE, " Note ") s +#define ACOL_WARN(s) ACOL_TAG(ACOL_YELLOW, "Warning") s +#define ACOL_ERR(s) ACOL_TAG(ACOL_RED, " Error ") s + struct AttrState { uint8_t cattrs; uint8_t attrs; diff --git a/kern/monitor.c b/kern/monitor.c index c97da78..528671c 100644 --- a/kern/monitor.c +++ b/kern/monitor.c @@ -7,9 +7,13 @@ #include #include +#include #include #include #include +#include + +#include #define CMDBUF_SIZE 80 // enough for one VGA text line @@ -25,7 +29,10 @@ struct Command { static struct Command commands[] = { { "help", "Display this list of commands", mon_help }, { "kerninfo", "Display information about the kernel", mon_kerninfo }, - { "backtrace", "Display current backtrace", mon_backtrace } + { "backtrace", "Display current backtrace", mon_backtrace }, + { "showmappings", "Display the physical mappings for range", mon_showmappings }, + { "mperms", "Change the permissions of a memory range", mon_mperms } + }; /***** Implementations of basic kernel monitor commands *****/ @@ -46,7 +53,7 @@ mon_kerninfo(int argc, char **argv, struct Trapframe *tf) extern char _start[], entry[], etext[], edata[], end[]; cprintf("Special kernel symbols:\n"); - cprintf(" _start %08x (phys)\n", _start); + cprintf(" _start %08x (phys)\n", _start); cprintf(" entry %08x (virt) %08x (phys)\n", entry, entry - KERNBASE); cprintf(" etext %08x (virt) %08x (phys)\n", etext, etext - KERNBASE); cprintf(" edata %08x (virt) %08x (phys)\n", edata, edata - KERNBASE); @@ -75,7 +82,7 @@ mon_backtrace(int argc, char **argv, struct Trapframe *tf) ebp = (uint32_t*) ebp[0]; debuginfo_eip(eip, &info); - cprintf(" %s:%d: %.*s+%d\n", + cprintf(" %s:%d: %.*s+%d\n", info.eip_file, info.eip_line, info.eip_fn_namelen, info.eip_fn_name, eip - info.eip_fn_addr); @@ -84,7 +91,102 @@ mon_backtrace(int argc, char **argv, struct Trapframe *tf) return 0; } +#define EXPECT_ARGS(n, ac) if(ac - 1 != n) { \ + cprintf(ACOL_ERR("Expected %d arguments, " \ + "got %d\n"), n, ac - 1); \ + return 1; } +#define VA_TXT ACOL_CYAN "VA" ACOL_CLEAR +#define PA_TXT ACOL_GREEN "PA" ACOL_CLEAR + +char* +decode_pte_perms(pte_t pte, char* buffer) { + buffer[0] = (pte & PTE_W) ? 'w' : 'r'; + buffer[1] = (pte & PTE_U) ? 'u' : 'k'; + return buffer; +} + +void +get_pagebounds(char* one, char* two, uintptr_t* pone, uintptr_t* ptwo) { + long from = strtol(one, NULL, 0); + long to = strtol(two, NULL, 0); + *pone = ROUNDDOWN(from, PGSIZE); + *ptwo = ROUNDUP(to, PGSIZE); + if(*pone != from) cprintf(ACOL_WARN("Aligning start address %p down to %p\n"), + from, *pone); + if(*ptwo != to) cprintf(ACOL_WARN("Aligning end address %p up to %p\n"), + to, *ptwo); +} + +int +mon_showmappings(int argc, char** argv, struct Trapframe* tf) { + EXPECT_ARGS(2, argc); + uintptr_t va_start, va_end; + char buffer[3] = {0}; + + get_pagebounds(argv[1], argv[2], &va_start, &va_end); + + if(va_start == va_end) va_end += PGSIZE; + while(va_start < va_end) { + pte_t* pte = pgdir_walk(kern_pgdir, (const void*) va_start, 0); + cprintf(VA_TXT " 0x%08p -> ", va_start); + + if(pte && (*pte & PTE_P)) { + cprintf(PA_TXT " 0x%08p (%s)\n", PTE_ADDR(*pte), + decode_pte_perms(*pte, buffer)); + } else { + cprintf(PA_TXT " ------------\n"); + } + + va_start += PGSIZE; + } + + return 0; +} + +int mon_mperms(int argc, char** argv, struct Trapframe* tf) { + EXPECT_ARGS(3, argc); + pte_t perms = 0; + enum { + PERM_ADD, + PERM_REMOVE, + PERM_SET + } pmode; + + const char* str = argv[1]; + if(str[0] == '+') { pmode = PERM_ADD; str++; } + else if(str[0] == '-') { pmode = PERM_REMOVE; str++; } + else pmode = PERM_SET; + + while(*str) { + if(*str == 'w') perms |= PTE_W; + else if(*str == 'u') perms |= PTE_U; + else { + cprintf(ACOL_ERR("Unknown permission character %c\n"), *str); + return 1; + } + str++; + } + + uintptr_t va_start, va_end; + get_pagebounds(argv[2], argv[3], &va_start, &va_end); + if(va_start == va_end) va_end += PGSIZE; + while(va_start < va_end) { + pte_t* pte = pgdir_walk(kern_pgdir, (void*) va_start, 0); + if(!pte || !(*pte & PTE_P)) { va_start += PGSIZE; continue; } + + if(pmode == PERM_ADD) { + *pte |= perms; + } else if(pmode == PERM_REMOVE) { + *pte &= ~perms; + } else if(pmode == PERM_SET) { + *pte = PTE_ADDR(*pte) | perms | PTE_P; + } + va_start += PGSIZE; + } + + return 0; +} /***** Kernel monitor command interpreter *****/ diff --git a/kern/monitor.h b/kern/monitor.h index 0aa0f26..4da7606 100644 --- a/kern/monitor.h +++ b/kern/monitor.h @@ -15,5 +15,7 @@ void monitor(struct Trapframe *tf); int mon_help(int argc, char **argv, struct Trapframe *tf); int mon_kerninfo(int argc, char **argv, struct Trapframe *tf); int mon_backtrace(int argc, char **argv, struct Trapframe *tf); +int mon_showmappings(int argc, char **argv, struct Trapframe *tf); +int mon_mperms(int argc, char** argv, struct Trapframe* tf); #endif // !JOS_KERN_MONITOR_H