mirror of
https://github.com/SmallPond/MIT6.828_OS.git
synced 2026-07-05 03:18:01 +08:00
LAB 4 IS DONE.
This commit is contained in:
16
lab/user/Makefrag
Normal file
16
lab/user/Makefrag
Normal file
@@ -0,0 +1,16 @@
|
||||
OBJDIRS += user
|
||||
|
||||
|
||||
USERLIBS += jos
|
||||
|
||||
$(OBJDIR)/user/%.o: user/%.c $(OBJDIR)/.vars.USER_CFLAGS
|
||||
@echo + cc[USER] $<
|
||||
@mkdir -p $(@D)
|
||||
$(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/user/%: $(OBJDIR)/user/%.o $(OBJDIR)/lib/entry.o $(USERLIBS:%=$(OBJDIR)/lib/lib%.a) user/user.ld
|
||||
@echo + ld $@
|
||||
$(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/lib $(USERLIBS:%=-l%) $(GCC_LIB)
|
||||
$(V)$(OBJDUMP) -S $@ > $@.asm
|
||||
$(V)$(NM) -n $@ > $@.sym
|
||||
|
||||
11
lab/user/badsegment.c
Normal file
11
lab/user/badsegment.c
Normal file
@@ -0,0 +1,11 @@
|
||||
// program to cause a general protection exception
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
// Try to load the kernel's TSS selector into the DS register.
|
||||
asm volatile("movw $0x28,%ax; movw %ax,%ds");
|
||||
}
|
||||
|
||||
10
lab/user/breakpoint.c
Normal file
10
lab/user/breakpoint.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// program to cause a breakpoint trap
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
asm volatile("int $3");
|
||||
}
|
||||
|
||||
11
lab/user/buggyhello.c
Normal file
11
lab/user/buggyhello.c
Normal file
@@ -0,0 +1,11 @@
|
||||
// buggy hello world -- unmapped pointer passed to kernel
|
||||
// kernel should destroy user environment in response
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
sys_cputs((char*)1, 1);
|
||||
}
|
||||
|
||||
13
lab/user/buggyhello2.c
Normal file
13
lab/user/buggyhello2.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// buggy hello world 2 -- pointed-to region extends into unmapped memory
|
||||
// kernel should destroy user environment in response
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
const char *hello = "hello, world\n";
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
sys_cputs(hello, 1024*1024);
|
||||
}
|
||||
|
||||
13
lab/user/divzero.c
Normal file
13
lab/user/divzero.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// buggy program - causes a divide by zero exception
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
int zero;
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
zero = 0;
|
||||
cprintf("1/0 is %08x!\n", 1/zero);
|
||||
}
|
||||
|
||||
90
lab/user/dumbfork.c
Normal file
90
lab/user/dumbfork.c
Normal file
@@ -0,0 +1,90 @@
|
||||
// Ping-pong a counter between two processes.
|
||||
// Only need to start one of these -- splits into two, crudely.
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
envid_t dumbfork(void);
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
int i;
|
||||
|
||||
// fork a child process
|
||||
who = dumbfork();
|
||||
|
||||
// print a message and yield to the other a few times
|
||||
for (i = 0; i < (who ? 10 : 20); i++) {
|
||||
cprintf("%d: I am the %s!\n", i, who ? "parent" : "child");
|
||||
sys_yield();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
duppage(envid_t dstenv, void *addr)
|
||||
{
|
||||
int r;
|
||||
|
||||
// This is NOT what you should do in your fork.
|
||||
if ((r = sys_page_alloc(dstenv, addr, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_alloc: %e", r);
|
||||
// dstenv 的 addr 映射到 envs[0]的UTEMP,
|
||||
if ((r = sys_page_map(dstenv, addr, 0, UTEMP, PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("sys_page_map: %e", r);
|
||||
|
||||
memmove(UTEMP, addr, PGSIZE);
|
||||
if ((r = sys_page_unmap(0, UTEMP)) < 0)
|
||||
panic("sys_page_unmap: %e", r);
|
||||
}
|
||||
|
||||
envid_t
|
||||
dumbfork(void)
|
||||
{
|
||||
envid_t envid;
|
||||
uint8_t *addr;
|
||||
int r;
|
||||
extern unsigned char end[];
|
||||
|
||||
// Allocate a new child environment.
|
||||
// The kernel will initialize it with a copy of our register state,
|
||||
// so that the child will appear to have called sys_exofork() too -
|
||||
// except that in the child, this "fake" call to sys_exofork()
|
||||
// will return 0 instead of the envid of the child.
|
||||
envid = sys_exofork();
|
||||
cprintf("envid: %d\n",envid);
|
||||
if (envid < 0)
|
||||
panic("sys_exofork: %e", envid);
|
||||
if (envid == 0) {
|
||||
// We're the child.
|
||||
// The copied value of the global variable 'thisenv'
|
||||
// is no longer valid (it refers to the parent!).
|
||||
// Fix it and return 0.
|
||||
// "child, sysgetenvid() : 1
|
||||
// cprintf("child, sysgetenvid() :%d\n", ENVX(sys_getenvid()));
|
||||
thisenv = &envs[ENVX(sys_getenvid())];
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We're the parent.
|
||||
// Eagerly copy our entire address space into the child.
|
||||
// This is NOT what you should do in your fork implementation.
|
||||
// 用户程序通常从 UTEXT处开始。
|
||||
for (addr = (uint8_t*) UTEXT; addr < end; addr += PGSIZE) {
|
||||
// copying addr :00800000
|
||||
// copying addr :00801000
|
||||
// copying addr :00802000
|
||||
cprintf("copying addr :%08x\n", (uint32_t)addr);
|
||||
duppage(envid, addr);
|
||||
}
|
||||
// Also copy the stack we are currently running on.
|
||||
duppage(envid, ROUNDDOWN(&addr, PGSIZE));
|
||||
|
||||
// Start the child environment running
|
||||
if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
|
||||
panic("sys_env_set_status: %e", r);
|
||||
|
||||
return envid;
|
||||
}
|
||||
|
||||
12
lab/user/evilhello.c
Normal file
12
lab/user/evilhello.c
Normal file
@@ -0,0 +1,12 @@
|
||||
// evil hello world -- kernel pointer passed to kernel
|
||||
// kernel should destroy user environment in response
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
// try to print the kernel entry point as a string! mua ha ha!
|
||||
sys_cputs((char*)0xf010000c, 100);
|
||||
}
|
||||
|
||||
25
lab/user/fairness.c
Normal file
25
lab/user/fairness.c
Normal file
@@ -0,0 +1,25 @@
|
||||
// Demonstrate lack of fairness in IPC.
|
||||
// Start three instances of this program as envs 1, 2, and 3.
|
||||
// (user/idle is env 0).
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who, id;
|
||||
|
||||
id = sys_getenvid();
|
||||
|
||||
if (thisenv == &envs[1]) {
|
||||
while (1) {
|
||||
ipc_recv(&who, 0, 0);
|
||||
cprintf("%x recv from %x\n", id, who);
|
||||
}
|
||||
} else {
|
||||
cprintf("%x loop sending to %x\n", id, envs[1].env_id);
|
||||
while (1)
|
||||
ipc_send(envs[1].env_id, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
24
lab/user/faultalloc.c
Normal file
24
lab/user/faultalloc.c
Normal file
@@ -0,0 +1,24 @@
|
||||
// test user-level fault handler -- alloc pages to fix faults
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
handler(struct UTrapframe *utf)
|
||||
{
|
||||
int r;
|
||||
void *addr = (void*)utf->utf_fault_va;
|
||||
|
||||
cprintf("fault %x\n", addr);
|
||||
if ((r = sys_page_alloc(0, ROUNDDOWN(addr, PGSIZE),
|
||||
PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("allocating at %x in page fault handler: %e", addr, r);
|
||||
snprintf((char*) addr, 100, "this string was faulted in at %x", addr);
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
set_pgfault_handler(handler);
|
||||
cprintf("%s\n", (char*)0xDeadBeef);
|
||||
cprintf("%s\n", (char*)0xCafeBffe);
|
||||
}
|
||||
24
lab/user/faultallocbad.c
Normal file
24
lab/user/faultallocbad.c
Normal file
@@ -0,0 +1,24 @@
|
||||
// test user-level fault handler -- alloc pages to fix faults
|
||||
// doesn't work because we sys_cputs instead of cprintf (exercise: why?)
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
handler(struct UTrapframe *utf)
|
||||
{
|
||||
int r;
|
||||
void *addr = (void*)utf->utf_fault_va;
|
||||
|
||||
cprintf("fault %x\n", addr);
|
||||
if ((r = sys_page_alloc(0, ROUNDDOWN(addr, PGSIZE),
|
||||
PTE_P|PTE_U|PTE_W)) < 0)
|
||||
panic("allocating at %x in page fault handler: %e", addr, r);
|
||||
snprintf((char*) addr, 100, "this string was faulted in at %x", addr);
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
set_pgfault_handler(handler);
|
||||
sys_cputs((char*)0xDEADBEEF, 4);
|
||||
}
|
||||
14
lab/user/faultbadhandler.c
Normal file
14
lab/user/faultbadhandler.c
Normal file
@@ -0,0 +1,14 @@
|
||||
// test bad pointer for user-level fault handler
|
||||
// this is going to fault in the fault handler accessing eip (always!)
|
||||
// so eventually the kernel kills it (PFM_KILL) because
|
||||
// we outrun the stack with invocations of the user-level handler
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
sys_page_alloc(0, (void*) (UXSTACKTOP - PGSIZE), PTE_P|PTE_U|PTE_W);
|
||||
sys_env_set_pgfault_upcall(0, (void*) 0xDeadBeef);
|
||||
*(int*)0 = 0;
|
||||
}
|
||||
19
lab/user/faultdie.c
Normal file
19
lab/user/faultdie.c
Normal file
@@ -0,0 +1,19 @@
|
||||
// test user-level fault handler -- just exit when we fault
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
handler(struct UTrapframe *utf)
|
||||
{
|
||||
void *addr = (void*)utf->utf_fault_va;
|
||||
uint32_t err = utf->utf_err;
|
||||
cprintf("i faulted at va %x, err %x\n", addr, err & 7);
|
||||
sys_env_destroy(sys_getenvid());
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
set_pgfault_handler(handler);
|
||||
*(int*)0xDeadBeef = 0;
|
||||
}
|
||||
11
lab/user/faultevilhandler.c
Normal file
11
lab/user/faultevilhandler.c
Normal file
@@ -0,0 +1,11 @@
|
||||
// test evil pointer for user-level fault handler
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
sys_page_alloc(0, (void*) (UXSTACKTOP - PGSIZE), PTE_P|PTE_U|PTE_W);
|
||||
sys_env_set_pgfault_upcall(0, (void*) 0xF0100020);
|
||||
*(int*)0 = 0;
|
||||
}
|
||||
12
lab/user/faultnostack.c
Normal file
12
lab/user/faultnostack.c
Normal file
@@ -0,0 +1,12 @@
|
||||
// test user fault handler being called with no exception stack mapped
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void _pgfault_upcall();
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
sys_env_set_pgfault_upcall(0, (void*) _pgfault_upcall);
|
||||
*(int*)0 = 0;
|
||||
}
|
||||
10
lab/user/faultread.c
Normal file
10
lab/user/faultread.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// buggy program - faults with a read from location zero
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
cprintf("I read %08x from location 0!\n", *(unsigned*)0);
|
||||
}
|
||||
|
||||
10
lab/user/faultreadkernel.c
Normal file
10
lab/user/faultreadkernel.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// buggy program - faults with a read from kernel space
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
cprintf("I read %08x from location 0xf0100000!\n", *(unsigned*)0xf0100000);
|
||||
}
|
||||
|
||||
146
lab/user/faultregs.c
Normal file
146
lab/user/faultregs.c
Normal file
@@ -0,0 +1,146 @@
|
||||
// test register restore on user-level page fault return
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
struct regs
|
||||
{
|
||||
struct PushRegs regs;
|
||||
uintptr_t eip;
|
||||
uint32_t eflags;
|
||||
uintptr_t esp;
|
||||
};
|
||||
|
||||
#define SAVE_REGS(base) \
|
||||
"\tmovl %%edi, "base"+0x00\n" \
|
||||
"\tmovl %%esi, "base"+0x04\n" \
|
||||
"\tmovl %%ebp, "base"+0x08\n" \
|
||||
"\tmovl %%ebx, "base"+0x10\n" \
|
||||
"\tmovl %%edx, "base"+0x14\n" \
|
||||
"\tmovl %%ecx, "base"+0x18\n" \
|
||||
"\tmovl %%eax, "base"+0x1c\n" \
|
||||
"\tmovl %%esp, "base"+0x28\n"
|
||||
|
||||
#define LOAD_REGS(base) \
|
||||
"\tmovl "base"+0x00, %%edi\n" \
|
||||
"\tmovl "base"+0x04, %%esi\n" \
|
||||
"\tmovl "base"+0x08, %%ebp\n" \
|
||||
"\tmovl "base"+0x10, %%ebx\n" \
|
||||
"\tmovl "base"+0x14, %%edx\n" \
|
||||
"\tmovl "base"+0x18, %%ecx\n" \
|
||||
"\tmovl "base"+0x1c, %%eax\n" \
|
||||
"\tmovl "base"+0x28, %%esp\n"
|
||||
|
||||
static struct regs before, during, after;
|
||||
|
||||
static void
|
||||
check_regs(struct regs* a, const char *an, struct regs* b, const char *bn,
|
||||
const char *testname)
|
||||
{
|
||||
int mismatch = 0;
|
||||
|
||||
cprintf("%-6s %-8s %-8s\n", "", an, bn);
|
||||
|
||||
#define CHECK(name, field) \
|
||||
do { \
|
||||
cprintf("%-6s %08x %08x ", #name, a->field, b->field); \
|
||||
if (a->field == b->field) \
|
||||
cprintf("OK\n"); \
|
||||
else { \
|
||||
cprintf("MISMATCH\n"); \
|
||||
mismatch = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
CHECK(edi, regs.reg_edi);
|
||||
CHECK(esi, regs.reg_esi);
|
||||
CHECK(ebp, regs.reg_ebp);
|
||||
CHECK(ebx, regs.reg_ebx);
|
||||
CHECK(edx, regs.reg_edx);
|
||||
CHECK(ecx, regs.reg_ecx);
|
||||
CHECK(eax, regs.reg_eax);
|
||||
CHECK(eip, eip);
|
||||
CHECK(eflags, eflags);
|
||||
CHECK(esp, esp);
|
||||
|
||||
#undef CHECK
|
||||
|
||||
cprintf("Registers %s ", testname);
|
||||
if (!mismatch)
|
||||
cprintf("OK\n");
|
||||
else
|
||||
cprintf("MISMATCH\n");
|
||||
}
|
||||
|
||||
static void
|
||||
pgfault(struct UTrapframe *utf)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (utf->utf_fault_va != (uint32_t)UTEMP)
|
||||
panic("pgfault expected at UTEMP, got 0x%08x (eip %08x)",
|
||||
utf->utf_fault_va, utf->utf_eip);
|
||||
|
||||
// Check registers in UTrapframe
|
||||
during.regs = utf->utf_regs;
|
||||
during.eip = utf->utf_eip;
|
||||
during.eflags = utf->utf_eflags & ~FL_RF;
|
||||
during.esp = utf->utf_esp;
|
||||
check_regs(&before, "before", &during, "during", "in UTrapframe");
|
||||
|
||||
// Map UTEMP so the write succeeds
|
||||
if ((r = sys_page_alloc(0, UTEMP, PTE_U|PTE_P|PTE_W)) < 0)
|
||||
panic("sys_page_alloc: %e", r);
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
set_pgfault_handler(pgfault);
|
||||
|
||||
asm volatile(
|
||||
// Light up eflags to catch more errors
|
||||
"\tpushl %%eax\n"
|
||||
"\tpushfl\n"
|
||||
"\tpopl %%eax\n"
|
||||
"\torl $0x8d5, %%eax\n"
|
||||
"\tpushl %%eax\n"
|
||||
"\tpopfl\n"
|
||||
|
||||
// Save before registers
|
||||
// eflags
|
||||
"\tmov %%eax, %0+0x24\n"
|
||||
// eip
|
||||
"\tleal 0f, %%eax\n"
|
||||
"\tmovl %%eax, %0+0x20\n"
|
||||
"\tpopl %%eax\n"
|
||||
// others
|
||||
SAVE_REGS("%0")
|
||||
|
||||
// Fault at UTEMP
|
||||
"\t0: movl $42, 0x400000\n"
|
||||
|
||||
// Save after registers (except eip and eflags)
|
||||
SAVE_REGS("%1")
|
||||
// Restore registers (except eip and eflags). This
|
||||
// way, the test will run even if EIP is the *only*
|
||||
// thing restored correctly.
|
||||
LOAD_REGS("%0")
|
||||
// Save after eflags (now that stack is back); note
|
||||
// that we were very careful not to modify eflags in
|
||||
// since we saved it
|
||||
"\tpushl %%eax\n"
|
||||
"\tpushfl\n"
|
||||
"\tpopl %%eax\n"
|
||||
"\tmov %%eax, %1+0x24\n"
|
||||
"\tpopl %%eax\n"
|
||||
: : "m" (before), "m" (after) : "memory", "cc");
|
||||
|
||||
// Check UTEMP to roughly determine that EIP was restored
|
||||
// correctly (of course, we probably wouldn't get this far if
|
||||
// it weren't)
|
||||
if (*(int*)UTEMP != 42)
|
||||
cprintf("EIP after page-fault MISMATCH\n");
|
||||
after.eip = before.eip;
|
||||
|
||||
check_regs(&before, "before", &after, "after", "after page-fault");
|
||||
}
|
||||
10
lab/user/faultwrite.c
Normal file
10
lab/user/faultwrite.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// buggy program - faults with a write to location zero
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
*(unsigned*)0 = 0;
|
||||
}
|
||||
|
||||
10
lab/user/faultwritekernel.c
Normal file
10
lab/user/faultwritekernel.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// buggy program - faults with a write to a kernel location
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
*(unsigned*)0xf0100000 = 0;
|
||||
}
|
||||
|
||||
38
lab/user/forktree.c
Normal file
38
lab/user/forktree.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// Fork a binary tree of processes and display their structure.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
#define DEPTH 3
|
||||
|
||||
void forktree(const char *cur);
|
||||
|
||||
void
|
||||
forkchild(const char *cur, char branch)
|
||||
{
|
||||
char nxt[DEPTH+1];
|
||||
|
||||
if (strlen(cur) >= DEPTH)
|
||||
return;
|
||||
|
||||
snprintf(nxt, DEPTH+1, "%s%c", cur, branch);
|
||||
if (fork() == 0) {
|
||||
forktree(nxt);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
forktree(const char *cur)
|
||||
{
|
||||
cprintf("%04x: I am '%s'\n", sys_getenvid(), cur);
|
||||
|
||||
forkchild(cur, '0');
|
||||
forkchild(cur, '1');
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
forktree("");
|
||||
}
|
||||
|
||||
9
lab/user/hello.c
Normal file
9
lab/user/hello.c
Normal file
@@ -0,0 +1,9 @@
|
||||
// hello, world
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
cprintf("hello, world\n");
|
||||
cprintf("i am environment %08x\n", thisenv->env_id);
|
||||
}
|
||||
20
lab/user/idle.c
Normal file
20
lab/user/idle.c
Normal file
@@ -0,0 +1,20 @@
|
||||
// idle loop
|
||||
|
||||
#include <inc/x86.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
binaryname = "idle";
|
||||
|
||||
// Loop forever, simply trying to yield to a different environment.
|
||||
// Instead of busy-waiting like this,
|
||||
// a better way would be to use the processor's HLT instruction
|
||||
// to cause the processor to stop executing until the next interrupt -
|
||||
// doing so allows the processor to conserve power more effectively.
|
||||
while (1) {
|
||||
sys_yield();
|
||||
}
|
||||
}
|
||||
|
||||
29
lab/user/pingpong.c
Normal file
29
lab/user/pingpong.c
Normal file
@@ -0,0 +1,29 @@
|
||||
// Ping-pong a counter between two processes.
|
||||
// Only need to start one of these -- splits into two with fork.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
|
||||
if ((who = fork()) != 0) {
|
||||
// get the ball rolling
|
||||
cprintf("send 0 from %x to %x\n", sys_getenvid(), who);
|
||||
ipc_send(who, 0, 0, 0);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
uint32_t i = ipc_recv(&who, 0, 0);
|
||||
cprintf("%x got %d from %x\n", sys_getenvid(), i, who);
|
||||
if (i == 10)
|
||||
return;
|
||||
i++;
|
||||
ipc_send(who, i, 0, 0);
|
||||
if (i == 10)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
33
lab/user/pingpongs.c
Normal file
33
lab/user/pingpongs.c
Normal file
@@ -0,0 +1,33 @@
|
||||
// Ping-pong a counter between two shared-memory processes.
|
||||
// Only need to start one of these -- splits into two with sfork.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
uint32_t val;
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
uint32_t i;
|
||||
|
||||
i = 0;
|
||||
if ((who = sfork()) != 0) {
|
||||
cprintf("i am %08x; thisenv is %p\n", sys_getenvid(), thisenv);
|
||||
// get the ball rolling
|
||||
cprintf("send 0 from %x to %x\n", sys_getenvid(), who);
|
||||
ipc_send(who, 0, 0, 0);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ipc_recv(&who, 0, 0);
|
||||
cprintf("%x got %d from %x (thisenv is %p %x)\n", sys_getenvid(), val, who, thisenv, thisenv->env_id);
|
||||
if (val == 10)
|
||||
return;
|
||||
++val;
|
||||
ipc_send(who, 0, 0, 0);
|
||||
if (val == 10)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
53
lab/user/primes.c
Normal file
53
lab/user/primes.c
Normal file
@@ -0,0 +1,53 @@
|
||||
// Concurrent version of prime sieve of Eratosthenes.
|
||||
// Invented by Doug McIlroy, inventor of Unix pipes.
|
||||
// See http://swtch.com/~rsc/thread/.
|
||||
// The picture halfway down the page and the text surrounding it
|
||||
// explain what's going on here.
|
||||
//
|
||||
// Since NENV is 1024, we can print 1022 primes before running out.
|
||||
// The remaining two environments are the integer generator at the bottom
|
||||
// of main and user/idle.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
unsigned
|
||||
primeproc(void)
|
||||
{
|
||||
int i, id, p;
|
||||
envid_t envid;
|
||||
|
||||
// fetch a prime from our left neighbor
|
||||
top:
|
||||
p = ipc_recv(&envid, 0, 0);
|
||||
cprintf("CPU %d: %d ", thisenv->env_cpunum, p);
|
||||
|
||||
// fork a right neighbor to continue the chain
|
||||
if ((id = fork()) < 0)
|
||||
panic("fork: %e", id);
|
||||
if (id == 0)
|
||||
goto top;
|
||||
|
||||
// filter out multiples of our prime
|
||||
while (1) {
|
||||
i = ipc_recv(&envid, 0, 0);
|
||||
if (i % p)
|
||||
ipc_send(id, i, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int i, id;
|
||||
|
||||
// fork the first prime process in the chain
|
||||
if ((id = fork()) < 0)
|
||||
panic("fork: %e", id);
|
||||
if (id == 0)
|
||||
primeproc();
|
||||
|
||||
// feed all the integers through
|
||||
for (i = 2; ; i++)
|
||||
ipc_send(id, i, 0, 0);
|
||||
}
|
||||
|
||||
39
lab/user/sendpage.c
Normal file
39
lab/user/sendpage.c
Normal file
@@ -0,0 +1,39 @@
|
||||
// Test Conversation between parent and child environment
|
||||
// Contributed by Varun Agrawal at Stony Brook
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
const char *str1 = "hello child environment! how are you?";
|
||||
const char *str2 = "hello parent environment! I'm good.";
|
||||
|
||||
#define TEMP_ADDR ((char*)0xa00000)
|
||||
#define TEMP_ADDR_CHILD ((char*)0xb00000)
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t who;
|
||||
|
||||
if ((who = fork()) == 0) {
|
||||
// Child
|
||||
ipc_recv(&who, TEMP_ADDR_CHILD, 0);
|
||||
cprintf("%x got message: %s\n", who, TEMP_ADDR_CHILD);
|
||||
if (strncmp(TEMP_ADDR_CHILD, str1, strlen(str1)) == 0)
|
||||
cprintf("child received correct message\n");
|
||||
|
||||
memcpy(TEMP_ADDR_CHILD, str2, strlen(str2) + 1);
|
||||
ipc_send(who, 0, TEMP_ADDR_CHILD, PTE_P | PTE_W | PTE_U);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parent
|
||||
sys_page_alloc(thisenv->env_id, TEMP_ADDR, PTE_P | PTE_W | PTE_U);
|
||||
memcpy(TEMP_ADDR, str1, strlen(str1) + 1);
|
||||
ipc_send(who, 0, TEMP_ADDR, PTE_P | PTE_W | PTE_U);
|
||||
|
||||
ipc_recv(&who, TEMP_ADDR, 0);
|
||||
cprintf("%x got message: %s\n", who, TEMP_ADDR);
|
||||
if (strncmp(TEMP_ADDR, str2, strlen(str2)) == 0)
|
||||
cprintf("parent received correct message\n");
|
||||
return;
|
||||
}
|
||||
10
lab/user/softint.c
Normal file
10
lab/user/softint.c
Normal file
@@ -0,0 +1,10 @@
|
||||
// buggy program - causes an illegal software interrupt
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
asm volatile("int $14"); // page fault
|
||||
}
|
||||
|
||||
31
lab/user/spin.c
Normal file
31
lab/user/spin.c
Normal file
@@ -0,0 +1,31 @@
|
||||
// Test preemption by forking off a child process that just spins forever.
|
||||
// Let it run for a couple time slices, then kill it.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
envid_t env;
|
||||
|
||||
cprintf("I am the parent. Forking the child...\n");
|
||||
if ((env = fork()) == 0) {
|
||||
cprintf("I am the child. Spinning...\n");
|
||||
while (1)
|
||||
/* do nothing */;
|
||||
}
|
||||
|
||||
cprintf("I am the parent. Running the child...\n");
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
sys_yield();
|
||||
|
||||
cprintf("I am the parent. Killing the child...\n");
|
||||
sys_env_destroy(env);
|
||||
}
|
||||
|
||||
39
lab/user/stresssched.c
Normal file
39
lab/user/stresssched.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <inc/lib.h>
|
||||
|
||||
volatile int counter;
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
int seen;
|
||||
envid_t parent = sys_getenvid();
|
||||
|
||||
// Fork several environments
|
||||
for (i = 0; i < 20; i++)
|
||||
if (fork() == 0)
|
||||
break;
|
||||
if (i == 20) {
|
||||
sys_yield();
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the parent to finish forking
|
||||
while (envs[ENVX(parent)].env_status != ENV_FREE)
|
||||
asm volatile("pause");
|
||||
|
||||
// Check that one environment doesn't run on two CPUs at once
|
||||
for (i = 0; i < 10; i++) {
|
||||
sys_yield();
|
||||
for (j = 0; j < 10000; j++)
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter != 10*10000)
|
||||
panic("ran on two CPUs at once (counter is %d)", counter);
|
||||
|
||||
// Check that we see environments running on different CPUs
|
||||
cprintf("[%08x] stresssched on CPU %d\n", thisenv->env_id, thisenv->env_cpunum);
|
||||
|
||||
}
|
||||
|
||||
27
lab/user/testbss.c
Normal file
27
lab/user/testbss.c
Normal file
@@ -0,0 +1,27 @@
|
||||
// test reads and writes to a large bss
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
#define ARRAYSIZE (1024*1024)
|
||||
|
||||
uint32_t bigarray[ARRAYSIZE];
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
cprintf("Making sure bss works right...\n");
|
||||
for (i = 0; i < ARRAYSIZE; i++)
|
||||
if (bigarray[i] != 0)
|
||||
panic("bigarray[%d] isn't cleared!\n", i);
|
||||
for (i = 0; i < ARRAYSIZE; i++)
|
||||
bigarray[i] = i;
|
||||
for (i = 0; i < ARRAYSIZE; i++)
|
||||
if (bigarray[i] != i)
|
||||
panic("bigarray[%d] didn't hold its value!\n", i);
|
||||
|
||||
cprintf("Yes, good. Now doing a wild write off the end...\n");
|
||||
bigarray[ARRAYSIZE+1024] = 0;
|
||||
panic("SHOULD HAVE TRAPPED!!!");
|
||||
}
|
||||
72
lab/user/user.ld
Normal file
72
lab/user/user.ld
Normal file
@@ -0,0 +1,72 @@
|
||||
/* Simple linker script for JOS user-level programs.
|
||||
See the GNU ld 'info' manual ("info ld") to learn the syntax. */
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Load programs at this address: "." means the current address */
|
||||
. = 0x800020;
|
||||
|
||||
.text : {
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
}
|
||||
|
||||
PROVIDE(etext = .); /* Define the 'etext' symbol to this value */
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.* .gnu.linkonce.r.*)
|
||||
}
|
||||
|
||||
/* Adjust the address for the data segment to the next page */
|
||||
. = ALIGN(0x1000);
|
||||
|
||||
.data : {
|
||||
*(.data)
|
||||
}
|
||||
|
||||
PROVIDE(edata = .);
|
||||
|
||||
.bss : {
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
PROVIDE(end = .);
|
||||
|
||||
|
||||
/* Place debugging symbols so that they can be found by
|
||||
* the kernel debugger.
|
||||
* Specifically, the four words at 0x200000 mark the beginning of
|
||||
* the stabs, the end of the stabs, the beginning of the stabs
|
||||
* string table, and the end of the stabs string table, respectively.
|
||||
*/
|
||||
|
||||
.stab_info 0x200000 : {
|
||||
LONG(__STAB_BEGIN__);
|
||||
LONG(__STAB_END__);
|
||||
LONG(__STABSTR_BEGIN__);
|
||||
LONG(__STABSTR_END__);
|
||||
}
|
||||
|
||||
.stab : {
|
||||
__STAB_BEGIN__ = DEFINED(__STAB_BEGIN__) ? __STAB_BEGIN__ : .;
|
||||
*(.stab);
|
||||
__STAB_END__ = DEFINED(__STAB_END__) ? __STAB_END__ : .;
|
||||
BYTE(0) /* Force the linker to allocate space
|
||||
for this section */
|
||||
}
|
||||
|
||||
.stabstr : {
|
||||
__STABSTR_BEGIN__ = DEFINED(__STABSTR_BEGIN__) ? __STABSTR_BEGIN__ : .;
|
||||
*(.stabstr);
|
||||
__STABSTR_END__ = DEFINED(__STABSTR_END__) ? __STABSTR_END__ : .;
|
||||
BYTE(0) /* Force the linker to allocate space
|
||||
for this section */
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame .note.GNU-stack .comment)
|
||||
}
|
||||
}
|
||||
17
lab/user/yield.c
Normal file
17
lab/user/yield.c
Normal file
@@ -0,0 +1,17 @@
|
||||
// yield the processor to other environments
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
umain(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
cprintf("Hello, I am environment %08x.\n", thisenv->env_id);
|
||||
for (i = 0; i < 5; i++) {
|
||||
sys_yield();
|
||||
cprintf("Back in environment %08x, iteration %d.\n",
|
||||
thisenv->env_id, i);
|
||||
}
|
||||
cprintf("All done in environment %08x.\n", thisenv->env_id);
|
||||
}
|
||||
Reference in New Issue
Block a user