1/*
2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <sel4/sel4.h>
12#include <vka/vka.h>
13#include <vka/capops.h>
14
15#include <sel4vm/guest_vm.h>
16#include <sel4vm/guest_memory.h>
17#include <sel4vm/guest_memory_helpers.h>
18
19#include <sel4vmmplatsupport/guest_memory_util.h>
20
21struct device_frame_cookie {
22    vka_object_t frame;
23    cspacepath_t mapped_frame;
24    vm_t *vm;
25    uintptr_t addr;
26    vm_memory_reservation_t *reservation;
27    seL4_CapRights_t rights;
28};
29
30struct ut_alloc_iterator_cookie {
31    vm_t *vm;
32    vm_memory_reservation_t *reservation;
33    uintptr_t paddr;
34    bool with_paddr;
35};
36
37static vm_frame_t device_frame_iterator(uintptr_t addr, void *cookie)
38{
39    cspacepath_t return_frame;
40    vm_t *vm;
41    int page_size;
42    vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 };
43
44    struct device_frame_cookie *device_cookie = (struct device_frame_cookie *)cookie;
45    if (!device_cookie) {
46        return frame_result;
47    }
48    vm = device_cookie->vm;
49    page_size = seL4_PageBits;
50
51    int ret = vka_cspace_alloc_path(vm->vka, &return_frame);
52    if (ret) {
53        ZF_LOGE("Failed to allocate cspace path from device frame");
54        return frame_result;
55    }
56    ret = vka_cnode_copy(&return_frame, &device_cookie->mapped_frame, seL4_AllRights);
57    if (ret) {
58        ZF_LOGE("Failed to cnode_copy for device frame");
59        vka_cspace_free_path(vm->vka, return_frame);
60        return frame_result;
61    }
62    frame_result.cptr = return_frame.capPtr;
63    frame_result.rights = device_cookie->rights;
64    frame_result.vaddr = device_cookie->addr;
65    frame_result.size_bits = page_size;
66
67    return frame_result;
68}
69
70static vm_frame_t ut_alloc_iterator(uintptr_t addr, void *cookie)
71{
72    int ret;
73    int error;
74    vka_object_t object;
75    uintptr_t alloc_addr;
76    cspacepath_t path;
77    vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 };
78    struct ut_alloc_iterator_cookie *alloc_cookie = (struct ut_alloc_iterator_cookie *)cookie;
79    vm_t *vm = alloc_cookie->vm;
80    int page_size = seL4_PageBits;
81    uintptr_t frame_start = ROUND_DOWN(addr, BIT(page_size));
82
83    if (alloc_cookie->with_paddr) {
84        uintptr_t base_vaddr;
85        size_t size;
86        vm_get_reservation_memory_region(alloc_cookie->reservation, &base_vaddr, &size);
87        alloc_addr = ROUND_DOWN(alloc_cookie->paddr + (addr - base_vaddr),  BIT(page_size));
88    } else {
89        alloc_addr = frame_start;
90    }
91    error = vka_cspace_alloc_path(vm->vka, &path);
92    if (error) {
93        ZF_LOGE("Failed to allocate path");
94        return frame_result;
95    }
96    error = simple_get_frame_cap(vm->simple, (void *)alloc_addr, page_size, &path);
97    if (error) {
98        /* attempt to allocate */
99        uintptr_t vka_cookie;
100        error = vka_utspace_alloc_at(vm->vka, &path, kobject_get_type(KOBJECT_FRAME, page_size), page_size, alloc_addr,
101                                     &vka_cookie);
102    }
103    if (error) {
104        ZF_LOGE("Failed to allocate page");
105        vka_cspace_free_path(vm->vka, path);
106        return frame_result;
107    }
108
109    frame_result.cptr = path.capPtr;
110    frame_result.rights = seL4_AllRights;
111    frame_result.vaddr = frame_start;
112    frame_result.size_bits = page_size;
113    return frame_result;
114}
115
116static vm_frame_t maybe_device_alloc_iterator(uintptr_t addr, void *cookie)
117{
118    int ret;
119    vka_object_t object;
120    vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 };
121    vm_t *vm = (vm_t *)cookie;
122    if (!vm) {
123        return frame_result;
124    }
125    int page_size = seL4_PageBits;
126    uintptr_t frame_start = ROUND_DOWN(addr, BIT(page_size));
127    ret = vka_alloc_frame_maybe_device(vm->vka, page_size, true, &object);
128    if (ret) {
129        ZF_LOGE("Failed to allocate frame for address 0x%x", addr);
130        return frame_result;
131    }
132    frame_result.cptr = object.cptr;
133    frame_result.rights = seL4_AllRights;
134    frame_result.vaddr = frame_start;
135    frame_result.size_bits = page_size;
136    return frame_result;
137}
138
139static vm_frame_t frame_alloc_iterator(uintptr_t addr, void *cookie)
140{
141    int ret;
142    vka_object_t object;
143    vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 };
144    vm_t *vm = (vm_t *)cookie;
145    if (!vm) {
146        return frame_result;
147    }
148    int page_size = seL4_PageBits;
149    uintptr_t frame_start = ROUND_DOWN(addr, BIT(page_size));
150    ret = vka_alloc_frame(vm->vka, page_size, &object);
151    if (ret) {
152        ZF_LOGE("Failed to allocate frame for address 0x%x", addr);
153        return frame_result;
154    }
155    frame_result.cptr = object.cptr;
156    frame_result.rights = seL4_AllRights;
157    frame_result.vaddr = frame_start;
158    frame_result.size_bits = page_size;
159    return frame_result;
160}
161
162void *create_allocated_reservation_frame(vm_t *vm, uintptr_t addr, seL4_CapRights_t rights,
163                                         memory_fault_callback_fn alloc_fault_callback, void *alloc_fault_cookie)
164{
165    int err;
166    struct device_frame_cookie *cookie;
167    int page_size = seL4_PageBits;
168    void *alloc_addr;
169    vspace_t *vmm_vspace = &vm->mem.vmm_vspace;
170    ps_io_ops_t *ops = vm->io_ops;
171
172    err = ps_calloc(&ops->malloc_ops, 1, sizeof(struct device_frame_cookie), (void **)&cookie);
173    if (err) {
174        ZF_LOGE("Failed to create allocated vm frame: Unable to allocate cookie");
175        return NULL;
176    }
177
178    /* Reserve emulated vm frame */
179    cookie->reservation = vm_reserve_memory_at(vm, addr, PAGE_SIZE_4K,
180                                               alloc_fault_callback, (void *)alloc_fault_cookie);
181    if (!cookie->reservation) {
182        ZF_LOGE("Failed to create allocated vm frame: Unable to reservate emulated frame");
183        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
184        return NULL;
185    }
186
187    err = vka_alloc_frame(vm->vka, page_size, &cookie->frame);
188    if (err) {
189        ZF_LOGE("Failed vka_alloc_frame for allocated device frame");
190        vm_free_reserved_memory(vm, cookie->reservation);
191        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
192        return NULL;
193    }
194    vka_cspace_make_path(vm->vka, cookie->frame.cptr, &cookie->mapped_frame);
195    alloc_addr = vspace_map_pages(vmm_vspace, &cookie->mapped_frame.capPtr,
196                                  NULL, seL4_AllRights, 1, page_size, 0);
197    if (!alloc_addr) {
198        ZF_LOGE("Failed to map allocated frame into vmm vspace");
199        vka_free_object(vm->vka, &cookie->frame);
200        vm_free_reserved_memory(vm, cookie->reservation);
201        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
202        return NULL;
203    }
204
205    cookie->vm = vm;
206    cookie->addr = addr;
207    cookie->rights = rights;
208
209    /* Map the allocated frame */
210    err = vm_map_reservation(vm, cookie->reservation, device_frame_iterator, (void *)cookie);
211    if (err) {
212        ZF_LOGE("Failed to map allocated frame into vm");
213        vka_free_object(vm->vka, &cookie->frame);
214        vm_free_reserved_memory(vm, cookie->reservation);
215        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
216        return NULL;
217    }
218
219    return alloc_addr;
220}
221
222void *create_device_reservation_frame(vm_t *vm, uintptr_t addr, seL4_CapRights_t rights,
223                                      memory_fault_callback_fn fault_callback, void *fault_cookie)
224{
225    int err;
226    struct device_frame_cookie *cookie;
227    int page_size = seL4_PageBits;
228    void *dev_addr;
229    vspace_t *vmm_vspace = &vm->mem.vmm_vspace;
230    ps_io_ops_t *ops = vm->io_ops;
231
232    err = ps_calloc(&ops->malloc_ops, 1, sizeof(struct device_frame_cookie), (void **)&cookie);
233    if (err) {
234        ZF_LOGE("Failed to create device vm frame: Unable to allocate cookie");
235        return NULL;
236    }
237
238    /* Reserve emulated vm frame */
239    cookie->reservation = vm_reserve_memory_at(vm, addr, PAGE_SIZE_4K,
240                                               fault_callback, (void *)fault_cookie);
241    if (!cookie->reservation) {
242        ZF_LOGE("Failed to create device vm frame: Unable to reservate emulated frame");
243        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
244        return NULL;
245    }
246
247    err = vka_cspace_alloc_path(vm->vka, &cookie->mapped_frame);
248    if (err) {
249        ZF_LOGE("Failed to create device vm frame: Unable to allocate cslot");
250        vm_free_reserved_memory(vm, cookie->reservation);
251        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
252        return NULL;
253    }
254
255    err = simple_get_frame_cap(vm->simple, (void *)addr, page_size, &cookie->mapped_frame);
256    if (err) {
257        /* attempt to allocate */
258        uintptr_t vka_cookie;
259        err = vka_utspace_alloc_at(vm->vka, &cookie->mapped_frame, kobject_get_type(KOBJECT_FRAME, page_size), page_size, addr,
260                                   &vka_cookie);
261    }
262    if (err) {
263        ZF_LOGE("Failed to allocate page");
264        vka_cspace_free_path(vm->vka, cookie->mapped_frame);
265        vm_free_reserved_memory(vm, cookie->reservation);
266        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
267        return NULL;
268    }
269    dev_addr = vspace_map_pages(vmm_vspace, &cookie->mapped_frame.capPtr,
270                                NULL, seL4_AllRights, 1, page_size, 0);
271    if (!dev_addr) {
272        ZF_LOGE("Failed to map device frame into vmm vspace");
273        vka_cspace_free_path(vm->vka, cookie->mapped_frame);
274        vm_free_reserved_memory(vm, cookie->reservation);
275        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
276        return NULL;
277    }
278
279    cookie->vm = vm;
280    cookie->addr = addr;
281    cookie->rights = rights;
282
283    /* Map the emulated frame */
284    err = vm_map_reservation(vm, cookie->reservation, device_frame_iterator, (void *)cookie);
285    if (err) {
286        ZF_LOGE("Failed to map device frame into vm");
287        vspace_unmap_pages(vmm_vspace, dev_addr, 1, page_size, NULL);
288        vka_cspace_free_path(vm->vka, cookie->mapped_frame);
289        vm_free_reserved_memory(vm, cookie->reservation);
290        ps_free(&ops->malloc_ops, sizeof(struct device_frame_cookie), (void **)&cookie);
291        return NULL;
292    }
293
294    return dev_addr;
295}
296
297int map_ut_alloc_reservation(vm_t *vm, vm_memory_reservation_t *reservation)
298{
299    struct ut_alloc_iterator_cookie *cookie;
300    ps_io_ops_t *ops = vm->io_ops;
301    int err = ps_calloc(&ops->malloc_ops, 1, sizeof(struct ut_alloc_iterator_cookie), (void **)&cookie);
302    if (err) {
303        ZF_LOGE("Failed to map ut alloc reservation: Unable to allocate cookie");
304        return -1;
305    }
306    cookie->vm = vm;
307    cookie->with_paddr = false;
308    cookie->reservation = reservation;
309    return vm_map_reservation(vm, reservation, ut_alloc_iterator, (void *)cookie);
310}
311
312int map_ut_alloc_reservation_with_base_paddr(vm_t *vm, uintptr_t paddr, vm_memory_reservation_t *reservation)
313{
314    struct ut_alloc_iterator_cookie *cookie;
315    ps_io_ops_t *ops = vm->io_ops;
316    int err = ps_calloc(&ops->malloc_ops, 1, sizeof(struct ut_alloc_iterator_cookie), (void **)&cookie);
317    if (err) {
318        ZF_LOGE("Failed to map ut alloc reservation: Unable to allocate cookie");
319        return -1;
320    }
321    cookie->vm = vm;
322    cookie->paddr = paddr;
323    cookie->with_paddr = true;
324    cookie->reservation = reservation;
325    return vm_map_reservation(vm, reservation, ut_alloc_iterator, (void *)cookie);
326}
327
328int map_frame_alloc_reservation(vm_t *vm, vm_memory_reservation_t *reservation)
329{
330    return vm_map_reservation(vm, reservation, frame_alloc_iterator, (void *)vm);
331}
332
333int map_maybe_device_reservation(vm_t *vm, vm_memory_reservation_t *reservation)
334{
335    return vm_map_reservation(vm, reservation, maybe_device_alloc_iterator, (void *)vm);
336}
337