Merge branch 'lab4' into lab5

This commit is contained in:
Danila Fedorin 2019-05-14 16:42:08 -07:00
commit e9f683f6d6
25 changed files with 975 additions and 92 deletions

22
answers-lab2.txt Normal file
View File

@ -0,0 +1,22 @@
1. The entry given by PDX(UVPT) is mapped to the page directory itself,
to allow programs to read existing memory mappings. The entry at PDX(UPAGES)
is mapped to the pages variable in memory so that the kernel (and potentially other ring 0 programs) can access it. The entry pointed to by PDX(KSTACKTOP-KSTACKSIZE) is mapped
to the bootstack location. Finally, both the memory pointed to by 0 and PDX(KERNBASE) are mapped to kernel memory. However, the mappings at VA 0 are read-only, so user programs can't touch them, while the mappings at PDX(KERNBASE) are kernel-private and RW.
A table could be as follows:
400 - Kernel memory
... - Kernel memory
3c0 - Kernel memory
3bf - Kernel Stack
3bd - UVPT
3bc - UPAGES
2. The kernel memory is mapped as kernel read write. This means there are several flags set in the kernel page directory and page table entries, which indicate that this is restricted memory. The lower 3 bits of the CS register will be checked when an access to this memory is made, and, if they are not 0 or 1 (indicating kernel code), the CPU generates a fault, and the user program gives up control back to the OS. Thus, unless a program is started in ring 0, it will not be able to read or write kernel memory, as it should.
3. The absolute maximum is 4GB, since we use 32-bit integers for referencing memory. Some of this memory is used for the kernel itself, as well as for the page directory and tables.
4. The page directory and the corresponding pages are all 4kb. The page directory can have 1024 entries, and each of these point to a page table. Thus, we use approximatey 4MB (slightly more than that, actually, due to the size of the page directory itself) of memory. Additionally, the "pages" structs (which are used to keep track of available physical pages), will require ~1000000 entries, each of which is between 6 and 8 bytes (depending on whether GCC aligns struct sizes). This means another 8MB is used to keep track of free pages, to a total of around 12MB.
5. We switch to high EIP when we jump to "relocated". Relocated is a label, and a symbol that's inserted by the linker. Since the linker is configured to link the kernel high, relocated points to the upper portion of memory, where KERNBASE is. However, the entry page directory, just like our full page directory later on, sets up two mappings, one starting at 0 (creating a one to one mapping between some of the virtual addresses and their physical counterparts), and one starting at KERNBASE. Thus, we can continue to run at a low EIP. The only reason I can think of as to why we NEED to make the switch, besides the elementary "the kernel links high", is that we need to be able to write to various symbols, also linked above KERNBASE.

View File

@ -3,6 +3,10 @@
#include <inc/types.h>
#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 */

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

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

@ -9,6 +9,7 @@
#include <kern/console.h>
#include <kern/trap.h>
#include <kern/picirq.h>
#include <kern/ansi.h>
static void cons_intr(int (*proc)(void));
static void cons_putc(int c);
@ -133,6 +134,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)
@ -141,6 +143,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;
@ -162,10 +168,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

@ -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
@ -247,6 +255,7 @@ env_alloc(struct Env **newenv_store, envid_t parent_id)
// Enable interrupts while in user mode.
// LAB 4: Your code here.
e->env_tf.tf_eflags |= FL_IF;
// Clear the page fault handler until user installs one.
e->env_pgfault_upcall = 0;
@ -279,6 +288,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 +356,24 @@ load_icode(struct Env *e, uint8_t *binary)
// LAB 3: Your code here.
// TODO validate the headers
lcr3(PADDR(e->env_pgdir));
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);
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,9 +387,13 @@ void
env_create(uint8_t *binary, enum EnvType type)
{
// LAB 3: Your code here.
// If this is the file server (type == ENV_TYPE_FS) give it I/O privileges.
// LAB 5: 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);
}
//
@ -486,7 +524,14 @@ 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));
unlock_kernel();
env_pop_tf(&e->env_tf);
}

View File

@ -3,6 +3,7 @@
#include <inc/stdio.h>
#include <inc/string.h>
#include <inc/assert.h>
#include <inc/x86.h>
#include <kern/monitor.h>
#include <kern/console.h>
@ -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();
@ -43,6 +55,7 @@ i386_init(void)
// Acquire the big kernel lock before waking up APs
// Your code here:
lock_kernel();
// Starting non-boot CPUs
boot_aps();
@ -115,6 +128,8 @@ mp_main(void)
// only one CPU can enter the scheduler at a time!
//
// Your code here:
lock_kernel();
sched_yield();
// Remove this after you finish Exercise 6
for (;;);

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,14 @@
#include <inc/assert.h>
#include <inc/x86.h>
#include <kern/env.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 +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 *****/

View File

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

View File

@ -6,6 +6,7 @@
#include <inc/string.h>
#include <inc/assert.h>
#include <kern/monitor.h>
#include <kern/pmap.h>
#include <kern/kclock.h>
#include <kern/env.h>
@ -107,8 +108,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:
@ -129,9 +132,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);
@ -153,11 +153,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
@ -181,6 +186,9 @@ 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);
//////////////////////////////////////////////////////////////////////
// Map the 'envs' array read-only by the user at linear address UENVS
@ -189,6 +197,10 @@ mem_init(void)
// - the new image at UENVS -- kernel R, user R
// - envs itself -- kernel RW, user NONE
// LAB 3: Your code here.
cprintf("Mapping envs from %p to %p\n", UENVS, ROUNDUP(envs_size, PGSIZE));
boot_map_region(kern_pgdir,
UENVS, ROUNDUP(envs_size, PGSIZE),
PADDR(envs), PTE_U);
//////////////////////////////////////////////////////////////////////
// Use the physical memory that 'bootstack' refers to as the kernel
@ -201,6 +213,9 @@ 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);
//////////////////////////////////////////////////////////////////////
// Map all of physical memory at KERNBASE.
@ -210,6 +225,9 @@ 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);
// Initialize the SMP-related parts of the memory map
mem_init_mp();
@ -261,6 +279,11 @@ mem_init_mp(void)
// Permissions: kernel RW, user NONE
//
// LAB 4: Your code here:
for(int i = 0; i < NCPU; i++) {
uintptr_t kstacktop = KSTACKTOP - i * (KSTKSIZE + KSTKGAP);
boot_map_region(kern_pgdir, kstacktop - KSTKSIZE,
KSTKSIZE, PADDR(percpu_kstacks[i]), PTE_W);
}
}
@ -269,6 +292,15 @@ 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;
if(pagenum == PGNUM(MPENTRY_PADDR)) return true;
return false;
}
//
// Initialize page structure and memory free list.
@ -302,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];
}
}
}
@ -323,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;
}
//
@ -334,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;
}
//
@ -375,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)];
}
//
@ -393,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;
}
}
//
@ -424,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;
}
@ -442,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;
}
//
@ -464,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);
}
//
@ -511,7 +605,15 @@ mmio_map_region(physaddr_t pa, size_t size)
// Hint: The staff solution uses boot_map_region.
//
// Your code here:
panic("mmio_map_region not implemented");
size = ROUNDUP(size, PGSIZE);
if((base + size) > MMIOLIM)
panic("Not enough memory-mapped IO space!");
boot_map_region(kern_pgdir, base, size, pa, PTE_PCD | PTE_PWT | PTE_W);
uintptr_t to_return = base;
base += size;
return (void*) to_return;
}
static uintptr_t user_mem_check_addr;
@ -538,6 +640,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;
}

View File

@ -30,6 +30,23 @@ sched_yield(void)
// below to halt the cpu.
// LAB 4: Your code here.
struct Env* next_env = curenv ? curenv + 1 : envs;
struct Env* end_env = envs + NENV;
struct Env* to_run = NULL;
for(int i = 0; i < NENV; i++, next_env++) {
if(next_env == end_env) next_env = envs;
if(next_env->env_status == ENV_RUNNABLE) {
to_run = next_env;
break;
}
}
if(!to_run && curenv && curenv->env_status == ENV_RUNNING) {
to_run = curenv;
}
if(to_run) env_run(to_run);
// sched_halt never returns
sched_halt();
@ -77,7 +94,7 @@ sched_halt(void)
"pushl $0\n"
// LAB 4:
// Uncomment the following line after completing exercise 13
//"sti\n"
"sti\n"
"1:\n"
"hlt\n"
"jmp 1b\n"

View File

@ -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);
}
@ -78,9 +76,16 @@ sys_exofork(void)
// status is set to ENV_NOT_RUNNABLE, and the register set is copied
// from the current environment -- but tweaked so sys_exofork
// will appear to return 0.
struct Env* new_env;
int error_code;
error_code = env_alloc(&new_env, curenv->env_id);
if(error_code < 0) return error_code;
// LAB 4: Your code here.
panic("sys_exofork not implemented");
new_env->env_tf = curenv->env_tf;
new_env->env_tf.tf_regs.reg_eax = 0;
new_env->env_status = ENV_NOT_RUNNABLE;
return new_env->env_id;
}
// Set envid's env_status to status, which must be ENV_RUNNABLE
@ -98,9 +103,17 @@ sys_env_set_status(envid_t envid, int status)
// You should set envid2env's third argument to 1, which will
// check whether the current environment has permission to set
// envid's status.
struct Env* env;
int error_code;
// LAB 4: Your code here.
panic("sys_env_set_status not implemented");
error_code = envid2env(envid, &env, 1);
if(error_code < 0) return error_code;
if(status != ENV_RUNNABLE && status != ENV_NOT_RUNNABLE)
return -E_INVAL;
env->env_status = status;
return 0;
}
// Set envid's trap frame to 'tf'.
@ -130,10 +143,18 @@ sys_env_set_trapframe(envid_t envid, struct Trapframe *tf)
static int
sys_env_set_pgfault_upcall(envid_t envid, void *func)
{
// LAB 4: Your code here.
panic("sys_env_set_pgfault_upcall not implemented");
struct Env* env;
int return_code;
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
env->env_pgfault_upcall = func;
return 0;
}
#define SYS_CHECKPERMS(perm) \
((((perm) & (PTE_P | PTE_U)) == (PTE_P | PTE_U)) && \
(((perm) & ~(PTE_P | PTE_U | PTE_W | PTE_AVAIL)) == 0))
#define SYS_CHECKADDR(addr) (((uintptr_t) (addr) < UTOP) && ((uintptr_t) (addr) % PGSIZE == 0))
// Allocate a page of memory and map it at 'va' with permission
// 'perm' in the address space of 'envid'.
// The page's contents are set to 0.
@ -159,9 +180,22 @@ sys_page_alloc(envid_t envid, void *va, int perm)
// parameters for correctness.
// If page_insert() fails, remember to free the page you
// allocated!
struct Env* env;
int return_code;
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
if(!SYS_CHECKADDR(va)) return -E_INVAL;
// LAB 4: Your code here.
panic("sys_page_alloc not implemented");
struct PageInfo* page = page_alloc(1);
if(!page) return -E_NO_MEM;
if((return_code = page_insert(env->env_pgdir, page, va, perm)) < 0) {
page_free(page);
return return_code;
}
return 0;
}
// Map the page of memory at 'srcva' in srcenvid's address space
@ -190,9 +224,24 @@ sys_page_map(envid_t srcenvid, void *srcva,
// parameters for correctness.
// Use the third argument to page_lookup() to
// check the current permissions on the page.
struct Env *srcenv, *dstenv;
pte_t* srcpte;
int return_code;
// LAB 4: Your code here.
panic("sys_page_map not implemented");
if((return_code = envid2env(srcenvid, &srcenv, 1)) < 0) return return_code;
if((return_code = envid2env(dstenvid, &dstenv, 1)) < 0) return return_code;
if(!SYS_CHECKADDR(srcva)) return -E_INVAL;
if(!SYS_CHECKADDR(dstva)) return -E_INVAL;
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
struct PageInfo* page = page_lookup(srcenv->env_pgdir, srcva, &srcpte);
if(page == NULL) return -E_INVAL;
if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL;
if((return_code = page_insert(dstenv->env_pgdir, page, dstva, perm)) < 0)
return return_code;
return 0;
}
// Unmap the page of memory at 'va' in the address space of 'envid'.
@ -206,9 +255,14 @@ static int
sys_page_unmap(envid_t envid, void *va)
{
// Hint: This function is a wrapper around page_remove().
struct Env* env;
int return_code;
// LAB 4: Your code here.
panic("sys_page_unmap not implemented");
if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
if(!SYS_CHECKADDR(va)) return -E_INVAL;
page_remove(env->env_pgdir, va);
return 0;
}
// Try to send 'value' to the target env 'envid'.
@ -252,8 +306,38 @@ sys_page_unmap(envid_t envid, void *va)
static int
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
{
// LAB 4: Your code here.
panic("sys_ipc_try_send not implemented");
struct Env* dest_env;
struct Env* src_env;
int return_code;
if((return_code = envid2env(0, &src_env, 0)) < 0)
return return_code;
if((return_code = envid2env(envid, &dest_env, 0)) < 0)
return return_code;
if(!dest_env->env_ipc_recving)
return -E_IPC_NOT_RECV;
if((uintptr_t) srcva < UTOP && dest_env->env_ipc_dstva) {
if(!SYS_CHECKADDR(srcva)) return -E_INVAL;
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
pte_t* srcpte;
struct PageInfo* page = page_lookup(src_env->env_pgdir, srcva, &srcpte);
if(page == NULL) return -E_INVAL;
if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL;
page_insert(dest_env->env_pgdir, page, dest_env->env_ipc_dstva, perm);
dest_env->env_ipc_perm = perm;
}
dest_env->env_ipc_from = src_env->env_id;
dest_env->env_ipc_value = value;
dest_env->env_ipc_recving = false;
if(dest_env->env_status == ENV_NOT_RUNNABLE)
dest_env->env_status = ENV_RUNNABLE;
return 0;
}
// Block until a value is ready. Record that you want to receive
@ -270,8 +354,20 @@ sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm)
static int
sys_ipc_recv(void *dstva)
{
struct Env* env;
int return_code;
if((return_code = envid2env(0, &env, 1)) < 0)
return return_code;
// LAB 4: Your code here.
panic("sys_ipc_recv not implemented");
if((uintptr_t) dstva < UTOP) {
if(!SYS_CHECKADDR(dstva)) return -E_INVAL;
env->env_ipc_dstva = dstva;
}
env->env_ipc_recving = true;
env->env_status = ENV_NOT_RUNNABLE;
return 0;
}
@ -283,9 +379,35 @@ 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);
case SYS_yield:
sys_yield();
return 0;
case SYS_exofork:
return sys_exofork();
case SYS_env_set_status:
return sys_env_set_status(a1, a2);
case SYS_env_set_pgfault_upcall:
return sys_env_set_pgfault_upcall(a1, (void*) a2);
case SYS_page_alloc:
return sys_page_alloc(a1, (void*) a2, a3);
case SYS_page_map:
return sys_page_map(a1, (void*) a2, a3, (void*) a4, a5);
case SYS_page_unmap:
return sys_page_unmap(a1, (void*) a2);
case SYS_ipc_try_send:
return sys_ipc_try_send(a1, a2, (void*) a3, a4);
case SYS_ipc_recv:
return sys_ipc_recv((void*) a1);
default:
return -E_INVAL;
}

View File

@ -68,6 +68,33 @@ 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 irq_timer();
void irq_kbd();
void irq_serial();
void irq_spurious();
void irq_ide();
void irq_error();
void
trap_init(void)
@ -84,6 +111,33 @@ 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);
SETGATE(idt[IRQ_OFFSET + IRQ_TIMER], 0, GD_KT, irq_timer, 0);
SETGATE(idt[IRQ_OFFSET + IRQ_KBD], 0, GD_KT, irq_kbd, 0);
SETGATE(idt[IRQ_OFFSET + IRQ_SERIAL], 0, GD_KT, irq_serial, 0);
SETGATE(idt[IRQ_OFFSET + IRQ_SPURIOUS], 0, GD_KT, irq_spurious, 0);
SETGATE(idt[IRQ_OFFSET + IRQ_IDE], 0, GD_KT, irq_ide, 0);
SETGATE(idt[IRQ_OFFSET + IRQ_ERROR], 0, GD_KT, irq_error, 0);
// Per-CPU setup
trap_init_percpu();
@ -120,18 +174,18 @@ trap_init_percpu(void)
// Setup a TSS so that we get the right stack
// when we trap to the kernel.
ts.ts_esp0 = KSTACKTOP;
ts.ts_ss0 = GD_KD;
ts.ts_iomb = sizeof(struct Taskstate);
thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - thiscpu->cpu_id * (KSTKSIZE + KSTKGAP);
thiscpu->cpu_ts.ts_ss0 = GD_KD;
thiscpu->cpu_ts.ts_iomb = sizeof(struct Taskstate);
// Initialize the TSS slot of the gdt.
gdt[GD_TSS0 >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts),
sizeof(struct Taskstate) - 1, 0);
gdt[GD_TSS0 >> 3].sd_s = 0;
gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
// Load the TSS selector (like other segment selectors, the
// bottom three bits are special; we leave them 0)
ltr(GD_TSS0);
ltr(GD_TSS0 + (cpunum() << 3));
// Load the IDT
lidt(&idt_pd);
@ -188,6 +242,25 @@ 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;
} else if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) {
lapic_eoi();
sched_yield();
}
// Handle spurious interrupts
// The hardware sometimes raises these because of noise on the
@ -241,6 +314,7 @@ trap(struct Trapframe *tf)
// Acquire the big kernel lock before doing any
// serious kernel work.
// LAB 4: Your code here.
lock_kernel();
assert(curenv);
// Garbage collect if current enviroment is a zombie
@ -320,11 +394,39 @@ page_fault_handler(struct Trapframe *tf)
// (the 'tf' variable points at 'curenv->env_tf').
// LAB 4: Your code here.
if(!curenv->env_pgfault_upcall) {
// Destroy the environment that caused the fault.
cprintf("[%08x] user fault va %08x ip %08x\n",
curenv->env_id, fault_va, tf->tf_eip);
print_trapframe(tf);
env_destroy(curenv);
}
user_mem_assert(curenv, curenv->env_pgfault_upcall, 1, PTE_U | PTE_P);
user_mem_assert(curenv, (void*) UXSTACKTOP - 1, 1, PTE_U | PTE_P | PTE_W);
// Destroy the environment that caused the fault.
cprintf("[%08x] user fault va %08x ip %08x\n",
curenv->env_id, fault_va, tf->tf_eip);
print_trapframe(tf);
env_destroy(curenv);
uintptr_t top_addr = UXSTACKTOP;
if(tf->tf_esp <= UXSTACKTOP && tf->tf_esp >= (UXSTACKTOP - PGSIZE)) {
top_addr = tf->tf_esp - 4;
}
struct UTrapframe utf;
utf.utf_eflags = tf->tf_eflags;
utf.utf_eip = tf->tf_eip;
utf.utf_err = tf->tf_err;
utf.utf_esp = tf->tf_esp;
utf.utf_fault_va = fault_va;
utf.utf_regs = tf->tf_regs;
struct UTrapframe* push_to = (struct UTrapframe*) top_addr - 1;
if((uintptr_t) push_to < USTACKTOP - PGSIZE) {
cprintf("[%08x] stack overflow in page fault handler\n",
curenv->env_id);
env_destroy(curenv);
}
*push_to = utf;
curenv->env_tf.tf_eip = (uintptr_t) curenv->env_pgfault_upcall;
curenv->env_tf.tf_esp = (uintptr_t) push_to;
env_run(curenv);
}

View File

@ -44,9 +44,50 @@
.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);
TRAPHANDLER_NOEC(irq_timer, IRQ_OFFSET + IRQ_TIMER);
TRAPHANDLER_NOEC(irq_kbd, IRQ_OFFSET + IRQ_KBD);
TRAPHANDLER_NOEC(irq_serial, IRQ_OFFSET + IRQ_SERIAL);
TRAPHANDLER_NOEC(irq_spurious, IRQ_OFFSET + IRQ_SPURIOUS);
TRAPHANDLER_NOEC(irq_ide, IRQ_OFFSET + IRQ_IDE);
TRAPHANDLER_NOEC(irq_error, IRQ_OFFSET + IRQ_ERROR);
// HINT 1 : TRAPHANDLER_NOEC(t_divide, T_DIVIDE);
// Do something like this if there is no error code for the trap
@ -59,4 +100,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

View File

@ -23,18 +23,22 @@ pgfault(struct UTrapframe *utf)
// Hint:
// Use the read-only page table mappings at uvpt
// (see <inc/memlayout.h>).
// LAB 4: Your code here.
if(!((err & FEC_WR) && (uvpt[(uintptr_t) addr >> PGSHIFT] & PTE_COW)))
panic("page fault (addr %p)! %c", addr, (err & FEC_WR) ? 'w' : 'r');
// Allocate a new page, map it at a temporary location (PFTEMP),
// copy the data from the old page to the new page, then move the new
// page to the old page's address.
// Hint:
// You should make three system calls.
void* temp_addr = (void*) PFTEMP;
void* fault_addr = ROUNDDOWN(addr, PGSIZE);
if(sys_page_alloc(0, temp_addr, PTE_P | PTE_W | PTE_U) < 0)
panic("failed to allocate new page");
// LAB 4: Your code here.
panic("pgfault not implemented");
memcpy(temp_addr, fault_addr, PGSIZE);
sys_page_map(0, temp_addr, 0, fault_addr, PTE_P | PTE_U | PTE_W);
sys_page_unmap(0, temp_addr);
}
//
@ -52,9 +56,27 @@ static int
duppage(envid_t envid, unsigned pn)
{
int r;
bool change_own = false;
pte_t new_pte = uvpt[pn];
pte_t perms = new_pte & (PTE_P | PTE_U | PTE_W | PTE_AVAIL);
void* addr = (void*) (pn * PGSIZE);
// If we're writable, remove write permission
if((new_pte & PTE_W) || (new_pte & PTE_COW)) {
perms = (perms & ~PTE_W) | PTE_COW;
change_own = true;
}
// Map either with the same permissions or with COW.
if((r = sys_page_map(0, addr, envid, addr, perms)) < 0)
return r;
// Update our own permissions if necessary
if(change_own) {
if((r = sys_page_map(0, addr, 0, addr, perms)) < 0)
return r;
}
// LAB 4: Your code here.
panic("duppage not implemented");
return 0;
}
@ -77,8 +99,43 @@ duppage(envid_t envid, unsigned pn)
envid_t
fork(void)
{
// LAB 4: Your code here.
panic("fork not implemented");
set_pgfault_handler(pgfault);
int return_code;
envid_t forked;
forked = sys_exofork();
if(forked < 0) return forked;
if(forked == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; }
// Map all accessible page directory entries
for(int pde_i = 0; pde_i < PDX(UTOP); pde_i++) {
pde_t pde = uvpd[pde_i];
if(!(pde & PTE_P)) continue;
// For each PDE, map all the underlying PTEs
for(int pte_i = 0; pte_i < NPTENTRIES; pte_i++) {
int pn = pde_i * NPTENTRIES + pte_i;
pte_t pte = uvpt[pn];
if(!(pte & PTE_P)) continue;
// Do not map user exception stack, though
if(pn == ((UXSTACKTOP - PGSIZE) >> PGSHIFT)) continue;
if((return_code = duppage(forked, pn)) < 0) return return_code;
}
}
// Allocate new page for the exception stack
return_code = sys_page_alloc(forked, (void*) UXSTACKTOP - PGSIZE,
PTE_P | PTE_U | PTE_W);
if(return_code < 0) return return_code;
// Set the upcall entry point
sys_env_set_pgfault_upcall(forked, thisenv->env_pgfault_upcall);
sys_env_set_status(forked, ENV_RUNNABLE);
return forked;
}
// Challenge!

View File

@ -22,9 +22,14 @@
int32_t
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
{
// LAB 4: Your code here.
panic("ipc_recv not implemented");
return 0;
int return_code;
if((return_code = sys_ipc_recv(pg ? pg : (void*) ~0)) < 0)
return return_code;
if(from_env_store) *from_env_store = thisenv->env_ipc_from;
if(perm_store) *perm_store = thisenv->env_ipc_perm;
return thisenv->env_ipc_value;
}
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
@ -38,8 +43,12 @@ ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
void
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
{
// LAB 4: Your code here.
panic("ipc_send not implemented");
int return_code = -E_IPC_NOT_RECV;
while(return_code == -E_IPC_NOT_RECV) {
return_code = sys_ipc_try_send(to_env, val, pg ? pg : (void*) ~0, perm);
sys_yield();
}
if(return_code != 0) panic("failed to send\n");
}
// Find the first environment of the given type. We'll use this to

View File

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

View File

@ -65,18 +65,29 @@ _pgfault_upcall:
// ways as registers become unavailable as scratch space.
//
// LAB 4: Your code here.
mov 40(%esp), %eax // Take the EIP from memory
mov 48(%esp), %ebp // Take the ESP from memory
sub $4, %ebp // Push onto trap-time ESP
mov %eax, (%ebp)
mov %ebp, 48(%esp) // Put ESP back
// Restore the trap-time registers. After you do this, you
// can no longer modify any general-purpose registers.
// LAB 4: Your code here.
add $0x8, %esp
popal
// Restore eflags from the stack. After you do this, you can
// no longer use arithmetic operations or anything else that
// modifies eflags.
// LAB 4: Your code here.
add $0x4, %esp
popfl
// Switch back to the adjusted trap-time stack.
// LAB 4: Your code here.
pop %esp
// Return to re-execute the instruction that faulted.
// LAB 4: Your code here.
ret

View File

@ -27,9 +27,9 @@ set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
int r;
if (_pgfault_handler == 0) {
// First time through!
// LAB 4: Your code here.
panic("set_pgfault_handler not implemented");
if(sys_page_alloc(0, (void*) UXSTACKTOP - PGSIZE, PTE_U | PTE_P | PTE_W) < 0)
panic("set_pgfault_handler");
sys_env_set_pgfault_upcall(0, _pgfault_upcall);
}
// Save handler pointer for assembly to call.

View File

@ -214,11 +214,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

@ -2,6 +2,7 @@
#include <inc/syscall.h>
#include <inc/lib.h>
#include <inc/x86.h>
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,6 +38,20 @@ 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)
{

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

9
user/getc.c Normal file
View File

@ -0,0 +1,9 @@
#include <inc/lib.h>
void
umain(int argc, char **argv)
{
char c;
while(!(c = sys_cgetc()));
cprintf("got character %c\n", c);
}