1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#include <autoconf.h>
14#include <sel4utils/gen_config.h>
15
16#include <inttypes.h>
17#include <sel4/sel4.h>
18#include <vka/object.h>
19#include <vka/capops.h>
20#include <sel4utils/mapping.h>
21#include <sel4utils/util.h>
22#include <vspace/mapping.h>
23
24static int map_page(vka_t *vka, vspace_map_page_fn_t map_page_fn, vspace_get_map_obj_fn map_obj_fn,
25                    seL4_CPtr root, seL4_CPtr frame, void *vaddr, seL4_CapRights_t rights,
26                    int cacheable, vka_object_t *objects, int *num_objects)
27{
28    int n;
29    if (!num_objects) {
30        num_objects = &n;
31    }
32
33    if (!vka || !root) {
34        return EINVAL;
35    }
36
37    seL4_ARCH_VMAttributes attr = cacheable ? seL4_ARCH_Default_VMAttributes :
38                                  seL4_ARCH_Uncached_VMAttributes;
39
40    *num_objects = 0;
41    int error = map_page_fn(frame, root, (seL4_Word) vaddr, rights, attr);
42    while (error == seL4_FailedLookup) {
43        vspace_map_obj_t obj = {0};
44        error = map_obj_fn(seL4_MappingFailedLookupLevel(), &obj);
45        /* we should not get an incorrect values for seL4_MappingFailedLookupLevel */
46        assert(error == 0);
47
48        vka_object_t object;
49        error = vka_alloc_object(vka, obj.type, obj.size_bits, &object);
50        if (objects) {
51            objects[*num_objects] = object;
52        }
53        if (error) {
54            ZF_LOGE("Mapping structure allocation failed");
55            return error;
56        }
57
58        error = vspace_map_obj(&obj, object.cptr, root,
59                               (seL4_Word)vaddr, seL4_ARCH_Default_VMAttributes);
60        if (error == seL4_DeleteFirst) {
61            /* this is the case where the allocation of the page table needed to map in
62             * a page table for the meta data, so delete this one and continue */
63            vka_free_object(vka, &object);
64        } else {
65            (*num_objects)++;
66            if (error) {
67                ZF_LOGE("Failed to map page table %d", error);
68                return error;
69            }
70        }
71        error = map_page_fn(frame, root, (seL4_Word) vaddr, rights, attr);
72    }
73    if (error != seL4_NoError) {
74        ZF_LOGE("Failed to map page at address %p with cap %"PRIuPTR", error: %d", vaddr, frame, error);
75    }
76    return error;
77}
78
79int sel4utils_map_page(vka_t *vka, seL4_CPtr vspace_root, seL4_CPtr frame, void *vaddr,
80                       seL4_CapRights_t rights, int cacheable, vka_object_t *objects, int *num_objects)
81{
82    return map_page(vka, seL4_ARCH_Page_Map, vspace_get_map_obj, vspace_root, frame, vaddr, rights,
83                    cacheable, objects, num_objects);
84}
85
86#ifndef CONFIG_ARCH_RISCV
87int sel4utils_map_iospace_page(vka_t *vka, seL4_CPtr iospace, seL4_CPtr frame, seL4_Word vaddr,
88                               seL4_CapRights_t rights, int cacheable, seL4_Word size_bits,
89                               vka_object_t *pts, int *num_pts)
90{
91    return map_page(vka, vspace_iospace_map_page, vspace_get_iospace_map_obj, iospace, frame, (void *) vaddr, rights,
92                    cacheable, pts, num_pts);
93}
94#endif /* CONFIG_ARCH_RISCV */
95#ifdef CONFIG_VTX
96
97/*map a frame into guest os's physical address space*/
98int sel4utils_map_ept_page(vka_t *vka, seL4_CPtr pd, seL4_CPtr frame, seL4_Word vaddr,
99                           seL4_CapRights_t rights, int cacheable, seL4_Word size_bits,
100                           vka_object_t *pagetable, vka_object_t *pagedir, vka_object_t *pdpt)
101{
102    vka_object_t objects[3];
103    int num_objects;
104    int error = map_page(vka, seL4_X86_Page_MapEPT, vspace_get_ept_map_obj, pd, frame, (void *) vaddr, rights, cacheable,
105                         objects,
106                         &num_objects);
107    *pagetable = objects[0];
108    *pagedir = objects[1];
109    *pdpt = objects[2];
110    return error;
111}
112
113#endif /* CONFIG_VTX */
114
115/* Some more generic routines for helping with mapping */
116void *sel4utils_dup_and_map(vka_t *vka, vspace_t *vspace, seL4_CPtr page, size_t size_bits)
117{
118    cspacepath_t page_path;
119    cspacepath_t copy_path;
120    /* First need to copy the cap */
121    int error = vka_cspace_alloc_path(vka, &copy_path);
122    if (error != seL4_NoError) {
123        return NULL;
124    }
125    vka_cspace_make_path(vka, page, &page_path);
126    error = vka_cnode_copy(&copy_path, &page_path, seL4_AllRights);
127    if (error != seL4_NoError) {
128        vka_cspace_free(vka, copy_path.capPtr);
129        return NULL;
130    }
131    /* Now map it in */
132    void *mapping = vspace_map_pages(vspace, &copy_path.capPtr, NULL,  seL4_AllRights, 1, size_bits, 1);
133    if (!mapping) {
134        vka_cnode_delete(&copy_path);
135        vka_cspace_free(vka, copy_path.capPtr);
136        return NULL;
137    }
138    return mapping;
139}
140
141void sel4utils_unmap_dup(vka_t *vka, vspace_t *vspace, void *mapping, size_t size_bits)
142{
143    /* Grab a copy of the cap */
144    seL4_CPtr copy = vspace_get_cap(vspace, mapping);
145    cspacepath_t copy_path;
146    assert(copy);
147    /* now free the mapping */
148    vspace_unmap_pages(vspace, mapping, 1, size_bits, VSPACE_PRESERVE);
149    /* delete and free the cap */
150    vka_cspace_make_path(vka, copy, &copy_path);
151    vka_cnode_delete(&copy_path);
152    vka_cspace_free(vka, copy);
153}
154