Intermediate commit of lab 3 changes

This commit is contained in:
Danila Fedorin 2019-04-22 22:16:32 -07:00
commit 73dad8b484
12 changed files with 394 additions and 34 deletions

View File

@ -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 \

49
kern/ansi.c Normal file
View File

@ -0,0 +1,49 @@
#include <kern/ansi.h>
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;
}
}

36
kern/ansi.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _ANSI_H_
#define _ANSI_H_
#include <inc/types.h>
#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

View File

@ -7,6 +7,7 @@
#include <inc/assert.h>
#include <kern/console.h>
#include <kern/ansi.h>
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))

View File

@ -116,6 +116,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();
@ -177,8 +184,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(p + PDX(UTOP), kern_pgdir + PDX(UTOP), NPDENTRIES - PDX(UTOP));
// UVPT maps the env's own page table read-only.
// Permissions: kernel R, user R
@ -267,6 +275,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);
len = ROUNDUP(len, PGSIZE);
void* last_va = va + len;
struct PageInfo* p;
while(va < last_va) {
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");
}
}
//
@ -324,8 +343,23 @@ 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));
}
// 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.
}

View File

@ -27,6 +27,12 @@ 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");
// Lab 2 memory management initialization functions
mem_init();

View File

@ -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 <inc/stab.h> 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

View File

@ -7,10 +7,13 @@
#include <inc/assert.h>
#include <inc/x86.h>
#include <kern/ansi.h>
#include <kern/console.h>
#include <kern/monitor.h>
#include <kern/kdebug.h>
#include <kern/trap.h>
#include <kern/pmap.h>
#include <inc/string.h>
#define CMDBUF_SIZE 80 // enough for one VGA text line
@ -26,6 +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 },
{ "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 *****/
@ -62,10 +69,124 @@ 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;
}
/***** Kernel monitor command interpreter *****/

View File

@ -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

View File

@ -103,8 +103,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:
@ -125,9 +127,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);
@ -149,11 +148,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
@ -177,6 +181,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;
//////////////////////////////////////////////////////////////////////
// Map the 'envs' array read-only by the user at linear address UENVS
@ -185,6 +194,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_W);
kern_pgdir[PDX(UENVS)] |= PTE_U;
kern_pgdir[PDX(UPAGES)] &= ~PTE_W;
//////////////////////////////////////////////////////////////////////
// Use the physical memory that 'bootstack' refers to as the kernel
@ -197,6 +211,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.
@ -206,6 +225,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();
@ -237,6 +262,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.
@ -266,11 +299,15 @@ page_init(void)
// free pages!
size_t i;
for (i = 0; i < npages; 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];
}
}
}
//
// Allocates a physical page. If (alloc_flags & ALLOC_ZERO), fills the entire
@ -287,8 +324,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;
}
//
@ -298,9 +344,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;
}
//
@ -339,8 +386,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)];
}
//
@ -357,7 +421,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;
}
}
//
@ -388,7 +461,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;
}
@ -406,10 +486,17 @@ 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
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;
}
//
// Unmaps the physical page at virtual address 'va'.
// If there is no physical page at that address, silently does nothing.
@ -428,7 +515,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);
}
//

View File

@ -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':

View File

@ -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