1#include <pager/pager.h>
2#include <stdio.h>
3
4// hardcoded for ARM pmap (should get from pmap)
5#define VSPACE_BEGIN   ((lvaddr_t)1UL*1024*1024*1024) // 1G
6
7static bool is_in_pmap(genvaddr_t vaddr)
8{
9    struct pmap *pmap = get_current_pmap();
10
11    errval_t err = pmap->f.lookup(pmap, vaddr, NULL);
12    return err_is_ok(err);
13}
14
15static errval_t alloc_4k(struct capref *retframe)
16{
17    assert(retframe);
18    size_t frame_sz = 4096u;
19    errval_t err = frame_alloc(retframe, frame_sz, &frame_sz);
20    if (err_is_fail(err)) {
21        DEBUG_ERR(err, "frame_alloc");
22        return err;
23    }
24    if (frame_sz > 4096) {
25        printf("alloc_4k: wasting %zu bytes of memory\n", frame_sz - 4096);
26    }
27    return SYS_ERR_OK;
28}
29
30static errval_t handle_pagefault(void *addr)
31{
32    errval_t result = SYS_ERR_OK;
33    errval_t err;
34    genvaddr_t vaddr = vspace_lvaddr_to_genvaddr((lvaddr_t)addr);
35    if (vaddr > VSPACE_BEGIN) {
36        if (is_in_pmap(vaddr)) {
37            printf("handle_pagefault: returning -- mapping exists already in pmap?\n");
38        } else {
39            printf("handle_pagefault: no mapping for address, allocating frame\n");
40            struct capref frame;
41            err = alloc_4k(&frame);
42            if (err_is_fail(err)) {
43                DEBUG_ERR(err, "alloc_4k");
44            }
45            struct pmap *pmap = get_current_pmap();
46            err = pmap->f.map(pmap, vaddr, frame, 0, 4096,
47                              VREGION_FLAGS_READ_WRITE, NULL, NULL);
48            if (err_is_fail(err)) {
49                DEBUG_ERR(err, "pmap->f.map");
50            }
51            printf("handle_pagefault: returning -- did install page\n");
52            return SYS_ERR_OK;
53        }
54    } else {
55        printf("handle_pagefault: invalid access to %p (< 0x%" PRIxLVADDR ")\n", addr, VSPACE_BEGIN);
56        // TODO: good error code
57        return LIB_ERR_PMAP_ADDR_NOT_FREE;
58    }
59
60    return result;
61}
62
63static void exn_handler(enum exception_type type, int subtype,
64                        void *addr, arch_registers_state_t *regs)
65{
66    printf("exn_handler: exception type=%d, subtype=%d, addr=%p\n",
67            type, subtype, addr);
68    errval_t err;
69    if (type == EXCEPT_PAGEFAULT) {
70        err = handle_pagefault(addr);
71        if (err_is_fail(err)) {
72            // could not handle page fault, exiting for now
73            // TODO: do something sensible here
74            exit(1);
75        }
76    } else {
77        printf("exn_handler: don't know what to do with exception type %d\n", type);
78    }
79    return;
80}
81
82#define INTERNAL_STACK_SIZE (1<<14)
83static char internal_ex_stack[INTERNAL_STACK_SIZE];
84
85errval_t pager_install_handler(char *ex_stack, size_t stack_size)
86{
87    // setup exception stack pointers
88    char *ex_stack_top = NULL;
89    if (ex_stack && stack_size >= 4096u) {
90        ex_stack_top = ex_stack + stack_size;
91    } else { // use our exception stack region
92        ex_stack = internal_ex_stack;
93        ex_stack_top = ex_stack + INTERNAL_STACK_SIZE;
94    }
95    assert(ex_stack);
96    assert(ex_stack_top);
97
98    exception_handler_fn old_handler;
99    errval_t err;
100    void *old_stack_base, *old_stack_top;
101
102    err = thread_set_exception_handler(exn_handler, &old_handler,
103            ex_stack, ex_stack_top, &old_stack_base, &old_stack_top);
104    if (err_is_fail(err)) {
105        DEBUG_ERR(err, "thread_set_exception_handler");
106    }
107    return 0;
108}
109