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/Makefrag b/kern/Makefrag index 00c7efd..4dd63b5 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 \ @@ -55,7 +56,8 @@ KERN_BINFILES := user/hello \ user/faultread \ user/faultreadkernel \ user/faultwrite \ - user/faultwritekernel + user/faultwritekernel \ + user/getc # Binary files for LAB4 KERN_BINFILES += user/idle \ 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..8869cba --- /dev/null +++ b/kern/ansi.h @@ -0,0 +1,36 @@ +#ifndef _ANSI_H_ +#define _ANSI_H_ + +#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; + 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 88869ea..2060513 100644 --- a/kern/console.c +++ b/kern/console.c @@ -9,6 +9,7 @@ #include #include #include +#include static void cons_intr(int (*proc)(void)); static void cons_putc(int c); @@ -130,6 +131,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) @@ -138,6 +140,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; @@ -159,10 +165,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/kern/env.c b/kern/env.c index 0a6a7a6..1a5af25 100644 --- a/kern/env.c +++ b/kern/env.c @@ -119,6 +119,13 @@ env_init(void) { // Set up envs array // LAB 3: Your code here. + size_t i = NENV; + while(true) { + i--; + envs[i].env_link = env_free_list; + env_free_list = &envs[i]; + if(i == 0) break; + } // Per-CPU part of the initialization env_init_percpu(); @@ -180,8 +187,9 @@ env_setup_vm(struct Env *e) // is an exception -- you need to increment env_pgdir's // pp_ref for env_free to work correctly. // - The functions in kern/pmap.h are handy. - - // LAB 3: Your code here. + p->pp_ref++; + e->env_pgdir = page2kva(p); + 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 @@ -279,6 +287,17 @@ region_alloc(struct Env *e, void *va, size_t len) // 'va' and 'len' values that are not page-aligned. // You should round va down, and round (va + len) up. // (Watch out for corner-cases!) + va = ROUNDDOWN(va, PGSIZE); + size_t count = ROUNDUP(len, PGSIZE) / PGSIZE; + struct PageInfo* p; + + while(count--) { + if(!(p = page_alloc(0))) + 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; + } } // @@ -336,10 +355,24 @@ load_icode(struct Env *e, uint8_t *binary) // LAB 3: Your code here. + // TODO validate the headers + struct Elf* elf = (struct Elf*) binary; + struct Proghdr* ph = (struct Proghdr*) (binary + elf->e_phoff); + struct Proghdr* phend = ph + elf->e_phnum; + for(; ph < phend; ph++) { + if(ph->p_type != ELF_PROG_LOAD) continue; + + region_alloc(e, (void*) ph->p_va, ph->p_memsz); + lcr3(PADDR(e->env_pgdir)); + memcpy((void*) ph->p_va, binary + ph->p_offset, ph->p_filesz); + 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. - - // LAB 3: Your code here. + region_alloc(e, (void*) USTACKTOP - PGSIZE, PGSIZE); } // @@ -353,6 +386,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); } // @@ -483,7 +521,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/init.c b/kern/init.c index a5bc649..02ce70d 100644 --- a/kern/init.c +++ b/kern/init.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ static void boot_aps(void); +void sysenter_handler(); void i386_init(void) @@ -26,6 +28,16 @@ i386_init(void) cons_init(); cprintf("444544 decimal is %o octal!\n", 444544); + cprintf("\33[31m" "C" + "\33[33m" "o" + "\33[32m" "l" + "\33[36m" "o" + "\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/kdebug.c b/kern/kdebug.c index f4ee8ee..3cd504b 100644 --- a/kern/kdebug.c +++ b/kern/kdebug.c @@ -196,7 +196,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: @@ -204,6 +205,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 diff --git a/kern/monitor.c b/kern/monitor.c index 7156224..89e6efd 100644 --- a/kern/monitor.c +++ b/kern/monitor.c @@ -7,10 +7,14 @@ #include #include +#include +#include #include #include #include #include +#include +#include #define CMDBUF_SIZE 80 // enough for one VGA text line @@ -26,6 +30,12 @@ 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 }, + { "showmappings", "Display the physical mappings for range", mon_showmappings }, + { "mperms", "Change the permissions of a memory range", mon_mperms }, + { "resume", "Resume from a breakpoint", mon_resume }, + { "step", "Step to next instruction", mon_step } + }; /***** Implementations of basic kernel monitor commands *****/ @@ -46,7 +56,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); @@ -62,10 +72,161 @@ 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; } +#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; +} + +// 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 *****/ diff --git a/kern/monitor.h b/kern/monitor.h index 0aa0f26..0e51db1 100644 --- a/kern/monitor.h +++ b/kern/monitor.h @@ -15,5 +15,9 @@ 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); +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/pmap.c b/kern/pmap.c index ea10edc..fe2a616 100644 --- a/kern/pmap.c +++ b/kern/pmap.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -105,8 +106,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: @@ -127,9 +130,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); @@ -151,11 +151,16 @@ 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); ////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. + size_t envs_size = sizeof(struct Env) * NENV; + envs = boot_alloc(envs_size); + memset(envs, 0, envs_size); ////////////////////////////////////////////////////////////////////// // Now that we've allocated the initial kernel data structures, we set @@ -179,6 +184,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_U); + kern_pgdir[PDX(UPAGES)] |= PTE_U; + kern_pgdir[PDX(UPAGES)] &= ~PTE_W; ////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS @@ -187,6 +197,11 @@ mem_init(void) // - the new image at UENVS -- kernel R, user R // - envs itself -- kernel RW, user NONE // LAB 3: Your code here. + boot_map_region(kern_pgdir, + UENVS, ROUNDUP(envs_size, PGSIZE), + PADDR(envs), PTE_U); + kern_pgdir[PDX(UENVS)] |= PTE_U; + kern_pgdir[PDX(UPAGES)] &= ~PTE_W; ////////////////////////////////////////////////////////////////////// // Use the physical memory that 'bootstack' refers to as the kernel @@ -199,6 +214,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; + kern_pgdir[PDX(KSTACKTOP-KSTKSIZE)] &= ~PTE_U; ////////////////////////////////////////////////////////////////////// // Map all of physical memory at KERNBASE. @@ -208,6 +228,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; + // Initialize the SMP-related parts of the memory map mem_init_mp(); @@ -267,6 +293,14 @@ mem_init_mp(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. @@ -300,9 +334,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]; + } } } @@ -321,8 +359,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; } // @@ -332,9 +379,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; } // @@ -373,8 +421,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)]; } // @@ -391,7 +456,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; + } } // @@ -422,7 +496,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; } @@ -440,8 +521,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; } // @@ -462,7 +550,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); } // @@ -536,6 +632,23 @@ 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 = to_report; 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; + to_report = (uintptr_t) bottom; + } return 0; } diff --git a/kern/syscall.c b/kern/syscall.c index 5291c6a..2483269 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -20,9 +20,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. - - // LAB 3: Your code here. - + user_mem_assert(curenv, s, len, 0); // Print the string supplied by the user. cprintf("%.*s", len, s); } @@ -271,9 +269,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 2dfaa17..4b90526 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -68,6 +68,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) @@ -84,6 +104,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, 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); + 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(); @@ -188,6 +228,22 @@ trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. + if (tf->tf_trapno == T_PGFLT) { + page_fault_handler(tf); + return; + } else if (tf->tf_trapno == T_BRKPT || tf->tf_trapno == T_DEBUG) { + monitor(tf); + return; + } else if (tf->tf_trapno == T_SYSCALL) { + 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; + } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the diff --git a/kern/trapentry.S b/kern/trapentry.S index 7b51b6a..fb2a3c7 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -44,9 +44,44 @@ .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. */ +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 @@ -59,4 +94,15 @@ * Lab 3: Your code here for _alltraps */ - +.globl _alltraps +_alltraps: + sub $0x2, %esp + pushw %ds + sub $0x2, %esp + pushw %es + pushal + mov $(GD_KD), %eax + movw %ax, %ds + movw %ax, %es + pushl %esp + call trap 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) diff --git a/lib/printfmt.c b/lib/printfmt.c index 2aeb2dc..598ae4c 100644 --- a/lib/printfmt.c +++ b/lib/printfmt.c @@ -207,11 +207,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': diff --git a/lib/syscall.c b/lib/syscall.c index 7880c8a..9233e23 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,16 +38,30 @@ 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 sys_cgetc(void) { - return syscall(SYS_cgetc, 0, 0, 0, 0, 0, 0); + return fast_syscall(SYS_cgetc, 0, 0, 0, 0); } int diff --git a/student.info b/student.info index f3ede52..7014618 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 +Lab Class # : Lab 2 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); +}