1106686Stjr/*
2106686Stjr * Copyright 2017, Data61
3106686Stjr * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4106686Stjr * ABN 41 687 119 230.
5106686Stjr *
6106686Stjr * This software may be distributed and modified according to the terms of
7106686Stjr * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8106686Stjr * See "LICENSE_BSD2.txt" for details.
9106686Stjr *
10106686Stjr * @TAG(DATA61_BSD)
11106686Stjr */
12106686Stjr
13106686Stjr#include <allocman/allocman.h>
14106686Stjr#include <allocman/util.h>
15106686Stjr#include <stdlib.h>
16106686Stjr#include <assert.h>
17106686Stjr#include <string.h>
18106686Stjr#include <sel4/sel4.h>
19106686Stjr#include <allocman/vka.h>
20106686Stjr#include <vka/object.h>
21106686Stjr#include <allocman/cspace/vka.h>
22106686Stjr#include <allocman/utspace/vka.h>
23106686Stjr#include <allocman/mspace/malloc.h>
24106686Stjr
25106686Stjr/**
26106686Stjr * Allocate a slot in a cspace.
27106686Stjr *
28106686Stjr * @param data cookie for the underlying allocator
29106686Stjr * @param res pointer to a cptr to store the allocated slot
30106686Stjr * @return 0 on success
31106686Stjr */
32106686Stjrstatic int am_vka_cspace_alloc(void *data, seL4_CPtr *res)
33106686Stjr{
34106686Stjr    int error;
35106686Stjr    cspacepath_t path;
36106686Stjr
37106686Stjr    assert(data);
38106686Stjr    assert(res);
39106686Stjr
40106686Stjr    error = allocman_cspace_alloc((allocman_t *) data, &path);
41106686Stjr    if (!error) {
42106686Stjr        *res = path.capPtr;
43106686Stjr    }
44106686Stjr
45106686Stjr    return error;
46106686Stjr}
47106686Stjr
48106686Stjr/**
49106686Stjr * Convert an allocated cptr to a cspacepath, for use in
50106686Stjr * operations such as Untyped_Retype
51106686Stjr *
52106686Stjr * @param data cookie for the underlying allocator
53106686Stjr * @param slot a cslot allocated by the cspace alloc function
54106686Stjr * @param res pointer to a cspacepath struct to fill out
55106686Stjr */
56106686Stjrstatic void am_vka_cspace_make_path (void *data, seL4_CPtr slot, cspacepath_t *res)
57137587Snik{
58137587Snik    assert(data);
59106686Stjr    assert(res);
60106686Stjr
61106686Stjr    *res = allocman_cspace_make_path((allocman_t*) data, slot);
62106686Stjr}
63106686Stjr
64106686Stjr/**
65106686Stjr * Free an allocated cslot
66106686Stjr *
67106686Stjr * @param data cookie for the underlying allocator
68106686Stjr * @param slot a cslot allocated by the cspace alloc function
69106686Stjr */
70106686Stjrstatic void am_vka_cspace_free (void *data, seL4_CPtr slot)
71106686Stjr{
72106686Stjr    cspacepath_t path;
73106686Stjr    assert(data);
74106686Stjr    path = allocman_cspace_make_path((allocman_t*)data, slot);
75106686Stjr
76106686Stjr    allocman_cspace_free((allocman_t *) data, &path);
77106686Stjr}
78106686Stjr
79106686Stjr/**
80106686Stjr * Allocate a portion of an untyped into an object
81106686Stjr *
82106686Stjr * @param data cookie for the underlying allocator
83106686Stjr * @param dest path to an empty cslot to place the cap to the allocated object
84106686Stjr * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
85106686Stjr * @param size_bits the size of the object to allocate (as passed to Untyped_Retype)
86106686Stjr * @param can_use_dev whether the allocator can use device untyped instead of regular untyped
87106686Stjr * @param res pointer to a location to store the cookie representing this allocation
88106686Stjr * @return 0 on success
89106686Stjr */
90106686Stjrstatic int am_vka_utspace_alloc_maybe_device (void *data, const cspacepath_t *dest,
91106686Stjr                seL4_Word type, seL4_Word size_bits, bool can_use_dev, seL4_Word *res)
92106686Stjr{
93106686Stjr    int error;
94106686Stjr
95106686Stjr    assert(data);
96106686Stjr    assert(res);
97106686Stjr    assert(dest);
98106686Stjr
99106686Stjr    /* allocman uses the size in memory internally, where as vka expects size_bits
100106686Stjr     * as passed to Untyped_Retype, so do a conversion here */
101106686Stjr    size_bits = vka_get_object_size(type, size_bits);
102106686Stjr
103106686Stjr    *res = allocman_utspace_alloc((allocman_t *) data, size_bits, type, (cspacepath_t*)dest, can_use_dev, &error);
104106686Stjr
105106686Stjr    return error;
106106686Stjr}
107106686Stjr
108106686Stjr/**
109106686Stjr * Allocate a portion of an untyped into an object
110106686Stjr *
111106686Stjr * @param data cookie for the underlying allocator
112106686Stjr * @param dest path to an empty cslot to place the cap to the allocated object
113106686Stjr * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
114106686Stjr * @param size_bits the size of the object to allocate (as passed to Untyped_Retype)
115106686Stjr * @param res pointer to a location to store the cookie representing this allocation
116106686Stjr * @return 0 on success
117106686Stjr */
118106686Stjrstatic int am_vka_utspace_alloc (void *data, const cspacepath_t *dest, seL4_Word type, seL4_Word size_bits, seL4_Word *res)
119106686Stjr{
120106686Stjr    return am_vka_utspace_alloc_maybe_device(data, dest, type, size_bits, false, res);
121106686Stjr}
122106686Stjr
123106686Stjr/**
124106686Stjr * Allocate a portion of an untyped into an object
125106686Stjr *
126137587Snik * @param data cookie for the underlying allocator
127106686Stjr * @param dest path to an empty cslot to place the cap to the allocated object
128106686Stjr * @param type the seL4 object type to allocate (as passed to Untyped_Retype)
129106686Stjr * @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