1/**
2 * \file
3 * \brief architecture-independent shadow page table traversal code for
4 *        linked-list pmap implementation.
5 */
6
7/*
8 * Copyright (c) 2018, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
14 */
15
16#include <barrelfish/barrelfish.h>
17#include <barrelfish/pmap_target.h>
18
19#include <pmap_ds.h>
20#include <pmap_priv.h>
21
22/**
23 * \brief Starting at a given root, return the vnode with entry equal to #entry
24 */
25struct vnode *pmap_find_vnode(struct vnode *root, uint16_t entry)
26{
27    assert(root != NULL);
28    assert(root->v.is_vnode);
29    assert(entry < PTABLE_ENTRIES);
30    struct vnode *n;
31
32    for(n = root->v.u.vnode.children; n != NULL; n = n->v.meta.next) {
33        if (!n->v.is_vnode) {
34            // check whether entry is inside a large region
35            uint16_t end = n->v.entry + n->v.u.frame.pte_count;
36            if (n->v.entry <= entry && entry < end) {
37                //if (n->v.entry < entry) {
38                //    debug_printf("%d \\in [%d, %d]\n", entry, n->v.entry, end);
39                //}
40                return n;
41            }
42        }
43        else if(n->v.entry == entry) {
44            // return n if n is a vnode and the indices match
45            return n;
46        }
47    }
48    return NULL;
49}
50
51bool pmap_inside_region(struct vnode *root, uint16_t entry, uint16_t npages)
52{
53    assert(root != NULL);
54    assert(root->v.is_vnode);
55
56    struct vnode *n;
57
58    for (n = root->v.u.vnode.children; n; n = n->v.meta.next) {
59        if (!n->v.is_vnode) {
60            uint16_t end = n->v.entry + n->v.u.frame.pte_count;
61            if (n->v.entry <= entry && entry + npages <= end) {
62                return true;
63            }
64        }
65    }
66
67    return false;
68}
69
70void pmap_remove_vnode(struct vnode *root, struct vnode *item)
71{
72    assert(root->v.is_vnode);
73    struct vnode *walk = root->v.u.vnode.children;
74    struct vnode *prev = NULL;
75    while (walk) {
76        if (walk == item) {
77            if (prev) {
78                prev->v.meta.next = walk->v.meta.next;
79                return;
80            } else {
81                root->v.u.vnode.children = walk->v.meta.next;
82                return;
83            }
84        }
85        prev = walk;
86        walk = walk->v.meta.next;
87    }
88    USER_PANIC("Should not get here");
89}
90
91errval_t pmap_vnode_mgmt_init(struct pmap *pmap)
92{
93    struct pmap_vnode_mgmt *m = &pmap->m;
94    if (get_current_pmap() == pmap) {
95        slab_init(&m->slab, sizeof(struct vnode), NULL);
96        /* use static buffer for own pmap */
97        slab_grow(&m->slab, m->slab_buffer, INIT_SLAB_BUFFER_SIZE);
98    } else {
99        /* malloc initial buffer for other pmaps */
100        uint8_t *buf = malloc(INIT_SLAB_BUFFER_SIZE);
101        if (!buf) {
102            return LIB_ERR_MALLOC_FAIL;
103        }
104        slab_init(&m->slab, sizeof(struct vnode), NULL);
105        slab_grow(&m->slab, buf, INIT_SLAB_BUFFER_SIZE);
106    }
107
108    return SYS_ERR_OK;
109}
110
111void pmap_vnode_init(struct pmap *p, struct vnode *v)
112{
113    v->v.u.vnode.children = NULL;
114    v->v.meta.next = NULL;
115}
116
117void pmap_vnode_insert_child(struct vnode *root, struct vnode *newvnode)
118{
119    newvnode->v.meta.next = root->v.u.vnode.children;
120    root->v.u.vnode.children = newvnode;
121}
122
123void pmap_vnode_free(struct pmap *pmap, struct vnode *n)
124{
125    slab_free(&pmap->m.slab, n);
126}
127
128errval_t pmap_refill_slabs(struct pmap *pmap, size_t max_slabs)
129{
130    return pmap_slab_refill(pmap, &pmap->m.slab, max_slabs);
131}
132