1/**
2 * \file
3 * \brief Protect test
4 */
5/*
6 * Copyright (c) 2014, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <assert.h>
18
19#include <barrelfish/barrelfish.h>
20#include <barrelfish/except.h>
21
22#define EX_STACK_SIZE 16384
23static char ex_stack[EX_STACK_SIZE];
24static char *ex_stack_end = ex_stack + EX_STACK_SIZE;
25
26#define ALL_PRIVILEGES (VREGION_FLAGS_READ | VREGION_FLAGS_WRITE | VREGION_FLAGS_EXECUTE)
27#define NO_PRIVILEGES 0x0
28
29#define PAGES 100
30
31struct bf_mem {
32    struct capref  frame;
33    void           *vmem;
34    struct memobj  *memobj;
35    struct vregion *vregion;
36};
37
38struct bf_mem BFmem;
39size_t pagesize;
40
41static void
42bf_alloc_pages(struct bf_mem *bfmem, size_t npages)
43{
44    errval_t err;
45    size_t retfsize;
46    const size_t nbytes = npages*BASE_PAGE_SIZE;
47    // allocate a frame
48    err = frame_alloc(&bfmem->frame, nbytes, &retfsize);
49    if (err_is_fail(err)) {
50        fprintf(stderr, "frame_alloc: %s\n", err_getstring(err));
51        abort();
52    }
53    assert(retfsize >= nbytes);
54    // map frame rw
55    err = vspace_map_one_frame_attr(&bfmem->vmem, retfsize, bfmem->frame,
56                                    VREGION_FLAGS_READ_WRITE,
57                                    &bfmem->memobj,
58                                    &bfmem->vregion);
59    if (err_is_fail(err)) {
60        fprintf(stderr, "vspace_map: %s\n", err_getstring(err));
61        abort();
62    }
63    genvaddr_t mem = (genvaddr_t) bfmem->vmem;
64    if (X86_64_PDIR_BASE(mem) != X86_64_PDIR_BASE(mem + retfsize - 1)) {
65        debug_printf("WARN: mapping overlaps leaf pt!\n");
66    }
67}
68
69__attribute__((unused))
70static paging_x86_64_flags_t vregion_to_pmap_flag(vregion_flags_t vregion_flags)
71{
72    paging_x86_64_flags_t pmap_flags =
73        PTABLE_USER_SUPERVISOR | PTABLE_EXECUTE_DISABLE;
74    if (!(vregion_flags & VREGION_FLAGS_GUARD)) {
75        if (vregion_flags & VREGION_FLAGS_WRITE) {
76            pmap_flags |= PTABLE_READ_WRITE;
77        }
78        if (vregion_flags & VREGION_FLAGS_EXECUTE) {
79            pmap_flags &= ~PTABLE_EXECUTE_DISABLE;
80        }
81        if (vregion_flags & VREGION_FLAGS_NOCACHE) {
82            pmap_flags |= PTABLE_CACHE_DISABLED;
83        }
84    }
85    return pmap_flags;
86}
87
88//#define DIRECT_INVOKE
89static void
90bf_protect(struct bf_mem *bfm, size_t off, size_t len,
91           vs_prot_flags_t flags)
92{
93    //debug_printf("%s: off:%zd len:%zd flags:%u\n", __FUNCTION__, off, len, flags);
94    errval_t err;
95#if defined(DIRECT_INVOKE)
96    err = invoke_frame_modify_flags(bfm->frame, off / pagesize, len / pagesize,
97            vregion_to_pmap_flag(flags));
98#else
99    err = bfm->memobj->f.protect(bfm->memobj, bfm->vregion, off, len, flags);
100#endif
101    if (err_is_fail(err)) {
102        fprintf(stderr, "vmpup: memobj.f.protect: %s\n", err_getstring(err));
103        abort();
104    }
105}
106
107
108static void
109bf_handler(enum exception_type type, int subtype,
110           void *vaddr,
111           arch_registers_state_t *regs)
112{
113    assert(type == EXCEPT_PAGEFAULT);
114    assert(subtype == PAGEFLT_WRITE);
115    debug_printf("got exception %d(%d) on %p\n", type, subtype, vaddr);
116
117    assert((uintptr_t)BFmem.vmem <= (uintptr_t)vaddr);
118    uintptr_t off_unprotect = (uintptr_t)vaddr - (uintptr_t)BFmem.vmem;
119    bf_protect(&BFmem, off_unprotect, pagesize, ALL_PRIVILEGES);
120}
121
122
123int main(int argc, char **argv)
124{
125    char *mem;
126    pagesize = BASE_PAGE_SIZE;
127
128    bf_alloc_pages(&BFmem, PAGES);
129    mem = BFmem.vmem;
130    thread_set_exception_handler(bf_handler, NULL, ex_stack, ex_stack_end, NULL, NULL);
131    debug_printf("MEM=%p\n", mem);
132
133    bf_protect(&BFmem, 0, PAGES*pagesize, NO_PRIVILEGES);
134
135    for (size_t i = 0; i < PAGES; i++) {
136        mem[i * pagesize] = 20;
137    }
138}