1/**
2 * \file
3 * \brief New retype test
4 */
5
6/*
7 * Copyright (c) 2016, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <barrelfish/barrelfish.h>
17
18// adapted from usr/monitor/capops/internal.h
19#define GOTO_IF_ERR(err, label) do { \
20    if (err_is_fail(err)) { \
21        printf("...fail: %s\n", err_getstring(err)); \
22        result = 1; \
23        goto label; \
24    } \
25} while (0)
26
27static bool quiet = false;
28
29#define OUT(fmt...) \
30do { \
31    if (!quiet) { \
32        printf(fmt); \
33    } \
34} while(0)
35
36//{{{1 setup & helpers
37static struct capref bunch_o_ram;
38static struct frame_identity bor_id;
39
40static void setup(size_t bytes)
41{
42    errval_t err;
43    err = ram_alloc(&bunch_o_ram, log2ceil(bytes));
44    assert(err_is_ok(err));
45    err = frame_identify(bunch_o_ram, &bor_id);
46    assert(err_is_ok(err));
47}
48
49static void cleanup(void)
50{
51    errval_t err;
52    err = cap_revoke(bunch_o_ram);
53    assert(err_is_ok(err));
54    err = cap_destroy(bunch_o_ram);
55    assert(err_is_ok(err));
56}
57
58static void print_unexpected(char *info, genpaddr_t expected_base,
59                            char *expected_size, genpaddr_t actual_base,
60                            size_t actual_size)
61{
62    printf("...fail: %sexpected %#"PRIxGENPADDR", %s; got %#"PRIxGENPADDR", %zu bytes\n",
63            info, expected_base, expected_size, actual_base, actual_size);
64}
65
66//{{{1 test_retype_single
67static int test_retype_single(void)
68{
69    OUT("%s:\n", __FUNCTION__);
70    setup(LARGE_PAGE_SIZE);
71
72    int result = 0;
73    errval_t err;
74    struct frame_identity fi;
75    struct capref cap, cap2, cnram, cncap;
76
77    /* get slots for results */
78    err = slot_alloc(&cap);
79    assert(err_is_ok(err));
80    err = slot_alloc(&cap2);
81    assert(err_is_ok(err));
82    err = slot_alloc(&cnram);
83    assert(err_is_ok(err));
84    err = slot_alloc(&cncap);
85    assert(err_is_ok(err));
86
87    /* allocate 4kB Frame at offset 0 of 2MB region */
88    OUT("  allocate 4kB Frame at offset 0 of 2MB region: ");
89    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, BASE_PAGE_SIZE, 1);
90    GOTO_IF_ERR(err, out);
91    err = frame_identify(cap, &fi);
92    assert(err_is_ok(err));
93
94    if (bor_id.base != fi.base || fi.bytes != BASE_PAGE_SIZE) {
95        print_unexpected("", bor_id.base, "4kB", fi.base, fi.bytes);
96        result = 1;
97        goto out;
98    }
99    OUT("...ok\n");
100
101    /* allocate 16kB RAM at offset 4kB of 2MB region */
102    OUT("  allocate 16kB RAM at offset 4kB of 2MB region: ");
103    err = cap_retype(cap2, bunch_o_ram, BASE_PAGE_SIZE, ObjType_RAM, BASE_PAGE_SIZE * 4, 1);
104    GOTO_IF_ERR(err, out);
105    err = frame_identify(cap2, &fi);
106    assert(err_is_ok(err));
107
108    if (bor_id.base + BASE_PAGE_SIZE != fi.base || fi.bytes != 4*BASE_PAGE_SIZE) {
109        print_unexpected("", bor_id.base + BASE_PAGE_SIZE, "16kB", fi.base, fi.bytes);
110        result = 1;
111        goto out;
112    }
113    OUT("...ok\n");
114
115#if 0 // this test does not make sense with twolevel cspace layout
116    /* split 16kB into 4kB CNode, and 3x4kB Frame */
117    OUT("  split 16kB into 4kB CNode, and 3x4kB Frame: ");
118    err = cap_retype(cnram, cap2, 0, ObjType_RAM, BASE_PAGE_SIZE, 1);
119    GOTO_IF_ERR(err, out);
120    err = cnode_create_from_mem(cncap, cnram, &tmp.cnode, DEFAULT_CNODE_BITS);
121    GOTO_IF_ERR(err, out);
122    tmp.slot = 0;
123
124    err = cap_retype(tmp, cap2, BASE_PAGE_SIZE, ObjType_Frame, BASE_PAGE_SIZE, 3);
125    GOTO_IF_ERR(err, out);
126    // offset of slot 0 is 8kB --> addrs should be (2+slot) * BASE_PAGE_SIZE
127    for (tmp.slot = 0; tmp.slot <= 2; tmp.slot++) {
128        err = invoke_frame_identify(tmp, &fi);
129        assert(err_is_ok(err));
130        if (bor_id.base + (2+tmp.slot)*BASE_PAGE_SIZE != fi.base ||
131            fi.bytes != BASE_PAGE_SIZE)
132        {
133            char buf[16];
134            snprintf(buf, 16, "slot %d: ", tmp.slot);
135            print_unexpected(buf, bor_id.base + (2+tmp.slot) * BASE_PAGE_SIZE,
136                    "4kB", fi.base, fi.bytes);
137            result = 1;
138            goto out;
139        }
140    }
141
142    OUT("...ok\n");
143#endif
144
145
146out:
147    slot_free(cap);
148    slot_free(cap2);
149    slot_free(cnram);
150    slot_free(cncap);
151    /* this also cleans up any descendants of bunch_o_ram */
152    cleanup();
153    return result;
154}
155
156//{{{1 test_retype_multi
157static int test_retype_multi(void)
158{
159    OUT("%s:\n", __FUNCTION__);
160    setup(LARGE_PAGE_SIZE);
161
162    int result = 0;
163    errval_t err;
164    struct frame_identity fi;
165    struct capref cap, cap2;
166
167    /* get slots for results */
168    err = slot_alloc(&cap);
169    assert(err_is_ok(err));
170    err = slot_alloc(&cap2);
171    assert(err_is_ok(err));
172
173    /* allocate 4kB Frame at offset 0 of 2MB region */
174    OUT("  allocate 4kB Frame at offset 0 of 2MB region: ");
175    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, BASE_PAGE_SIZE, 1);
176    GOTO_IF_ERR(err, out);
177    err = frame_identify(cap, &fi);
178    assert(err_is_ok(err));
179
180    if (bor_id.base != fi.base || fi.bytes != BASE_PAGE_SIZE) {
181        print_unexpected("", bor_id.base, "4kB", fi.base, fi.bytes);
182        result = 1;
183        goto out;
184    }
185    OUT("...ok\n");
186
187    /* allocate 16kB RAM at offset 4kB of 2MB region */
188    OUT("  allocate 16kB RAM at offset 4kB of 2MB region: ");
189    err = cap_retype(cap2, bunch_o_ram, BASE_PAGE_SIZE, ObjType_RAM, BASE_PAGE_SIZE * 4, 1);
190    GOTO_IF_ERR(err, out);
191    err = frame_identify(cap2, &fi);
192    assert(err_is_ok(err));
193
194    if (bor_id.base + BASE_PAGE_SIZE != fi.base || fi.bytes != 4*BASE_PAGE_SIZE) {
195        print_unexpected("", bor_id.base + BASE_PAGE_SIZE, "16kB", fi.base, fi.bytes);
196        result = 1;
197        goto out;
198    }
199    OUT("...ok\n");
200
201    /* delete first cap and retype first 4k again */
202    OUT("  deleting first 4kB descendant\n");
203    err = cap_delete(cap);
204    assert(err_is_ok(err));
205
206    OUT("  allocating first 4kB again: ");
207    err = cap_retype(cap, bunch_o_ram, 0, ObjType_RAM, BASE_PAGE_SIZE, 1);
208    GOTO_IF_ERR(err, out);
209    err = frame_identify(cap, &fi);
210    assert(err_is_ok(err));
211
212    if (bor_id.base != fi.base || fi.bytes != BASE_PAGE_SIZE) {
213        print_unexpected("", bor_id.base, "4kB", fi.base, fi.bytes);
214        result = 1;
215        goto out;
216    }
217    OUT("...ok\n");
218
219out:
220    slot_free(cap);
221    slot_free(cap2);
222    /* this also cleans up any descendants of bunch_o_ram */
223    cleanup();
224    return result;
225}
226
227//{{{1 test_retype_overlap
228static int test_retype_overlap(void)
229{
230    errval_t err;
231    int result = 0;
232    struct capref cap, cap2;
233    //struct frame_identity fi;
234
235    err = slot_alloc(&cap);
236    assert(err_is_ok(err));
237    err = slot_alloc(&cap2);
238    assert(err_is_ok(err));
239
240    setup(LARGE_PAGE_SIZE);
241    OUT("overlap testing with 32 pages allocated at offset 0:\n");
242    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, 32*BASE_PAGE_SIZE, 1);
243    assert(err_is_ok(err));
244
245    OUT("  allocating 16 pages at offset 16 pages: ");
246    err = cap_retype(cap2, bunch_o_ram, 16*BASE_PAGE_SIZE,
247            ObjType_Frame, 16*BASE_PAGE_SIZE, 1);
248    if (err_no(err) != SYS_ERR_REVOKE_FIRST) {
249        OUT("...fail: %s\n", err_getstring(err));
250        result = 1;
251        goto out;
252    }
253    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
254
255    OUT("  allocating 4kB at offset 31 pages: ");
256    err = cap_retype(cap2, bunch_o_ram, BASE_PAGE_SIZE,
257            ObjType_Frame, 31*BASE_PAGE_SIZE, 1);
258    if (err_no(err) != SYS_ERR_REVOKE_FIRST) {
259        OUT("...fail: %s\n", err_getstring(err));
260        result = 1;
261        goto out;
262    }
263    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
264
265    OUT("  allocating 16kB at offset 31 pages: ");
266    err = cap_retype(cap2, bunch_o_ram, 4*BASE_PAGE_SIZE,
267            ObjType_Frame, 31*BASE_PAGE_SIZE, 1);
268    if (err_no(err) != SYS_ERR_REVOKE_FIRST) {
269        OUT("...fail: %s\n", err_getstring(err));
270        result = 1;
271        goto out;
272    }
273    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
274
275    OUT("  allocating 32 pages at offset 0: ");
276    err = cap_retype(cap2, bunch_o_ram, 0,
277            ObjType_Frame, 32*BASE_PAGE_SIZE, 1);
278    if (err_no(err) != SYS_ERR_REVOKE_FIRST) {
279        OUT("...fail: %s\n", err_getstring(err));
280        result = 1;
281        goto out;
282    }
283    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
284
285out:
286    slot_free(cap);
287    slot_free(cap2);
288    cleanup();
289    return result;
290}
291
292//{{{1 test_non_aligned
293static int test_non_aligned(void)
294{
295    errval_t err;
296    int result = 0;
297    struct capref cap;
298
299    err = slot_alloc(&cap);
300    assert(err_is_ok(err));
301
302    setup(LARGE_PAGE_SIZE);
303    OUT("  offset 1024: ");
304    err = cap_retype(cap, bunch_o_ram, 1024, ObjType_Frame, 32*BASE_PAGE_SIZE, 1);
305    if (err_no(err) != SYS_ERR_RETYPE_INVALID_OFFSET) {
306        OUT("...fail: %s\n", err_getstring(err));
307        result = 1;
308        goto out;
309    }
310    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
311    OUT("  offset >= object size: ");
312    err = cap_retype(cap, bunch_o_ram, LARGE_PAGE_SIZE, ObjType_Frame,
313            32*BASE_PAGE_SIZE, 1);
314    if (err_no(err) != SYS_ERR_RETYPE_INVALID_OFFSET) {
315        OUT("...fail: %s\n", err_getstring(err));
316        result = 1;
317        goto out;
318    }
319    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
320    OUT("  offset + objects >= object size: ");
321    err = cap_retype(cap, bunch_o_ram, LARGE_PAGE_SIZE - 31*BASE_PAGE_SIZE, ObjType_Frame,
322            32*BASE_PAGE_SIZE, 1);
323    if (err_no(err) != SYS_ERR_RETYPE_INVALID_OFFSET) {
324        OUT("...fail: %s\n", err_getstring(err));
325        result = 1;
326        goto out;
327    }
328    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
329    OUT("  object size 6kB: ");
330    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, 6144, 1);
331    if (err_no(err) != SYS_ERR_INVALID_SIZE) {
332        OUT("...fail: %s\n", err_getstring(err));
333        result = 1;
334        goto out;
335    }
336    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
337
338    OUT("  objects do not fit into cap: ");
339    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, BASE_PAGE_SIZE, 513);
340    if (err_no(err) != SYS_ERR_RETYPE_INVALID_COUNT) {
341        OUT("...fail: %s\n", err_getstring(err));
342        result = 1;
343        goto out;
344    }
345    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
346
347    OUT("  object larger than cap: ");
348    err = cap_retype(cap, bunch_o_ram, 0, ObjType_Frame, 513*BASE_PAGE_SIZE, 1);
349    if (err_no(err) != SYS_ERR_INVALID_SIZE) {
350        OUT("...fail: %s\n", err_getstring(err));
351        result = 1;
352        goto out;
353    }
354    OUT("...ok: retype fails with '%s'\n", err_getstring(err));
355
356out:
357    slot_free(cap);
358    cleanup();
359    return result;
360}
361
362//{{{1 main
363int main(int argc, char *argv[])
364{
365    if (argc >= 2) {
366        quiet = !strncmp(argv[1], "quiet", 5);
367    }
368    int result = 0;
369    OUT("0: Non-overlapping retype test, no deletion\n");
370    result |= test_retype_single() << 0;
371    OUT("1: Non-overlapping retype test, with deletions\n");
372    result |= test_retype_multi() << 1;
373    OUT("2: Overlapping retype test\n");
374    result |= test_retype_overlap() << 2;
375    OUT("3: Non-aligned retype test\n");
376    result |= test_non_aligned() << 3;
377
378    printf("retype: result: %x\n", result);
379
380    return result;
381}
382