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