1/**
2 * \file
3 * \brief test that vnode_inherit cannot create unrevokable ptes
4 */
5
6/*
7 * Copyright (c) 2017, 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 <stdlib.h>
17
18#include <barrelfish/barrelfish.h>
19#include <barrelfish/except.h>
20#include <barrelfish/sys_debug.h>
21
22// Defined in lib/barrelfish/target/x86_64/pmap_target.c
23errval_t get_ptable(struct pmap_x86 *pmap, genvaddr_t base,
24                    struct vnode **ptable);
25
26#ifdef DELETE_FRAME
27#define EX_STACK_SIZE 16384
28static char ex_stack[EX_STACK_SIZE];
29static char *ex_stack_top = ex_stack + EX_STACK_SIZE;
30
31static void exhandler(enum exception_type type, int subtype, void *vaddr,
32        arch_registers_state_t *regs)
33{
34    debug_printf("Got fault on %p\n", vaddr);
35    debug_printf("Test completed: SUCCESS.\n");
36    exit(0);
37}
38#endif
39
40int main(int argc, char *argv[])
41{
42    errval_t err;
43
44    struct pmap_x86 *x86 = (struct pmap_x86*)get_current_pmap();
45
46    struct memobj *memobj = NULL;
47    struct vregion *vregion = NULL;
48
49    /* get frame cap */
50    struct capref frame;
51    size_t rb;
52    err = frame_alloc(&frame, 4096, &rb);
53    assert(err_is_ok(err));
54    assert(rb == 4096);
55
56    void *vbase;
57    err = vspace_map_one_frame(&vbase, BASE_PAGE_SIZE, frame, &memobj, &vregion);
58    assert(err_is_ok(err));
59
60    genvaddr_t base = vregion_get_base_addr(vregion);
61    debug_printf("our region is at %#"PRIxGENVADDR"\n", base);
62
63    /* get struct vnode for ptable for our region */
64    struct vnode *ptable = NULL;
65    err = get_ptable(x86, base, &ptable);
66    assert(err_is_ok(err));
67    assert(ptable);
68
69    /* allocate a empty ptable */
70    genvaddr_t cloned_base;
71    err = x86->p.f.determine_addr_raw(&x86->p, LARGE_PAGE_SIZE,
72                                      LARGE_PAGE_SIZE, &cloned_base);
73    assert(err_is_ok(err));
74    debug_printf("cloned ptable is at %#"PRIxGENVADDR"\n", cloned_base);
75
76    struct vnode *cloned = NULL;
77    err = get_ptable(x86, cloned_base, &cloned);
78    assert(err_is_ok(err));
79    assert(cloned);
80
81    /* clone ptable */
82    debug_printf("calling vnode inherit\n");
83    err = vnode_inherit(cloned->v.u.vnode.invokable, ptable->v.u.vnode.invokable,
84                        0, PTABLE_SIZE, ptable->u.vnode.mcn, cloned->u.vnode.mcn);
85    assert(err_is_ok(err));
86
87    size_t ptentry = X86_64_PTABLE_BASE(base);
88    genvaddr_t cloned_addr = cloned_base | (ptentry << BASE_PAGE_BITS);
89    debug_printf("cloned region is at %#"PRIxGENVADDR"\n", cloned_addr);
90
91    debug_printf("Writing to original region\n");
92    uint8_t *b = vbase;
93    for (int i = 0; i < BASE_PAGE_SIZE; i++) {
94        b[i] = i % UINT8_MAX;
95    }
96    sys_debug_flush_cache();
97
98    char *exitmsg = NULL;
99    int retval = 0;
100
101#ifdef DELETE_FRAME
102    debug_printf("Deleting Frame cap, check should fault\n");
103    exitmsg = "FAILURE";
104    retval = 1;
105
106    /* install exception handler, to gracefully handle expected faults */
107    err = thread_set_exception_handler(exhandler, NULL, ex_stack, ex_stack_top,
108                                       NULL, NULL);
109    assert(err_is_ok(err));
110
111    /* delete frame cap, should unmap region in both page tables */
112    err = cap_destroy(frame);
113    assert(err_is_ok(err));
114#else
115    exitmsg = "SUCCESS";
116#endif
117
118    debug_printf("Checking cloned region\n");
119    b = (void *)cloned_addr;
120    for (int i = 0; i < BASE_PAGE_SIZE; i++) {
121        if (b[i] != (i % UINT8_MAX)) {
122            debug_printf("Error at byte %d: %hhu, %u\n", i, b[i], i % UINT8_MAX);
123        }
124    }
125    debug_printf("Cloned region checked successfully!\n");
126
127#if !defined(DELETE_FRAME)
128
129    sys_debug_flush_cache();
130    debug_printf("Checking original region\n");
131    b = vbase;
132    for (int i = 0; i < BASE_PAGE_SIZE; i++) {
133        if (b[i] != (i % UINT8_MAX)) {
134            debug_printf("Error at byte %d: %hhu, %u\n", i, b[i], i % UINT8_MAX);
135        }
136    }
137    debug_printf("Original region checked successfully\n");
138#endif
139
140    debug_printf("Test completed: %s.\n", exitmsg);
141
142    return retval;
143}
144