1433d6423SLionel Sambuc /* Test for sys_vumap() - by D.C. van Moolenbroek */
2433d6423SLionel Sambuc #include <minix/drivers.h>
3433d6423SLionel Sambuc #include <minix/ds.h>
4433d6423SLionel Sambuc #include <sys/mman.h>
5*f83d70a5SDavid van Moolenbroek #include <machine/vmparam.h>
6433d6423SLionel Sambuc #include <assert.h>
7433d6423SLionel Sambuc
8433d6423SLionel Sambuc #include "com.h"
9433d6423SLionel Sambuc
10433d6423SLionel Sambuc struct buf {
11433d6423SLionel Sambuc int pages;
12433d6423SLionel Sambuc int flags;
13433d6423SLionel Sambuc vir_bytes addr;
14433d6423SLionel Sambuc phys_bytes phys;
15433d6423SLionel Sambuc };
16433d6423SLionel Sambuc #define BUF_PREALLOC 0x1 /* if set, immediately allocate the page */
17433d6423SLionel Sambuc #define BUF_ADJACENT 0x2 /* virtually contiguous with the last buffer */
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc static unsigned int count = 0, failures = 0;
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc static int success;
22433d6423SLionel Sambuc static char *fail_file;
23433d6423SLionel Sambuc static int fail_line;
24433d6423SLionel Sambuc
25433d6423SLionel Sambuc static int relay;
26433d6423SLionel Sambuc static endpoint_t endpt;
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc static int verbose;
29433d6423SLionel Sambuc
30433d6423SLionel Sambuc static enum {
31433d6423SLionel Sambuc GE_NONE, /* no exception */
32433d6423SLionel Sambuc GE_REVOKED, /* revoked grant */
33433d6423SLionel Sambuc GE_INVALID /* invalid grant */
34433d6423SLionel Sambuc } grant_exception = GE_NONE;
35433d6423SLionel Sambuc
36433d6423SLionel Sambuc static int grant_access = 0;
37433d6423SLionel Sambuc
38433d6423SLionel Sambuc #define expect(r) expect_f((r), __FILE__, __LINE__)
39433d6423SLionel Sambuc
alloc_buf(struct buf * buf,phys_bytes next)40433d6423SLionel Sambuc static void alloc_buf(struct buf *buf, phys_bytes next)
41433d6423SLionel Sambuc {
42433d6423SLionel Sambuc void *tmp = NULL;
43433d6423SLionel Sambuc vir_bytes addr;
44433d6423SLionel Sambuc size_t len;
45433d6423SLionel Sambuc int r, prealloc, flags;
46433d6423SLionel Sambuc
47433d6423SLionel Sambuc /* is_allocated() cannot handle buffers that are not physically
48433d6423SLionel Sambuc * contiguous, and we cannot guarantee physical contiguity if not
49433d6423SLionel Sambuc * not preallocating.
50433d6423SLionel Sambuc */
51433d6423SLionel Sambuc assert((buf->flags & BUF_PREALLOC) || buf->pages == 1);
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc len = buf->pages * PAGE_SIZE;
54433d6423SLionel Sambuc prealloc = (buf->flags & BUF_PREALLOC);
55433d6423SLionel Sambuc flags = MAP_ANON | (prealloc ? (MAP_CONTIG | MAP_PREALLOC) : 0);
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc if (prealloc) {
58433d6423SLionel Sambuc /* Allocate a same-sized piece of memory elsewhere, to make it
59433d6423SLionel Sambuc * very unlikely that the actual piece of memory will end up
60433d6423SLionel Sambuc * being physically contiguous with the last piece.
61433d6423SLionel Sambuc */
62433d6423SLionel Sambuc tmp = mmap((void *) (buf->addr + len + PAGE_SIZE), len,
63433d6423SLionel Sambuc PROT_READ | PROT_WRITE, MAP_ANON | MAP_PREALLOC |
64433d6423SLionel Sambuc MAP_CONTIG, -1, 0L);
65433d6423SLionel Sambuc
66433d6423SLionel Sambuc if (tmp == MAP_FAILED)
67433d6423SLionel Sambuc panic("unable to allocate temporary buffer");
68433d6423SLionel Sambuc }
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc addr = (vir_bytes) mmap((void *) buf->addr, len,
71433d6423SLionel Sambuc PROT_READ | PROT_WRITE, flags, -1, 0L);
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc if (addr != buf->addr)
74433d6423SLionel Sambuc panic("unable to allocate buffer (2)");
75433d6423SLionel Sambuc
76433d6423SLionel Sambuc if (!prealloc)
77433d6423SLionel Sambuc return;
78433d6423SLionel Sambuc
79433d6423SLionel Sambuc if ((r = munmap(tmp, len)) != OK)
80433d6423SLionel Sambuc panic("unable to unmap buffer (%d)", errno);
81433d6423SLionel Sambuc
82433d6423SLionel Sambuc if ((r = sys_umap(SELF, VM_D, addr, len, &buf->phys)) < 0)
83433d6423SLionel Sambuc panic("unable to get physical address of buffer (%d)", r);
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if (buf->phys != next)
86433d6423SLionel Sambuc return;
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc if (verbose)
89433d6423SLionel Sambuc printf("WARNING: alloc noncontigous range, second try\n");
90433d6423SLionel Sambuc
91433d6423SLionel Sambuc /* Can't remap this to elsewhere, so we run the risk of allocating the
92433d6423SLionel Sambuc * exact same physically contiguous page again. However, now that we've
93433d6423SLionel Sambuc * unmapped the temporary memory also, there's a small chance we'll end
94433d6423SLionel Sambuc * up with a different physical page this time. Who knows.
95433d6423SLionel Sambuc */
96433d6423SLionel Sambuc munmap((void *) addr, len);
97433d6423SLionel Sambuc
98433d6423SLionel Sambuc addr = (vir_bytes) mmap((void *) buf->addr, len,
99433d6423SLionel Sambuc PROT_READ | PROT_WRITE, flags, -1, 0L);
100433d6423SLionel Sambuc
101433d6423SLionel Sambuc if (addr != buf->addr)
102433d6423SLionel Sambuc panic("unable to allocate buffer, second try");
103433d6423SLionel Sambuc
104433d6423SLionel Sambuc if ((r = sys_umap(SELF, VM_D, addr, len, &buf->phys)) < 0)
105433d6423SLionel Sambuc panic("unable to get physical address of buffer (%d)", r);
106433d6423SLionel Sambuc
107433d6423SLionel Sambuc /* Still the same page? Screw it. */
108433d6423SLionel Sambuc if (buf->phys == next)
109433d6423SLionel Sambuc panic("unable to allocate noncontiguous range");
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc
alloc_bufs(struct buf * buf,int count)112433d6423SLionel Sambuc static void alloc_bufs(struct buf *buf, int count)
113433d6423SLionel Sambuc {
114433d6423SLionel Sambuc static vir_bytes base = 0x80000000L;
115433d6423SLionel Sambuc phys_bytes next;
116433d6423SLionel Sambuc int i;
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc /* Allocate the given memory in virtually contiguous blocks whenever
119433d6423SLionel Sambuc * each next buffer is requested to be adjacent. Insert a virtual gap
120433d6423SLionel Sambuc * after each such block. Make sure that each two adjacent buffers in a
121433d6423SLionel Sambuc * block are physically non-contiguous.
122433d6423SLionel Sambuc */
123433d6423SLionel Sambuc for (i = 0; i < count; i++) {
124433d6423SLionel Sambuc if (i > 0 && (buf[i].flags & BUF_ADJACENT)) {
125433d6423SLionel Sambuc next = buf[i-1].phys + buf[i-1].pages * PAGE_SIZE;
126433d6423SLionel Sambuc } else {
127433d6423SLionel Sambuc base += PAGE_SIZE * 16;
128433d6423SLionel Sambuc next = 0L;
129433d6423SLionel Sambuc }
130433d6423SLionel Sambuc
131433d6423SLionel Sambuc buf[i].addr = base;
132433d6423SLionel Sambuc
133433d6423SLionel Sambuc alloc_buf(&buf[i], next);
134433d6423SLionel Sambuc
135433d6423SLionel Sambuc base += buf[i].pages * PAGE_SIZE;
136433d6423SLionel Sambuc }
137433d6423SLionel Sambuc
138433d6423SLionel Sambuc #if DEBUG
139433d6423SLionel Sambuc for (i = 0; i < count; i++)
140433d6423SLionel Sambuc printf("Buf %d: %d pages, flags %x, vir %08x, phys %08x\n", i,
141433d6423SLionel Sambuc buf[i].pages, buf[i].flags, buf[i].addr, buf[i].phys);
142433d6423SLionel Sambuc #endif
143433d6423SLionel Sambuc }
144433d6423SLionel Sambuc
free_bufs(struct buf * buf,int count)145433d6423SLionel Sambuc static void free_bufs(struct buf *buf, int count)
146433d6423SLionel Sambuc {
147433d6423SLionel Sambuc int i, j, r;
148433d6423SLionel Sambuc
149433d6423SLionel Sambuc for (i = 0; i < count; i++) {
150433d6423SLionel Sambuc for (j = 0; j < buf[i].pages; j++) {
151433d6423SLionel Sambuc r = munmap((void *) (buf[i].addr + j * PAGE_SIZE),
152433d6423SLionel Sambuc PAGE_SIZE);
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc if (r != OK)
155433d6423SLionel Sambuc panic("unable to unmap range (%d)", errno);
156433d6423SLionel Sambuc }
157433d6423SLionel Sambuc }
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc
is_allocated(vir_bytes addr,size_t bytes,phys_bytes * phys)160433d6423SLionel Sambuc static int is_allocated(vir_bytes addr, size_t bytes, phys_bytes *phys)
161433d6423SLionel Sambuc {
162433d6423SLionel Sambuc int r;
163433d6423SLionel Sambuc
164433d6423SLionel Sambuc /* This will have to do for now. Of course, we could use sys_vumap with
165433d6423SLionel Sambuc * VUA_READ for this, but that would defeat the point of one test. It
166433d6423SLionel Sambuc * is still a decent alternative in case sys_umap's behavior ever
167433d6423SLionel Sambuc * changes, though.
168433d6423SLionel Sambuc */
169433d6423SLionel Sambuc r = sys_umap(SELF, VM_D, addr, bytes, phys);
170433d6423SLionel Sambuc
171433d6423SLionel Sambuc return r == OK;
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc
is_buf_allocated(struct buf * buf)174433d6423SLionel Sambuc static int is_buf_allocated(struct buf *buf)
175433d6423SLionel Sambuc {
176433d6423SLionel Sambuc return is_allocated(buf->addr, buf->pages * PAGE_SIZE, &buf->phys);
177433d6423SLionel Sambuc }
178433d6423SLionel Sambuc
test_group(char * name)179433d6423SLionel Sambuc static void test_group(char *name)
180433d6423SLionel Sambuc {
181433d6423SLionel Sambuc if (verbose)
182433d6423SLionel Sambuc printf("Test group: %s (%s)\n",
183433d6423SLionel Sambuc name, relay ? "relay" : "local");
184433d6423SLionel Sambuc }
185433d6423SLionel Sambuc
expect_f(int res,char * file,int line)186433d6423SLionel Sambuc static void expect_f(int res, char *file, int line)
187433d6423SLionel Sambuc {
188433d6423SLionel Sambuc if (!res && success) {
189433d6423SLionel Sambuc success = FALSE;
190433d6423SLionel Sambuc fail_file = file;
191433d6423SLionel Sambuc fail_line = line;
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc }
194433d6423SLionel Sambuc
got_result(char * desc)195433d6423SLionel Sambuc static void got_result(char *desc)
196433d6423SLionel Sambuc {
197433d6423SLionel Sambuc count++;
198433d6423SLionel Sambuc
199433d6423SLionel Sambuc if (!success) {
200433d6423SLionel Sambuc failures++;
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc printf("#%02d: %-38s\t[FAIL]\n", count, desc);
203433d6423SLionel Sambuc printf("- failure at %s:%d\n", fail_file, fail_line);
204433d6423SLionel Sambuc } else {
205433d6423SLionel Sambuc if (verbose)
206433d6423SLionel Sambuc printf("#%02d: %-38s\t[PASS]\n", count, desc);
207433d6423SLionel Sambuc }
208433d6423SLionel Sambuc }
209433d6423SLionel Sambuc
relay_vumap(struct vumap_vir * vvec,int vcount,size_t offset,int access,struct vumap_phys * pvec,int * pcount)210433d6423SLionel Sambuc static int relay_vumap(struct vumap_vir *vvec, int vcount, size_t offset,
211433d6423SLionel Sambuc int access, struct vumap_phys *pvec, int *pcount)
212433d6423SLionel Sambuc {
213433d6423SLionel Sambuc struct vumap_vir gvvec[MAPVEC_NR + 3];
214433d6423SLionel Sambuc cp_grant_id_t vgrant, pgrant;
215433d6423SLionel Sambuc message m;
216433d6423SLionel Sambuc int i, r, gaccess;
217433d6423SLionel Sambuc
218433d6423SLionel Sambuc assert(vcount > 0 && vcount <= MAPVEC_NR + 3);
219433d6423SLionel Sambuc assert(*pcount > 0 && *pcount <= MAPVEC_NR + 3);
220433d6423SLionel Sambuc
221433d6423SLionel Sambuc /* Allow grant access flags to be overridden for testing purposes. */
222433d6423SLionel Sambuc if (!(gaccess = grant_access)) {
223433d6423SLionel Sambuc if (access & VUA_READ) gaccess |= CPF_READ;
224433d6423SLionel Sambuc if (access & VUA_WRITE) gaccess |= CPF_WRITE;
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc
227433d6423SLionel Sambuc for (i = 0; i < vcount; i++) {
228433d6423SLionel Sambuc gvvec[i].vv_grant = cpf_grant_direct(endpt, vvec[i].vv_addr,
229433d6423SLionel Sambuc vvec[i].vv_size, gaccess);
230433d6423SLionel Sambuc assert(gvvec[i].vv_grant != GRANT_INVALID);
231433d6423SLionel Sambuc gvvec[i].vv_size = vvec[i].vv_size;
232433d6423SLionel Sambuc }
233433d6423SLionel Sambuc
234433d6423SLionel Sambuc vgrant = cpf_grant_direct(endpt, (vir_bytes) gvvec,
235433d6423SLionel Sambuc sizeof(gvvec[0]) * vcount, CPF_READ);
236433d6423SLionel Sambuc assert(vgrant != GRANT_INVALID);
237433d6423SLionel Sambuc
238433d6423SLionel Sambuc pgrant = cpf_grant_direct(endpt, (vir_bytes) pvec,
239433d6423SLionel Sambuc sizeof(pvec[0]) * *pcount, CPF_WRITE);
240433d6423SLionel Sambuc assert(pgrant != GRANT_INVALID);
241433d6423SLionel Sambuc
242433d6423SLionel Sambuc /* This must be done after allocating all other grants. */
243433d6423SLionel Sambuc if (grant_exception != GE_NONE) {
244433d6423SLionel Sambuc cpf_revoke(gvvec[vcount - 1].vv_grant);
245433d6423SLionel Sambuc if (grant_exception == GE_INVALID)
246433d6423SLionel Sambuc gvvec[vcount - 1].vv_grant = GRANT_INVALID;
247433d6423SLionel Sambuc }
248433d6423SLionel Sambuc
249433d6423SLionel Sambuc m.m_type = VTR_RELAY;
250433d6423SLionel Sambuc m.VTR_VGRANT = vgrant;
251433d6423SLionel Sambuc m.VTR_VCOUNT = vcount;
252433d6423SLionel Sambuc m.VTR_OFFSET = offset;
253433d6423SLionel Sambuc m.VTR_ACCESS = access;
254433d6423SLionel Sambuc m.VTR_PGRANT = pgrant;
255433d6423SLionel Sambuc m.VTR_PCOUNT = *pcount;
256433d6423SLionel Sambuc
257433d6423SLionel Sambuc r = ipc_sendrec(endpt, &m);
258433d6423SLionel Sambuc
259433d6423SLionel Sambuc cpf_revoke(pgrant);
260433d6423SLionel Sambuc cpf_revoke(vgrant);
261433d6423SLionel Sambuc
262433d6423SLionel Sambuc for (i = 0; i < vcount - !!grant_exception; i++)
263433d6423SLionel Sambuc cpf_revoke(gvvec[i].vv_grant);
264433d6423SLionel Sambuc
265433d6423SLionel Sambuc *pcount = m.VTR_PCOUNT;
266433d6423SLionel Sambuc
267433d6423SLionel Sambuc return (r != OK) ? r : m.m_type;
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc
do_vumap(endpoint_t endpt,struct vumap_vir * vvec,int vcount,size_t offset,int access,struct vumap_phys * pvec,int * pcount)270433d6423SLionel Sambuc static int do_vumap(endpoint_t endpt, struct vumap_vir *vvec, int vcount,
271433d6423SLionel Sambuc size_t offset, int access, struct vumap_phys *pvec, int *pcount)
272433d6423SLionel Sambuc {
273433d6423SLionel Sambuc struct vumap_phys pv_backup[MAPVEC_NR + 3];
274433d6423SLionel Sambuc int r, pc_backup, pv_test = FALSE;
275433d6423SLionel Sambuc
276433d6423SLionel Sambuc /* Make a copy of pvec and pcount for later. */
277433d6423SLionel Sambuc pc_backup = *pcount;
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc /* We cannot compare pvec contents before and after when relaying,
280433d6423SLionel Sambuc * since the original contents are not transferred.
281433d6423SLionel Sambuc */
282433d6423SLionel Sambuc if (!relay && pvec != NULL && pc_backup >= 1 &&
283433d6423SLionel Sambuc pc_backup <= MAPVEC_NR + 3) {
284433d6423SLionel Sambuc pv_test = TRUE;
285433d6423SLionel Sambuc memcpy(pv_backup, pvec, sizeof(*pvec) * pc_backup);
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc
288433d6423SLionel Sambuc /* Reset the test result. */
289433d6423SLionel Sambuc success = TRUE;
290433d6423SLionel Sambuc
291433d6423SLionel Sambuc /* Perform the vumap call, either directly or through a relay. */
292433d6423SLionel Sambuc if (relay) {
293433d6423SLionel Sambuc assert(endpt == SELF);
294433d6423SLionel Sambuc r = relay_vumap(vvec, vcount, offset, access, pvec, pcount);
295433d6423SLionel Sambuc } else {
296433d6423SLionel Sambuc r = sys_vumap(endpt, vvec, vcount, offset, access, pvec,
297433d6423SLionel Sambuc pcount);
298433d6423SLionel Sambuc }
299433d6423SLionel Sambuc
300433d6423SLionel Sambuc /* Upon failure, pvec and pcount must be unchanged. */
301433d6423SLionel Sambuc if (r != OK) {
302433d6423SLionel Sambuc expect(pc_backup == *pcount);
303433d6423SLionel Sambuc
304433d6423SLionel Sambuc if (pv_test)
305433d6423SLionel Sambuc expect(memcmp(pv_backup, pvec,
306433d6423SLionel Sambuc sizeof(*pvec) * pc_backup) == 0);
307433d6423SLionel Sambuc }
308433d6423SLionel Sambuc
309433d6423SLionel Sambuc return r;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc
test_basics(void)312433d6423SLionel Sambuc static void test_basics(void)
313433d6423SLionel Sambuc {
314433d6423SLionel Sambuc struct vumap_vir vvec[2];
315433d6423SLionel Sambuc struct vumap_phys pvec[4];
316433d6423SLionel Sambuc struct buf buf[4];
317433d6423SLionel Sambuc int r, pcount;
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc test_group("basics");
320433d6423SLionel Sambuc
321433d6423SLionel Sambuc buf[0].pages = 1;
322433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
323433d6423SLionel Sambuc buf[1].pages = 2;
324433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC;
325433d6423SLionel Sambuc buf[2].pages = 1;
326433d6423SLionel Sambuc buf[2].flags = BUF_PREALLOC;
327433d6423SLionel Sambuc buf[3].pages = 1;
328433d6423SLionel Sambuc buf[3].flags = BUF_PREALLOC | BUF_ADJACENT;
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc alloc_bufs(buf, 4);
331433d6423SLionel Sambuc
332433d6423SLionel Sambuc /* Test single whole page. */
333433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
334433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
335433d6423SLionel Sambuc pcount = 1;
336433d6423SLionel Sambuc
337433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
338433d6423SLionel Sambuc
339433d6423SLionel Sambuc expect(r == OK);
340433d6423SLionel Sambuc expect(pcount == 1);
341433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys);
342433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size);
343433d6423SLionel Sambuc
344433d6423SLionel Sambuc got_result("single whole page");
345433d6423SLionel Sambuc
346433d6423SLionel Sambuc /* Test single partial page. */
347433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr + 123;
348433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE - 456;
349433d6423SLionel Sambuc pcount = 1;
350433d6423SLionel Sambuc
351433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
352433d6423SLionel Sambuc
353433d6423SLionel Sambuc expect(r == OK);
354433d6423SLionel Sambuc expect(pcount == 1);
355433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys + 123);
356433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size);
357433d6423SLionel Sambuc
358433d6423SLionel Sambuc got_result("single partial page");
359433d6423SLionel Sambuc
360433d6423SLionel Sambuc /* Test multiple contiguous whole pages. */
361433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr;
362433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2;
363433d6423SLionel Sambuc pcount = 1;
364433d6423SLionel Sambuc
365433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
366433d6423SLionel Sambuc
367433d6423SLionel Sambuc expect(r == OK);
368433d6423SLionel Sambuc expect(pcount == 1);
369433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[1].phys);
370433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size);
371433d6423SLionel Sambuc
372433d6423SLionel Sambuc got_result("multiple contiguous whole pages");
373433d6423SLionel Sambuc
374433d6423SLionel Sambuc /* Test range in multiple contiguous pages. */
375433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr + 234;
376433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2 - 234;
377433d6423SLionel Sambuc pcount = 2;
378433d6423SLionel Sambuc
379433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
380433d6423SLionel Sambuc
381433d6423SLionel Sambuc expect(r == OK);
382433d6423SLionel Sambuc expect(pcount == 1);
383433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[1].phys + 234);
384433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size);
385433d6423SLionel Sambuc
386433d6423SLionel Sambuc got_result("range in multiple contiguous pages");
387433d6423SLionel Sambuc
388433d6423SLionel Sambuc /* Test multiple noncontiguous whole pages. */
389433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr;
390433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2;
391433d6423SLionel Sambuc pcount = 3;
392433d6423SLionel Sambuc
393433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
394433d6423SLionel Sambuc
395433d6423SLionel Sambuc expect(r == OK);
396433d6423SLionel Sambuc expect(pcount == 2);
397433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys);
398433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE);
399433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[3].phys);
400433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE);
401433d6423SLionel Sambuc
402433d6423SLionel Sambuc got_result("multiple noncontiguous whole pages");
403433d6423SLionel Sambuc
404433d6423SLionel Sambuc /* Test range in multiple noncontiguous pages. */
405433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr + 1;
406433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2 - 2;
407433d6423SLionel Sambuc pcount = 2;
408433d6423SLionel Sambuc
409433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
410433d6423SLionel Sambuc
411433d6423SLionel Sambuc expect(r == OK);
412433d6423SLionel Sambuc expect(pcount == 2);
413433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys + 1);
414433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE - 1);
415433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[3].phys);
416433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE - 1);
417433d6423SLionel Sambuc
418433d6423SLionel Sambuc got_result("range in multiple noncontiguous pages");
419433d6423SLionel Sambuc
420433d6423SLionel Sambuc /* Test single-input result truncation. */
421433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr + PAGE_SIZE / 2;
422433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
423433d6423SLionel Sambuc pvec[1].vp_addr = 0L;
424433d6423SLionel Sambuc pvec[1].vp_size = 0;
425433d6423SLionel Sambuc pcount = 1;
426433d6423SLionel Sambuc
427433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
428433d6423SLionel Sambuc
429433d6423SLionel Sambuc expect(r == OK);
430433d6423SLionel Sambuc expect(pcount == 1);
431433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys + PAGE_SIZE / 2);
432433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE / 2);
433433d6423SLionel Sambuc expect(pvec[1].vp_addr == 0L);
434433d6423SLionel Sambuc expect(pvec[1].vp_size == 0);
435433d6423SLionel Sambuc
436433d6423SLionel Sambuc got_result("single-input result truncation");
437433d6423SLionel Sambuc
438433d6423SLionel Sambuc /* Test multiple inputs, contiguous first. */
439433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
440433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
441433d6423SLionel Sambuc vvec[1].vv_addr = buf[2].addr + PAGE_SIZE - 1;
442433d6423SLionel Sambuc vvec[1].vv_size = 2;
443433d6423SLionel Sambuc pcount = 3;
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
446433d6423SLionel Sambuc
447433d6423SLionel Sambuc expect(r == OK);
448433d6423SLionel Sambuc expect(pcount == 3);
449433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys);
450433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE);
451433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[2].phys + PAGE_SIZE - 1);
452433d6423SLionel Sambuc expect(pvec[1].vp_size == 1);
453433d6423SLionel Sambuc expect(pvec[2].vp_addr == buf[3].phys);
454433d6423SLionel Sambuc expect(pvec[2].vp_size == 1);
455433d6423SLionel Sambuc
456433d6423SLionel Sambuc got_result("multiple inputs, contiguous first");
457433d6423SLionel Sambuc
458433d6423SLionel Sambuc /* Test multiple inputs, contiguous last. */
459433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr + 123;
460433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2 - 456;
461433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr + 234;
462433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE * 2 - 345;
463433d6423SLionel Sambuc pcount = 4;
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_WRITE, pvec, &pcount);
466433d6423SLionel Sambuc
467433d6423SLionel Sambuc expect(r == OK);
468433d6423SLionel Sambuc expect(pcount == 3);
469433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys + 123);
470433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE - 123);
471433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[3].phys);
472433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE - (456 - 123));
473433d6423SLionel Sambuc expect(pvec[2].vp_addr == buf[1].phys + 234);
474433d6423SLionel Sambuc expect(pvec[2].vp_size == vvec[1].vv_size);
475433d6423SLionel Sambuc
476433d6423SLionel Sambuc got_result("multiple inputs, contiguous last");
477433d6423SLionel Sambuc
478433d6423SLionel Sambuc /* Test multiple-inputs result truncation. */
479433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr + 2;
480433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2 - 3;
481433d6423SLionel Sambuc vvec[1].vv_addr = buf[0].addr;
482433d6423SLionel Sambuc vvec[1].vv_size = 135;
483433d6423SLionel Sambuc pvec[2].vp_addr = 0xDEADBEEFL;
484433d6423SLionel Sambuc pvec[2].vp_size = 1234;
485433d6423SLionel Sambuc pcount = 2;
486433d6423SLionel Sambuc
487433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
488433d6423SLionel Sambuc
489433d6423SLionel Sambuc expect(r == OK);
490433d6423SLionel Sambuc expect(pcount == 2);
491433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys + 2);
492433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE - 2);
493433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[3].phys);
494433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE - 1);
495433d6423SLionel Sambuc expect(pvec[2].vp_addr == 0xDEADBEEFL);
496433d6423SLionel Sambuc expect(pvec[2].vp_size == 1234);
497433d6423SLionel Sambuc
498433d6423SLionel Sambuc got_result("multiple-inputs result truncation");
499433d6423SLionel Sambuc
500433d6423SLionel Sambuc free_bufs(buf, 4);
501433d6423SLionel Sambuc }
502433d6423SLionel Sambuc
test_endpt(void)503433d6423SLionel Sambuc static void test_endpt(void)
504433d6423SLionel Sambuc {
505433d6423SLionel Sambuc struct vumap_vir vvec[1];
506433d6423SLionel Sambuc struct vumap_phys pvec[1];
507433d6423SLionel Sambuc struct buf buf[1];
508433d6423SLionel Sambuc int r, pcount;
509433d6423SLionel Sambuc
510433d6423SLionel Sambuc test_group("endpoint");
511433d6423SLionel Sambuc
512433d6423SLionel Sambuc buf[0].pages = 1;
513433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
514433d6423SLionel Sambuc
515433d6423SLionel Sambuc alloc_bufs(buf, 1);
516433d6423SLionel Sambuc
517433d6423SLionel Sambuc /* Test NONE endpoint. */
518433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
519433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
520433d6423SLionel Sambuc pcount = 1;
521433d6423SLionel Sambuc
522433d6423SLionel Sambuc r = do_vumap(NONE, vvec, 1, 0, VUA_READ, pvec, &pcount);
523433d6423SLionel Sambuc
524433d6423SLionel Sambuc expect(r == EINVAL);
525433d6423SLionel Sambuc
526433d6423SLionel Sambuc got_result("NONE endpoint");
527433d6423SLionel Sambuc
528433d6423SLionel Sambuc /* Test ANY endpoint. */
529433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
530433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
531433d6423SLionel Sambuc pcount = 1;
532433d6423SLionel Sambuc
533433d6423SLionel Sambuc r = do_vumap(ANY, vvec, 1, 0, VUA_READ, pvec, &pcount);
534433d6423SLionel Sambuc
535433d6423SLionel Sambuc expect(r == EINVAL);
536433d6423SLionel Sambuc
537433d6423SLionel Sambuc got_result("ANY endpoint");
538433d6423SLionel Sambuc
539433d6423SLionel Sambuc free_bufs(buf, 1);
540433d6423SLionel Sambuc }
541433d6423SLionel Sambuc
test_vector1(void)542433d6423SLionel Sambuc static void test_vector1(void)
543433d6423SLionel Sambuc {
544433d6423SLionel Sambuc struct vumap_vir vvec[2];
545433d6423SLionel Sambuc struct vumap_phys pvec[3];
546433d6423SLionel Sambuc struct buf buf[2];
547433d6423SLionel Sambuc int r, pcount;
548433d6423SLionel Sambuc
549433d6423SLionel Sambuc test_group("vector, part 1");
550433d6423SLionel Sambuc
551433d6423SLionel Sambuc buf[0].pages = 2;
552433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
553433d6423SLionel Sambuc buf[1].pages = 1;
554433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC;
555433d6423SLionel Sambuc
556433d6423SLionel Sambuc alloc_bufs(buf, 2);
557433d6423SLionel Sambuc
558433d6423SLionel Sambuc /* Test zero virtual memory size. */
559433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
560433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2;
561433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr;
562433d6423SLionel Sambuc vvec[1].vv_size = 0;
563433d6423SLionel Sambuc pcount = 3;
564433d6423SLionel Sambuc
565433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
566433d6423SLionel Sambuc
567433d6423SLionel Sambuc expect(r == EINVAL);
568433d6423SLionel Sambuc
569433d6423SLionel Sambuc got_result("zero virtual memory size");
570433d6423SLionel Sambuc
571433d6423SLionel Sambuc /* Test excessive virtual memory size. */
572433d6423SLionel Sambuc vvec[1].vv_size = (vir_bytes) -1;
573433d6423SLionel Sambuc
574433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
575433d6423SLionel Sambuc
576433d6423SLionel Sambuc expect(r == EFAULT || r == EPERM);
577433d6423SLionel Sambuc
578433d6423SLionel Sambuc got_result("excessive virtual memory size");
579433d6423SLionel Sambuc
580433d6423SLionel Sambuc /* Test invalid virtual memory. */
581433d6423SLionel Sambuc vvec[1].vv_addr = 0L;
582433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE;
583433d6423SLionel Sambuc
584433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
585433d6423SLionel Sambuc
586433d6423SLionel Sambuc expect(r == EFAULT);
587433d6423SLionel Sambuc
588433d6423SLionel Sambuc got_result("invalid virtual memory");
589433d6423SLionel Sambuc
590433d6423SLionel Sambuc /* Test virtual memory overrun. */
591433d6423SLionel Sambuc vvec[0].vv_size++;
592433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr;
593433d6423SLionel Sambuc
594433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
595433d6423SLionel Sambuc
596433d6423SLionel Sambuc expect(r == EFAULT);
597433d6423SLionel Sambuc
598433d6423SLionel Sambuc got_result("virtual memory overrun");
599433d6423SLionel Sambuc
600433d6423SLionel Sambuc free_bufs(buf, 2);
601433d6423SLionel Sambuc }
602433d6423SLionel Sambuc
test_vector2(void)603433d6423SLionel Sambuc static void test_vector2(void)
604433d6423SLionel Sambuc {
605433d6423SLionel Sambuc struct vumap_vir vvec[2], *vvecp;
606433d6423SLionel Sambuc struct vumap_phys pvec[3], *pvecp;
607433d6423SLionel Sambuc struct buf buf[2];
608433d6423SLionel Sambuc phys_bytes dummy;
609433d6423SLionel Sambuc int r, pcount;
610433d6423SLionel Sambuc
611433d6423SLionel Sambuc test_group("vector, part 2");
612433d6423SLionel Sambuc
613433d6423SLionel Sambuc buf[0].pages = 2;
614433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
615433d6423SLionel Sambuc buf[1].pages = 1;
616433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC;
617433d6423SLionel Sambuc
618433d6423SLionel Sambuc alloc_bufs(buf, 2);
619433d6423SLionel Sambuc
620433d6423SLionel Sambuc /* Test zero virtual count. */
621433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
622433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 2;
623433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr;
624433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE;
625433d6423SLionel Sambuc pcount = 3;
626433d6423SLionel Sambuc
627433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 0, 0, VUA_READ, pvec, &pcount);
628433d6423SLionel Sambuc
629433d6423SLionel Sambuc expect(r == EINVAL);
630433d6423SLionel Sambuc
631433d6423SLionel Sambuc got_result("zero virtual count");
632433d6423SLionel Sambuc
633433d6423SLionel Sambuc /* Test negative virtual count. */
634433d6423SLionel Sambuc r = do_vumap(SELF, vvec, -1, 0, VUA_WRITE, pvec, &pcount);
635433d6423SLionel Sambuc
636433d6423SLionel Sambuc expect(r == EINVAL);
637433d6423SLionel Sambuc
638433d6423SLionel Sambuc got_result("negative virtual count");
639433d6423SLionel Sambuc
640433d6423SLionel Sambuc /* Test zero physical count. */
641433d6423SLionel Sambuc pcount = 0;
642433d6423SLionel Sambuc
643433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_WRITE, pvec, &pcount);
644433d6423SLionel Sambuc
645433d6423SLionel Sambuc expect(r == EINVAL);
646433d6423SLionel Sambuc
647433d6423SLionel Sambuc got_result("zero physical count");
648433d6423SLionel Sambuc
649433d6423SLionel Sambuc /* Test negative physical count. */
650433d6423SLionel Sambuc pcount = -1;
651433d6423SLionel Sambuc
652433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
653433d6423SLionel Sambuc
654433d6423SLionel Sambuc expect(r == EINVAL);
655433d6423SLionel Sambuc
656433d6423SLionel Sambuc got_result("negative physical count");
657433d6423SLionel Sambuc
658433d6423SLionel Sambuc /* Test invalid virtual vector pointer. */
659433d6423SLionel Sambuc pcount = 2;
660433d6423SLionel Sambuc
661433d6423SLionel Sambuc r = do_vumap(SELF, NULL, 2, 0, VUA_READ, pvec, &pcount);
662433d6423SLionel Sambuc
663433d6423SLionel Sambuc expect(r == EFAULT);
664433d6423SLionel Sambuc
665433d6423SLionel Sambuc got_result("invalid virtual vector pointer");
666433d6423SLionel Sambuc
667433d6423SLionel Sambuc /* Test unallocated virtual vector. */
668433d6423SLionel Sambuc vvecp = (struct vumap_vir *) mmap(NULL, PAGE_SIZE,
669433d6423SLionel Sambuc PROT_READ | PROT_WRITE, MAP_ANON, -1, 0L);
670433d6423SLionel Sambuc
671433d6423SLionel Sambuc if (vvecp == MAP_FAILED)
672433d6423SLionel Sambuc panic("unable to allocate virtual vector");
673433d6423SLionel Sambuc
674433d6423SLionel Sambuc r = do_vumap(SELF, vvecp, 2, 0, VUA_READ, pvec, &pcount);
675433d6423SLionel Sambuc
676433d6423SLionel Sambuc expect(r == EFAULT);
677433d6423SLionel Sambuc expect(!is_allocated((vir_bytes) vvecp, PAGE_SIZE, &dummy));
678433d6423SLionel Sambuc
679433d6423SLionel Sambuc got_result("unallocated virtual vector pointer");
680433d6423SLionel Sambuc
681433d6423SLionel Sambuc munmap((void *) vvecp, PAGE_SIZE);
682433d6423SLionel Sambuc
683433d6423SLionel Sambuc /* Test invalid physical vector pointer. */
684433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, NULL, &pcount);
685433d6423SLionel Sambuc
686433d6423SLionel Sambuc expect(r == EFAULT);
687433d6423SLionel Sambuc
688433d6423SLionel Sambuc got_result("invalid physical vector pointer");
689433d6423SLionel Sambuc
690433d6423SLionel Sambuc /* Test unallocated physical vector. */
691433d6423SLionel Sambuc pvecp = (struct vumap_phys *) mmap(NULL, PAGE_SIZE,
692433d6423SLionel Sambuc PROT_READ | PROT_WRITE, MAP_ANON, -1, 0L);
693433d6423SLionel Sambuc
694433d6423SLionel Sambuc if (pvecp == MAP_FAILED)
695433d6423SLionel Sambuc panic("unable to allocate physical vector");
696433d6423SLionel Sambuc
697433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvecp, &pcount);
698433d6423SLionel Sambuc
699433d6423SLionel Sambuc expect(r == OK);
700433d6423SLionel Sambuc expect(is_allocated((vir_bytes) pvecp, PAGE_SIZE, &dummy));
701433d6423SLionel Sambuc expect(pcount == 2);
702433d6423SLionel Sambuc expect(pvecp[0].vp_size == PAGE_SIZE * 2);
703433d6423SLionel Sambuc expect(pvecp[0].vp_addr == buf[0].phys);
704433d6423SLionel Sambuc expect(pvecp[1].vp_size == PAGE_SIZE);
705433d6423SLionel Sambuc expect(pvecp[1].vp_addr == buf[1].phys);
706433d6423SLionel Sambuc
707433d6423SLionel Sambuc got_result("unallocated physical vector pointer");
708433d6423SLionel Sambuc
709433d6423SLionel Sambuc munmap((void *) pvecp, PAGE_SIZE);
710433d6423SLionel Sambuc
711433d6423SLionel Sambuc free_bufs(buf, 2);
712433d6423SLionel Sambuc }
713433d6423SLionel Sambuc
test_grant(void)714433d6423SLionel Sambuc static void test_grant(void)
715433d6423SLionel Sambuc {
716433d6423SLionel Sambuc struct vumap_vir vvec[2];
717433d6423SLionel Sambuc struct vumap_phys pvec[3];
718433d6423SLionel Sambuc struct buf buf[2];
719433d6423SLionel Sambuc int r, pcount;
720433d6423SLionel Sambuc
721433d6423SLionel Sambuc test_group("grant");
722433d6423SLionel Sambuc
723433d6423SLionel Sambuc buf[0].pages = 1;
724433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
725433d6423SLionel Sambuc buf[1].pages = 2;
726433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC;
727433d6423SLionel Sambuc
728433d6423SLionel Sambuc alloc_bufs(buf, 2);
729433d6423SLionel Sambuc
730433d6423SLionel Sambuc /* Test write-only access on read-only grant. */
731433d6423SLionel Sambuc grant_access = CPF_READ; /* override */
732433d6423SLionel Sambuc
733433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
734433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
735433d6423SLionel Sambuc pcount = 1;
736433d6423SLionel Sambuc
737433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
738433d6423SLionel Sambuc
739433d6423SLionel Sambuc expect(r == EPERM);
740433d6423SLionel Sambuc
741433d6423SLionel Sambuc got_result("write-only access on read-only grant");
742433d6423SLionel Sambuc
743433d6423SLionel Sambuc /* Test read-write access on read-only grant. */
744433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
745433d6423SLionel Sambuc
746433d6423SLionel Sambuc expect(r == EPERM);
747433d6423SLionel Sambuc
748433d6423SLionel Sambuc got_result("read-write access on read-only grant");
749433d6423SLionel Sambuc
750433d6423SLionel Sambuc /* Test read-only access on write-only grant. */
751433d6423SLionel Sambuc grant_access = CPF_WRITE; /* override */
752433d6423SLionel Sambuc
753433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
754433d6423SLionel Sambuc
755433d6423SLionel Sambuc expect(r == EPERM);
756433d6423SLionel Sambuc
757433d6423SLionel Sambuc got_result("read-only access on write-only grant");
758433d6423SLionel Sambuc
759433d6423SLionel Sambuc /* Test read-write access on write grant. */
760433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
761433d6423SLionel Sambuc
762433d6423SLionel Sambuc expect(r == EPERM);
763433d6423SLionel Sambuc
764433d6423SLionel Sambuc got_result("read-write access on write-only grant");
765433d6423SLionel Sambuc
766433d6423SLionel Sambuc /* Test read-only access on read-write grant. */
767433d6423SLionel Sambuc grant_access = CPF_READ | CPF_WRITE; /* override */
768433d6423SLionel Sambuc
769433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
770433d6423SLionel Sambuc
771433d6423SLionel Sambuc expect(r == OK);
772433d6423SLionel Sambuc expect(pcount == 1);
773433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE);
774433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys);
775433d6423SLionel Sambuc
776433d6423SLionel Sambuc got_result("read-only access on read-write grant");
777433d6423SLionel Sambuc
778433d6423SLionel Sambuc grant_access = 0; /* reset */
779433d6423SLionel Sambuc
780433d6423SLionel Sambuc /* Test invalid grant. */
781433d6423SLionel Sambuc grant_exception = GE_INVALID;
782433d6423SLionel Sambuc
783433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
784433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
785433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr;
786433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE * 2;
787433d6423SLionel Sambuc pcount = 3;
788433d6423SLionel Sambuc
789433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
790433d6423SLionel Sambuc
791433d6423SLionel Sambuc expect(r == EINVAL);
792433d6423SLionel Sambuc
793433d6423SLionel Sambuc got_result("invalid grant");
794433d6423SLionel Sambuc
795433d6423SLionel Sambuc /* Test revoked grant. */
796433d6423SLionel Sambuc grant_exception = GE_REVOKED;
797433d6423SLionel Sambuc
798433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, 0, VUA_READ, pvec, &pcount);
799433d6423SLionel Sambuc
800433d6423SLionel Sambuc expect(r == EPERM);
801433d6423SLionel Sambuc
802433d6423SLionel Sambuc got_result("revoked grant");
803433d6423SLionel Sambuc
804433d6423SLionel Sambuc grant_exception = GE_NONE;
805433d6423SLionel Sambuc
806433d6423SLionel Sambuc free_bufs(buf, 2);
807433d6423SLionel Sambuc }
808433d6423SLionel Sambuc
test_offset(void)809433d6423SLionel Sambuc static void test_offset(void)
810433d6423SLionel Sambuc {
811433d6423SLionel Sambuc struct vumap_vir vvec[2];
812433d6423SLionel Sambuc struct vumap_phys pvec[3];
813433d6423SLionel Sambuc struct buf buf[4];
814433d6423SLionel Sambuc size_t off, off2;
815433d6423SLionel Sambuc int r, pcount;
816433d6423SLionel Sambuc
817433d6423SLionel Sambuc test_group("offsets");
818433d6423SLionel Sambuc
819433d6423SLionel Sambuc buf[0].pages = 1;
820433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
821433d6423SLionel Sambuc buf[1].pages = 2;
822433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC;
823433d6423SLionel Sambuc buf[2].pages = 1;
824433d6423SLionel Sambuc buf[2].flags = BUF_PREALLOC;
825433d6423SLionel Sambuc buf[3].pages = 1;
826433d6423SLionel Sambuc buf[3].flags = BUF_PREALLOC | BUF_ADJACENT;
827433d6423SLionel Sambuc
828433d6423SLionel Sambuc alloc_bufs(buf, 4);
829433d6423SLionel Sambuc
830433d6423SLionel Sambuc /* Test offset into aligned page. */
831433d6423SLionel Sambuc off = 123;
832433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
833433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
834433d6423SLionel Sambuc pcount = 2;
835433d6423SLionel Sambuc
836433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, off, VUA_READ, pvec, &pcount);
837433d6423SLionel Sambuc
838433d6423SLionel Sambuc expect(r == OK);
839433d6423SLionel Sambuc expect(pcount == 1);
840433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys + off);
841433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size - off);
842433d6423SLionel Sambuc
843433d6423SLionel Sambuc got_result("offset into aligned page");
844433d6423SLionel Sambuc
845433d6423SLionel Sambuc /* Test offset into unaligned page. */
846433d6423SLionel Sambuc off2 = 456;
847433d6423SLionel Sambuc assert(off + off2 < PAGE_SIZE);
848433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr + off;
849433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE - off;
850433d6423SLionel Sambuc pcount = 2;
851433d6423SLionel Sambuc
852433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
853433d6423SLionel Sambuc
854433d6423SLionel Sambuc expect(r == OK);
855433d6423SLionel Sambuc expect(pcount == 1);
856433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys + off + off2);
857433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size - off2);
858433d6423SLionel Sambuc
859433d6423SLionel Sambuc got_result("offset into unaligned page");
860433d6423SLionel Sambuc
861433d6423SLionel Sambuc /* Test offset into unaligned page set. */
862433d6423SLionel Sambuc off = 1234;
863433d6423SLionel Sambuc off2 = 567;
864433d6423SLionel Sambuc assert(off + off2 < PAGE_SIZE);
865433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr + off;
866433d6423SLionel Sambuc vvec[0].vv_size = (PAGE_SIZE - off) * 2;
867433d6423SLionel Sambuc pcount = 3;
868433d6423SLionel Sambuc
869433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
870433d6423SLionel Sambuc
871433d6423SLionel Sambuc expect(r == OK);
872433d6423SLionel Sambuc expect(pcount == 1);
873433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[1].phys + off + off2);
874433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size - off2);
875433d6423SLionel Sambuc
876433d6423SLionel Sambuc got_result("offset into contiguous page set");
877433d6423SLionel Sambuc
878433d6423SLionel Sambuc /* Test offset into noncontiguous page set. */
879433d6423SLionel Sambuc vvec[0].vv_addr = buf[2].addr + off;
880433d6423SLionel Sambuc vvec[0].vv_size = (PAGE_SIZE - off) * 2;
881433d6423SLionel Sambuc pcount = 3;
882433d6423SLionel Sambuc
883433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, off2, VUA_READ, pvec, &pcount);
884433d6423SLionel Sambuc
885433d6423SLionel Sambuc expect(r == OK);
886433d6423SLionel Sambuc expect(pcount == 2);
887433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[2].phys + off + off2);
888433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE - off - off2);
889433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[3].phys);
890433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE - off);
891433d6423SLionel Sambuc
892433d6423SLionel Sambuc got_result("offset into noncontiguous page set");
893433d6423SLionel Sambuc
894433d6423SLionel Sambuc /* Test offset to last byte. */
895433d6423SLionel Sambuc off = PAGE_SIZE - off2 - 1;
896433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr + off2;
897433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE - off2;
898433d6423SLionel Sambuc pcount = 2;
899433d6423SLionel Sambuc
900433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, off, VUA_READ, pvec, &pcount);
901433d6423SLionel Sambuc
902433d6423SLionel Sambuc expect(r == OK);
903433d6423SLionel Sambuc expect(pcount == 1);
904433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys + off + off2);
905433d6423SLionel Sambuc expect(pvec[0].vp_size == 1);
906433d6423SLionel Sambuc
907433d6423SLionel Sambuc got_result("offset to last byte");
908433d6423SLionel Sambuc
909433d6423SLionel Sambuc /* Test offset at range end. */
910433d6423SLionel Sambuc off = 234;
911433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr + off;
912433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE - off * 2;
913433d6423SLionel Sambuc vvec[1].vv_addr = vvec[0].vv_addr + vvec[0].vv_size;
914433d6423SLionel Sambuc vvec[1].vv_size = off;
915433d6423SLionel Sambuc
916433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, vvec[0].vv_size, VUA_READ, pvec, &pcount);
917433d6423SLionel Sambuc
918433d6423SLionel Sambuc expect(r == EINVAL);
919433d6423SLionel Sambuc
920433d6423SLionel Sambuc got_result("offset at range end");
921433d6423SLionel Sambuc
922433d6423SLionel Sambuc /* Test offset beyond range end. */
923433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr;
924433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
925433d6423SLionel Sambuc vvec[1].vv_addr = buf[1].addr + PAGE_SIZE;
926433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE;
927433d6423SLionel Sambuc
928433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 2, PAGE_SIZE + off, VUA_READ, pvec, &pcount);
929433d6423SLionel Sambuc
930433d6423SLionel Sambuc expect(r == EINVAL);
931433d6423SLionel Sambuc
932433d6423SLionel Sambuc got_result("offset beyond range end");
933433d6423SLionel Sambuc
934433d6423SLionel Sambuc /* Test negative offset. */
935433d6423SLionel Sambuc vvec[0].vv_addr = buf[1].addr + off + off2;
936433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE;
937433d6423SLionel Sambuc
938433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, (size_t) -1, VUA_READ, pvec, &pcount);
939433d6423SLionel Sambuc
940433d6423SLionel Sambuc expect(r == EINVAL);
941433d6423SLionel Sambuc
942433d6423SLionel Sambuc got_result("negative offset");
943433d6423SLionel Sambuc
944433d6423SLionel Sambuc free_bufs(buf, 4);
945433d6423SLionel Sambuc }
946433d6423SLionel Sambuc
test_access(void)947433d6423SLionel Sambuc static void test_access(void)
948433d6423SLionel Sambuc {
949433d6423SLionel Sambuc struct vumap_vir vvec[3];
950433d6423SLionel Sambuc struct vumap_phys pvec[4], *pvecp;
951433d6423SLionel Sambuc struct buf buf[7];
952433d6423SLionel Sambuc int i, r, pcount, pindex;
953433d6423SLionel Sambuc
954433d6423SLionel Sambuc test_group("access");
955433d6423SLionel Sambuc
956433d6423SLionel Sambuc buf[0].pages = 1;
957433d6423SLionel Sambuc buf[0].flags = 0;
958433d6423SLionel Sambuc buf[1].pages = 1;
959433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC | BUF_ADJACENT;
960433d6423SLionel Sambuc buf[2].pages = 1;
961433d6423SLionel Sambuc buf[2].flags = BUF_ADJACENT;
962433d6423SLionel Sambuc
963433d6423SLionel Sambuc alloc_bufs(buf, 3);
964433d6423SLionel Sambuc
965433d6423SLionel Sambuc /* Test no access flags. */
966433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
967433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 3;
968433d6423SLionel Sambuc pcount = 4;
969433d6423SLionel Sambuc
970433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, 0, pvec, &pcount);
971433d6423SLionel Sambuc
972433d6423SLionel Sambuc expect(r == EINVAL);
973433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[0]));
974433d6423SLionel Sambuc expect(is_buf_allocated(&buf[1]));
975433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[2]));
976433d6423SLionel Sambuc
977433d6423SLionel Sambuc got_result("no access flags");
978433d6423SLionel Sambuc
979433d6423SLionel Sambuc /* Test read-only access. */
980433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
981433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 3;
982433d6423SLionel Sambuc pcount = 1;
983433d6423SLionel Sambuc
984433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
985433d6423SLionel Sambuc
986433d6423SLionel Sambuc expect(r == EFAULT);
987433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[0]));
988433d6423SLionel Sambuc expect(is_buf_allocated(&buf[1]));
989433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[2]));
990433d6423SLionel Sambuc
991433d6423SLionel Sambuc got_result("read-only access");
992433d6423SLionel Sambuc
993433d6423SLionel Sambuc /* Test read-write access. */
994433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
995433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 3;
996433d6423SLionel Sambuc pcount = 4;
997433d6423SLionel Sambuc
998433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ | VUA_WRITE, pvec, &pcount);
999433d6423SLionel Sambuc
1000433d6423SLionel Sambuc expect(r == EFAULT);
1001433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[0]));
1002433d6423SLionel Sambuc expect(is_buf_allocated(&buf[1]));
1003433d6423SLionel Sambuc expect(!is_buf_allocated(&buf[2]));
1004433d6423SLionel Sambuc
1005433d6423SLionel Sambuc got_result("read-write access");
1006433d6423SLionel Sambuc
1007433d6423SLionel Sambuc /* Test write-only access. */
1008433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
1009433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE * 3;
1010433d6423SLionel Sambuc pcount = 4;
1011433d6423SLionel Sambuc
1012433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_WRITE, pvec, &pcount);
1013433d6423SLionel Sambuc
1014433d6423SLionel Sambuc expect(r == OK);
1015433d6423SLionel Sambuc /* We don't control the physical addresses of the faulted-in pages, so
1016433d6423SLionel Sambuc * they may or may not end up being contiguous with their neighbours.
1017433d6423SLionel Sambuc */
1018433d6423SLionel Sambuc expect(pcount >= 1 && pcount <= 3);
1019433d6423SLionel Sambuc expect(is_buf_allocated(&buf[0]));
1020433d6423SLionel Sambuc expect(is_buf_allocated(&buf[1]));
1021433d6423SLionel Sambuc expect(is_buf_allocated(&buf[2]));
1022433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys);
1023433d6423SLionel Sambuc switch (pcount) {
1024433d6423SLionel Sambuc case 1:
1025433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE * 3);
1026433d6423SLionel Sambuc break;
1027433d6423SLionel Sambuc case 2:
1028433d6423SLionel Sambuc expect(pvec[0].vp_size + pvec[1].vp_size == PAGE_SIZE * 3);
1029433d6423SLionel Sambuc if (pvec[0].vp_size > PAGE_SIZE)
1030433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[2].phys);
1031433d6423SLionel Sambuc else
1032433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[1].phys);
1033433d6423SLionel Sambuc break;
1034433d6423SLionel Sambuc case 3:
1035433d6423SLionel Sambuc expect(pvec[0].vp_size == PAGE_SIZE);
1036433d6423SLionel Sambuc expect(pvec[1].vp_addr == buf[1].phys);
1037433d6423SLionel Sambuc expect(pvec[1].vp_size == PAGE_SIZE);
1038433d6423SLionel Sambuc expect(pvec[2].vp_addr == buf[2].phys);
1039433d6423SLionel Sambuc expect(pvec[2].vp_size == PAGE_SIZE);
1040433d6423SLionel Sambuc break;
1041433d6423SLionel Sambuc }
1042433d6423SLionel Sambuc
1043433d6423SLionel Sambuc got_result("write-only access");
1044433d6423SLionel Sambuc
1045433d6423SLionel Sambuc free_bufs(buf, 3);
1046433d6423SLionel Sambuc
1047433d6423SLionel Sambuc /* Test page faulting. */
1048433d6423SLionel Sambuc buf[0].pages = 1;
1049433d6423SLionel Sambuc buf[0].flags = 0;
1050433d6423SLionel Sambuc buf[1].pages = 1;
1051433d6423SLionel Sambuc buf[1].flags = BUF_PREALLOC | BUF_ADJACENT;
1052433d6423SLionel Sambuc buf[2].pages = 1;
1053433d6423SLionel Sambuc buf[2].flags = 0;
1054433d6423SLionel Sambuc buf[3].pages = 2;
1055433d6423SLionel Sambuc buf[3].flags = BUF_PREALLOC;
1056433d6423SLionel Sambuc buf[4].pages = 1;
1057433d6423SLionel Sambuc buf[4].flags = BUF_ADJACENT;
1058433d6423SLionel Sambuc buf[5].pages = 1;
1059433d6423SLionel Sambuc buf[5].flags = BUF_ADJACENT;
1060433d6423SLionel Sambuc buf[6].pages = 1;
1061433d6423SLionel Sambuc buf[6].flags = 0;
1062433d6423SLionel Sambuc
1063433d6423SLionel Sambuc alloc_bufs(buf, 7);
1064433d6423SLionel Sambuc
1065433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr + PAGE_SIZE - 1;
1066433d6423SLionel Sambuc vvec[0].vv_size = PAGE_SIZE - 1;
1067433d6423SLionel Sambuc vvec[1].vv_addr = buf[2].addr;
1068433d6423SLionel Sambuc vvec[1].vv_size = PAGE_SIZE;
1069433d6423SLionel Sambuc vvec[2].vv_addr = buf[3].addr + 123;
1070433d6423SLionel Sambuc vvec[2].vv_size = PAGE_SIZE * 4 - 456;
1071433d6423SLionel Sambuc pvecp = (struct vumap_phys *) buf[6].addr;
1072433d6423SLionel Sambuc pcount = 7;
1073433d6423SLionel Sambuc assert(sizeof(struct vumap_phys) * pcount <= PAGE_SIZE);
1074433d6423SLionel Sambuc
1075433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 3, 0, VUA_WRITE, pvecp, &pcount);
1076433d6423SLionel Sambuc
1077433d6423SLionel Sambuc expect(r == OK);
1078433d6423SLionel Sambuc /* Same story but more possibilities. I hope I got this right. */
1079*f83d70a5SDavid van Moolenbroek expect(pcount >= 3 && pcount <= 6);
1080433d6423SLionel Sambuc for (i = 0; i < 7; i++)
1081433d6423SLionel Sambuc expect(is_buf_allocated(&buf[i]));
1082433d6423SLionel Sambuc expect(pvecp[0].vp_addr = buf[0].phys);
1083433d6423SLionel Sambuc if (pvecp[0].vp_size == 1) {
1084433d6423SLionel Sambuc expect(pvecp[1].vp_addr == buf[1].phys);
1085433d6423SLionel Sambuc expect(pvecp[1].vp_size == PAGE_SIZE - 2);
1086433d6423SLionel Sambuc pindex = 2;
1087433d6423SLionel Sambuc } else {
1088433d6423SLionel Sambuc expect(pvecp[0].vp_size == PAGE_SIZE - 1);
1089433d6423SLionel Sambuc pindex = 1;
1090433d6423SLionel Sambuc }
1091433d6423SLionel Sambuc expect(pvecp[pindex].vp_addr == buf[2].phys);
1092433d6423SLionel Sambuc expect(pvecp[pindex].vp_size == PAGE_SIZE);
1093433d6423SLionel Sambuc pindex++;
1094433d6423SLionel Sambuc expect(pvecp[pindex].vp_addr == buf[3].phys + 123);
1095433d6423SLionel Sambuc switch (pcount - pindex) {
1096433d6423SLionel Sambuc case 1:
1097433d6423SLionel Sambuc expect(pvecp[pindex].vp_size == PAGE_SIZE * 4 - 456);
1098433d6423SLionel Sambuc break;
1099433d6423SLionel Sambuc case 2:
1100433d6423SLionel Sambuc if (pvecp[pindex].vp_size > PAGE_SIZE * 2 - 123) {
1101433d6423SLionel Sambuc expect(pvecp[pindex].vp_size == PAGE_SIZE * 3 - 123);
1102433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_addr == buf[5].phys);
1103433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_size ==
1104433d6423SLionel Sambuc PAGE_SIZE - (456 - 123));
1105433d6423SLionel Sambuc } else {
1106433d6423SLionel Sambuc expect(pvecp[pindex].vp_size == PAGE_SIZE * 2 - 123);
1107433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_addr == buf[4].phys);
1108433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_size ==
1109433d6423SLionel Sambuc PAGE_SIZE * 2 - (456 - 123));
1110433d6423SLionel Sambuc }
1111433d6423SLionel Sambuc break;
1112433d6423SLionel Sambuc case 3:
1113433d6423SLionel Sambuc expect(pvecp[pindex].vp_size == PAGE_SIZE * 2 - 123);
1114433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_addr == buf[4].phys);
1115433d6423SLionel Sambuc expect(pvecp[pindex + 1].vp_size == PAGE_SIZE);
1116433d6423SLionel Sambuc expect(pvecp[pindex + 2].vp_addr == buf[5].phys);
1117433d6423SLionel Sambuc expect(pvecp[pindex + 2].vp_size == PAGE_SIZE - (456 - 123));
1118433d6423SLionel Sambuc break;
1119433d6423SLionel Sambuc default:
1120433d6423SLionel Sambuc expect(0);
1121433d6423SLionel Sambuc }
1122433d6423SLionel Sambuc
1123433d6423SLionel Sambuc got_result("page faulting");
1124433d6423SLionel Sambuc
1125433d6423SLionel Sambuc free_bufs(buf, 7);
1126433d6423SLionel Sambuc
1127433d6423SLionel Sambuc /* MISSING: tests to see whether a request with VUA_WRITE or
1128433d6423SLionel Sambuc * (VUA_READ|VUA_WRITE) correctly gets an EFAULT for a read-only page.
1129433d6423SLionel Sambuc * As of writing, support for such protection is missing from the
1130433d6423SLionel Sambuc * system at all.
1131433d6423SLionel Sambuc */
1132433d6423SLionel Sambuc }
1133433d6423SLionel Sambuc
phys_limit(struct vumap_vir * vvec,int vcount,struct vumap_phys * pvec,int pcount,struct buf * buf,char * desc)1134433d6423SLionel Sambuc static void phys_limit(struct vumap_vir *vvec, int vcount,
1135433d6423SLionel Sambuc struct vumap_phys *pvec, int pcount, struct buf *buf, char *desc)
1136433d6423SLionel Sambuc {
1137433d6423SLionel Sambuc int i, r;
1138433d6423SLionel Sambuc
1139433d6423SLionel Sambuc r = do_vumap(SELF, vvec, vcount, 0, VUA_READ, pvec, &pcount);
1140433d6423SLionel Sambuc
1141433d6423SLionel Sambuc expect(r == OK);
1142433d6423SLionel Sambuc expect(pcount == MAPVEC_NR);
1143433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR; i++) {
1144433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i].phys);
1145433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1146433d6423SLionel Sambuc }
1147433d6423SLionel Sambuc
1148433d6423SLionel Sambuc got_result(desc);
1149433d6423SLionel Sambuc }
1150433d6423SLionel Sambuc
test_limits(void)1151433d6423SLionel Sambuc static void test_limits(void)
1152433d6423SLionel Sambuc {
1153433d6423SLionel Sambuc struct vumap_vir vvec[MAPVEC_NR + 3];
1154433d6423SLionel Sambuc struct vumap_phys pvec[MAPVEC_NR + 3];
1155433d6423SLionel Sambuc struct buf buf[MAPVEC_NR + 9];
1156433d6423SLionel Sambuc int i, r, vcount, pcount, nr_bufs;
1157433d6423SLionel Sambuc
1158433d6423SLionel Sambuc test_group("limits");
1159433d6423SLionel Sambuc
1160433d6423SLionel Sambuc /* Test large contiguous range. */
1161433d6423SLionel Sambuc buf[0].pages = MAPVEC_NR + 2;
1162433d6423SLionel Sambuc buf[0].flags = BUF_PREALLOC;
1163433d6423SLionel Sambuc
1164433d6423SLionel Sambuc alloc_bufs(buf, 1);
1165433d6423SLionel Sambuc
1166433d6423SLionel Sambuc vvec[0].vv_addr = buf[0].addr;
1167433d6423SLionel Sambuc vvec[0].vv_size = (MAPVEC_NR + 2) * PAGE_SIZE;
1168433d6423SLionel Sambuc pcount = 2;
1169433d6423SLionel Sambuc
1170433d6423SLionel Sambuc r = do_vumap(SELF, vvec, 1, 0, VUA_READ, pvec, &pcount);
1171433d6423SLionel Sambuc
1172433d6423SLionel Sambuc expect(r == OK);
1173433d6423SLionel Sambuc expect(pcount == 1);
1174433d6423SLionel Sambuc expect(pvec[0].vp_addr == buf[0].phys);
1175433d6423SLionel Sambuc expect(pvec[0].vp_size == vvec[0].vv_size);
1176433d6423SLionel Sambuc
1177433d6423SLionel Sambuc got_result("large contiguous range");
1178433d6423SLionel Sambuc
1179433d6423SLionel Sambuc free_bufs(buf, 1);
1180433d6423SLionel Sambuc
1181433d6423SLionel Sambuc /* I'd like to test MAPVEC_NR contiguous ranges of MAPVEC_NR pages
1182433d6423SLionel Sambuc * each, but chances are we don't have that much contiguous memory
1183433d6423SLionel Sambuc * available at all. In fact, the previous test may already fail
1184433d6423SLionel Sambuc * because of this..
1185433d6423SLionel Sambuc */
1186433d6423SLionel Sambuc
1187433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR + 2; i++) {
1188433d6423SLionel Sambuc buf[i].pages = 1;
1189433d6423SLionel Sambuc buf[i].flags = BUF_PREALLOC;
1190433d6423SLionel Sambuc }
1191433d6423SLionel Sambuc buf[i].pages = 1;
1192433d6423SLionel Sambuc buf[i].flags = BUF_PREALLOC | BUF_ADJACENT;
1193433d6423SLionel Sambuc
1194433d6423SLionel Sambuc alloc_bufs(buf, MAPVEC_NR + 3);
1195433d6423SLionel Sambuc
1196433d6423SLionel Sambuc /* Test virtual limit, one below. */
1197433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR + 2; i++) {
1198433d6423SLionel Sambuc vvec[i].vv_addr = buf[i].addr;
1199433d6423SLionel Sambuc vvec[i].vv_size = PAGE_SIZE;
1200433d6423SLionel Sambuc }
1201433d6423SLionel Sambuc vvec[i - 1].vv_size += PAGE_SIZE;
1202433d6423SLionel Sambuc
1203433d6423SLionel Sambuc pcount = MAPVEC_NR + 3;
1204433d6423SLionel Sambuc
1205433d6423SLionel Sambuc r = do_vumap(SELF, vvec, MAPVEC_NR - 1, 0, VUA_READ, pvec, &pcount);
1206433d6423SLionel Sambuc
1207433d6423SLionel Sambuc expect(r == OK);
1208433d6423SLionel Sambuc expect(pcount == MAPVEC_NR - 1);
1209433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR - 1; i++) {
1210433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i].phys);
1211433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1212433d6423SLionel Sambuc }
1213433d6423SLionel Sambuc
1214433d6423SLionel Sambuc got_result("virtual limit, one below");
1215433d6423SLionel Sambuc
1216433d6423SLionel Sambuc /* Test virtual limit, exact match. */
1217433d6423SLionel Sambuc pcount = MAPVEC_NR + 3;
1218433d6423SLionel Sambuc
1219433d6423SLionel Sambuc r = do_vumap(SELF, vvec, MAPVEC_NR, 0, VUA_WRITE, pvec, &pcount);
1220433d6423SLionel Sambuc
1221433d6423SLionel Sambuc expect(r == OK);
1222433d6423SLionel Sambuc expect(pcount == MAPVEC_NR);
1223433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR; i++) {
1224433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i].phys);
1225433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1226433d6423SLionel Sambuc }
1227433d6423SLionel Sambuc
1228433d6423SLionel Sambuc got_result("virtual limit, exact match");
1229433d6423SLionel Sambuc
1230433d6423SLionel Sambuc /* Test virtual limit, one above. */
1231433d6423SLionel Sambuc pcount = MAPVEC_NR + 3;
1232433d6423SLionel Sambuc
1233433d6423SLionel Sambuc r = do_vumap(SELF, vvec, MAPVEC_NR + 1, 0, VUA_READ, pvec, &pcount);
1234433d6423SLionel Sambuc
1235433d6423SLionel Sambuc expect(r == OK);
1236433d6423SLionel Sambuc expect(pcount == MAPVEC_NR);
1237433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR; i++) {
1238433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i].phys);
1239433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1240433d6423SLionel Sambuc }
1241433d6423SLionel Sambuc
1242433d6423SLionel Sambuc got_result("virtual limit, one above");
1243433d6423SLionel Sambuc
1244433d6423SLionel Sambuc /* Test virtual limit, two above. */
1245433d6423SLionel Sambuc pcount = MAPVEC_NR + 3;
1246433d6423SLionel Sambuc
1247433d6423SLionel Sambuc r = do_vumap(SELF, vvec, MAPVEC_NR + 2, 0, VUA_WRITE, pvec, &pcount);
1248433d6423SLionel Sambuc
1249433d6423SLionel Sambuc expect(r == OK);
1250433d6423SLionel Sambuc expect(pcount == MAPVEC_NR);
1251433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR; i++) {
1252433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i].phys);
1253433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1254433d6423SLionel Sambuc }
1255433d6423SLionel Sambuc
1256433d6423SLionel Sambuc got_result("virtual limit, two above");
1257433d6423SLionel Sambuc
1258433d6423SLionel Sambuc /* Test physical limit, one below, aligned. */
1259433d6423SLionel Sambuc pcount = MAPVEC_NR - 1;
1260433d6423SLionel Sambuc
1261433d6423SLionel Sambuc r = do_vumap(SELF, vvec + 2, MAPVEC_NR, 0, VUA_READ, pvec, &pcount);
1262433d6423SLionel Sambuc
1263433d6423SLionel Sambuc expect(r == OK);
1264433d6423SLionel Sambuc expect(pcount == MAPVEC_NR - 1);
1265433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR - 1; i++) {
1266433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i + 2].phys);
1267433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1268433d6423SLionel Sambuc }
1269433d6423SLionel Sambuc
1270433d6423SLionel Sambuc got_result("physical limit, one below, aligned");
1271433d6423SLionel Sambuc
1272433d6423SLionel Sambuc /* Test physical limit, one below, unaligned. */
1273433d6423SLionel Sambuc pcount = MAPVEC_NR - 1;
1274433d6423SLionel Sambuc
1275433d6423SLionel Sambuc r = do_vumap(SELF, vvec + 3, MAPVEC_NR, 0, VUA_READ, pvec, &pcount);
1276433d6423SLionel Sambuc
1277433d6423SLionel Sambuc expect(r == OK);
1278433d6423SLionel Sambuc expect(pcount == MAPVEC_NR - 1);
1279433d6423SLionel Sambuc for (i = 0; i < MAPVEC_NR - 1; i++) {
1280433d6423SLionel Sambuc expect(pvec[i].vp_addr == buf[i + 3].phys);
1281433d6423SLionel Sambuc expect(pvec[i].vp_size == PAGE_SIZE);
1282433d6423SLionel Sambuc }
1283433d6423SLionel Sambuc
1284433d6423SLionel Sambuc got_result("physical limit, one below, unaligned");
1285433d6423SLionel Sambuc
1286433d6423SLionel Sambuc free_bufs(buf, MAPVEC_NR + 3);
1287433d6423SLionel Sambuc
1288433d6423SLionel Sambuc nr_bufs = sizeof(buf) / sizeof(buf[0]);
1289433d6423SLionel Sambuc
1290433d6423SLionel Sambuc /* This ends up looking in our virtual address space as follows:
1291433d6423SLionel Sambuc * [P] [P] [P] [PPP] [PPP] ...(MAPVEC_NR x [PPP])... [PPP]
1292433d6423SLionel Sambuc * ..where P is a page, and the blocks are virtually contiguous.
1293433d6423SLionel Sambuc */
1294433d6423SLionel Sambuc for (i = 0; i < nr_bufs; i += 3) {
1295433d6423SLionel Sambuc buf[i].pages = 1;
1296433d6423SLionel Sambuc buf[i].flags = BUF_PREALLOC;
1297433d6423SLionel Sambuc buf[i + 1].pages = 1;
1298433d6423SLionel Sambuc buf[i + 1].flags =
1299433d6423SLionel Sambuc BUF_PREALLOC | ((i >= 3) ? BUF_ADJACENT : 0);
1300433d6423SLionel Sambuc buf[i + 2].pages = 1;
1301433d6423SLionel Sambuc buf[i + 2].flags =
1302433d6423SLionel Sambuc BUF_PREALLOC | ((i >= 3) ? BUF_ADJACENT : 0);
1303433d6423SLionel Sambuc }
1304433d6423SLionel Sambuc
1305433d6423SLionel Sambuc alloc_bufs(buf, nr_bufs);
1306433d6423SLionel Sambuc
1307433d6423SLionel Sambuc for (i = 0; i < 3; i++) {
1308433d6423SLionel Sambuc vvec[i].vv_addr = buf[i].addr;
1309433d6423SLionel Sambuc vvec[i].vv_size = PAGE_SIZE;
1310433d6423SLionel Sambuc }
1311433d6423SLionel Sambuc for ( ; i < nr_bufs / 3 + 1; i++) {
1312433d6423SLionel Sambuc vvec[i].vv_addr = buf[(i - 2) * 3].addr;
1313433d6423SLionel Sambuc vvec[i].vv_size = PAGE_SIZE * 3;
1314433d6423SLionel Sambuc }
1315433d6423SLionel Sambuc vcount = i;
1316433d6423SLionel Sambuc
1317433d6423SLionel Sambuc /* Out of each of the following tests, one will be aligned (that is,
1318433d6423SLionel Sambuc * the last pvec entry will be for the last page in a vvec entry) and
1319433d6423SLionel Sambuc * two will be unaligned.
1320433d6423SLionel Sambuc */
1321433d6423SLionel Sambuc
1322433d6423SLionel Sambuc /* Test physical limit, exact match. */
1323433d6423SLionel Sambuc phys_limit(vvec, vcount, pvec, MAPVEC_NR, buf,
1324433d6423SLionel Sambuc "physical limit, exact match, try 1");
1325433d6423SLionel Sambuc phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR, buf + 1,
1326433d6423SLionel Sambuc "physical limit, exact match, try 2");
1327433d6423SLionel Sambuc phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR, buf + 2,
1328433d6423SLionel Sambuc "physical limit, exact match, try 3");
1329433d6423SLionel Sambuc
1330433d6423SLionel Sambuc /* Test physical limit, one above. */
1331433d6423SLionel Sambuc phys_limit(vvec, vcount, pvec, MAPVEC_NR + 1, buf,
1332433d6423SLionel Sambuc "physical limit, one above, try 1");
1333433d6423SLionel Sambuc phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR + 1, buf + 1,
1334433d6423SLionel Sambuc "physical limit, one above, try 2");
1335433d6423SLionel Sambuc phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR + 1, buf + 2,
1336433d6423SLionel Sambuc "physical limit, one above, try 3");
1337433d6423SLionel Sambuc
1338433d6423SLionel Sambuc /* Test physical limit, two above. */
1339433d6423SLionel Sambuc phys_limit(vvec, vcount, pvec, MAPVEC_NR + 2, buf,
1340433d6423SLionel Sambuc "physical limit, two above, try 1");
1341433d6423SLionel Sambuc phys_limit(vvec + 1, vcount - 1, pvec, MAPVEC_NR + 2, buf + 1,
1342433d6423SLionel Sambuc "physical limit, two above, try 2");
1343433d6423SLionel Sambuc phys_limit(vvec + 2, vcount - 2, pvec, MAPVEC_NR + 2, buf + 2,
1344433d6423SLionel Sambuc "physical limit, two above, try 3");
1345433d6423SLionel Sambuc
1346433d6423SLionel Sambuc free_bufs(buf, nr_bufs);
1347433d6423SLionel Sambuc }
1348433d6423SLionel Sambuc
do_tests(int use_relay)1349433d6423SLionel Sambuc static void do_tests(int use_relay)
1350433d6423SLionel Sambuc {
1351433d6423SLionel Sambuc relay = use_relay;
1352433d6423SLionel Sambuc
1353433d6423SLionel Sambuc test_basics();
1354433d6423SLionel Sambuc
1355433d6423SLionel Sambuc if (!relay) test_endpt(); /* local only */
1356433d6423SLionel Sambuc
1357433d6423SLionel Sambuc test_vector1();
1358433d6423SLionel Sambuc
1359433d6423SLionel Sambuc if (!relay) test_vector2(); /* local only */
1360433d6423SLionel Sambuc
1361433d6423SLionel Sambuc if (relay) test_grant(); /* remote only */
1362433d6423SLionel Sambuc
1363433d6423SLionel Sambuc test_offset();
1364433d6423SLionel Sambuc
1365433d6423SLionel Sambuc test_access();
1366433d6423SLionel Sambuc
1367433d6423SLionel Sambuc test_limits();
1368433d6423SLionel Sambuc }
1369433d6423SLionel Sambuc
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * UNUSED (info))1370433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
1371433d6423SLionel Sambuc {
1372433d6423SLionel Sambuc int r;
1373433d6423SLionel Sambuc
1374433d6423SLionel Sambuc verbose = (env_argc > 1 && !strcmp(env_argv[1], "-v"));
1375433d6423SLionel Sambuc
1376433d6423SLionel Sambuc if (verbose)
1377433d6423SLionel Sambuc printf("Starting sys_vumap test set\n");
1378433d6423SLionel Sambuc
1379433d6423SLionel Sambuc do_tests(FALSE /*use_relay*/);
1380433d6423SLionel Sambuc
1381433d6423SLionel Sambuc if ((r = ds_retrieve_label_endpt("vumaprelay", &endpt)) != OK)
1382433d6423SLionel Sambuc panic("unable to obtain endpoint for 'vumaprelay' (%d)", r);
1383433d6423SLionel Sambuc
1384433d6423SLionel Sambuc do_tests(TRUE /*use_relay*/);
1385433d6423SLionel Sambuc
1386433d6423SLionel Sambuc if (verbose)
1387433d6423SLionel Sambuc printf("Completed sys_vumap test set, %u/%u tests failed\n",
1388433d6423SLionel Sambuc failures, count);
1389433d6423SLionel Sambuc
1390433d6423SLionel Sambuc /* The returned code will determine the outcome of the RS call, and
1391433d6423SLionel Sambuc * thus the entire test. The actual error code does not matter.
1392433d6423SLionel Sambuc */
1393433d6423SLionel Sambuc return (failures) ? EINVAL : OK;
1394433d6423SLionel Sambuc }
1395433d6423SLionel Sambuc
sef_local_startup(void)1396433d6423SLionel Sambuc static void sef_local_startup(void)
1397433d6423SLionel Sambuc {
1398433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh);
1399433d6423SLionel Sambuc
1400433d6423SLionel Sambuc sef_startup();
1401433d6423SLionel Sambuc }
1402433d6423SLionel Sambuc
main(int argc,char ** argv)1403433d6423SLionel Sambuc int main(int argc, char **argv)
1404433d6423SLionel Sambuc {
1405433d6423SLionel Sambuc env_setargs(argc, argv);
1406433d6423SLionel Sambuc
1407433d6423SLionel Sambuc sef_local_startup();
1408433d6423SLionel Sambuc
1409433d6423SLionel Sambuc return 0;
1410433d6423SLionel Sambuc }
1411