From af7ec7b7dac78f445176e8a03e0f8913cdd72c8b Mon Sep 17 00:00:00 2001 From: Yeongjin Jang Date: Tue, 2 Apr 2019 02:49:09 -0700 Subject: [PATCH 01/29] add hint --- kern/kdebug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kern/kdebug.c b/kern/kdebug.c index 9547143..b66ab45 100644 --- a/kern/kdebug.c +++ b/kern/kdebug.c @@ -171,7 +171,8 @@ debuginfo_eip(uintptr_t addr, struct Eipdebuginfo *info) // Search within [lline, rline] for the line number stab. - // If found, set info->eip_line to the right line number. + // If found, set info->eip_line to the correct line number. + // e.g., info->eip_line = stabs[lline].n_desc // If not found, return -1. // // Hint: From 575eb44598a44b4a584356ef52da40b7fc2dcab8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 2 Apr 2019 12:25:19 -0700 Subject: [PATCH 02/29] Edit student info file --- student.info | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/student.info b/student.info index f3ede52..8a21af1 100644 --- a/student.info +++ b/student.info @@ -1,5 +1,5 @@ -OSU ID (xxx-yyy-zzz) : 933456789 -FLIP ID (e.g., jangye) : jangye -Name : Yeongjin Jang +OSU ID (xxx-yyy-zzz) : 932700867 +FLIP ID (e.g., jangye) : fedorind +Name : Danila Fedorin CS 444/544 ? : 444 Lab Class # : Lab 1 From 62b840a99451d8d040a6c1717c0ca5b88b11a8da Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 2 Apr 2019 12:32:39 -0700 Subject: [PATCH 03/29] Change lab number --- student.info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/student.info b/student.info index 8a21af1..7014618 100644 --- a/student.info +++ b/student.info @@ -2,4 +2,4 @@ OSU ID (xxx-yyy-zzz) : 932700867 FLIP ID (e.g., jangye) : fedorind Name : Danila Fedorin CS 444/544 ? : 444 -Lab Class # : Lab 1 +Lab Class # : Lab 2 From b0880daaa332f3cc26d6f6db8a4e63cc8aa01b66 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 4 Apr 2019 20:37:11 -0700 Subject: [PATCH 04/29] Implement octal printing. --- lib/printfmt.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/printfmt.c b/lib/printfmt.c index 802adcd..b1de635 100644 --- a/lib/printfmt.c +++ b/lib/printfmt.c @@ -205,11 +205,9 @@ vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) // (unsigned) octal case 'o': - // LAB 1: Replace this with your code. - putch('X', putdat); - putch('X', putdat); - putch('X', putdat); - break; + num = getuint(&ap, lflag); + base = 8; + goto number; // pointer case 'p': From 8ef5e2f810a0363e5ee3217982d6faa629f33862 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 4 Apr 2019 20:37:40 -0700 Subject: [PATCH 05/29] Add the needed binary search to find line numbers. --- kern/kdebug.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kern/kdebug.c b/kern/kdebug.c index b66ab45..cc59033 100644 --- a/kern/kdebug.c +++ b/kern/kdebug.c @@ -180,6 +180,12 @@ debuginfo_eip(uintptr_t addr, struct Eipdebuginfo *info) // Look at the STABS documentation and to find // which one. // Your code here. + stab_binsearch(stabs, &lline, &rline, N_SLINE, addr); + if(lline <= rline) { + info->eip_line = stabs[lline].n_desc; + } else { + info->eip_line = -1; + } // Search backwards from the line number for the relevant filename From dd3281aba0121dba7cf565314e60228cb0b6219b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 4 Apr 2019 20:37:53 -0700 Subject: [PATCH 06/29] Implement the backtrace code. --- kern/monitor.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/kern/monitor.c b/kern/monitor.c index ee25809..c97da78 100644 --- a/kern/monitor.c +++ b/kern/monitor.c @@ -25,6 +25,7 @@ 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 } }; /***** Implementations of basic kernel monitor commands *****/ @@ -61,6 +62,25 @@ mon_backtrace(int argc, char **argv, struct Trapframe *tf) // LAB 1: Your code here. // HINT 1: use read_ebp(). // HINT 2: print the current ebp on the first line (not current_ebp[0]) + uint32_t* ebp; + uint32_t eip; + struct Eipdebuginfo info; + + ebp = (uint32_t*) read_ebp(); + cprintf("Stack backtrace:\n"); + while(ebp) { + eip = ebp[1]; + cprintf(" ebp %08x eip %08x args %08x %08x %08x %08x %08x\n", + ebp, eip, ebp[2], ebp[3], ebp[4], ebp[5], ebp[6]); + ebp = (uint32_t*) ebp[0]; + + debuginfo_eip(eip, &info); + 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); + }; + return 0; } From f00ab71fb54032e3c88578b781b0caff1bdd4d7f Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 4 Apr 2019 21:46:17 -0700 Subject: [PATCH 07/29] Implement very bad state machine to match a subset of ANSI escape codes. --- kern/init.c | 8 ++++++++ lib/printfmt.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/kern/init.c b/kern/init.c index df46700..729fae9 100644 --- a/kern/init.c +++ b/kern/init.c @@ -38,6 +38,14 @@ i386_init(void) // Test the stack backtrace function (lab 1 only) test_backtrace(5); + // Test ANSI color escape codes + cprintf("\33[31m" "C" + "\33[33m" "o" + "\33[32m" "l" + "\33[36m" "o" + "\33[34m" "r" + "\33[0m" " Works!" "\n"); + // Drop into the kernel monitor. while (1) monitor(NULL); diff --git a/lib/printfmt.c b/lib/printfmt.c index b1de635..7535e93 100644 --- a/lib/printfmt.c +++ b/lib/printfmt.c @@ -79,6 +79,54 @@ getint(va_list *ap, int lflag) // Main function to format and print a string. void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); +struct AttrState { + uint8_t cattrs; + uint8_t attrs; + enum { + NORMAL, + ESC, + BRACKET, + COLOR_FG, + COLOR + } state; +}; + +void +putchw(void (*putch)(int, void*), int c, void* data, struct AttrState* s) { + switch(s->state) { + case NORMAL: + if(c != 27) putch(c | (s->cattrs << 8), data); + else s->state = ESC; + return; + case ESC: + s->state = (c == '[') ? BRACKET : NORMAL; + return; + case BRACKET: + if(c == '3') { + s->state = COLOR_FG; + } else if(c == '0') { + s->state = COLOR; + s->attrs = 0; + } else { + s->state = NORMAL; + } + return; + case COLOR_FG: + if(c >= '0' && c <= '9') { + s->attrs = (s->attrs & ~(0x07)) | (c - '0'); + c |= ((c - '0') << 8); + s->state = COLOR; + } else { + s->state = NORMAL; + } + return; + case COLOR: + s->state = (c == ';') ? BRACKET : NORMAL; + if(c == 'm') s->cattrs = s->attrs; + return; + } +} + void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) { @@ -87,12 +135,17 @@ vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) unsigned long long num; int base, lflag, width, precision, altflag; char padc; + struct AttrState attst; + + attst.state = NORMAL; + attst.cattrs = 0; + attst.attrs = 0; while (1) { while ((ch = *(unsigned char *) fmt++) != '%') { if (ch == '\0') return; - putch(ch, putdat); + putchw(putch, ch, putdat, &attst); } // Process a %-escape sequence From 47a176223bc1630f27d3289afa3c98697596c6ba Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 5 Apr 2019 19:20:33 -0700 Subject: [PATCH 08/29] Fix color support to work everywhere via hacky static variable --- kern/Makefrag | 1 + kern/ansi.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ kern/ansi.h | 20 ++++++++++++++++++ kern/console.c | 15 ++++++++++++-- lib/printfmt.c | 55 +------------------------------------------------- 5 files changed, 84 insertions(+), 56 deletions(-) create mode 100644 kern/ansi.c create mode 100644 kern/ansi.h diff --git a/kern/Makefrag b/kern/Makefrag index 3b2982e..458dd57 100644 --- a/kern/Makefrag +++ b/kern/Makefrag @@ -17,6 +17,7 @@ KERN_SRCFILES := kern/entry.S \ kern/entrypgdir.c \ kern/init.c \ kern/console.c \ + kern/ansi.c \ kern/monitor.c \ kern/pmap.c \ kern/env.c \ diff --git a/kern/ansi.c b/kern/ansi.c new file mode 100644 index 0000000..c90057e --- /dev/null +++ b/kern/ansi.c @@ -0,0 +1,49 @@ +#include + +uint8_t vga_colors[8] = { + [0] = 0, + [1] = 4, + [2] = 2, + [3] = 6, + [4] = 1, + [5] = 5, + [6] = 3, + [7] = 7 +}; + +void +ansi_step(void (*putcf)(int), int c, struct AttrState* s) { + switch(s->state) { + case NORMAL: + if(c != 27) putcf(c | (s->cattrs << 8)); + else s->state = ESC; + return; + case ESC: + s->state = (c == '[') ? BRACKET : NORMAL; + return; + case BRACKET: + if(c == '3') { + s->state = COLOR_FG; + } else if(c == '0') { + s->state = COLOR; + s->attrs = 0; + } else { + s->state = NORMAL; + } + return; + case COLOR_FG: + if(c >= '0' && c <= '9') { + s->attrs = (s->attrs & ~(0x07)) | vga_colors[c - '0']; + c |= ((c - '0') << 8); + s->state = COLOR; + } else { + s->state = NORMAL; + } + return; + case COLOR: + s->state = (c == ';') ? BRACKET : NORMAL; + if(c == 'm') s->cattrs = s->attrs; + return; + } +} + diff --git a/kern/ansi.h b/kern/ansi.h new file mode 100644 index 0000000..970f9c6 --- /dev/null +++ b/kern/ansi.h @@ -0,0 +1,20 @@ +#ifndef _ANSI_H_ +#define _ANSI_H_ + +#include + +struct AttrState { + uint8_t cattrs; + uint8_t attrs; + enum { + NORMAL, + ESC, + BRACKET, + COLOR_FG, + COLOR + } state; +}; + +void ansi_step(void (*putcf)(int), int c, struct AttrState* s); + +#endif diff --git a/kern/console.c b/kern/console.c index 7d312a7..8019dad 100644 --- a/kern/console.c +++ b/kern/console.c @@ -7,6 +7,7 @@ #include #include +#include static void cons_intr(int (*proc)(void)); static void cons_putc(int c); @@ -128,6 +129,7 @@ lpt_putc(int c) static unsigned addr_6845; static uint16_t *crt_buf; static uint16_t crt_pos; +static struct AttrState attst; static void cga_init(void) @@ -136,6 +138,10 @@ cga_init(void) uint16_t was; unsigned pos; + attst.cattrs = 0; + attst.attrs = 0; + attst.state = NORMAL; + cp = (uint16_t*) (KERNBASE + CGA_BUF); was = *cp; *cp = (uint16_t) 0xA55A; @@ -157,10 +163,15 @@ cga_init(void) crt_pos = pos; } - +static void cga_putc_internal(int c); static void -cga_putc(int c) +cga_putc(int c){ + ansi_step(cga_putc_internal, c, &attst); +} + +static void +cga_putc_internal(int c) { // if no attribute given, then use black on white if (!(c & ~0xFF)) diff --git a/lib/printfmt.c b/lib/printfmt.c index 7535e93..b1de635 100644 --- a/lib/printfmt.c +++ b/lib/printfmt.c @@ -79,54 +79,6 @@ getint(va_list *ap, int lflag) // Main function to format and print a string. void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...); -struct AttrState { - uint8_t cattrs; - uint8_t attrs; - enum { - NORMAL, - ESC, - BRACKET, - COLOR_FG, - COLOR - } state; -}; - -void -putchw(void (*putch)(int, void*), int c, void* data, struct AttrState* s) { - switch(s->state) { - case NORMAL: - if(c != 27) putch(c | (s->cattrs << 8), data); - else s->state = ESC; - return; - case ESC: - s->state = (c == '[') ? BRACKET : NORMAL; - return; - case BRACKET: - if(c == '3') { - s->state = COLOR_FG; - } else if(c == '0') { - s->state = COLOR; - s->attrs = 0; - } else { - s->state = NORMAL; - } - return; - case COLOR_FG: - if(c >= '0' && c <= '9') { - s->attrs = (s->attrs & ~(0x07)) | (c - '0'); - c |= ((c - '0') << 8); - s->state = COLOR; - } else { - s->state = NORMAL; - } - return; - case COLOR: - s->state = (c == ';') ? BRACKET : NORMAL; - if(c == 'm') s->cattrs = s->attrs; - return; - } -} - void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) { @@ -135,17 +87,12 @@ vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap) unsigned long long num; int base, lflag, width, precision, altflag; char padc; - struct AttrState attst; - - attst.state = NORMAL; - attst.cattrs = 0; - attst.attrs = 0; while (1) { while ((ch = *(unsigned char *) fmt++) != '%') { if (ch == '\0') return; - putchw(putch, ch, putdat, &attst); + putch(ch, putdat); } // Process a %-escape sequence From ca51596893702bff8d328dd1e2f7605ddfc1ded6 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 19 Apr 2019 01:14:51 -0700 Subject: [PATCH 09/29] Initial implementation of lab 2. --- kern/pmap.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 19 deletions(-) diff --git a/kern/pmap.c b/kern/pmap.c index 8c809f1..a514b2a 100644 --- a/kern/pmap.c +++ b/kern/pmap.c @@ -102,8 +102,10 @@ boot_alloc(uint32_t n) // to a multiple of PGSIZE. // // LAB 2: Your code here. + result = nextfree; + nextfree = ROUNDUP(nextfree + n, PGSIZE); - return NULL; + return result; } // Set up a two-level page table: @@ -124,9 +126,6 @@ mem_init(void) // Find out how much memory the machine has (npages & npages_basemem). i386_detect_memory(); - // Remove this line when you're ready to test this function. - panic("mem_init: This function is not finished\n"); - ////////////////////////////////////////////////////////////////////// // create initial page directory. kern_pgdir = (pde_t *) boot_alloc(PGSIZE); @@ -148,7 +147,9 @@ mem_init(void) // array. 'npages' is the number of physical pages in memory. Use memset // to initialize all fields of each struct PageInfo to 0. // Your code goes here: - + size_t pages_size = sizeof(struct PageInfo) * npages; + pages = boot_alloc(pages_size); + memset(pages, 0, pages_size); ////////////////////////////////////////////////////////////////////// // Now that we've allocated the initial kernel data structures, we set @@ -172,6 +173,11 @@ mem_init(void) // (ie. perm = PTE_U | PTE_P) // - pages itself -- kernel RW, user NONE // Your code goes here: + boot_map_region(kern_pgdir, + UPAGES, ROUNDUP(pages_size, PGSIZE), + PADDR(pages), PTE_W); + kern_pgdir[PDX(UPAGES)] |= PTE_U | PTE_P; + kern_pgdir[PDX(UPAGES)] &= ~PTE_W; ////////////////////////////////////////////////////////////////////// // Use the physical memory that 'bootstack' refers to as the kernel @@ -184,6 +190,11 @@ mem_init(void) // overwrite memory. Known as a "guard page". // Permissions: kernel RW, user NONE // Your code goes here: + boot_map_region(kern_pgdir, + KSTACKTOP-KSTKSIZE, KSTKSIZE, + PADDR(bootstack), PTE_W); + kern_pgdir[PDX(KSTACKTOP-KSTKSIZE)] |= PTE_W | PTE_P; + kern_pgdir[PDX(KSTACKTOP-KSTKSIZE)] &= ~PTE_U; ////////////////////////////////////////////////////////////////////// // Map all of physical memory at KERNBASE. @@ -193,6 +204,12 @@ mem_init(void) // we just set up the mapping anyway. // Permissions: kernel RW, user NONE // Your code goes here: + boot_map_region(kern_pgdir, + KERNBASE, 0x100000000 - KERNBASE, + 0, PTE_W); + kern_pgdir[PDX(KERNBASE)] |= PTE_W | PTE_P; + kern_pgdir[PDX(KERNBASE)] &= ~PTE_U; + // Check that the initial page directory has been set up correctly. check_kern_pgdir(); @@ -224,6 +241,14 @@ mem_init(void) // The 'pages' array has one 'struct PageInfo' entry per physical page. // Pages are reference counted, and free pages are kept on a linked list. // -------------------------------------------------------------- +bool +is_reserved(size_t pagenum) { + if(pagenum == 0) return true; + if(pagenum >= PGNUM(IOPHYSMEM) && + pagenum < PGNUM(PADDR(boot_alloc(0)))) return true; + + return false; +} // // Initialize page structure and memory free list. @@ -253,9 +278,13 @@ page_init(void) // free pages! size_t i; for (i = 0; i < npages; i++) { - pages[i].pp_ref = 0; - pages[i].pp_link = page_free_list; - page_free_list = &pages[i]; + if(is_reserved(i)) { + pages[i].pp_ref = 1; + } else { + pages[i].pp_ref = 0; + pages[i].pp_link = page_free_list; + page_free_list = &pages[i]; + } } } @@ -274,8 +303,17 @@ page_init(void) struct PageInfo * page_alloc(int alloc_flags) { - // Fill this function in - return 0; + struct PageInfo* to_return = page_free_list; + if(to_return == 0) return NULL; + + page_free_list = to_return->pp_link; + to_return->pp_link = NULL; + + if(alloc_flags & ALLOC_ZERO) { + memset(page2kva(to_return), 0, PGSIZE); + } + + return to_return; } // @@ -285,9 +323,10 @@ page_alloc(int alloc_flags) void page_free(struct PageInfo *pp) { - // Fill this function in - // Hint: You may want to panic if pp->pp_ref is nonzero or - // pp->pp_link is not NULL. + if(pp->pp_ref || pp->pp_link != NULL) + panic("Freeing page with nonzero reference count!"); + pp->pp_link = page_free_list; + page_free_list = pp; } // @@ -326,8 +365,25 @@ page_decref(struct PageInfo* pp) pte_t * pgdir_walk(pde_t *pgdir, const void *va, int create) { + pte_t* base_table = NULL; + + if(pgdir[PDX(va)] & PTE_P) { + // We have a valid page table; awesome! + base_table = KADDR(PTE_ADDR(pgdir[PDX(va)])); + } else { + if(!create) return NULL; + + struct PageInfo* page = page_alloc(ALLOC_ZERO); + if(!page) return NULL; + + page->pp_ref++; + physaddr_t ppa = page2pa(page); + pgdir[PDX(va)] = ppa | PTE_P | PTE_U | PTE_W; + base_table = KADDR(ppa); + } + // Fill this function in - return NULL; + return &base_table[PTX(va)]; } // @@ -344,7 +400,16 @@ pgdir_walk(pde_t *pgdir, const void *va, int create) static void boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm) { - // Fill this function in + size_t count = size / PGSIZE; + uintptr_t start_va = va; + physaddr_t start_pa = pa; + while(count-- && start_va <= va && start_pa <= pa) { + pte_t* pte = pgdir_walk(pgdir, (void*) va, true); + *pte = pa | perm | PTE_P; + + va += PGSIZE; + pa += PGSIZE; + } } // @@ -375,7 +440,14 @@ boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm int page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm) { - // Fill this function in + pte_t* pte; + if(!(pte = pgdir_walk(pgdir, va, true))) return -E_NO_MEM; + + pp->pp_ref++; + if(*pte & PTE_P) page_remove(pgdir, va); + *pte = page2pa(pp) | PTE_P | perm; + tlb_invalidate(pgdir, va); + return 0; } @@ -393,8 +465,15 @@ page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm) struct PageInfo * page_lookup(pde_t *pgdir, void *va, pte_t **pte_store) { - // Fill this function in - return NULL; + pte_t* pte; + if(!(pte = pgdir_walk(pgdir, va, false))) { + if(pte_store) *pte_store = NULL; + return NULL; + } + + struct PageInfo* pp = pa2page(PTE_ADDR(*pte)); + if(pte_store) *pte_store = pte; + return pp; } // @@ -415,7 +494,15 @@ page_lookup(pde_t *pgdir, void *va, pte_t **pte_store) void page_remove(pde_t *pgdir, void *va) { - // Fill this function in + pte_t* pte; + struct PageInfo* pp; + + pp = page_lookup(pgdir, va, &pte); + if(!(*pte & PTE_P)) return; + + if(!(--(pp->pp_ref))) page_free(pp); + *pte = 0; + tlb_invalidate(pgdir, va); } // From 60ee3619af039ce7d8140486cb0ff325a18fffdf Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 19 Apr 2019 11:24:59 -0700 Subject: [PATCH 10/29] Add some macros for color support --- kern/ansi.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/kern/ansi.h b/kern/ansi.h index 970f9c6..c5df2d5 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_GREEM 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; From e484704ce89a7862ef729a5e369eab870b5f6dda Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 19 Apr 2019 13:19:15 -0700 Subject: [PATCH 11/29] Implement the showmappings command --- kern/ansi.h | 6 +++--- kern/monitor.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++--- kern/monitor.h | 1 + 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/kern/ansi.h b/kern/ansi.h index c5df2d5..8869cba 100644 --- a/kern/ansi.h +++ b/kern/ansi.h @@ -6,7 +6,7 @@ #define ACOL_WRAP(s) "\33[" s "m" #define ACOL_BLACK ACOL_WRAP("30") #define ACOL_RED ACOL_WRAP("31") -#define ACOL_GREEM ACOL_WRAP("32") +#define ACOL_GREEN ACOL_WRAP("32") #define ACOL_YELLOW ACOL_WRAP("33") #define ACOL_BLUE ACOL_WRAP("34") #define ACOL_MAGENTA ACOL_WRAP("35") @@ -15,9 +15,9 @@ #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_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 +#define ACOL_ERR(s) ACOL_TAG(ACOL_RED, " Error ") s struct AttrState { uint8_t cattrs; diff --git a/kern/monitor.c b/kern/monitor.c index c97da78..1e626e2 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,8 @@ 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 } }; /***** Implementations of basic kernel monitor commands *****/ @@ -46,7 +51,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 +80,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,6 +89,53 @@ 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; +} + +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); + + char buffer[3] = {0}; + + 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; +} /***** Kernel monitor command interpreter *****/ diff --git a/kern/monitor.h b/kern/monitor.h index 0aa0f26..35d2793 100644 --- a/kern/monitor.h +++ b/kern/monitor.h @@ -15,5 +15,6 @@ 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); #endif // !JOS_KERN_MONITOR_H From e1d239139af10c013804d515f090017f67d9f16a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 19 Apr 2019 17:36:23 -0700 Subject: [PATCH 12/29] Add permission changing kernel function --- kern/monitor.c | 72 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 11 deletions(-) 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 *****/ From c07415cffc9d5939bfc2f75831218a4243e2e929 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 19 Apr 2019 18:54:37 -0700 Subject: [PATCH 13/29] fixup! Add permission changing kernel function --- kern/monitor.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kern/monitor.h b/kern/monitor.h index 35d2793..4da7606 100644 --- a/kern/monitor.h +++ b/kern/monitor.h @@ -16,5 +16,6 @@ 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 From 8120dfde6505965ce291cdfbd7ba0b748e5091a2 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 01:44:23 -0700 Subject: [PATCH 14/29] Intermediate commit (trap is close to working). --- kern/env.c | 23 +++++++++++++++++------ kern/trap.c | 40 ++++++++++++++++++++++++++++++++++++++++ kern/trapentry.S | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/kern/env.c b/kern/env.c index bbde139..51e1f36 100644 --- a/kern/env.c +++ b/kern/env.c @@ -186,7 +186,7 @@ env_setup_vm(struct Env *e) // - The functions in kern/pmap.h are handy. p->pp_ref++; e->env_pgdir = page2kva(p); - memcpy(p + PDX(UTOP), kern_pgdir + PDX(UTOP), NPDENTRIES - PDX(UTOP)); + memcpy(e->env_pgdir + PDX(UTOP), kern_pgdir + PDX(UTOP), NPDENTRIES - PDX(UTOP)); // UVPT maps the env's own page table read-only. // Permissions: kernel R, user R @@ -285,6 +285,7 @@ region_alloc(struct Env *e, void *va, size_t len) panic("Failed to allocate memory"); if(page_insert(e->env_pgdir, p, va, PTE_U | PTE_W)) panic("Failed to allocate memory for page table"); + va += PGSIZE; } } @@ -356,12 +357,11 @@ load_icode(struct Env *e, uint8_t *binary) memset((void*) ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz); lcr3(PADDR(kern_pgdir)); } + e->env_tf.tf_eip = elf->e_entry; // Now map one page for the program's initial stack // at virtual address USTACKTOP - PGSIZE. - region_alloc(e, USTACKTOP - PGSIZE, PGSIZE); - - // LAB 3: Your code here. + region_alloc(e, (void*) USTACKTOP - PGSIZE, PGSIZE); } // @@ -375,6 +375,11 @@ void env_create(uint8_t *binary, enum EnvType type) { // LAB 3: Your code here. + struct Env* new_env; + if(env_alloc(&new_env, 0) < 0) + panic("Failed to allocate environment"); + new_env->env_type = type; + load_icode(new_env, binary); } // @@ -491,7 +496,13 @@ env_run(struct Env *e) // e->env_tf to sensible values. // LAB 3: Your code here. - - panic("env_run not yet implemented"); + if(curenv && curenv->env_status == ENV_RUNNING) { + curenv->env_status = ENV_RUNNABLE; + } + curenv = e; + e->env_status = ENV_RUNNING; + e->env_runs++; + lcr3(PADDR(e->env_pgdir)); + env_pop_tf(&e->env_tf); } diff --git a/kern/trap.c b/kern/trap.c index 7f6075f..fc8252e 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -61,6 +61,26 @@ static const char *trapname(int trapno) // XYZ: write a function declaration here... // e.g., void t_divide(); +void t_divide(); +void t_debug(); +void t_nmi(); +void t_brkpt(); +void t_oflow(); +void t_bound(); +void t_illop(); +void t_device(); +void t_dblflt(); +void t_tss(); +void t_segnp(); +void t_stack(); +void t_gpflt(); +void t_pgflt(); +void t_fperr(); +void t_align(); +void t_mchk(); +void t_simderr(); +void t_syscall(); +void t_default(); void trap_init(void) @@ -77,6 +97,26 @@ trap_init(void) * */ // LAB 3: Your code here. + SETGATE(idt[T_DIVIDE], 0, GD_KT, t_divide, 0); + SETGATE(idt[T_DEBUG], 0, GD_KT, t_debug, 0); + SETGATE(idt[T_NMI], 0, GD_KT, t_nmi, 0); + SETGATE(idt[T_BRKPT], 0, GD_KT, t_brkpt, 0); + SETGATE(idt[T_OFLOW], 0, GD_KT, t_oflow, 0); + SETGATE(idt[T_BOUND], 0, GD_KT, t_bound, 0); + SETGATE(idt[T_ILLOP], 0, GD_KT, t_illop, 0); + SETGATE(idt[T_DEVICE], 0, GD_KT, t_device, 0); + SETGATE(idt[T_DBLFLT], 0, GD_KT, t_dblflt, 0); + SETGATE(idt[T_TSS], 0, GD_KT, t_tss, 0); + SETGATE(idt[T_SEGNP], 0, GD_KT, t_segnp, 0); + SETGATE(idt[T_STACK], 0, GD_KT, t_stack, 0); + SETGATE(idt[T_GPFLT], 0, GD_KT, t_gpflt, 0); + SETGATE(idt[T_PGFLT], 0, GD_KT, t_pgflt, 0); + SETGATE(idt[T_FPERR], 0, GD_KT, t_fperr, 0); + SETGATE(idt[T_ALIGN], 0, GD_KT, t_align, 0); + SETGATE(idt[T_MCHK], 0, GD_KT, t_mchk, 0); + SETGATE(idt[T_SIMDERR], 0, GD_KT, t_simderr, 0); + SETGATE(idt[T_SYSCALL], 0, GD_KT, t_syscall, 3); + SETGATE(idt[T_DEFAULT], 0, GD_KT, t_default, 0); // Per-CPU setup trap_init_percpu(); diff --git a/kern/trapentry.S b/kern/trapentry.S index 80dfe58..406033b 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -46,6 +46,26 @@ /* * Lab 3: Your code here for generating entry points for the different traps. */ +TRAPHANDLER_NOEC(t_divide, T_DIVIDE); +TRAPHANDLER_NOEC(t_debug, T_DEBUG); +TRAPHANDLER_NOEC(t_nmi, T_NMI); +TRAPHANDLER_NOEC(t_brkpt, T_BRKPT); +TRAPHANDLER_NOEC(t_oflow, T_OFLOW); +TRAPHANDLER_NOEC(t_bound, T_OFLOW); +TRAPHANDLER_NOEC(t_illop, T_OFLOW); +TRAPHANDLER_NOEC(t_device, T_OFLOW); +TRAPHANDLER(t_dblflt, T_OFLOW); +TRAPHANDLER(t_tss, T_TSS); +TRAPHANDLER(t_segnp, T_SEGNP); +TRAPHANDLER(t_stack, T_STACK); +TRAPHANDLER(t_gpflt, T_GPFLT); +TRAPHANDLER(t_pgflt, T_PGFLT); +TRAPHANDLER_NOEC(t_fperr, T_FPERR); +TRAPHANDLER(t_align, T_ALIGN); +TRAPHANDLER_NOEC(t_mchk, T_MCHK); +TRAPHANDLER_NOEC(t_simderr, T_SIMDERR); +TRAPHANDLER_NOEC(t_syscall, T_SYSCALL); +TRAPHANDLER(t_default, T_DEFAULT); // HINT 1 : TRAPHANDLER_NOEC(t_divide, T_DIVIDE); // Do something like this if there is no error code for the trap @@ -58,4 +78,15 @@ * Lab 3: Your code here for _alltraps */ - +.globl _alltraps +_alltraps: + sub $0x2, %esp + push %ds + sub $0x2, %esp + push %es + pushal + mov $(GD_KD), %eax + movl %eax, %ds + movl %eax, %es + pushl %esp + call trap From 667f2df4cc9acdc82d102562bac5b074dc26dd36 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 02:06:11 -0700 Subject: [PATCH 15/29] Fix the trap function. God fucking damn it 16 bit registers! --- kern/trapentry.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kern/trapentry.S b/kern/trapentry.S index 406033b..3e7a622 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -81,9 +81,11 @@ TRAPHANDLER(t_default, T_DEFAULT); .globl _alltraps _alltraps: sub $0x2, %esp - push %ds + mov %ds, %eax + push %ax sub $0x2, %esp - push %es + mov %es, %eax + push %ax pushal mov $(GD_KD), %eax movl %eax, %ds From 6ab267bb9b0db4c4f37f27a5907c4cbe87c65531 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 14:26:02 -0700 Subject: [PATCH 16/29] Add basic trap handlers --- kern/trap.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kern/trap.c b/kern/trap.c index fc8252e..e7b6a1a 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -100,7 +100,7 @@ trap_init(void) SETGATE(idt[T_DIVIDE], 0, GD_KT, t_divide, 0); SETGATE(idt[T_DEBUG], 0, GD_KT, t_debug, 0); SETGATE(idt[T_NMI], 0, GD_KT, t_nmi, 0); - SETGATE(idt[T_BRKPT], 0, GD_KT, t_brkpt, 0); + SETGATE(idt[T_BRKPT], 0, GD_KT, t_brkpt, 3); SETGATE(idt[T_OFLOW], 0, GD_KT, t_oflow, 0); SETGATE(idt[T_BOUND], 0, GD_KT, t_bound, 0); SETGATE(idt[T_ILLOP], 0, GD_KT, t_illop, 0); @@ -196,6 +196,11 @@ trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. + if (tf->tf_trapno == T_PGFLT) { + page_fault_handler(tf); + } else if (tf->tf_trapno == T_BRKPT) { + monitor(tf); + } // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); From bbdb8bd8110c1404a115540fd9b6e08190ed981c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 16:14:21 -0700 Subject: [PATCH 17/29] Avoid corrupting eax during system call. --- kern/trapentry.S | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/kern/trapentry.S b/kern/trapentry.S index 3e7a622..31b211f 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -81,14 +81,12 @@ TRAPHANDLER(t_default, T_DEFAULT); .globl _alltraps _alltraps: sub $0x2, %esp - mov %ds, %eax - push %ax + pushw %ds sub $0x2, %esp - mov %es, %eax - push %ax + pushw %es pushal mov $(GD_KD), %eax - movl %eax, %ds - movl %eax, %es + movw %ax, %ds + movw %ax, %es pushl %esp call trap From eae0475758d2945884808df951d8748f9300cbe2 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 16:14:41 -0700 Subject: [PATCH 18/29] Seemingly implement system calls (still appears to have a bug). --- kern/syscall.c | 30 +++++++++++++++++++++++++++--- kern/trap.c | 7 +++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/kern/syscall.c b/kern/syscall.c index 414d489..59adfa7 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -19,8 +19,25 @@ sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. + const char* bottom = ROUNDDOWN(s, PGSIZE); + size_t aligned_count = ROUNDUP(len, PGSIZE) / PGSIZE; + while(aligned_count--) { + if (!(curenv->env_pgdir[PDX(bottom)] & PTE_P)) { + cprintf("[%08x] Tried to print unmapped address\n", curenv->env_id); + env_destroy(curenv); + return; + } - // LAB 3: Your code here. + pde_t pgdir_allowed = curenv->env_pgdir[PDX(bottom)] & PTE_U; + pde_t pt_allowed = *pgdir_walk(curenv->env_pgdir, bottom, 0) & PTE_U; + if(((curenv->env_tf.tf_cs & 0b11) > 1) && !(pt_allowed & pgdir_allowed)) { + cprintf("[%08x] Tried to print forbidden memory\n", curenv->env_id); + env_destroy(curenv); + return; + } + + bottom += PGSIZE; + } // Print the string supplied by the user. cprintf("%.*s", len, s); @@ -70,9 +87,16 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, // Return any appropriate return value. // LAB 3: Your code here. - panic("syscall not implemented"); - switch (syscallno) { + case SYS_cputs: + sys_cputs((const char*) a1, a2); + return 0; + case SYS_cgetc: + return sys_cgetc(); + case SYS_getenvid: + return sys_getenvid(); + case SYS_env_destroy: + return sys_env_destroy(a1); default: return -E_INVAL; } diff --git a/kern/trap.c b/kern/trap.c index e7b6a1a..2a4abef 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -200,6 +200,13 @@ trap_dispatch(struct Trapframe *tf) page_fault_handler(tf); } else if (tf->tf_trapno == T_BRKPT) { monitor(tf); + } else if (tf->tf_trapno == T_SYSCALL) { + syscall(tf->tf_regs.reg_eax, + tf->tf_regs.reg_edx, + tf->tf_regs.reg_ecx, + tf->tf_regs.reg_ebx, + tf->tf_regs.reg_edi, + tf->tf_regs.reg_esi); } // Unexpected trap: The user process or the kernel has a bug. From f0e2ab8abdd9cf0f278c6c280c3638a802fd3721 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 16:31:01 -0700 Subject: [PATCH 19/29] Do not crash on handled traps. --- kern/trap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kern/trap.c b/kern/trap.c index 2a4abef..8ed3fa8 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -198,8 +198,10 @@ trap_dispatch(struct Trapframe *tf) // LAB 3: Your code here. if (tf->tf_trapno == T_PGFLT) { page_fault_handler(tf); + return; } else if (tf->tf_trapno == T_BRKPT) { monitor(tf); + return; } else if (tf->tf_trapno == T_SYSCALL) { syscall(tf->tf_regs.reg_eax, tf->tf_regs.reg_edx, @@ -207,6 +209,7 @@ trap_dispatch(struct Trapframe *tf) tf->tf_regs.reg_ebx, tf->tf_regs.reg_edi, tf->tf_regs.reg_esi); + return; } // Unexpected trap: The user process or the kernel has a bug. From f4e319649441bdaeb2738129882ba9f5b0e58b7e Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 17:09:54 -0700 Subject: [PATCH 20/29] Fix permissions. --- kern/pmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kern/pmap.c b/kern/pmap.c index 58c0a41..2c590f2 100644 --- a/kern/pmap.c +++ b/kern/pmap.c @@ -183,8 +183,8 @@ mem_init(void) // Your code goes here: boot_map_region(kern_pgdir, UPAGES, ROUNDUP(pages_size, PGSIZE), - PADDR(pages), PTE_W); - kern_pgdir[PDX(UPAGES)] |= PTE_U | PTE_P; + PADDR(pages), PTE_U); + kern_pgdir[PDX(UPAGES)] |= PTE_U; kern_pgdir[PDX(UPAGES)] &= ~PTE_W; ////////////////////////////////////////////////////////////////////// @@ -196,7 +196,7 @@ mem_init(void) // LAB 3: Your code here. boot_map_region(kern_pgdir, UENVS, ROUNDUP(envs_size, PGSIZE), - PADDR(envs), PTE_W); + PADDR(envs), PTE_U); kern_pgdir[PDX(UENVS)] |= PTE_U; kern_pgdir[PDX(UPAGES)] &= ~PTE_W; From 92310757993d56ccce8d9a7eebd5ca90e4b5b614 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 17:10:25 -0700 Subject: [PATCH 21/29] Properly set environment pointer. --- lib/libmain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/libmain.c b/lib/libmain.c index 8a14b29..74df518 100644 --- a/lib/libmain.c +++ b/lib/libmain.c @@ -13,7 +13,8 @@ libmain(int argc, char **argv) { // set thisenv to point at our Env structure in envs[]. // LAB 3: Your code here. - thisenv = 0; + envid_t id = sys_getenvid(); + thisenv = &envs[ENVX(id)]; // save the name of the program so that panic() can use it if (argc > 0) From 94b52c57309c754aa1dabc9914ed7bd92a3bdb92 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 17:10:35 -0700 Subject: [PATCH 22/29] Forward return value of syscall. --- kern/trap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kern/trap.c b/kern/trap.c index 8ed3fa8..88ca879 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -203,12 +203,13 @@ trap_dispatch(struct Trapframe *tf) monitor(tf); return; } else if (tf->tf_trapno == T_SYSCALL) { - syscall(tf->tf_regs.reg_eax, + int32_t returned = syscall(tf->tf_regs.reg_eax, tf->tf_regs.reg_edx, tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx, tf->tf_regs.reg_edi, tf->tf_regs.reg_esi); + tf->tf_regs.reg_eax = returned; return; } From 113093f919a9be4196137912ba5747a3abc68b37 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 20:37:41 -0700 Subject: [PATCH 23/29] Fix page table copying bug. --- kern/env.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kern/env.c b/kern/env.c index 51e1f36..1b53826 100644 --- a/kern/env.c +++ b/kern/env.c @@ -186,7 +186,7 @@ env_setup_vm(struct Env *e) // - The functions in kern/pmap.h are handy. p->pp_ref++; e->env_pgdir = page2kva(p); - memcpy(e->env_pgdir + PDX(UTOP), kern_pgdir + PDX(UTOP), NPDENTRIES - PDX(UTOP)); + memcpy(e->env_pgdir + PDX(UTOP), kern_pgdir + PDX(UTOP), sizeof(pde_t) * (NPDENTRIES - PDX(UTOP))); // UVPT maps the env's own page table read-only. // Permissions: kernel R, user R @@ -276,11 +276,10 @@ region_alloc(struct Env *e, void *va, size_t len) // You should round va down, and round (va + len) up. // (Watch out for corner-cases!) va = ROUNDDOWN(va, PGSIZE); - len = ROUNDUP(len, PGSIZE); - void* last_va = va + len; + size_t count = ROUNDUP(len, PGSIZE) / PGSIZE; struct PageInfo* p; - while(va < last_va) { + while(count--) { if(!(p = page_alloc(0))) panic("Failed to allocate memory"); if(page_insert(e->env_pgdir, p, va, PTE_U | PTE_W)) From 8cd1daf8dd263cec60194ad6e870147f30b94e3b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 20:37:53 -0700 Subject: [PATCH 24/29] Implement the memcheck. --- kern/pmap.c | 16 ++++++++++++++++ kern/syscall.c | 21 +-------------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/kern/pmap.c b/kern/pmap.c index 2c590f2..9bd5767 100644 --- a/kern/pmap.c +++ b/kern/pmap.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -562,6 +563,21 @@ int user_mem_check(struct Env *env, const void *va, size_t len, int perm) { // LAB 3: Your code here. + const char* bottom = ROUNDDOWN(va, PGSIZE); + size_t aligned_count = ROUNDUP(len, PGSIZE) / PGSIZE; + pde_t mask = PTE_P | PTE_U | PTE_W; + pde_t perms = mask; + +#define VALID ((perms & (perm | PTE_P)) == (perm | PTE_P)) +#define DO_CHECK if(!VALID) { user_mem_check_addr = (uintptr_t) bottom; return -E_FAULT; } + + while(aligned_count--) { + perms &= env->env_pgdir[PDX(bottom)] & mask; + DO_CHECK; + perms &= (*pgdir_walk(env->env_pgdir, bottom, 0)) & mask; + DO_CHECK; + bottom += PGSIZE; + } return 0; } diff --git a/kern/syscall.c b/kern/syscall.c index 59adfa7..d332f11 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -19,26 +19,7 @@ sys_cputs(const char *s, size_t len) { // Check that the user has permission to read memory [s, s+len). // Destroy the environment if not. - const char* bottom = ROUNDDOWN(s, PGSIZE); - size_t aligned_count = ROUNDUP(len, PGSIZE) / PGSIZE; - while(aligned_count--) { - if (!(curenv->env_pgdir[PDX(bottom)] & PTE_P)) { - cprintf("[%08x] Tried to print unmapped address\n", curenv->env_id); - env_destroy(curenv); - return; - } - - pde_t pgdir_allowed = curenv->env_pgdir[PDX(bottom)] & PTE_U; - pde_t pt_allowed = *pgdir_walk(curenv->env_pgdir, bottom, 0) & PTE_U; - if(((curenv->env_tf.tf_cs & 0b11) > 1) && !(pt_allowed & pgdir_allowed)) { - cprintf("[%08x] Tried to print forbidden memory\n", curenv->env_id); - env_destroy(curenv); - return; - } - - bottom += PGSIZE; - } - + user_mem_assert(curenv, s, len, 0); // Print the string supplied by the user. cprintf("%.*s", len, s); } From 0fe97e52c3169e425cb775f17210989d1d0df194 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 23 Apr 2019 20:46:11 -0700 Subject: [PATCH 25/29] Change address reporting to fit the grading script's standards. --- kern/pmap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kern/pmap.c b/kern/pmap.c index 9bd5767..01e1ff4 100644 --- a/kern/pmap.c +++ b/kern/pmap.c @@ -563,13 +563,14 @@ int user_mem_check(struct Env *env, const void *va, size_t len, int perm) { // LAB 3: Your code here. + uintptr_t to_report = (uintptr_t) va; const char* bottom = ROUNDDOWN(va, PGSIZE); size_t aligned_count = ROUNDUP(len, PGSIZE) / PGSIZE; pde_t mask = PTE_P | PTE_U | PTE_W; pde_t perms = mask; #define VALID ((perms & (perm | PTE_P)) == (perm | PTE_P)) -#define DO_CHECK if(!VALID) { user_mem_check_addr = (uintptr_t) bottom; return -E_FAULT; } +#define DO_CHECK if(!VALID) { user_mem_check_addr = to_report; return -E_FAULT; } while(aligned_count--) { perms &= env->env_pgdir[PDX(bottom)] & mask; @@ -577,6 +578,7 @@ user_mem_check(struct Env *env, const void *va, size_t len, int perm) perms &= (*pgdir_walk(env->env_pgdir, bottom, 0)) & mask; DO_CHECK; bottom += PGSIZE; + to_report = (uintptr_t) bottom; } return 0; From 7d7620405324693b7f6e9690e75ccede66b8f757 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 24 Apr 2019 23:49:13 -0700 Subject: [PATCH 26/29] Add debugging kernel monitor functions --- kern/monitor.c | 42 +++++++++++++++++++++++++++++++++++++++++- kern/monitor.h | 2 ++ kern/trap.c | 2 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/kern/monitor.c b/kern/monitor.c index d2affd9..89e6efd 100644 --- a/kern/monitor.c +++ b/kern/monitor.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -31,7 +32,9 @@ static struct Command commands[] = { { "kerninfo", "Display information about the kernel", mon_kerninfo }, { "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 } + { "mperms", "Change the permissions of a memory range", mon_mperms }, + { "resume", "Resume from a breakpoint", mon_resume }, + { "step", "Step to next instruction", mon_step } }; @@ -188,6 +191,43 @@ int mon_mperms(int argc, char** argv, struct Trapframe* tf) { return 0; } +// This is a nice thought and all... +// But we should modify the trap frame. +// I feel stupid. +static inline void +set_eflag(uint16_t flagno, int value) { + uint32_t temp; + uint32_t mask = ~(1 << flagno); + uint32_t regv = value << flagno; + asm volatile("pushfl\n\t" + "pop %w0\n\t" + "and %w1, %w0\n\t" + "or %w2, %w0\n\t" + "push %w0\n\t" + "popfl\n\t" + : "=r" (temp) + : "r" (mask), "r" (regv)); +} + +#define EXPECT_BRKPT if(!(tf->tf_trapno == T_BRKPT || tf->tf_trapno == T_DEBUG)) { \ + cprintf(ACOL_ERR("I don't think I should resume from this.\n")); \ + return 0; } +#define EFLAGS_TF 0x8 + +int mon_resume(int argc, char** argv, struct Trapframe* tf) { + EXPECT_BRKPT; + tf->tf_eflags &= ~(1 << EFLAGS_TF); + env_pop_tf(tf); + return 0; +} + +int mon_step(int argc, char** argv, struct Trapframe* tf) { + EXPECT_BRKPT; + tf->tf_eflags |= 1 << EFLAGS_TF; + env_pop_tf(tf); + return 0; +} + /***** Kernel monitor command interpreter *****/ #define WHITESPACE "\t\r\n " diff --git a/kern/monitor.h b/kern/monitor.h index 4da7606..0e51db1 100644 --- a/kern/monitor.h +++ b/kern/monitor.h @@ -17,5 +17,7 @@ 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); +int mon_resume(int argc, char** argv, struct Trapframe* tf); +int mon_step(int argc, char** argv, struct Trapframe* tf); #endif // !JOS_KERN_MONITOR_H diff --git a/kern/trap.c b/kern/trap.c index 88ca879..4ce2170 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -199,7 +199,7 @@ trap_dispatch(struct Trapframe *tf) if (tf->tf_trapno == T_PGFLT) { page_fault_handler(tf); return; - } else if (tf->tf_trapno == T_BRKPT) { + } else if (tf->tf_trapno == T_BRKPT || tf->tf_trapno == T_DEBUG) { monitor(tf); return; } else if (tf->tf_trapno == T_SYSCALL) { From 3449b8c566e8ac173d882f0423cb66b579a2eb45 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 25 Apr 2019 17:14:57 -0700 Subject: [PATCH 27/29] Implement the fast syscall challenge. --- inc/x86.h | 19 +++++++++++++++++++ kern/init.c | 6 ++++++ kern/trapentry.S | 15 +++++++++++++++ lib/syscall.c | 17 ++++++++++++++++- 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/inc/x86.h b/inc/x86.h index cc15ff4..bb6891d 100644 --- a/inc/x86.h +++ b/inc/x86.h @@ -3,6 +3,10 @@ #include +#define MSR_IA32_SYSENTER_CS 0x174 +#define MSR_IA32_SYSENTER_EIP 0x176 +#define MSR_IA32_SYSENTER_ESP 0x175 + static inline void breakpoint(void) { @@ -261,4 +265,19 @@ xchg(volatile uint32_t *addr, uint32_t newval) return result; } +static inline void +write_msr(uint32_t reg, uint32_t low, uint32_t high) { + asm volatile("wrmsr\n\t" + :: "c" (reg), "a" (low), "d" (high)); +} + +static inline void +read_msr(uint32_t reg, uint32_t* low, uint32_t* high) { + uint32_t eax, edx; + asm volatile("rdmsr\n\t" + : "=a" (eax), "=d" (edx) : "c" (reg)); + *low = eax; + *high = edx; +} + #endif /* !JOS_INC_X86_H */ diff --git a/kern/init.c b/kern/init.c index b524643..0bdc695 100644 --- a/kern/init.c +++ b/kern/init.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,7 @@ #include #include +void sysenter_handler(); void i386_init(void) @@ -34,6 +36,10 @@ i386_init(void) "\33[34m" "r" "\33[0m" " Works!" "\n"); + write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) sysenter_handler, 0); + write_msr(MSR_IA32_SYSENTER_ESP, KSTACKTOP, 0); + write_msr(MSR_IA32_SYSENTER_CS, GD_KT, 0); + // Lab 2 memory management initialization functions mem_init(); diff --git a/kern/trapentry.S b/kern/trapentry.S index 31b211f..f1d236e 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -43,6 +43,21 @@ .text +.globl sysenter_handler +sysenter_handler: + push %ebp // holds env's stack pointer + push %esi // holds the env's return addr + push %edi + push %ebx + push %ecx + push %edx + push %eax + call syscall + add $0x14, %esp + pop %edx + pop %ecx + sysexit + /* * Lab 3: Your code here for generating entry points for the different traps. */ diff --git a/lib/syscall.c b/lib/syscall.c index 8d28dda..08d7654 100644 --- a/lib/syscall.c +++ b/lib/syscall.c @@ -2,6 +2,7 @@ #include #include +#include static inline int32_t syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5) @@ -37,10 +38,24 @@ syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, return ret; } +int32_t +fast_syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4) { + asm volatile( + "push %%ebp\n\t" + "mov %%esp, %%ebp\n\t" + "lea syscall_ret_%=, %%esi\n\t" + "sysenter\n\t" + "syscall_ret_%=: pop %%ebp\n\t" + : "+a" (num) + : "d" (a1), "c" (a2), "b" (a3), "D" (a4) + : "esi"); + return num; +} + void sys_cputs(const char *s, size_t len) { - syscall(SYS_cputs, 0, (uint32_t)s, len, 0, 0, 0); + fast_syscall(SYS_cputs, (uint32_t)s, len, 0, 0); } int From 74b1c2c69d7f60924299d9e45204158fa293ed7a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 25 Apr 2019 17:26:16 -0700 Subject: [PATCH 28/29] Switch getc to also use fast_syscall. --- lib/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/syscall.c b/lib/syscall.c index 08d7654..b7772d2 100644 --- a/lib/syscall.c +++ b/lib/syscall.c @@ -61,7 +61,7 @@ sys_cputs(const char *s, size_t len) int sys_cgetc(void) { - return syscall(SYS_cgetc, 0, 0, 0, 0, 0, 0); + return fast_syscall(SYS_cgetc, 0, 0, 0, 0); } int From 03b296f7e1459217d7208b2835b634c190ecec4a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Thu, 25 Apr 2019 19:58:37 -0700 Subject: [PATCH 29/29] Add a getc program --- kern/Makefrag | 3 ++- user/getc.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 user/getc.c diff --git a/kern/Makefrag b/kern/Makefrag index 778e3b6..3638910 100644 --- a/kern/Makefrag +++ b/kern/Makefrag @@ -50,7 +50,8 @@ KERN_BINFILES := user/hello \ user/faultread \ user/faultreadkernel \ user/faultwrite \ - user/faultwritekernel + user/faultwritekernel \ + user/getc KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES)) KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES)) diff --git a/user/getc.c b/user/getc.c new file mode 100644 index 0000000..0af8d57 --- /dev/null +++ b/user/getc.c @@ -0,0 +1,9 @@ +#include + +void +umain(int argc, char **argv) +{ + char c; + while(!(c = sys_cgetc())); + cprintf("got character %c\n", c); +}