@@ -0,0 +1,341 @@
1// sumtest: checks the kernel's direct copies to and from user
2// memory (copyin, copyout and copyinstr with sstatus.SUM).
3//
4// sumtest run the checks
5// sumtest time count copies per 20 ticks
6
7#include "kernel/types.h"
8#include "kernel/stat.h"
9#include "kernel/fcntl.h"
10#include "kernel/memlayout.h"
11#include "kernel/riscv.h"
12#include "user/user.h"
13
14char data[100] = "initialized data, copied by the kernel"; 15
16static int
18{
19 printf("sumtest: %s\n", what); 20 return 1;
21}
22
23// pass n bytes from src through a pipe into dst.
24// returns read()'s result.
25static int
26viapipe(char *dst, char *src, int n)
27{
28 int fds[2], r;
29
31 return -1;
32 if (write(fds[1], src, n) != n) { 35 return -1;
36 }
37 r = read(fds[0], dst, n); 40 return r;
41}
42
43// the kernel copies from and to the stack, data and heap.
44int
45copytest(void)
46{
47 char stack[100];
50 char *edge = heap + PGSIZE - 3; // 6 bytes across a page boundary 51 int fd;
52
54 return fail("sbrk failed"); 55 if (viapipe(stack, data, 100) != 100 || memcmp(stack, data, 100) != 0) 56 return fail("data -> pipe -> stack"); 57 if (viapipe(heap, stack, 100) != 100 || memcmp(heap, data, 100) != 0) 58 return fail("stack -> pipe -> heap"); 59 if (viapipe(edge, "abcdef", 6) != 6 || memcmp(edge, "abcdef", 6) != 0) 60 return fail("pipe -> across a page boundary"); 61
63 if (fd < 0 || write(fd, edge, 6) != 6) 64 return fail("write from across a page boundary"); 67 if (fd < 0 || fstat(fd, &st) < 0 || st.size != 6) 69 if (read(fd, stack, 6) != 6 || memcmp(stack, "abcdef", 6) != 0) 70 return fail("file -> stack"); 74 return 0;
75}
76
77// pages reserved with sbrklazy: the kernel's own access takes
78// the page fault.
79int
80lazytest(void)
81{
85 int fd;
86
88 return fail("sbrklazy failed"); 89 // copyout into a page nobody has touched
90 if (viapipe(p + PGSIZE + 10, "hello", 6) != 6 || 92 return fail("read() into an untouched lazy page"); 93 // copyin from a page nobody has touched: zeros
95 if (viapipe(buf, p + 2 * PGSIZE, 8) != 8 || 97 return fail("write() from an untouched lazy page"); 99 // copyinstr from an untouched page: the name "", which
100 // open() takes to mean the current directory
104 return fail("open() of a name in an untouched lazy page"); 107 return 0;
108}
109
110// every one of these addresses must be refused, in both
111// directions, and the kernel must survive.
112int
113badtest(void)
114{
115 char c;
118 struct {
120 char *what;
122 {0x80000000L, "kernel text (KERNBASE)"},
124 {0x0c000000L, "the PLIC"},
125 {0x10000000L, "the UART"},
126 {stackpage - PGSIZE, "the stack guard page"}, 127 {end, "the first byte beyond sbrk(0)"}, 129 {0xffffffffffffffffL, "the last address"},
130 };
131 int fd, fds[2], n, bads = 0;
133
134 for (int i = 0; i < sizeof(bad) / sizeof(bad[0]); i++) { 136
137 // copyout
139 if ((n = read(fd, a, 16)) > 0) { 140 printf("sumtest: read(fd, %p) into %s returned %d\n", a, bad[i].what, n); 141 bads++;
142 }
144 // copyin
146 return fail("pipe failed"); 147 if ((n = write(fds[1], a, 16)) > 0) { 149 printf("sumtest: write(pipe, %p) from %s returned %d\n", a, bad[i].what, 150 n);
151 bads++;
152 }
155 // copyinstr
157 printf("sumtest: open(%p) of %s returned %d\n", a, bad[i].what, fd); 159 bads++;
160 }
161 }
162
163 // a range that starts below sbrk(0) and ends beyond it: the
164 // kernel copies the 1 valid byte, then stops
166 return fail("pipe failed"); 167 if ((n = write(fds[1], (char *)end - 1, 16)) > 1) { 168 printf("sumtest: write(pipe, sbrk(0) - 1, 16) returned %d\n", n); 169 bads++;
170 }
173
174 // text is readable but not writable
176 if ((n = read(fd, (char *)fail, 16)) > 0) { 177 printf("sumtest: read() into the code of fail() returned %d\n", n); 178 bads++;
179 }
182 printf("sumtest: write() from the code of fail() failed\n"); 183 bads++;
184 }
185 return bads != 0;
186}
187
188// after sbrk(-n), the kernel must not reach the old pages.
189int
190shrinktest(void)
191{
193
195 return fail("sbrk failed"); 197 return fail("read() into new sbrk memory"); 199 if (viapipe(a + PGSIZE, "1234567", 8) > 0) 200 return fail("read() into memory given back with sbrk(-n) succeeded"); 201 return 0;
202}
203
204// user memory ends at USERTOP, and the kernel can copy right
205// up to it.
206int
207limittest(void)
208{
210 int n = USERTOP - end; 211 char *last = (char *)USERTOP - 8;
212
213 int r = 0;
214
216 return fail("sbrklazy up to USERTOP failed"); 218 r = fail("sbrk beyond USERTOP succeeded"); 219 last[-1] = 'x'; // a lazy page fault from user mode
220 if (viapipe(last, "1234567", 8) != 8 || strcmp(last, "1234567") != 0) 221 r = fail("read() into the last 8 bytes below USERTOP"); 222 // only the 4 bytes below USERTOP can be copied
223 if (viapipe(last + 4, "1234567", 8) != 4)
224 r = fail("read() across USERTOP did not stop at USERTOP"); 226 return r;
227}
228
229// a forked child's kernel page table maps what it inherited.
230int
232{
234 char stack[16];
236
240 return fail("fork failed"); 242 if (viapipe(heap, "child", 6) != 6 || strcmp(heap, "child") != 0) 244 if (viapipe(stack, "child", 6) != 6 || strcmp(stack, "child") != 0) 247 }
248 if (wait(&xstatus) != pid || xstatus != 0) 249 return fail("the child could not read() into inherited memory"); 250 if (strcmp(heap, "parent") != 0 || strcmp(stack, "parent") != 0) 251 return fail("the child's copies changed the parent's memory"); 253 return 0;
254}
255
256// count operations in 20 ticks (about 2 seconds).
257static int
258count(int (*op)(void))
259{
260 int n = 0, t0;
261
264 ;
266 while (uptime() - t0 < 20) { 267 for (int i = 0; i < 10; i++)
268 op();
269 n += 10;
270 }
271 return n;
272}
273
274int timefd, timefds[2];
275char timebuf[8192];
276
277static int
278opfstat(void)
279{
281 return fstat(timefd, &st); 282}
283
284static int
285oppipe(void)
286{
287 write(timefds[1], timebuf, 512); 288 return read(timefds[0], timebuf, 512); 289}
290
291static int
292opread(void)
293{
295 int n = read(fd, timebuf, sizeof(timebuf)); 297 return n;
298}
299
300void
301timing(void)
302{
304
305 write(fd, timebuf, sizeof(timebuf)); 309 printf("sumtest: fstat (copyout 24 bytes): %d in 20 ticks\n", 310 count(opfstat));
311 printf("sumtest: pipe write+read of 512 bytes: %d in 20 ticks\n", 312 count(oppipe));
313 printf("sumtest: open+read 8192 bytes+close: %d in 20 ticks\n", 314 count(opread));
316}
317
318int
320{
321 struct {
322 int (*f)(void);
324 } tests[] = {
325 {copytest, "copy"}, {lazytest, "lazy"}, {badtest, "bad pointers"},
326 {shrinktest, "shrink"}, {limittest, "limit"}, {forktest, "fork"}, 327 };
328 int failed = 0;
329
330 if (argc > 1 && strcmp(argv[1], "time") == 0) { 331 timing();
333 }
334 for (int i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
335 int r = tests[i].f();
336 printf("sumtest: %s: %s\n", tests[i].name, r ? "FAIL" : "OK"); 337 failed |= r;
338 }
339 printf("sumtest: %s\n", failed ? "SOME TESTS FAILED" : "ALL OK"); 341}