1/**
2 * \file
3 * \brief Modify flags (protect) new kernel memory test
4 */
5
6/*
7 * Copyright (c) 2013, 2015, 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 <barrelfish/barrelfish.h>
16#include <barrelfish/sys_debug.h> // sys_debug_flush_cache()
17#include <barrelfish/threads.h>
18#include <barrelfish/except.h>
19#include <stdio.h>
20#include "debug.h"
21#include "tests.h"
22
23static void *vbase = NULL, *vend = NULL;
24static struct memobj *memobj = NULL;
25static struct vregion *vregion = NULL;
26
27#define EX_STACK_SIZE 16384
28static char ex_stack[EX_STACK_SIZE];
29
30static void handler(enum exception_type type, int subtype, void *addr,
31        arch_registers_state_t *regs)
32{
33    static int count = 0;
34    ++count;
35    DEBUG_MODIFY_FLAGS("got exception %d(%d) on %p [%d]\n", type, subtype, addr, count);
36    errval_t err;
37    assert(type == EXCEPT_PAGEFAULT);
38#ifdef __x86__
39    assert(subtype == PAGEFLT_WRITE);
40#endif
41    assert(addr >= vbase && addr < vend);
42    DEBUG_MODIFY_FLAGS("got expected write pagefault on %p\n", addr);
43    // unprotect 4k page
44    genvaddr_t offset = (genvaddr_t)(lvaddr_t)addr - (genvaddr_t)(lvaddr_t)vbase;
45    err = memobj->f.protect(memobj, vregion, offset,
46            BASE_PAGE_SIZE, VREGION_FLAGS_READ_WRITE);
47    assert(err_is_ok(err));
48}
49
50int modify_flags(void)
51{
52    struct capref frame;
53    errval_t err;
54    size_t retsize;
55    err = frame_alloc(&frame, 16 * BASE_PAGE_SIZE, &retsize);
56    assert(err_is_ok(err));
57    // map read-write
58    err = vspace_map_anon_attr(&vbase, &memobj, &vregion, retsize, &retsize,
59            VREGION_FLAGS_READ_WRITE);
60    assert(err_is_ok(err));
61    err = memobj->f.fill(memobj, 0, frame, retsize);
62    assert(err_is_ok(err));
63    err = memobj->f.pagefault(memobj, vregion, 0, 0);
64    assert(err_is_ok(err));
65    assert(vbase);
66    vend = (unsigned char *)vbase + retsize;
67    unsigned char *base = vbase;
68    DEBUG_MODIFY_FLAGS("filling region %p\n", base);
69    for (int i = 0; i < retsize; i++) {
70        base[i] = i % 256;
71    }
72    sys_debug_flush_cache();
73    DEBUG_MODIFY_FLAGS("checking region %p\n", base);
74    // check
75    for (int i = 0; i < retsize; i++) {
76        if (base[i] != i % 256) {
77            debug_printf("failed at %d\n", i);
78        }
79        assert(base[i] == i % 256);
80    }
81    sys_debug_flush_cache();
82    // change region to read only
83    DEBUG_MODIFY_FLAGS("changing region %p perms to readonly\n", base);
84    err = memobj->f.protect(memobj, vregion, 0, retsize, VREGION_FLAGS_READ);
85    if (err_is_fail(err)) {
86        DEBUG_ERR(err, "protect");
87        return 1;
88    }
89    // check (reads should not fault)
90    DEBUG_MODIFY_FLAGS("checking region %p\n", base);
91    printf("%d\n", base[0]);
92    for (int i = 0; i < retsize; i++) {
93        assert(base[i] == i % 256);
94    }
95
96    // register exception handler for writes
97    err = thread_set_exception_handler(handler, NULL, ex_stack,
98            ex_stack+EX_STACK_SIZE, NULL, NULL);
99    assert(err_is_ok(err));
100
101    // this should fault
102    for (int i = 0; i < retsize / BASE_PAGE_SIZE; i++) {
103        DEBUG_MODIFY_FLAGS("provoke write pagefault on %p\n", base+i*BASE_PAGE_SIZE);
104        base[i * BASE_PAGE_SIZE] = 0x42;
105    }
106
107    printf("%s: done\n", __FUNCTION__);
108    return 0;
109}
110
111#ifdef STANDALONE
112int main(void)
113{
114    return modify_flags();
115}
116#endif
117