Skip to content

Commit 69ec007

Browse files
author
Cody Cutler
committed
lab4
1 parent d760ca9 commit 69ec007

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2686
-27
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
/lab?/
1616
/sol?/
1717
/myapi.key
18+
.suf

GNUmakefile

+3
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,12 @@ include lib/Makefrag
139139
include user/Makefrag
140140

141141

142+
CPUS ?= 1
143+
142144
QEMUOPTS = -hda $(OBJDIR)/kern/kernel.img -serial mon:stdio -gdb tcp::$(GDBPORT)
143145
QEMUOPTS += $(shell if $(QEMU) -nographic -help | grep -q '^-D '; then echo '-D qemu.log'; fi)
144146
IMAGES = $(OBJDIR)/kern/kernel.img
147+
QEMUOPTS += -smp $(CPUS)
145148
QEMUOPTS += $(QEMUEXTRA)
146149

147150
.gdbinit: .gdbinit.tmpl

conf/lab.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
LAB=3
2-
PACKAGEDATE=Wed Sep 3 09:38:39 EDT 2014
1+
LAB=4
2+
PACKAGEDATE=Wed Oct 8 09:40:26 EDT 2014

grade-lab4

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#!/usr/bin/env python
2+
3+
import re
4+
from gradelib import *
5+
6+
r = Runner(save("jos.out"),
7+
stop_breakpoint("readline"))
8+
9+
def E(s, trim=False):
10+
"""Expand $En in s to the environment ID of the n'th user
11+
environment."""
12+
13+
tmpl = "%x" if trim else "%08x"
14+
return re.sub(r"\$E([0-9]+)",
15+
lambda m: tmpl % (0x1000 + int(m.group(1))-1), s)
16+
17+
@test(5)
18+
def test_dumbfork():
19+
r.user_test("dumbfork")
20+
r.match(E(".00000000. new env $E1"),
21+
E(".$E1. new env $E2"),
22+
"0: I am the parent.",
23+
"9: I am the parent.",
24+
"0: I am the child.",
25+
"9: I am the child.",
26+
"19: I am the child.",
27+
E(".$E1. exiting gracefully"),
28+
E(".$E1. free env $E1"),
29+
E(".$E2. exiting gracefully"),
30+
E(".$E2. free env $E2"))
31+
32+
end_part("A")
33+
34+
@test(5)
35+
def test_faultread():
36+
r.user_test("faultread")
37+
r.match(E(".$E1. user fault va 00000000 ip 008....."),
38+
"TRAP frame at 0xf....... from CPU .",
39+
" trap 0x0000000e Page Fault",
40+
" err 0x00000004.*",
41+
E(".$E1. free env $E1"),
42+
no=["I read ........ from location 0."])
43+
44+
@test(5)
45+
def test_faultwrite():
46+
r.user_test("faultwrite")
47+
r.match(E(".$E1. user fault va 00000000 ip 008....."),
48+
"TRAP frame at 0xf....... from CPU .",
49+
" trap 0x0000000e Page Fault",
50+
" err 0x00000006.*",
51+
E(".$E1. free env $E1"))
52+
53+
@test(5)
54+
def test_faultdie():
55+
r.user_test("faultdie")
56+
r.match("i faulted at va deadbeef, err 6",
57+
E(".$E1. exiting gracefully"),
58+
E(".$E1. free env $E1"))
59+
60+
@test(5)
61+
def test_faultregs():
62+
r.user_test("faultregs")
63+
r.match("Registers in UTrapframe OK",
64+
"Registers after page-fault OK",
65+
no=["Registers in UTrapframe MISMATCH",
66+
"Registers after page-fault MISMATCH"])
67+
68+
@test(5)
69+
def test_faultalloc():
70+
r.user_test("faultalloc")
71+
r.match("fault deadbeef",
72+
"this string was faulted in at deadbeef",
73+
"fault cafebffe",
74+
"fault cafec000",
75+
"this string was faulted in at cafebffe",
76+
E(".$E1. exiting gracefully"),
77+
E(".$E1. free env $E1"))
78+
79+
@test(5)
80+
def test_faultallocbad():
81+
r.user_test("faultallocbad")
82+
r.match(E(".$E1. user_mem_check assertion failure for va deadbeef"),
83+
E(".$E1. free env $E1"))
84+
85+
@test(5)
86+
def test_faultnostack():
87+
r.user_test("faultnostack")
88+
r.match(E(".$E1. user_mem_check assertion failure for va eebfff.."),
89+
E(".$E1. free env $E1"))
90+
91+
@test(5)
92+
def test_faultbadhandler():
93+
r.user_test("faultbadhandler")
94+
r.match(E(".$E1. user_mem_check assertion failure for va (deadb|eebfe)..."),
95+
E(".$E1. free env $E1"))
96+
97+
@test(5)
98+
def test_faultevilhandler():
99+
r.user_test("faultevilhandler")
100+
r.match(E(".$E1. user_mem_check assertion failure for va (f0100|eebfe)..."),
101+
E(".$E1. free env $E1"))
102+
103+
@test(5)
104+
def test_forktree():
105+
r.user_test("forktree")
106+
r.match("....: I am .0.",
107+
"....: I am .1.",
108+
"....: I am .000.",
109+
"....: I am .100.",
110+
"....: I am .110.",
111+
"....: I am .111.",
112+
"....: I am .011.",
113+
"....: I am .001.",
114+
E(".$E1. exiting gracefully"),
115+
E(".$E2. exiting gracefully"),
116+
".0000200.. exiting gracefully",
117+
".0000200.. free env 0000200.")
118+
119+
end_part("B")
120+
121+
@test(5)
122+
def test_spin():
123+
r.user_test("spin")
124+
r.match(E(".00000000. new env $E1"),
125+
"I am the parent. Forking the child...",
126+
E(".$E1. new env $E2"),
127+
"I am the parent. Running the child...",
128+
"I am the child. Spinning...",
129+
"I am the parent. Killing the child...",
130+
E(".$E1. destroying $E2"),
131+
E(".$E1. free env $E2"),
132+
E(".$E1. exiting gracefully"),
133+
E(".$E1. free env $E1"))
134+
135+
@test(5)
136+
def test_stresssched():
137+
r.user_test("stresssched", make_args=["CPUS=4"])
138+
r.match(".000010... stresssched on CPU 0",
139+
".000010... stresssched on CPU 1",
140+
".000010... stresssched on CPU 2",
141+
".000010... stresssched on CPU 3",
142+
no=[".*ran on two CPUs at once"])
143+
144+
@test(5)
145+
def test_sendpage():
146+
r.user_test("sendpage", make_args=["CPUS=2"])
147+
r.match(".00000000. new env 00001000",
148+
E(".00000000. new env $E1"),
149+
E(".$E1. new env $E2"),
150+
E("$E1 got message: hello child environment! how are you?", trim=True),
151+
E("child received correct message", trim=True),
152+
E("$E2 got message: hello parent environment! I'm good", trim=True),
153+
E("parent received correct message", trim=True),
154+
E(".$E1. exiting gracefully"),
155+
E(".$E1. free env $E1"),
156+
E(".$E2. exiting gracefully"),
157+
E(".$E2. free env $E2"))
158+
159+
@test(5)
160+
def test_pingpong():
161+
r.user_test("pingpong", make_args=["CPUS=4"])
162+
r.match(E(".00000000. new env $E1"),
163+
E(".$E1. new env $E2"),
164+
E("send 0 from $E1 to $E2", trim=True),
165+
E("$E2 got 0 from $E1", trim=True),
166+
E("$E1 got 1 from $E2", trim=True),
167+
E("$E2 got 8 from $E1", trim=True),
168+
E("$E1 got 9 from $E2", trim=True),
169+
E("$E2 got 10 from $E1", trim=True),
170+
E(".$E1. exiting gracefully"),
171+
E(".$E1. free env $E1"),
172+
E(".$E2. exiting gracefully"),
173+
E(".$E2. free env $E2"))
174+
175+
@test(5)
176+
def test_primes():
177+
r.user_test("primes", stop_on_line("CPU .: 1877"), stop_on_line(".*panic"),
178+
make_args=["CPUS=4"], timeout=30)
179+
r.match(E(".00000000. new env $E1"),
180+
E(".$E1. new env $E2"),
181+
E("CPU .: 2 .$E2. new env $E3"),
182+
E("CPU .: 3 .$E3. new env $E4"),
183+
E("CPU .: 5 .$E4. new env $E5"),
184+
E("CPU .: 7 .$E5. new env $E6"),
185+
E("CPU .: 11 .$E6. new env $E7"),
186+
E("CPU .: 1877 .$E289. new env $E290"))
187+
188+
end_part("C")
189+
190+
run_tests()

inc/env.h

+11
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,20 @@ struct Env {
5151
enum EnvType env_type; // Indicates special system environments
5252
unsigned env_status; // Status of the environment
5353
uint32_t env_runs; // Number of times environment has run
54+
int env_cpunum; // The CPU that the env is running on
5455

5556
// Address space
5657
pde_t *env_pgdir; // Kernel virtual address of page dir
58+
59+
// Exception handling
60+
void *env_pgfault_upcall; // Page fault upcall entry point
61+
62+
// Lab 4 IPC
63+
bool env_ipc_recving; // Env is blocked receiving
64+
void *env_ipc_dstva; // VA at which to map received page
65+
uint32_t env_ipc_value; // Data value sent to us
66+
envid_t env_ipc_from; // envid of the sender
67+
int env_ipc_perm; // Perm of page mapping received
5768
};
5869

5970
#endif // !JOS_INC_ENV_H

inc/error.h

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ enum {
1515
E_FAULT = 6, // Memory fault
1616
E_NO_SYS = 7, // Unimplemented system call
1717

18+
E_IPC_NOT_RECV = 8, // Attempt to send to env that is not recving
19+
E_EOF = 9, // Unexpected end of file
20+
1821
MAXERROR
1922
};
2023

inc/lib.h

+37
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <inc/env.h>
1717
#include <inc/memlayout.h>
1818
#include <inc/syscall.h>
19+
#include <inc/trap.h>
1920

2021
#define USED(x) (void)(x)
2122

@@ -31,6 +32,9 @@ extern const volatile struct PageInfo pages[];
3132
// exit.c
3233
void exit(void);
3334

35+
// pgfault.c
36+
void set_pgfault_handler(void (*handler)(struct UTrapframe *utf));
37+
3438
// readline.c
3539
char* readline(const char *buf);
3640

@@ -39,6 +43,39 @@ void sys_cputs(const char *string, size_t len);
3943
int sys_cgetc(void);
4044
envid_t sys_getenvid(void);
4145
int sys_env_destroy(envid_t);
46+
void sys_yield(void);
47+
static envid_t sys_exofork(void);
48+
int sys_env_set_status(envid_t env, int status);
49+
int sys_env_set_pgfault_upcall(envid_t env, void *upcall);
50+
int sys_page_alloc(envid_t env, void *pg, int perm);
51+
int sys_page_map(envid_t src_env, void *src_pg,
52+
envid_t dst_env, void *dst_pg, int perm);
53+
int sys_page_unmap(envid_t env, void *pg);
54+
int sys_ipc_try_send(envid_t to_env, uint32_t value, void *pg, int perm);
55+
int sys_ipc_recv(void *rcv_pg);
56+
57+
// This must be inlined. Exercise for reader: why?
58+
static __inline envid_t __attribute__((always_inline))
59+
sys_exofork(void)
60+
{
61+
envid_t ret;
62+
__asm __volatile("int %2"
63+
: "=a" (ret)
64+
: "a" (SYS_exofork),
65+
"i" (T_SYSCALL)
66+
);
67+
return ret;
68+
}
69+
70+
// ipc.c
71+
void ipc_send(envid_t to_env, uint32_t value, void *pg, int perm);
72+
int32_t ipc_recv(envid_t *from_env_store, void *pg, int *perm_store);
73+
envid_t ipc_find_env(enum EnvType type);
74+
75+
// fork.c
76+
#define PTE_SHARE 0x400
77+
envid_t fork(void);
78+
envid_t sfork(void); // Challenge!
4279

4380

4481

inc/memlayout.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@
138138
// The location of the user-level STABS data structure
139139
#define USTABDATA (PTSIZE / 2)
140140

141+
// Physical address of startup code for non-boot CPUs (APs)
142+
#define MPENTRY_PADDR 0x7000
143+
141144
#ifndef __ASSEMBLER__
142145

143146
typedef uint32_t pte_t;
@@ -151,12 +154,12 @@ typedef uint32_t pde_t;
151154
*
152155
* One result of treating the page directory as a page table is that all PTEs
153156
* can be accessed through a "virtual page table" at virtual address UVPT (to
154-
* which uvpt is set in entry.S). The PTE for page number N is stored in
157+
* which uvpt is set in lib/entry.S). The PTE for page number N is stored in
155158
* uvpt[N]. (It's worth drawing a diagram of this!)
156159
*
157160
* A second consequence is that the contents of the current page directory
158161
* will always be available at virtual address (UVPT + (UVPT >> PGSHIFT)), to
159-
* which uvpd is set in entry.S.
162+
* which uvpd is set in lib/entry.S.
160163
*/
161164
extern volatile pte_t uvpt[]; // VA of "virtual page table"
162165
extern volatile pde_t uvpd[]; // VA of current page directory

inc/syscall.h

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ enum {
77
SYS_cgetc,
88
SYS_getenvid,
99
SYS_env_destroy,
10+
SYS_page_alloc,
11+
SYS_page_map,
12+
SYS_page_unmap,
13+
SYS_exofork,
14+
SYS_env_set_status,
15+
SYS_env_set_pgfault_upcall,
16+
SYS_yield,
17+
SYS_ipc_try_send,
18+
SYS_ipc_recv,
1019
NSYSCALLS
1120
};
1221

inc/trap.h

+11
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ struct Trapframe {
7474
uint16_t tf_padding4;
7575
} __attribute__((packed));
7676

77+
struct UTrapframe {
78+
/* information about the fault */
79+
uint32_t utf_fault_va; /* va for T_PGFLT, 0 otherwise */
80+
uint32_t utf_err;
81+
/* trap-time return state */
82+
struct PushRegs utf_regs;
83+
uintptr_t utf_eip;
84+
uint32_t utf_eflags;
85+
/* the trap-time stack to return to */
86+
uintptr_t utf_esp;
87+
} __attribute__((packed));
7788

7889
#endif /* !__ASSEMBLER__ */
7990

0 commit comments

Comments
 (0)