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
31    if (root->v.u.vnode.children) {
32        return root->v.u.vnode.children[entry];
33    } else {
34        return NULL;
35    }
36}
37
38bool pmap_inside_region(struct vnode *root, uint16_t entry, uint16_t npages)
39{
40    assert(root != NULL);
41    assert(root->v.is_vnode);
42
43    struct vnode *n = root->v.u.vnode.children[entry];
44
45    // empty or ptable
46    if (!n || n->v.is_vnode) {
47        return false;
48    }
49
50    uint16_t end = n->v.entry + n->v.u.frame.pte_count;
51    if (n->v.entry <= entry && entry + npages <= end) {
52        return true;
53    }
54
55    return false;
56}
57
58void pmap_remove_vnode(struct vnode *root, struct vnode *item)
59{
60    assert(root->v.is_vnode);
61    size_t pte_count = item->v.is_vnode ? 1 : item->v.u.frame.pte_count;
62    // check that we don't overflow children buffer
63    assert(item->v.entry + pte_count <= PTABLE_ENTRIES);
64    for (int i = 0; i < pte_count; i++) {
65        root->v.u.vnode.children[item->v.entry+i] = NULL;
66    }
67}
68
69errval_t pmap_vnode_mgmt_init(struct pmap *pmap)
70{
71    struct pmap_vnode_mgmt *m = &pmap->m;
72    /* special case init of own pmap vnode mgmt */
73    if (get_current_pmap() == pmap) {
74        /* use core state buffers */
75        slab_init(&m->slab, sizeof(struct vnode), NULL);
76        slab_grow(&m->slab, m->slab_buffer, INIT_SLAB_BUFFER_SIZE);
77
78        /* Initialize slab allocator for child arrays */
79        slab_init(&m->ptslab, PTSLAB_SLABSIZE, NULL);
80        slab_grow(&m->ptslab, m->ptslab_buffer, INIT_PTSLAB_BUFFER_SIZE);
81    } else {
82        /*initialize slab allocator for vnodes */
83        slab_init(&m->slab, sizeof(struct vnode), NULL);
84        uint8_t *buf = malloc(INIT_SLAB_BUFFER_SIZE);
85        if (!buf) {
86            return LIB_ERR_MALLOC_FAIL;
87        }
88        slab_grow(&m->slab, buf, INIT_SLAB_BUFFER_SIZE);
89
90        /* Initialize slab allocator for child arrays */
91        slab_init(&m->ptslab, PTSLAB_SLABSIZE, NULL);
92        buf = malloc(INIT_PTSLAB_BUFFER_SIZE);
93        if (!buf) {
94            return LIB_ERR_MALLOC_FAIL;
95        }
96        slab_grow(&m->ptslab, buf, INIT_PTSLAB_BUFFER_SIZE);
97    }
98
99    return SYS_ERR_OK;
100}
101
102void pmap_vnode_init(struct pmap *p, struct vnode *v)
103{
104    v->v.u.vnode.children = slab_alloc(&p->m.ptslab);
105    assert(v->v.u.vnode.children);
106    memset(v->v.u.vnode.children, 0, PTSLAB_SLABSIZE);
107}
108
109void pmap_vnode_insert_child(struct vnode *root, struct vnode *newvnode)
110{
111    size_t pte_count = newvnode->v.is_vnode ? 1 : newvnode->v.u.frame.pte_count;
112    // check that we don't overflow children buffer
113    assert(newvnode->v.entry + pte_count <= PTABLE_ENTRIES);
114    for (int i = 0; i < pte_count; i++) {
115        root->v.u.vnode.children[newvnode->v.entry+i] = newvnode;
116    }
117}
118
119void pmap_vnode_free(struct pmap *pmap, struct vnode *n)
120{
121    slab_free(&pmap->m.ptslab, n->v.u.vnode.children);
122    slab_free(&pmap->m.slab, n);
123}
124
125errval_t pmap_refill_slabs(struct pmap *pmap, size_t max_slabs)
126{
127    errval_t err;
128    err = pmap_slab_refill(pmap, &pmap->m.slab, max_slabs);
129    if (err_is_fail(err)) {
130        return err;
131    }
132    err = pmap_slab_refill(pmap, &pmap->m.ptslab, max_slabs);
133    if (err_is_fail(err)) {
134        return err;
135    }
136    /* for pmap_array, after refilling ptslabs, we need to make sure that we
137     * actually still have enough vnode slabs. */
138    err = pmap_slab_refill(pmap, &pmap->m.slab, max_slabs);
139    if (err_is_fail(err)) {
140        return err;
141    }
142    return SYS_ERR_OK;
143}
144