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 <allocman/allocman.h>
14#include <allocman/util.h>
15#include <stdlib.h>
16#include <assert.h>
17#include <string.h>
18#include <sel4/sel4.h>
19#include <allocman/vka.h>
20#include <vka/object.h>
21#include <allocman/cspace/vka.h>
22#include <allocman/utspace/vka.h>
23#include <allocman/mspace/malloc.h>
24
25/**
26 * Allocate a slot in a cspace.
27 *
28 * @param data cookie for the underlying allocator
29 * @param res pointer to a cptr to store the allocated slot
30 * @return 0 on success
31 */
32static int am_vka_cspace_alloc(void *data, seL4_CPtr *res)
33{
34    int error;
35    cspacepath_t path;
36
37    assert(data);
38    assert(res);
39
40    error = allocman_cspace_alloc((allocman_t *) data, &path);
41    if (!error) {
42        *res = path.capPtr;
43    }
44
45    return error;
46}
47
48/**
49 * Convert an allocated cptr to a cspacepath, for use in
50 * operations such as Untyped_Retype
51 *
52 * @param data cookie for the underlying allocator
53 * @param slot a cslot allocated by the cspace alloc function
54 * @param res pointer to a cspacepath struct to fill out
55 */
56static void am_vka_cspace_make_path (void *data, seL4_CPtr slot, cspacepath_t *res)
57{
58    assert(data);
59    assert(res);
60
61    *res = allocman_cspace_make_path((allocman_t*) data, slot);
62}
63
64/**
65 * Free an allocated cslot
66 *
67 * @param data cookie for the underlying allocator
68 * @param slot a cslot allocated by the cspace alloc function
69 */
70static void am_vka_cspace_free (void *data, seL4_CPtr slot)
71{
72    cspacepath_t path;
73    assert(data);
74    path = allocman_cspace_make_path((allocman_t*)data, slot);
75
76    allocman_cspace_free((allocman_t *) data, &path);
77}
78
79/**
80 * Allocate a portion of an untyped into an object
81 *
82 * @param data cookie for the underlying allocator
83 * @param dest path to an empty cslot to place the cap to the allocated object
84 * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
85 * @param size_bits the size of the object to allocate (as passed to Untyped_Retype)
86 * @param can_use_dev whether the allocator can use device untyped instead of regular untyped
87 * @param res pointer to a location to store the cookie representing this allocation
88 * @return 0 on success
89 */
90static int am_vka_utspace_alloc_maybe_device (void *data, const cspacepath_t *dest,
91                seL4_Word type, seL4_Word size_bits, bool can_use_dev, seL4_Word *res)
92{
93    int error;
94
95    assert(data);
96    assert(res);
97    assert(dest);
98
99    /* allocman uses the size in memory internally, where as vka expects size_bits
100     * as passed to Untyped_Retype, so do a conversion here */
101    size_bits = vka_get_object_size(type, size_bits);
102
103    *res = allocman_utspace_alloc((allocman_t *) data, size_bits, type, (cspacepath_t*)dest, can_use_dev, &error);
104
105    return error;
106}
107
108/**
109 * Allocate a portion of an untyped into an object
110 *
111 * @param data cookie for the underlying allocator
112 * @param dest path to an empty cslot to place the cap to the allocated object
113 * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
114 * @param size_bits the size of the object to allocate (as passed to Untyped_Retype)
115 * @param res pointer to a location to store the cookie representing this allocation
116 * @return 0 on success
117 */
118static int am_vka_utspace_alloc (void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, seL4_Word *res)
119{
120    return am_vka_utspace_alloc_maybe_device(data, dest, type, size_bits, false, res);
121}
122
123/**
124 * Allocate a portion of an untyped into an object
125 *
126 * @param data cookie for the underlying allocator
127 * @param dest path to an empty cslot to place the cap to the allocated object
128 * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
129 * @param size_bits the size of the object to allocate (as passed to Untyped_Retype)
130 * @param paddr the desired physical address of the start of the allocated object
131 * @param res pointer to a location to store the cookie representing this allocation
132 * @return 0 on success
133 */
134static int am_vka_utspace_alloc_at (void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, uintptr_t paddr, seL4_Word *res)
135{
136    int error;
137
138    assert(data);
139    assert(res);
140    assert(dest);
141
142    /* allocman uses the size in memory internally, where as vka expects size_bits
143     * as passed to Untyped_Retype, so do a conversion here */
144    size_bits = vka_get_object_size(type, size_bits);
145
146    *res = allocman_utspace_alloc_at((allocman_t *) data, size_bits, type, (cspacepath_t*)dest, paddr, true, &error);
147
148    return error;
149}
150
151/**
152 * Free a portion of an allocated untyped. Is the responsibility of the caller to
153 * have already deleted the object (by deleting all capabilities) first
154 *
155 * @param data cookie for the underlying allocator
156 * @param type the seL4 object type that was allocated (as passed to Untyped_Retype)
157 * @param size_bits the size of the object that was allocated (as passed to Untyped_Retype)
158 * @param target cookie to the allocation as given by the utspace alloc function
159 */
160static void am_vka_utspace_free (void *data, seL4_Word type, seL4_Word size_bits, seL4_Word target)
161{
162    assert(data);
163
164    /* allocman uses the size in memory internally, where as vka expects size_bits
165     * as passed to Untyped_Retype, so do a conversion here */
166    size_bits = vka_get_object_size(type, size_bits);
167
168    allocman_utspace_free((allocman_t *)data, target, size_bits);
169}
170
171static uintptr_t am_vka_utspace_paddr (void *data, seL4_Word target, seL4_Word type, seL4_Word size_bits)
172{
173    assert(data);
174
175    /* allocman uses the size in memory internally, where as vka expects size_bits
176     * as passed to Untyped_Retype, so do a conversion here */
177    size_bits = vka_get_object_size(type, size_bits);
178
179    return allocman_utspace_paddr((allocman_t *)data, target, size_bits);
180}
181
182/**
183 * Make a VKA object using this allocman
184 *
185 * @param structure for the vka interface object
186 * @param allocator to be used with this vka
187 */
188void allocman_make_vka(vka_t *vka, allocman_t *alloc)
189{
190    assert(vka);
191    assert(alloc);
192
193    vka->data = alloc;
194    vka->cspace_alloc = &am_vka_cspace_alloc;
195    vka->cspace_make_path = &am_vka_cspace_make_path;
196    vka->utspace_alloc = &am_vka_utspace_alloc;
197    vka->utspace_alloc_maybe_device = &am_vka_utspace_alloc_maybe_device;
198    vka->utspace_alloc_at = &am_vka_utspace_alloc_at;
199    vka->cspace_free = &am_vka_cspace_free;
200    vka->utspace_free = &am_vka_utspace_free;
201    vka->utspace_paddr = &am_vka_utspace_paddr;
202}
203
204int allocman_make_from_vka(vka_t *vka, allocman_t *alloc)
205{
206    int error;
207    assert(vka);
208    assert(alloc);
209
210    error = allocman_create(alloc, mspace_malloc_interface);
211    if (error) {
212        return error;
213    }
214    error = allocman_attach_utspace(alloc, utspace_vka_make_interface(vka));
215    assert(!error);
216    error = allocman_attach_cspace(alloc, cspace_vka_make_interface(vka));
217    assert(!error);
218    return 0;
219}
220