diff --git a/kern/monitor.c b/kern/monitor.c index 1e626e2..528671c 100644 --- a/kern/monitor.c +++ b/kern/monitor.c @@ -30,7 +30,9 @@ 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 }, - { "showmappings", "Display the physical mappings for range", mon_showmappings } + { "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 *****/ @@ -104,21 +106,26 @@ decode_pte_perms(pte_t pte, char* buffer) { 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); - long from = strtol(argv[1], NULL, 0); - long to = strtol(argv[2], NULL, 0); - - uintptr_t va_start = ROUNDDOWN(from, PGSIZE); - uintptr_t va_end = ROUNDUP(to, PGSIZE); - if(va_start != from) cprintf(ACOL_WARN("Aligning start address %p down to %p\n"), - from, va_start); - if(va_end != to) cprintf(ACOL_WARN("Aligning end address %p up to %p\n"), - to, va_end); - + 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); @@ -137,6 +144,49 @@ mon_showmappings(int argc, char** argv, struct Trapframe* tf) { 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 *****/