1/**
2 * \file
3 * \brief Test invalid vnode invocations.
4 */
5
6/*
7 * Copyright (c) 2014, HP Labs.
8 * Copyright (c) 2015, ETH Zurich.
9 * All rights reserved.
10 *
11 * This file is distributed under the terms in the attached LICENSE file.
12 * If you do not find this file, copies can be found by writing to:
13 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
14 */
15
16#include <barrelfish/barrelfish.h>
17#include <barrelfish/cap_predicates.h>
18#include <stdio.h>
19#include "debug.h"
20#include "tests.h"
21
22#define FRAME_ACCESS_DEFAULT \
23        (PTABLE_USER_SUPERVISOR | PTABLE_EXECUTE_DISABLE | PTABLE_READ_WRITE)
24
25static enum objtype types[7] =
26{
27    ObjType_VNode_x86_64_pml4,
28    ObjType_VNode_x86_64_pdpt,
29    ObjType_VNode_x86_64_pdir,
30    ObjType_VNode_x86_64_ptable,
31    ObjType_Frame,
32    ObjType_Frame,
33    ObjType_Frame
34};
35
36#define W SYS_ERR_WRONG_MAPPING
37#define O SYS_ERR_OK
38#define S SYS_ERR_VM_FRAME_TOO_SMALL
39
40static errval_t mapping_ok[4][7] =
41{         /*pml4*/ /*pdpt*/ /*pdir*/ /*pt*/ /*frm*/ /*2mfrm*/ /*1gfrm*/
42/*pml4*/{   W,       O,       W,       W,     W,      W,        W  },
43/*pdpt*/{   W,       W,       O,       W,     S,      S,        O  },
44/*pdir*/{   W,       W,       W,       O,     S,      O,        O  },
45/*pt  */{   W,       W,       W,       W,     O,      O,        O  },
46};
47
48static int pass = 0, fail = 0;
49static void check_result(errval_t err, int dest, int src)
50{
51    if (err_no(err) == mapping_ok[dest][src]) {
52        printf("%d<-%d PASSED (%s)\n", dest, src, err_getstring(err));
53        pass++;
54    } else {
55        printf("%d<-%d FAILED (expected: %s, was %s)\n",
56                dest, src, err_getstring(mapping_ok[dest][src]),
57                err_getstring(err));
58        fail++;
59    }
60}
61
62int invalid_mappings(void)
63{
64    // outline:
65    // get pml4, pdpt, pdir, ptable, and frame
66    // check all combinations to make sure that restrictions are implemented
67    // correctly in kernel space
68    // VALID:
69    // map pdpt in pml4
70    // map pdir in pdpt
71    // map pt   in pdir
72    // map frame in {pt, pdir, pdpt}
73    // INVALID:
74    // all other combinations
75
76    errval_t err;
77    struct capref caps[7];
78    struct capref mapping;
79
80    // allocate slot for mapping cap: can reuse
81    err = slot_alloc(&mapping);
82    if (err_is_fail(err)) {
83        debug_printf("slot_alloc: %s (%ld)\n", err_getstring(err), err);
84        return 1;
85    }
86
87    // allocate caps
88    for (int i = 0; i < 5; i++) {
89        // get 4k block
90        struct capref mem;
91        err = ram_alloc(&mem, BASE_PAGE_BITS);
92        if (err_is_fail(err)) {
93            debug_printf("ram_alloc: %s (%ld)\n", err_getstring(err), err);
94            return 1;
95        }
96
97        // get slot for retype dest
98        err = slot_alloc(&caps[i]);
99        if (err_is_fail(err)) {
100            debug_printf("slot_alloc: %s (%ld)\n", err_getstring(err), err);
101            return 1;
102        }
103        // retype to selected type
104        err = cap_retype(caps[i], mem, 0, types[i], BASE_PAGE_SIZE, 1);
105        if (err_is_fail(err)) {
106            debug_printf("cap_retype: %s (%ld)\n", err_getstring(err), err);
107            return 1;
108        }
109
110        // cleanup source cap
111        DEBUG_INVALID_MAPPINGS("delete ram cap\n");
112        err = cap_destroy(mem);
113        if (err_is_fail(err)) {
114            debug_printf("cap_delete(mem): %s (%ld)\n", err_getstring(err), err);
115            return 1;
116        }
117    }
118
119    // Do gigabyte frame tests
120    int last_source = 7;
121
122    // cap 6: 2M frame
123    size_t rb = 0;
124    err = frame_alloc(&caps[5], X86_64_LARGE_PAGE_SIZE, &rb);
125    if (err_is_fail(err) || rb != X86_64_LARGE_PAGE_SIZE) {
126        debug_printf("frame_alloc: %s (%ld)\n", err_getstring(err), err);
127        return 1;
128    }
129    // cap 7: 1G frame
130    err = frame_alloc(&caps[6], X86_64_HUGE_PAGE_SIZE, &rb);
131    if (err_is_fail(err) || rb != X86_64_HUGE_PAGE_SIZE) {
132        debug_printf("Cannot allocate 1GB frame (%s)\n", err_getcode(err));
133        last_source = 6;
134    }
135
136    paging_x86_64_flags_t attr = 0;
137    // select dest (ignore frame, asserts)
138    for (int i = 0; i < 4; i++) {
139        // select source
140        for (int j = 0; j < last_source; j++) {
141            if (j >= 4) {
142                // frame
143                attr = FRAME_ACCESS_DEFAULT;
144            } else {
145                // ptable
146                attr = PTABLE_ACCESS_DEFAULT;
147            }
148            // try mapping
149            err = vnode_map(caps[i], caps[j], /*slot*/0, attr, /*off*/0,
150                            /*count*/1, mapping);
151            check_result(err, i, j);
152            // unmap if mapping succeeded
153            if (err_is_ok(err)) {
154                err = vnode_unmap(caps[i], mapping);
155                if (err_is_fail(err)) {
156                    DEBUG_ERR(err, "vnode_unmap");
157                }
158                assert(err_is_ok(err));
159                // XXX: better API?
160                err = cap_delete(mapping);
161                assert(err_is_ok(err));
162            }
163        }
164    }
165
166    printf("All tests executed: %d PASSED, %d FAILED\n", pass, fail);
167
168    return 0;
169}
170
171#ifdef STANDALONE
172int main(void)
173{
174    return invalid_mappings();
175}
176#endif
177