1 /* Test for sys_vumap() - by D.C. van Moolenbroek */
2 #include <minix/drivers.h>
3 #include <minix/ds.h>
4 #include <sys/mman.h>
5 #include <machine/vmparam.h>
6 #include <assert.h>
7
8 #include "com.h"
9
10 struct buf {
11 int pages;
12 int flags;
13 vir_bytes addr;
14 phys_bytes phys;
15 };
16 #define BUF_PREALLOC 0x1 /* if set, immediately allocate the page */
17 #define BUF_ADJACENT 0x2 /* virtually contiguous with the last buffer */
18
19 static unsigned int count = 0, failures = 0;
20
21 static int success;
22 static char *fail_file;
23 static int fail_line;
24
25 static int relay;
26 static endpoint_t endpt;
27
28 static int verbose;
29
30 static enum {
31 GE_NONE, /* no exception */
32 GE_REVOKED, /* revoked grant */
33 GE_INVALID /* invalid grant */
34 } grant_exception = GE_NONE;
35
36 static int grant_access = 0;
37
38 #define expect(r) expect_f((r), __FILE__, __LINE__)
39
alloc_buf(struct buf * buf,phys_bytes next)40 static void alloc_buf(struct buf *buf, phys_bytes next)
41 {
42 void *tmp = NULL;
43 vir_bytes addr;
44 size_t len;
45 int r, prealloc, flags;
46
47 /* is_allocated() cannot handle buffers that are not physically
48 * contiguous, and we cannot guarantee physical contiguity if not
49 * not preallocating.
50 */
51 assert((buf->flags & BUF_PREALLOC) || buf->pages == 1);
52
53 len = buf->pages * PAGE_SIZE;
54 prealloc = (buf->flags & BUF_PREALLOC);
55 flags = MAP_ANON | (prealloc ? (MAP_CONTIG | MAP_PREALLOC) : 0);
56
57 if (prealloc) {
58 /* Allocate a same-sized piece of memory elsewhere, to make it
59 * very unlikely that the actual piece of memory will end up
60 * being physically contiguous with the last piece.
61 */
62 tmp = mmap((void *) (buf->addr + len + PAGE_SIZE), len,
63 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PREALLOC |
64 MAP_CONTIG, -1, 0L);
65
66 if (tmp == MAP_FAILED)
67 panic("unable to allocate temporary buffer");
68 }
69
70 addr = (vir_bytes) mmap((void *) buf->addr, len,
71 PROT_READ | PROT_WRITE, flags, -1, 0L);
72
73 if (addr != buf->addr)
74 panic("unable to allocate buffer (2)");
75
76 if (!prealloc)
77 return;
78
79 if ((r = munmap(tmp, len)) != OK)
80 panic("unable to unmap buffer (%d)", errno);
81
82 if ((r = sys_umap(SELF, VM_D, addr, len, &buf->phys)) < 0)
83 panic("unable to get physical address of buffer (%d)", r);
84
85 if (buf->phys != next)
86 return;
87
88 if (verbose)
89 printf("WARNING: alloc noncontigous range, second try\n");
90
91 /* Can't remap this to elsewhere, so we run the risk of allocating the
92 * exact same physically contiguous page again. However, now that we've
93 * unmapped the temporary memory also, there's a small chance we'll end
94 * up with a different physical page this time. Who knows.
95 */
96 munmap((void *) addr, len);
97
98 addr = (vir_bytes) mmap((void *) buf->addr, len,
99 PROT_READ | PROT_WRITE, flags, -1, 0L);
100
101 if (addr != buf->addr)
102 panic("unable to allocate buffer, second try");
103
104 if ((r = sys_umap(SELF, VM_D, addr, len, &buf->phys)) < 0)
105 panic("unable to get physical address of buffer (%d)", r);
106
107 /* Still the same page? Screw it. */
108 if (buf->phys == next)
109 panic("unable to allocate noncontiguous range");
110 }
111
alloc_bufs(struct buf * buf,int count)112 static void alloc_bufs(struct buf *buf, int count)
113 {
114 static vir_bytes base = 0x80000000L;
115 phys_bytes next;
116 int i;
117
118 /* Allocate the given memory in virtually contiguous blocks whenever
119 * each next buffer is requested to be adjacent. Insert a virtual gap
120 * after each such block. Make sure that each two adjacent buffers in a
121 * block are physically non-contiguous.
122 */
123 for (i = 0; i < count; i++) {
124 if (i > 0 && (buf[i].flags & BUF_ADJACENT)) {
125 next = buf[i-1].phys + buf[i-1].pages * PAGE_SIZE;
126 } else {
127 base += PAGE_SIZE * 16;
128 next = 0L;
129 }
130
131 buf[i].addr = base;
132
133 alloc_buf(&buf[i], next);
134
135 base += buf[i].pages * PAGE_SIZE;
136 }
137
138 #if DEBUG
139 for (i = 0; i < count; i++)
140 printf("Buf %d: %d pages, flags %x, vir %08x, phys %08x\n", i,
141 buf[i].pages, buf[i].flags, buf[i].addr, buf[i].phys);
142 #endif
143 }
144
free_bufs(struct buf * buf,int count)145 static void free_bufs(struct buf *buf, int count)
146 {
147 int i, j, r;
148
149 for (i = 0; i < count; i++) {
150 for (j = 0; j < buf[i].pages; j++) {
151 r = munmap((void *) (buf[i].addr + j * PAGE_SIZE),
152 PAGE_SIZE);
153
154 if (r != OK)
155 panic("unable to unmap range (%d)", errno);
156 }
157 }
158 }
159
is_allocated(vir_bytes addr,size_t bytes,phys_bytes * phys)160 static int is_allocated(vir_bytes addr, size_t bytes, phys_bytes *phys)
161 {
162 int r;
163
164 /* This will have to do for now. Of course, we could use sys_vumap with
165 * VUA_READ for this, but that would defeat the point of one test. It
166 * is still a decent alternative in case sys_umap's behavior ever
167 * changes, though.
168 */
169 r = sys_umap(SELF, VM_D, addr, bytes, phys);
170
171 return r == OK;
172 }
173
is_buf_allocated(struct buf * buf)174 static int is_buf_allocated(struct buf *buf)
175 {
176 return is_allocated(buf->addr, buf->pages * PAGE_SIZE, &buf->phys);
177 }
178
test_group(char * name)179 static void test_group(char *name)
180 {
181 if (verbose)
182 printf("Test group: %s (%s)\n",
183 name, relay ? "relay" : "local");
184 }
185
expect_f(int res,char * file,int line)186 static void expect_f(int res, char *file, int line)
187 {
188 if (!res && success) {
189 success = FALSE;
190 fail_file = file;
191 fail_line = line;
192 }
193 }
194
got_result(char * desc)195 static void got_result(char *desc)
196 {
197 count++;
198
199 if (!success) {
200 failures++;
201
202 printf("#%02d: %-38s\t[FAIL]\n", count, desc);
203 printf("- failure at %s:%d\n", fail_file, fail_line);
204 } else {
205 if (verbose)
206 printf("#%02d: %-38s\t[PASS]\n", count, desc);
207 }
208 }
209
relay_vumap(struct vumap_vir * vvec,int vcount,size_t offset,int access,struct vumap_phys * pvec,int * pcount)210 static int relay_vumap(struct vumap_vir *vvec, int vcount, size_t offset,
211 int access, struct vumap_phys *pvec, int *pcount)
212 {
213 struct vumap_vir gvvec[MAPVEC_NR + 3];
214 cp_grant_id_t vgrant, pgrant;
215 message m;
216 int i, r, gaccess;
217
218 assert(vcount > 0 && vcount <= MAPVEC_NR + 3);
219 assert(*pcount > 0 && *pcount <= MAPVEC_NR + 3);
220
221 /* Allow grant access flags to be overridden for testing purposes. */
222 if (!(gaccess = grant_access)) {
223 if (access & VUA_READ) gaccess |= CPF_READ;
224 if (access & VUA_WRITE) gaccess |= CPF_WRITE;
225 }
226
227 for (i = 0; i < vcount; i++) {
228 gvvec[i].vv_grant = cpf_grant_direct(endpt, vvec[i].vv_addr,
229 vvec[i].vv_size, gaccess);
230 assert(gvvec[i].vv_grant != GRANT_INVALID);
231 gvvec[i].vv_size = vvec[i].vv_size;
232 }
233
234 vgrant = cpf_grant_direct(endpt, (vir_bytes) gvvec,
235 sizeof(gvvec[0]) * vcount, CPF_READ);
236 assert(vgrant != GRANT_INVALID);
237
238 pgrant = cpf_grant_direct(endpt, (vir_bytes) pvec,
239 sizeof(pvec[0]) * *pcount, CPF_WRITE);
240 assert(pgrant != GRANT_INVALID);
241
242 /* This must be done after allocating all other grants. */
243 if (grant_exception != GE_NONE) {
244 cpf_revoke(gvvec[vcount - 1].vv_grant);
245 if (grant_exception == GE_INVALID)
246 gvvec[vcount - 1].vv_grant = GRANT_INVALID;
247 }
248
249 m.m_type = VTR_RELAY;
250 m.VTR_VGRANT = vgrant;
251 m.VTR_VCOUNT = vcount;
252 m.VTR_OFFSET = offset;
253 m.VTR_ACCESS = access;
254 m.VTR_PGRANT = pgrant;
255 m.VTR_PCOUNT = *pcount;
256
257 r = ipc_sendrec(endpt, &m);
258
259 cpf_revoke(pgrant);
260 cpf_revoke(vgrant);
261
262 for (i = 0; i < vcount - !!grant_exception; i++)
263 cpf_revoke(gvvec[i].vv_grant);
264
265 *pcount = m.VTR_PCOUNT;
266
267 return (r != OK) ? r : m.m_type;
268 }
269
do_vumap(endpoint_t endpt,struct vumap_vir * vvec,int vcount,size_t offset,int access,struct vumap_phys * pvec,int * pcount)270 static int do_vumap(endpoint_t endpt, struct vumap_vir *vvec, int vcount,
271 size_t offset, int access, struct vumap_phys *pvec, int *pcount)
272 {
273 struct vumap_phys pv_backup[MAPVEC_NR + 3];
274 int r, pc_backup, pv_test = FALSE;
275
276 /* Make a copy of pvec and pcount for later. */
277 pc_backup = *pcount;
278
279 /* We cannot compare pvec contents before and after when relaying,
280 * since the original contents are not transferred.
281 */
282 if (!relay && pvec != NULL && pc_backup >= 1 &&
283 pc_backup <= MAPVEC_NR + 3) {
284 pv_test = TRUE;
285 memcpy(pv_backup, pvec, sizeof(*pvec) * pc_backup);
286 }
287
288 /* Reset the test result. */
289 success = TRUE;
290
291 /* Perform the vumap call, either directly or through a relay. */
292 if (relay) {
293 assert(endpt == SELF);
294 r = relay_vumap(vvec, vcount, offset, access, pvec, pcount);
295 } else {
296 r = sys_vumap(endpt, vvec, vcount, offset, access, pvec,
297 pcount);
298 }
299
300 /* Upon failure, pvec and pcount must be unchanged. */
301 if (r != OK) {
302 expect(pc_backup == *pcount);
303
304 if (pv_test)
305 expect(memcmp(pv_backup, pvec,
306 sizeof(*pvec) * pc_backup) == 0);
307 }
308
309 return r;
310 }
311
test_basics(void)312 static void test_basics(void)
313 {
314 struct vumap_vir vvec[2];
315 struct vumap_phys pvec[4];
316 struct buf buf[4];
317 int r, pcount;
318
319 test_group("basics");
320
321 buf[0].pages = 1;
322 buf[0].flags = BUF_PREALLOC;
323 buf[1].pages = 2;
324 buf[1].flags = BUF_PREALLOC;
325 buf[2].pages = 1;
326 buf[2].flags = BUF_PREALLOC;
327 buf[3].pages = 1;
328 buf[3].flags = BUF_PREALLOC | BUF_ADJACENT;
329
330 alloc_bufs(buf, 4);
331
332 /* Test single whole page. */
333 vvec[0].vv_addr = buf[0].addr;
334 vvec[0].vv_size = PAGE_SIZE;
335 pcount = 1;
336
337 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
338
339 expect(r == OK);
340 expect(pcount == 1);
341 expect(pvec[0].vp_addr == buf[0].phys);
342 expect(pvec[0].vp_size == vvec[0].vv_size);
343
344 got_result("single whole page");
345
346 /* Test single partial page. */
347 vvec[0].vv_addr = buf[0].addr + 123;
348 vvec[0].vv_size = PAGE_SIZE - 456;
349 pcount = 1;
350
351 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
352
353 expect(r == OK);
354 expect(pcount == 1);
355 expect(pvec[0].vp_addr == buf[0].phys + 123);
356 expect(pvec[0].vp_size == vvec[0].vv_size);
357
358 got_result("single partial page");
359
360 /* Test multiple contiguous whole pages. */
361 vvec[0].vv_addr = buf[1].addr;
362 vvec[0].vv_size = PAGE_SIZE * 2;
363 pcount = 1;
364
365 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
366
367 expect(r == OK);
368 expect(pcount == 1);
369 expect(pvec[0].vp_addr == buf[1].phys);
370 expect(pvec[0].vp_size == vvec[0].vv_size);
371
372 got_result("multiple contiguous whole pages");
373
374 /* Test range in multiple contiguous pages. */
375 vvec[0].vv_addr = buf[1].addr + 234;
376 vvec[0].vv_size = PAGE_SIZE * 2 - 234;
377 pcount = 2;
378
379 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
380
381 expect(r == OK);
382 expect(pcount == 1);
383 expect(pvec[0].vp_addr == buf[1].phys + 234);
384 expect(pvec[0].vp_size == vvec[0].vv_size);
385
386 got_result("range in multiple contiguous pages");
387
388 /* Test multiple noncontiguous whole pages. */
389 vvec[0].vv_addr = buf[2].addr;
390 vvec[0].vv_size = PAGE_SIZE * 2;
391 pcount = 3;
392
393 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
394
395 expect(r == OK);
396 expect(pcount == 2);
397 expect(pvec[0].vp_addr == buf[2].phys);
398 expect(pvec[0].vp_size == PAGE_SIZE);
399 expect(pvec[1].vp_addr == buf[3].phys);
400 expect(pvec[1].vp_size == PAGE_SIZE);
401
402 got_result("multiple noncontiguous whole pages");
403
404 /* Test range in multiple noncontiguous pages. */
405 vvec[0].vv_addr = buf[2].addr + 1;
406 vvec[0].vv_size = PAGE_SIZE * 2 - 2;
407 pcount = 2;
408
409 r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
410
411 expect(r == OK);
412 expect(pcount == 2);
413 expect(pvec[0].vp_addr == buf[2].phys + 1);
414 expect(pvec[0].vp_size == PAGE_SIZE - 1);
415 expect(pvec[1].vp_addr == buf[3].phys);
416 expect(pvec[1].vp_size == PAGE_SIZE - 1);
417
418 got_result("range in multiple noncontiguous pages");
419
420 /* Test single-input result truncation. */
421 vvec[0].vv_addr = buf[2].addr + PAGE_SIZE / 2;
422 vvec[0].vv_size = PAGE_SIZE;
423 pvec[1].vp_addr = 0L;
424 pvec[1].vp_size = 0;
425 pcount = 1;
426
427 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
428
429 expect(r == OK);
430 expect(pcount == 1);
431 expect(pvec[0].vp_addr == buf[2].phys + PAGE_SIZE / 2);
432 expect(pvec[0].vp_size == PAGE_SIZE / 2);
433 expect(pvec[1].vp_addr == 0L);
434 expect(pvec[1].vp_size == 0);
435
436 got_result("single-input result truncation");
437
438 /* Test multiple inputs, contiguous first. */
439 vvec[0].vv_addr = buf[0].addr;
440 vvec[0].vv_size = PAGE_SIZE;
441 vvec[1].vv_addr = buf[2].addr + PAGE_SIZE - 1;
442 vvec[1].vv_size = 2;
443 pcount = 3;
444
445 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
446
447 expect(r == OK);
448 expect(pcount == 3);
449 expect(pvec[0].vp_addr == buf[0].phys);
450 expect(pvec[0].vp_size == PAGE_SIZE);
451 expect(pvec[1].vp_addr == buf[2].phys + PAGE_SIZE - 1);
452 expect(pvec[1].vp_size == 1);
453 expect(pvec[2].vp_addr == buf[3].phys);
454 expect(pvec[2].vp_size == 1);
455
456 got_result("multiple inputs, contiguous first");
457
458 /* Test multiple inputs, contiguous last. */
459 vvec[0].vv_addr = buf[2].addr + 123;
460 vvec[0].vv_size = PAGE_SIZE * 2 - 456;
461 vvec[1].vv_addr = buf[1].addr + 234;
462 vvec[1].vv_size = PAGE_SIZE * 2 - 345;
463 pcount = 4;
464
465 r = do_vumap(SELF, vvec, 2, 0, VUA_WRITE, pvec, &pcount);
466
467 expect(r == OK);
468 expect(pcount == 3);
469 expect(pvec[0].vp_addr == buf[2].phys + 123);
470 expect(pvec[0].vp_size == PAGE_SIZE - 123);
471 expect(pvec[1].vp_addr == buf[3].phys);
472 expect(pvec[1].vp_size == PAGE_SIZE - (456 - 123));
473 expect(pvec[2].vp_addr == buf[1].phys + 234);
474 expect(pvec[2].vp_size == vvec[1].vv_size);
475
476 got_result("multiple inputs, contiguous last");
477
478 /* Test multiple-inputs result truncation. */
479 vvec[0].vv_addr = buf[2].addr + 2;
480 vvec[0].vv_size = PAGE_SIZE * 2 - 3;
481 vvec[1].vv_addr = buf[0].addr;
482 vvec[1].vv_size = 135;
483 pvec[2].vp_addr = 0xDEADBEEFL;
484 pvec[2].vp_size = 1234;
485 pcount = 2;
486
487 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
488
489 expect(r == OK);
490 expect(pcount == 2);
491 expect(pvec[0].vp_addr == buf[2].phys + 2);
492 expect(pvec[0].vp_size == PAGE_SIZE - 2);
493 expect(pvec[1].vp_addr == buf[3].phys);
494 expect(pvec[1].vp_size == PAGE_SIZE - 1);
495 expect(pvec[2].vp_addr == 0xDEADBEEFL);
496 expect(pvec[2].vp_size == 1234);
497
498 got_result("multiple-inputs result truncation");
499
500 free_bufs(buf, 4);
501 }
502
test_endpt(void)503 static void test_endpt(void)
504 {
505 struct vumap_vir vvec[1];
506 struct vumap_phys pvec[1];
507 struct buf buf[1];
508 int r, pcount;
509
510 test_group("endpoint");
511
512 buf[0].pages = 1;
513 buf[0].flags = BUF_PREALLOC;
514
515 alloc_bufs(buf, 1);
516
517 /* Test NONE endpoint. */
518 vvec[0].vv_addr = buf[0].addr;
519 vvec[0].vv_size = PAGE_SIZE;
520 pcount = 1;
521
522 r = do_vumap(NONE, vvec, 1, 0, VUA_READ, pvec, &pcount);
523
524 expect(r == EINVAL);
525
526 got_result("NONE endpoint");
527
528 /* Test ANY endpoint. */
529 vvec[0].vv_addr = buf[0].addr;
530 vvec[0].vv_size = PAGE_SIZE;
531 pcount = 1;
532
533 r = do_vumap(ANY, vvec, 1, 0, VUA_READ, pvec, &pcount);
534
535 expect(r == EINVAL);
536
537 got_result("ANY endpoint");
538
539 free_bufs(buf, 1);
540 }
541
test_vector1(void)542 static void test_vector1(void)
543 {
544 struct vumap_vir vvec[2];
545 struct vumap_phys pvec[3];
546 struct buf buf[2];
547 int r, pcount;
548
549 test_group("vector, part 1");
550
551 buf[0].pages = 2;
552 buf[0].flags = BUF_PREALLOC;
553 buf[1].pages = 1;
554 buf[1].flags = BUF_PREALLOC;
555
556 alloc_bufs(buf, 2);
557
558 /* Test zero virtual memory size. */
559 vvec[0].vv_addr = buf[0].addr;
560 vvec[0].vv_size = PAGE_SIZE * 2;
561 vvec[1].vv_addr = buf[1].addr;
562 vvec[1].vv_size = 0;
563 pcount = 3;
564
565 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
566
567 expect(r == EINVAL);
568
569 got_result("zero virtual memory size");
570
571 /* Test excessive virtual memory size. */
572 vvec[1].vv_size = (vir_bytes) -1;
573
574 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
575
576 expect(r == EFAULT || r == EPERM);
577
578 got_result("excessive virtual memory size");
579
580 /* Test invalid virtual memory. */
581 vvec[1].vv_addr = 0L;
582 vvec[1].vv_size = PAGE_SIZE;
583
584 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
585
586 expect(r == EFAULT);
587
588 got_result("invalid virtual memory");
589
590 /* Test virtual memory overrun. */
591 vvec[0].vv_size++;
592 vvec[1].vv_addr = buf[1].addr;
593
594 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
595
596 expect(r == EFAULT);
597
598 got_result("virtual memory overrun");
599
600 free_bufs(buf, 2);
601 }
602
test_vector2(void)603 static void test_vector2(void)
604 {
605 struct vumap_vir vvec[2], *vvecp;
606 struct vumap_phys pvec[3], *pvecp;
607 struct buf buf[2];
608 phys_bytes dummy;
609 int r, pcount;
610
611 test_group("vector, part 2");
612
613 buf[0].pages = 2;
614 buf[0].flags = BUF_PREALLOC;
615 buf[1].pages = 1;
616 buf[1].flags = BUF_PREALLOC;
617
618 alloc_bufs(buf, 2);
619
620 /* Test zero virtual count. */
621 vvec[0].vv_addr = buf[0].addr;
622 vvec[0].vv_size = PAGE_SIZE * 2;
623 vvec[1].vv_addr = buf[1].addr;
624 vvec[1].vv_size = PAGE_SIZE;
625 pcount = 3;
626
627 r = do_vumap(SELF, vvec, 0, 0, VUA_READ, pvec, &pcount);
628
629 expect(r == EINVAL);
630
631 got_result("zero virtual count");
632
633 /* Test negative virtual count. */
634 r = do_vumap(SELF, vvec, -1, 0, VUA_WRITE, pvec, &pcount);
635
636 expect(r == EINVAL);
637
638 got_result("negative virtual count");
639
640 /* Test zero physical count. */
641 pcount = 0;
642
643 r = do_vumap(SELF, vvec, 2, 0, VUA_WRITE, pvec, &pcount);
644
645 expect(r == EINVAL);
646
647 got_result("zero physical count");
648
649 /* Test negative physical count. */
650 pcount = -1;
651
652 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
653
654 expect(r == EINVAL);
655
656 got_result("negative physical count");
657
658 /* Test invalid virtual vector pointer. */
659 pcount = 2;
660
661 r = do_vumap(SELF, NULL, 2, 0, VUA_READ, pvec, &pcount);
662
663 expect(r == EFAULT);
664
665 got_result("invalid virtual vector pointer");
666
667 /* Test unallocated virtual vector. */
668 vvecp = (struct vumap_vir *) mmap(NULL, PAGE_SIZE,
669 PROT_READ | PROT_WRITE, MAP_ANON, -1, 0L);
670
671 if (vvecp == MAP_FAILED)
672 panic("unable to allocate virtual vector");
673
674 r = do_vumap(SELF, vvecp, 2, 0, VUA_READ, pvec, &pcount);
675
676 expect(r == EFAULT);
677 expect(!is_allocated((vir_bytes) vvecp, PAGE_SIZE, &dummy));
678
679 got_result("unallocated virtual vector pointer");
680
681 munmap((void *) vvecp, PAGE_SIZE);
682
683 /* Test invalid physical vector pointer. */
684 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, NULL, &pcount);
685
686 expect(r == EFAULT);
687
688 got_result("invalid physical vector pointer");
689
690 /* Test unallocated physical vector. */
691 pvecp = (struct vumap_phys *) mmap(NULL, PAGE_SIZE,
692 PROT_READ | PROT_WRITE, MAP_ANON, -1, 0L);
693
694 if (pvecp == MAP_FAILED)
695 panic("unable to allocate physical vector");
696
697 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvecp, &pcount);
698
699 expect(r == OK);
700 expect(is_allocated((vir_bytes) pvecp, PAGE_SIZE, &dummy));
701 expect(pcount == 2);
702 expect(pvecp[0].vp_size == PAGE_SIZE * 2);
703 expect(pvecp[0].vp_addr == buf[0].phys);
704 expect(pvecp[1].vp_size == PAGE_SIZE);
705 expect(pvecp[1].vp_addr == buf[1].phys);
706
707 got_result("unallocated physical vector pointer");
708
709 munmap((void *) pvecp, PAGE_SIZE);
710
711 free_bufs(buf, 2);
712 }
713
test_grant(void)714 static void test_grant(void)
715 {
716 struct vumap_vir vvec[2];
717 struct vumap_phys pvec[3];
718 struct buf buf[2];
719 int r, pcount;
720
721 test_group("grant");
722
723 buf[0].pages = 1;
724 buf[0].flags = BUF_PREALLOC;
725 buf[1].pages = 2;
726 buf[1].flags = BUF_PREALLOC;
727
728 alloc_bufs(buf, 2);
729
730 /* Test write-only access on read-only grant. */
731 grant_access = CPF_READ; /* override */
732
733 vvec[0].vv_addr = buf[0].addr;
734 vvec[0].vv_size = PAGE_SIZE;
735 pcount = 1;
736
737 r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
738
739 expect(r == EPERM);
740
741 got_result("write-only access on read-only grant");
742
743 /* Test read-write access on read-only grant. */
744 r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
745
746 expect(r == EPERM);
747
748 got_result("read-write access on read-only grant");
749
750 /* Test read-only access on write-only grant. */
751 grant_access = CPF_WRITE; /* override */
752
753 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
754
755 expect(r == EPERM);
756
757 got_result("read-only access on write-only grant");
758
759 /* Test read-write access on write grant. */
760 r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
761
762 expect(r == EPERM);
763
764 got_result("read-write access on write-only grant");
765
766 /* Test read-only access on read-write grant. */
767 grant_access = CPF_READ | CPF_WRITE; /* override */
768
769 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
770
771 expect(r == OK);
772 expect(pcount == 1);
773 expect(pvec[0].vp_size == PAGE_SIZE);
774 expect(pvec[0].vp_addr == buf[0].phys);
775
776 got_result("read-only access on read-write grant");
777
778 grant_access = 0; /* reset */
779
780 /* Test invalid grant. */
781 grant_exception = GE_INVALID;
782
783 vvec[0].vv_addr = buf[0].addr;
784 vvec[0].vv_size = PAGE_SIZE;
785 vvec[1].vv_addr = buf[1].addr;
786 vvec[1].vv_size = PAGE_SIZE * 2;
787 pcount = 3;
788
789 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
790
791 expect(r == EINVAL);
792
793 got_result("invalid grant");
794
795 /* Test revoked grant. */
796 grant_exception = GE_REVOKED;
797
798 r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
799
800 expect(r == EPERM);
801
802 got_result("revoked grant");
803
804 grant_exception = GE_NONE;
805
806 free_bufs(buf, 2);
807 }
808
test_offset(void)809 static void test_offset(void)
810 {
811 struct vumap_vir vvec[2];
812 struct vumap_phys pvec[3];
813 struct buf buf[4];
814 size_t off, off2;
815 int r, pcount;
816
817 test_group("offsets");
818
819 buf[0].pages = 1;
820 buf[0].flags = BUF_PREALLOC;
821 buf[1].pages = 2;
822 buf[1].flags = BUF_PREALLOC;
823 buf[2].pages = 1;
824 buf[2].flags = BUF_PREALLOC;
825 buf[3].pages = 1;
826 buf[3].flags = BUF_PREALLOC | BUF_ADJACENT;
827
828 alloc_bufs(buf, 4);
829
830 /* Test offset into aligned page. */
831 off = 123;
832 vvec[0].vv_addr = buf[0].addr;
833 vvec[0].vv_size = PAGE_SIZE;
834 pcount = 2;
835
836 r = do_vumap(SELF, vvec, 1, off, VUA_READ, pvec, &pcount);
837
838 expect(r == OK);
839 expect(pcount == 1);
840 expect(pvec[0].vp_addr == buf[0].phys + off);
841 expect(pvec[0].vp_size == vvec[0].vv_size - off);
842
843 got_result("offset into aligned page");
844
845 /* Test offset into unaligned page. */
846 off2 = 456;
847 assert(off + off2 < PAGE_SIZE);
848 vvec[0].vv_addr = buf[0].addr + off;
849 vvec[0].vv_size = PAGE_SIZE - off;
850 pcount = 2;
851
852 r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
853
854 expect(r == OK);
855 expect(pcount == 1);
856 expect(pvec[0].vp_addr == buf[0].phys + off + off2);
857 expect(pvec[0].vp_size == vvec[0].vv_size - off2);
858
859 got_result("offset into unaligned page");
860
861 /* Test offset into unaligned page set. */
862 off = 1234;
863 off2 = 567;
864 assert(off + off2 < PAGE_SIZE);
865 vvec[0].vv_addr = buf[1].addr + off;
866 vvec[0].vv_size = (PAGE_SIZE - off) * 2;
867 pcount = 3;
868
869 r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
870
871 expect(r == OK);
872 expect(pcount == 1);
873 expect(pvec[0].vp_addr == buf[1].phys + off + off2);
874 expect(pvec[0].vp_size == vvec[0].vv_size - off2);
875
876 got_result("offset into contiguous page set");
877
878 /* Test offset into noncontiguous page set. */
879 vvec[0].vv_addr = buf[2].addr + off;
880 vvec[0].vv_size = (PAGE_SIZE - off) * 2;
881 pcount = 3;
882
883 r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
884
885 expect(r == OK);
886 expect(pcount == 2);
887 expect(pvec[0].vp_addr == buf[2].phys + off + off2);
888 expect(pvec[0].vp_size == PAGE_SIZE - off - off2);
889 expect(pvec[1].vp_addr == buf[3].phys);
890 expect(pvec[1].vp_size == PAGE_SIZE - off);
891
892 got_result("offset into noncontiguous page set");
893
894 /* Test offset to last byte. */
895 off = PAGE_SIZE - off2 - 1;
896 vvec[0].vv_addr = buf[0].addr + off2;
897 vvec[0].vv_size = PAGE_SIZE - off2;
898 pcount = 2;
899
900 r = do_vumap(SELF, vvec, 1, off, VUA_READ, pvec, &pcount);
901
902 expect(r == OK);
903 expect(pcount == 1);
904 expect(pvec[0].vp_addr == buf[0].phys + off + off2);
905 expect(pvec[0].vp_size == 1);
906
907 got_result("offset to last byte");
908
909 /* Test offset at range end. */
910 off = 234;
911 vvec[0].vv_addr = buf[1].addr + off;
912 vvec[0].vv_size = PAGE_SIZE - off * 2;
913 vvec[1].vv_addr = vvec[0].vv_addr + vvec[0].vv_size;
914 vvec[1].vv_size = off;
915
916 r = do_vumap(SELF, vvec, 2, vvec[0].vv_size, VUA_READ, pvec, &pcount);
917
918 expect(r == EINVAL);
919
920 got_result("offset at range end");
921
922 /* Test offset beyond range end. */
923 vvec[0].vv_addr = buf[1].addr;
924 vvec[0].vv_size = PAGE_SIZE;
925 vvec[1].vv_addr = buf[1].addr + PAGE_SIZE;
926 vvec[1].vv_size = PAGE_SIZE;
927
928 r = do_vumap(SELF, vvec, 2, PAGE_SIZE + off, VUA_READ, pvec, &pcount);
929
930 expect(r == EINVAL);
931
932 got_result("offset beyond range end");
933
934 /* Test negative offset. */
935 vvec[0].vv_addr = buf[1].addr + off + off2;
936 vvec[0].vv_size = PAGE_SIZE;
937
938 r = do_vumap(SELF, vvec, 1, (size_t) -1, VUA_READ, pvec, &pcount);
939
940 expect(r == EINVAL);
941
942 got_result("negative offset");
943
944 free_bufs(buf, 4);
945 }
946
test_access(void)947 static void test_access(void)
948 {
949 struct vumap_vir vvec[3];
950 struct vumap_phys pvec[4], *pvecp;
951 struct buf buf[7];
952 int i, r, pcount, pindex;
953
954 test_group("access");
955
956 buf[0].pages = 1;
957 buf[0].flags = 0;
958 buf[1].pages = 1;
959 buf[1].flags = BUF_PREALLOC | BUF_ADJACENT;
960 buf[2].pages = 1;
961 buf[2].flags = BUF_ADJACENT;
962
963 alloc_bufs(buf, 3);
964
965 /* Test no access flags. */
966 vvec[0].vv_addr = buf[0].addr;
967 vvec[0].vv_size = PAGE_SIZE * 3;
968 pcount = 4;
969
970 r = do_vumap(SELF, vvec, 1, 0, 0, pvec, &pcount);
971
972 expect(r == EINVAL);
973 expect(!is_buf_allocated(&buf[0]));
974 expect(is_buf_allocated(&buf[1]));
975 expect(!is_buf_allocated(&buf[2]));
976
977 got_result("no access flags");
978
979 /* Test read-only access. */
980 vvec[0].vv_addr = buf[0].addr;
981 vvec[0].vv_size = PAGE_SIZE * 3;
982 pcount = 1;
983
984 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
985
986 expect(r == EFAULT);
987 expect(!is_buf_allocated(&buf[0]));
988 expect(is_buf_allocated(&buf[1]));
989 expect(!is_buf_allocated(&buf[2]));
990
991 got_result("read-only access");
992
993 /* Test read-write access. */
994 vvec[0].vv_addr = buf[0].addr;
995 vvec[0].vv_size = PAGE_SIZE * 3;
996 pcount = 4;
997
998 r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
999
1000 expect(r == EFAULT);
1001 expect(!is_buf_allocated(&buf[0]));
1002 expect(is_buf_allocated(&buf[1]));
1003 expect(!is_buf_allocated(&buf[2]));
1004
1005 got_result("read-write access");
1006
1007 /* Test write-only access. */
1008 vvec[0].vv_addr = buf[0].addr;
1009 vvec[0].vv_size = PAGE_SIZE * 3;
1010 pcount = 4;
1011
1012 r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
1013
1014 expect(r == OK);
1015 /* We don't control the physical addresses of the faulted-in pages, so
1016 * they may or may not end up being contiguous with their neighbours.
1017 */
1018 expect(pcount >= 1 && pcount <= 3);
1019 expect(is_buf_allocated(&buf[0]));
1020 expect(is_buf_allocated(&buf[1]));
1021 expect(is_buf_allocated(&buf[2]));
1022 expect(pvec[0].vp_addr == buf[0].phys);
1023 switch (pcount) {
1024 case 1:
1025 expect(pvec[0].vp_size == PAGE_SIZE * 3);
1026 break;
1027 case 2:
1028 expect(pvec[0].vp_size + pvec[1].vp_size == PAGE_SIZE * 3);
1029 if (pvec[0].vp_size > PAGE_SIZE)
1030 expect(pvec[1].vp_addr == buf[2].phys);
1031 else
1032 expect(pvec[1].vp_addr == buf[1].phys);
1033 break;
1034 case 3:
1035 expect(pvec[0].vp_size == PAGE_SIZE);
1036 expect(pvec[1].vp_addr == buf[1].phys);
1037 expect(pvec[1].vp_size == PAGE_SIZE);
1038 expect(pvec[2].vp_addr == buf[2].phys);
1039 expect(pvec[2].vp_size == PAGE_SIZE);
1040 break;
1041 }
1042
1043 got_result("write-only access");
1044
1045 free_bufs(buf, 3);
1046
1047 /* Test page faulting. */
1048 buf[0].pages = 1;
1049 buf[0].flags = 0;
1050 buf[1].pages = 1;
1051 buf[1].flags = BUF_PREALLOC | BUF_ADJACENT;
1052 buf[2].pages = 1;
1053 buf[2].flags = 0;
1054 buf[3].pages = 2;
1055 buf[3].flags = BUF_PREALLOC;
1056 buf[4].pages = 1;
1057 buf[4].flags = BUF_ADJACENT;
1058 buf[5].pages = 1;
1059 buf[5].flags = BUF_ADJACENT;
1060 buf[6].pages = 1;
1061 buf[6].flags = 0;
1062
1063 alloc_bufs(buf, 7);
1064
1065 vvec[0].vv_addr = buf[0].addr + PAGE_SIZE - 1;
1066 vvec[0].vv_size = PAGE_SIZE - 1;
1067 vvec[1].vv_addr = buf[2].addr;
1068 vvec[1].vv_size = PAGE_SIZE;
1069 vvec[2].vv_addr = buf[3].addr + 123;
1070 vvec[2].vv_size = PAGE_SIZE * 4 - 456;
1071 pvecp = (struct vumap_phys *) buf[6].addr;
1072 pcount = 7;
1073 assert(sizeof(struct vumap_phys) * pcount <= PAGE_SIZE);
1074
1075 r = do_vumap(SELF, vvec, 3, 0, VUA_WRITE, pvecp, &pcount);
1076
1077 expect(r == OK);
1078 /* Same story but more possibilities. I hope I got this right. */
1079 expect(pcount >= 3 && pcount <= 6);
1080 for (i = 0; i < 7; i++)
1081 expect(is_buf_allocated(&buf[i]));
1082 expect(pvecp[0].vp_addr = buf[0].phys);
1083 if (pvecp[0].vp_size == 1) {
1084 expect(pvecp[1].vp_addr == buf[1].phys);
1085 expect(pvecp[1].vp_size == PAGE_SIZE - 2);
1086 pindex = 2;
1087 } else {
1088 expect(pvecp[0].vp_size == PAGE_SIZE - 1);
1089 pindex = 1;
1090 }
1091 expect(pvecp[pindex].vp_addr == buf[2].phys);
1092 expect(pvecp[pindex].vp_size == PAGE_SIZE);
1093 pindex++;
1094 expect(pvecp[pindex].vp_addr == buf[3].phys + 123);
1095 switch (pcount - pindex) {
1096 case 1:
1097 expect(pvecp[pindex].vp_size == PAGE_SIZE * 4 - 456);
1098 break;
1099 case 2:
1100 if (pvecp[pindex].vp_size > PAGE_SIZE * 2 - 123) {
1101 expect(pvecp[pindex].vp_size == PAGE_SIZE * 3 - 123);
1102 expect(pvecp[pindex + 1].vp_addr == buf[5].phys);
1103 expect(pvecp[pindex + 1].vp_size ==
1104 PAGE_SIZE - (456 - 123));
1105 } else {
1106 expect(pvecp[pindex].vp_size == PAGE_SIZE * 2 - 123);
1107 expect(pvecp[pindex + 1].vp_addr == buf[4].phys);
1108 expect(pvecp[pindex + 1].vp_size ==
1109 PAGE_SIZE * 2 - (456 - 123));
1110 }
1111 break;
1112 case 3:
1113 expect(pvecp[pindex].vp_size == PAGE_SIZE * 2 - 123);
1114 expect(pvecp[pindex + 1].vp_addr == buf[4].phys);
1115 expect(pvecp[pindex + 1].vp_size == PAGE_SIZE);
1116 expect(pvecp[pindex + 2].vp_addr == buf[5].phys);
1117 expect(pvecp[pindex + 2].vp_size == PAGE_SIZE - (456 - 123));
1118 break;
1119 default:
1120 expect(0);
1121 }
1122
1123 got_result("page faulting");
1124
1125 free_bufs(buf, 7);
1126
1127 /* MISSING: tests to see whether a request with VUA_WRITE or
1128 * (VUA_READ|VUA_WRITE) correctly gets an EFAULT for a read-only page.
1129 * As of writing, support for such protection is missing from the
1130 * system at all.
1131 */
1132 }
1133
phys_limit(struct vumap_vir * vvec,int vcount,struct vumap_phys * pvec,int pcount,struct buf * buf,char * desc)1134 static void phys_limit(struct vumap_vir *vvec, int vcount,
1135 struct vumap_phys *pvec, int pcount, struct buf *buf, char *desc)
1136 {
1137 int i, r;
1138
1139 r = do_vumap(SELF, vvec, vcount, 0, VUA_READ, pvec, &pcount);
1140
1141 expect(r == OK);
1142 expect(pcount == MAPVEC_NR);
1143 for (i = 0; i < MAPVEC_NR; i++) {
1144 expect(pvec[i].vp_addr == buf[i].phys);
1145 expect(pvec[i].vp_size == PAGE_SIZE);
1146 }
1147
1148 got_result(desc);
1149 }
1150
test_limits(void)1151 static void test_limits(void)
1152 {
1153 struct vumap_vir vvec[MAPVEC_NR + 3];
1154 struct vumap_phys pvec[MAPVEC_NR + 3];
1155 struct buf buf[MAPVEC_NR + 9];
1156 int i, r, vcount, pcount, nr_bufs;
1157
1158 test_group("limits");
1159
1160 /* Test large contiguous range. */
1161 buf[0].pages = MAPVEC_NR + 2;
1162 buf[0].flags = BUF_PREALLOC;
1163
1164 alloc_bufs(buf, 1);
1165
1166 vvec[0].vv_addr = buf[0].addr;
1167 vvec[0].vv_size = (MAPVEC_NR + 2) * PAGE_SIZE;
1168 pcount = 2;
1169
1170 r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
1171
1172 expect(r == OK);
1173 expect(pcount == 1);
1174 expect(pvec[0].vp_addr == buf[0].phys);
1175 expect(pvec[0].vp_size == vvec[0].vv_size);
1176
1177 got_result("large contiguous range");
1178
1179 free_bufs(buf, 1);
1180
1181 /* I'd like to test MAPVEC_NR contiguous ranges of MAPVEC_NR pages
1182 * each, but chances are we don't have that much contiguous memory
1183 * available at all. In fact, the previous test may already fail
1184 * because of this..
1185 */
1186
1187 for (i = 0; i < MAPVEC_NR + 2; i++) {
1188 buf[i].pages = 1;
1189 buf[i].flags = BUF_PREALLOC;
1190 }
1191 buf[i].pages = 1;
1192 buf[i].flags = BUF_PREALLOC | BUF_ADJACENT;
1193
1194 alloc_bufs(buf, MAPVEC_NR + 3);
1195
1196 /* Test virtual limit, one below. */
1197 for (i = 0; i < MAPVEC_NR + 2; i++) {
1198 vvec[i].vv_addr = buf[i].addr;
1199 vvec[i].vv_size = PAGE_SIZE;
1200 }
1201 vvec[i - 1].vv_size += PAGE_SIZE;
1202
1203 pcount = MAPVEC_NR + 3;
1204
1205 r = do_vumap(SELF, vvec, MAPVEC_NR - 1, 0, VUA_READ, pvec, &pcount);
1206
1207 expect(r == OK);
1208 expect(pcount == MAPVEC_NR - 1);
1209 for (i = 0; i < MAPVEC_NR - 1; i++) {
1210 expect(pvec[i].vp_addr == buf[i].phys);
1211 expect(pvec[i].vp_size == PAGE_SIZE);
1212 }
1213
1214 got_result("virtual limit, one below");
1215
1216 /* Test virtual limit, exact match. */
1217 pcount = MAPVEC_NR + 3;
1218
1219 r = do_vumap(SELF, vvec, MAPVEC_NR, 0, VUA_WRITE, pvec, &pcount);
1220
1221 expect(r == OK);
1222 expect(pcount == MAPVEC_NR);
1223 for (i = 0; i < MAPVEC_NR; i++) {
1224 expect(pvec[i].vp_addr == buf[i].phys);
1225 expect(pvec[i].vp_size == PAGE_SIZE);
1226 }
1227
1228 got_result("virtual limit, exact match");
1229
1230 /* Test virtual limit, one above. */
1231 pcount = MAPVEC_NR + 3;
1232
1233 r = do_vumap(SELF, vvec, MAPVEC_NR + 1, 0, VUA_READ, pvec, &pcount);
1234
1235 expect(r == OK);
1236 expect(pcount == MAPVEC_NR);
1237 for (i = 0; i < MAPVEC_NR; i++) {
1238 expect(pvec[i].vp_addr == buf[i].phys);
1239 expect(pvec[i].vp_size == PAGE_SIZE);
1240 }
1241
1242 got_result("virtual limit, one above");
1243
1244 /* Test virtual limit, two above. */
1245 pcount = MAPVEC_NR + 3;
1246
1247 r = do_vumap(SELF, vvec, MAPVEC_NR + 2, 0, VUA_WRITE, pvec, &pcount);
1248
1249 expect(r == OK);
1250 expect(pcount == MAPVEC_NR);
1251 for (i = 0; i < MAPVEC_NR; i++) {
1252 expect(pvec[i].vp_addr == buf[i].phys);
1253 expect(pvec[i].vp_size == PAGE_SIZE);
1254 }
1255
1256 got_result("virtual limit, two above");
1257
1258 /* Test physical limit, one below, aligned. */
1259 pcount = MAPVEC_NR - 1;
1260
1261 r = do_vumap(SELF, vvec + 2, MAPVEC_NR, 0, VUA_READ, pvec, &pcount);
1262
1263 expect(r == OK);
1264 expect(pcount == MAPVEC_NR - 1);
1265 for (i = 0; i < MAPVEC_NR - 1; i++) {
1266 expect(pvec[i].vp_addr == buf[i + 2].phys);
1267 expect(pvec[i].vp_size == PAGE_SIZE);
1268 }
1269
1270 got_result("physical limit, one below, aligned");
1271
1272 /* Test physical limit, one below, unaligned. */
1273 pcount = MAPVEC_NR - 1;
1274
1275 r = do_vumap(SELF, vvec + 3, MAPVEC_NR, 0, VUA_READ, pvec, &pcount);
1276
1277 expect(r == OK);
1278 expect(pcount == MAPVEC_NR - 1);
1279 for (i = 0; i < MAPVEC_NR - 1; i++) {
1280 expect(pvec[i].vp_addr == buf[i + 3].phys);
1281 expect(pvec[i].vp_size == PAGE_SIZE);
1282 }
1283
1284 got_result("physical limit, one below, unaligned");
1285
1286 free_bufs(buf, MAPVEC_NR + 3);
1287
1288 nr_bufs = sizeof(buf) / sizeof(buf[0]);
1289
1290 /* This ends up looking in our virtual address space as follows:
1291 * [P] [P] [P] [PPP] [PPP] ...(MAPVEC_NR x [PPP])... [PPP]
1292 * ..where P is a page, and the blocks are virtually contiguous.
1293 */
1294 for (i = 0; i < nr_bufs; i += 3) {
1295 buf[i].pages = 1;
1296 buf[i].flags = BUF_PREALLOC;
1297 buf[i + 1].pages = 1;
1298 buf[i + 1].flags =
1299 BUF_PREALLOC | ((i >= 3) ? BUF_ADJACENT : 0);
1300 buf[i + 2].pages = 1;
1301 buf[i + 2].flags =
1302 BUF_PREALLOC | ((i >= 3) ? BUF_ADJACENT : 0);
1303 }
1304
1305 alloc_bufs(buf, nr_bufs);
1306
1307 for (i = 0; i < 3; i++) {
1308 vvec[i].vv_addr = buf[i].addr;
1309 vvec[i].vv_size = PAGE_SIZE;
1310 }
1311 for ( ; i < nr_bufs / 3 + 1; i++) {
1312 vvec[i].vv_addr = buf[(i - 2) * 3].addr;
1313 vvec[i].vv_size = PAGE_SIZE * 3;
1314 }
1315 vcount = i;
1316
1317 /* Out of each of the following tests, one will be aligned (that is,
1318 * the last pvec entry will be for the last page in a vvec entry) and
1319 * two will be unaligned.
1320 */
1321
1322 /* Test physical limit, exact match. */
1323 phys_limit(vvec, vcount, pvec, MAPVEC_NR, buf,
1324 "physical limit, exact match, try 1");
1325 phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR, buf + 1,
1326 "physical limit, exact match, try 2");
1327 phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR, buf + 2,
1328 "physical limit, exact match, try 3");
1329
1330 /* Test physical limit, one above. */
1331 phys_limit(vvec, vcount, pvec, MAPVEC_NR + 1, buf,
1332 "physical limit, one above, try 1");
1333 phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR + 1, buf + 1,
1334 "physical limit, one above, try 2");
1335 phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR + 1, buf + 2,
1336 "physical limit, one above, try 3");
1337
1338 /* Test physical limit, two above. */
1339 phys_limit(vvec, vcount, pvec, MAPVEC_NR + 2, buf,
1340 "physical limit, two above, try 1");
1341 phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR + 2, buf + 1,
1342 "physical limit, two above, try 2");
1343 phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR + 2, buf + 2,
1344 "physical limit, two above, try 3");
1345
1346 free_bufs(buf, nr_bufs);
1347 }
1348
do_tests(int use_relay)1349 static void do_tests(int use_relay)
1350 {
1351 relay = use_relay;
1352
1353 test_basics();
1354
1355 if (!relay) test_endpt(); /* local only */
1356
1357 test_vector1();
1358
1359 if (!relay) test_vector2(); /* local only */
1360
1361 if (relay) test_grant(); /* remote only */
1362
1363 test_offset();
1364
1365 test_access();
1366
1367 test_limits();
1368 }
1369
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * UNUSED (info))1370 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
1371 {
1372 int r;
1373
1374 verbose = (env_argc > 1 && !strcmp(env_argv[1], "-v"));
1375
1376 if (verbose)
1377 printf("Starting sys_vumap test set\n");
1378
1379 do_tests(FALSE /*use_relay*/);
1380
1381 if ((r = ds_retrieve_label_endpt("vumaprelay", &endpt)) != OK)
1382 panic("unable to obtain endpoint for 'vumaprelay' (%d)", r);
1383
1384 do_tests(TRUE /*use_relay*/);
1385
1386 if (verbose)
1387 printf("Completed sys_vumap test set, %u/%u tests failed\n",
1388 failures, count);
1389
1390 /* The returned code will determine the outcome of the RS call, and
1391 * thus the entire test. The actual error code does not matter.
1392 */
1393 return (failures) ? EINVAL : OK;
1394 }
1395
sef_local_startup(void)1396 static void sef_local_startup(void)
1397 {
1398 sef_setcb_init_fresh(sef_cb_init_fresh);
1399
1400 sef_startup();
1401 }
1402
main(int argc,char ** argv)1403 int main(int argc, char **argv)
1404 {
1405 env_setargs(argc, argv);
1406
1407 sef_local_startup();
1408
1409 return 0;
1410 }
1411