Merge branch 'lab4' into lab5
This commit is contained in:
commit
e9f683f6d6
22
answers-lab2.txt
Normal file
22
answers-lab2.txt
Normal 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.
|
19
inc/x86.h
19
inc/x86.h
|
@ -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 */
|
||||
|
|
|
@ -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
49
kern/ansi.c
Normal 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
36
kern/ansi.h
Normal 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
|
|
@ -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))
|
||||
|
|
59
kern/env.c
59
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
15
kern/init.c
15
kern/init.c
|
@ -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 (;;);
|
||||
|
|
|
@ -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
|
||||
|
|
163
kern/monitor.c
163
kern/monitor.c
|
@ -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 *****/
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
159
kern/pmap.c
159
kern/pmap.c
|
@ -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;
|
||||
}
|
||||
|
|
19
kern/sched.c
19
kern/sched.c
|
@ -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"
|
||||
|
|
162
kern/syscall.c
162
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_exofork not implemented");
|
||||
error_code = env_alloc(&new_env, curenv->env_id);
|
||||
if(error_code < 0) return error_code;
|
||||
|
||||
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;
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_page_alloc not implemented");
|
||||
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
|
||||
if(!SYS_CHECKADDR(va)) return -E_INVAL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
124
kern/trap.c
124
kern/trap.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
75
lib/fork.c
75
lib/fork.c
|
@ -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!
|
||||
|
|
19
lib/ipc.c
19
lib/ipc.c
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
9
user/getc.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user