blob: 18377c4258efa2bafc6132956f4973b0bae6ba1f [file] [log] [blame]
TrustworthySystemscedc0562014-07-22 14:11:16 +10001/*
Anna Lyons92143412017-06-05 08:29:55 +10002 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
TrustworthySystemscedc0562014-07-22 14:11:16 +10005 *
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 *
Anna Lyons92143412017-06-05 08:29:55 +100010 * @TAG(DATA61_BSD)
TrustworthySystemscedc0562014-07-22 14:11:16 +100011 */
12
13#include <autoconf.h>
Yu Houe23dc542019-05-20 15:29:15 +100014#include <sel4platsupport/gen_config.h>
TrustworthySystemscedc0562014-07-22 14:11:16 +100015
TrustworthySystemscedc0562014-07-22 14:11:16 +100016#include <sel4platsupport/io.h>
Adrian Danis32095092017-05-25 17:00:35 +100017#ifdef CONFIG_ARCH_ARM
Alexander Kroh637e0d42015-06-26 13:44:02 +100018#include <platsupport/clock.h>
19#include <platsupport/mux.h>
20#endif
TrustworthySystemscedc0562014-07-22 14:11:16 +100021#include <utils/util.h>
Anna Lyons3a9da542016-02-29 14:07:08 +110022#include <vspace/page.h>
TrustworthySystemscedc0562014-07-22 14:11:16 +100023
24#include <vspace/vspace.h>
25#include <vka/capops.h>
26
Matthew Fernandez92702162016-06-10 15:35:43 +100027#include <stdint.h>
TrustworthySystemscedc0562014-07-22 14:11:16 +100028#include <stdlib.h>
29
30typedef struct io_mapping {
TrustworthySystemscedc0562014-07-22 14:11:16 +100031 /* address we returned to the user */
32 void *returned_addr;
33 /* base address of the mapping with respect to the vspace */
34 void *mapped_addr;
Anna Lyonsf2887a52016-09-30 16:06:15 +100035 size_t num_pages;
36 size_t page_size;
37 size_t page_size_bits;
38 /* caps for the mappings (s) */
TrustworthySystemscedc0562014-07-22 14:11:16 +100039 seL4_CPtr *caps;
Anna Lyonsf2887a52016-09-30 16:06:15 +100040 /* allocation cookie for allocation(s) */
41 seL4_Word *alloc_cookies;
TrustworthySystemscedc0562014-07-22 14:11:16 +100042 struct io_mapping *next, *prev;
43} io_mapping_t;
44
45typedef struct sel4platsupport_io_mapper_cookie {
Damon Lee28c5fdd2019-07-23 11:27:46 +100046 vspace_t *vspace;
47 vka_t *vka;
TrustworthySystemscedc0562014-07-22 14:11:16 +100048 io_mapping_t *head;
49} sel4platsupport_io_mapper_cookie_t;
50
Yu Houe9a9ff42019-07-18 17:26:01 +100051static void free_node(io_mapping_t *node)
Alexander Kroh637e0d42015-06-26 13:44:02 +100052{
Anna Lyonsf2887a52016-09-30 16:06:15 +100053 assert(node);
54 if (node->caps) {
55 free(node->caps);
56 }
57 if (node->alloc_cookies) {
58 free(node->alloc_cookies);
59 }
60 free(node);
61}
62
Yu Houe9a9ff42019-07-18 17:26:01 +100063static io_mapping_t *new_node(size_t num_pages)
Anna Lyonsf2887a52016-09-30 16:06:15 +100064{
65 io_mapping_t *ret = calloc(1, sizeof(io_mapping_t));
66
TrustworthySystemscedc0562014-07-22 14:11:16 +100067 if (!ret) {
68 return NULL;
69 }
Anna Lyonsf2887a52016-09-30 16:06:15 +100070
71 ret->caps = calloc(num_pages, sizeof(seL4_CPtr));
72 if (!ret->caps) {
73 free_node(ret);
74 return NULL;
75 }
76
77 ret->alloc_cookies = calloc(num_pages, sizeof(seL4_Word));
78 if (!ret->alloc_cookies) {
79 free_node(ret);
80 return NULL;
81 }
82
83 ret->num_pages = num_pages;
TrustworthySystemscedc0562014-07-22 14:11:16 +100084 return ret;
85}
86
Yu Houe9a9ff42019-07-18 17:26:01 +100087static void destroy_node(vka_t *vka, io_mapping_t *mapping)
Anna Lyonsf2887a52016-09-30 16:06:15 +100088{
89 cspacepath_t path;
90 for (size_t i = 0; i < mapping->num_pages; i++) {
91 /* free the allocation */
92 vka_utspace_free(vka, kobject_get_type(KOBJECT_FRAME, mapping->page_size_bits),
93 mapping->page_size_bits, mapping->alloc_cookies[i]);
94 /* free the caps */
Anna Lyons6899ede2016-10-04 10:05:57 +110095 vka_cspace_make_path(vka, mapping->caps[i], &path);
96 vka_cnode_delete(&path);
97 vka_cspace_free(vka, mapping->caps[i]);
Anna Lyonsf2887a52016-09-30 16:06:15 +100098 }
99 free_node(mapping);
100}
101
Yu Houe9a9ff42019-07-18 17:26:01 +1000102static void insert_node(sel4platsupport_io_mapper_cookie_t *io_mapper, io_mapping_t *node)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000103{
104 node->prev = NULL;
105 node->next = io_mapper->head;
106 if (io_mapper->head) {
107 io_mapper->head->prev = node;
108 }
109 io_mapper->head = node;
110}
111
Yu Houe9a9ff42019-07-18 17:26:01 +1000112static io_mapping_t *find_node(sel4platsupport_io_mapper_cookie_t *io_mapper, void *returned_addr)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000113{
114 io_mapping_t *current;
115 for (current = io_mapper->head; current; current = current->next) {
116 if (current->returned_addr == returned_addr) {
117 return current;
118 }
119 }
120 return NULL;
121}
122
Yu Houe9a9ff42019-07-18 17:26:01 +1000123static void remove_node(sel4platsupport_io_mapper_cookie_t *io_mapper, io_mapping_t *node)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000124{
125 if (node->prev) {
126 node->prev->next = node->next;
127 } else {
128 assert(io_mapper->head == node);
129 io_mapper->head = node->next;
130 }
131 if (node->next) {
132 node->next->prev = node->prev;
133 }
134}
135
Yu Houe9a9ff42019-07-18 17:26:01 +1000136static void *sel4platsupport_map_paddr_with_page_size(sel4platsupport_io_mapper_cookie_t *io_mapper, uintptr_t paddr,
137 size_t size, size_t page_size_bits, bool cached)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000138{
139
Damon Lee28c5fdd2019-07-23 11:27:46 +1000140 vka_t *vka = io_mapper->vka;
141 vspace_t *vspace = io_mapper->vspace;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000142
143 /* search at start of page */
144 int page_size = BIT(page_size_bits);
145 uintptr_t start = ROUND_DOWN(paddr, page_size);
Adrian Danis5f4e7d12016-03-03 15:27:15 +1100146 uintptr_t offset = paddr - start;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000147 size += offset;
148
Anna Lyonsf2887a52016-09-30 16:06:15 +1000149 io_mapping_t *mapping = new_node(BYTES_TO_SIZE_BITS_PAGES(size, page_size_bits));
150 assert(mapping->num_pages << page_size_bits >= size);
151 if (!mapping) {
152 ZF_LOGE("Failed to allocate node for %zu pages", mapping->num_pages);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000153 return NULL;
154 }
Anna Lyonsf2887a52016-09-30 16:06:15 +1000155 mapping->page_size_bits = page_size_bits;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000156
Anna Lyonsf2887a52016-09-30 16:06:15 +1000157 seL4_Word type = kobject_get_type(KOBJECT_FRAME, mapping->page_size_bits);
158 /* allocate all of the physical frame caps */
159 for (unsigned int i = 0; i < mapping->num_pages; i++) {
TrustworthySystemscedc0562014-07-22 14:11:16 +1000160 /* allocate a cslot */
Anna Lyonsf2887a52016-09-30 16:06:15 +1000161 int error = vka_cspace_alloc(vka, &mapping->caps[i]);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000162 if (error) {
Anna Lyons67c869c2016-03-30 11:16:41 +1100163 ZF_LOGE("cspace alloc failed");
TrustworthySystemscedc0562014-07-22 14:11:16 +1000164 assert(error == 0);
165 /* we don't clean up as everything has gone to hell */
166 return NULL;
167 }
168
169 /* create a path */
170 cspacepath_t path;
Anna Lyonsf2887a52016-09-30 16:06:15 +1000171 vka_cspace_make_path(vka, mapping->caps[i], &path);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000172
Anna Lyonsf2887a52016-09-30 16:06:15 +1000173 /* allocate the frame */
174 error = vka_utspace_alloc_at(vka, &path, type, page_size_bits, start + (i * page_size),
Anna Lyons6899ede2016-10-04 10:05:57 +1100175 &mapping->alloc_cookies[i]);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000176 if (error) {
177 /* free this slot, and then do general cleanup of the rest of the slots.
178 * this avoids a needless seL4_CNode_Delete of this slot, as there is no
179 * cap in it */
Anna Lyonsf2887a52016-09-30 16:06:15 +1000180 vka_cspace_free(vka, mapping->caps[i]);
181 mapping->num_pages = i;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000182 goto error;
183 }
TrustworthySystemscedc0562014-07-22 14:11:16 +1000184 }
185
186 /* Now map the frames in */
Yu Houe9a9ff42019-07-18 17:26:01 +1000187 mapping->mapped_addr = vspace_map_pages(vspace, mapping->caps, mapping->alloc_cookies, seL4_AllRights,
188 mapping->num_pages,
Anna Lyons6899ede2016-10-04 10:05:57 +1100189 mapping->page_size_bits, cached);
Anna Lyonsf2887a52016-09-30 16:06:15 +1000190 if (mapping->mapped_addr != NULL) {
191 /* fill out and insert node */
192 mapping->returned_addr = mapping->mapped_addr + offset;
193 insert_node(io_mapper, mapping);
194 return mapping->returned_addr;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000195 }
196error:
Anna Lyonsf2887a52016-09-30 16:06:15 +1000197 destroy_node(vka, mapping);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000198 return NULL;
199}
200
Yu Houe9a9ff42019-07-18 17:26:01 +1000201static void *sel4platsupport_map_paddr(void *cookie, uintptr_t paddr, size_t size, int cached,
202 UNUSED ps_mem_flags_t flags)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000203{
Damon Lee0cf1c702019-07-25 17:11:46 +1000204 if (!cookie) {
205 ZF_LOGE("cookie is NULL");
206 return NULL;
207 }
208
Yu Houe9a9ff42019-07-18 17:26:01 +1000209 sel4platsupport_io_mapper_cookie_t *io_mapper = (sel4platsupport_io_mapper_cookie_t *)cookie;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000210 int frame_size_index = 0;
211 /* find the largest reasonable frame size */
Anna Lyons3a9da542016-02-29 14:07:08 +1100212 while (frame_size_index + 1 < SEL4_NUM_PAGE_SIZES) {
213 if (size >> sel4_page_sizes[frame_size_index + 1] == 0) {
TrustworthySystemscedc0562014-07-22 14:11:16 +1000214 break;
215 }
216 frame_size_index++;
217 }
Alexander Kroh637e0d42015-06-26 13:44:02 +1000218
TrustworthySystemscedc0562014-07-22 14:11:16 +1000219 /* try mapping in this and all smaller frame sizes until something works */
220 for (int i = frame_size_index; i >= 0; i--) {
Anna Lyons3a9da542016-02-29 14:07:08 +1100221 void *result = sel4platsupport_map_paddr_with_page_size(io_mapper, paddr, size, sel4_page_sizes[i], cached);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000222 if (result) {
223 return result;
224 }
225 }
226
TrustworthySystemscedc0562014-07-22 14:11:16 +1000227 /* shit out of luck */
Anna Lyons67c869c2016-03-30 11:16:41 +1100228 ZF_LOGE("Failed to find a way to map address %p", (void *)paddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000229 return NULL;
230}
231
Yu Houe9a9ff42019-07-18 17:26:01 +1000232static void sel4platsupport_unmap_vaddr(void *cookie, void *vaddr, UNUSED size_t size)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000233{
Damon Lee0cf1c702019-07-25 17:11:46 +1000234 if (!cookie) {
235 ZF_LOGE("cookie is NULL");
236 }
237
Yu Houe9a9ff42019-07-18 17:26:01 +1000238 sel4platsupport_io_mapper_cookie_t *io_mapper = cookie;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000239
Damon Lee28c5fdd2019-07-23 11:27:46 +1000240 vspace_t *vspace = io_mapper->vspace;
241 vka_t *vka = io_mapper->vka;
Anna Lyonsf2887a52016-09-30 16:06:15 +1000242 io_mapping_t *mapping = find_node(io_mapper, vaddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000243
TrustworthySystemscedc0562014-07-22 14:11:16 +1000244 if (!mapping) {
Anna Lyons67c869c2016-03-30 11:16:41 +1100245 ZF_LOGF("Tried to unmap vaddr %p, which was never mapped in", vaddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000246 return;
247 }
TrustworthySystemscedc0562014-07-22 14:11:16 +1000248
Anna Lyonsf2887a52016-09-30 16:06:15 +1000249 /* unmap the pages */
250 vspace_unmap_pages(vspace, mapping->mapped_addr, mapping->num_pages, mapping->page_size_bits,
Alexander Kroh637e0d42015-06-26 13:44:02 +1000251 VSPACE_PRESERVE);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000252
Anna Lyonsf2887a52016-09-30 16:06:15 +1000253 /* clean up the node */
254 remove_node(io_mapper, mapping);
255 destroy_node(vka, mapping);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000256}
257
Damon Lee28c5fdd2019-07-23 11:27:46 +1000258int sel4platsupport_new_io_mapper(vspace_t *vspace, vka_t *vka, ps_io_mapper_t *io_mapper)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000259{
Anna Lyonsebee53e2018-03-13 16:30:44 +1100260 sel4platsupport_io_mapper_cookie_t *cookie = calloc(1, sizeof(sel4platsupport_io_mapper_cookie_t));
TrustworthySystemscedc0562014-07-22 14:11:16 +1000261 if (!cookie) {
Anna Lyonsf2887a52016-09-30 16:06:15 +1000262 ZF_LOGE("Failed to allocate %zu bytes", sizeof(sel4platsupport_io_mapper_cookie_t));
TrustworthySystemscedc0562014-07-22 14:11:16 +1000263 return -1;
264 }
Anna Lyonsf2887a52016-09-30 16:06:15 +1000265
266 cookie->vspace = vspace;
267 cookie->vka = vka;
268 io_mapper->cookie = cookie;
269 io_mapper->io_map_fn = sel4platsupport_map_paddr;
270 io_mapper->io_unmap_fn = sel4platsupport_unmap_vaddr;
271
TrustworthySystemscedc0562014-07-22 14:11:16 +1000272 return 0;
273}
Damon Lee3e7189f2019-07-18 14:06:09 +1000274
Yu Houe9a9ff42019-07-18 17:26:01 +1000275int sel4platsupport_new_malloc_ops(ps_malloc_ops_t *ops)
Anna Lyons40c16d92017-07-17 09:46:07 +1000276{
Anna Lyonsef212992017-09-29 08:57:01 +1000277 ps_new_stdlib_malloc_ops(ops);
Anna Lyons887abc32017-07-17 15:29:48 +1000278 return 0;
Anna Lyons40c16d92017-07-17 09:46:07 +1000279}
280
Damon Lee8869a2c2019-07-18 14:06:37 +1000281static char *sel4platsupport_io_fdt_get(void *cookie)
282{
283 return cookie != NULL ? (char *) cookie : NULL;
284}
285
286int sel4platsupport_new_fdt_ops(ps_io_fdt_t *io_fdt, simple_t *simple, ps_malloc_ops_t *malloc_ops)
287{
288 if (!io_fdt || !simple || !malloc_ops) {
289 ZF_LOGE("arguments are NULL");
290 return -1;
291 }
292
293 ssize_t block_size = simple_get_extended_bootinfo_length(simple, SEL4_BOOTINFO_HEADER_FDT);
Damon Lee89360ac2019-07-25 17:12:48 +1000294 if (block_size > 0) {
295 int error = ps_calloc(malloc_ops, 1, block_size, &io_fdt->cookie);
296 if (error) {
297 ZF_LOGE("Failed to allocate %zu bytes for the FDT", block_size);
298 return -1;
299 }
Damon Lee8869a2c2019-07-18 14:06:37 +1000300
Damon Lee89360ac2019-07-25 17:12:48 +1000301 /* Copy the FDT from the extended bootinfo */
302 ssize_t copied_size = simple_get_extended_bootinfo(simple, SEL4_BOOTINFO_HEADER_FDT,
303 io_fdt->cookie, block_size);
304 if (copied_size != block_size) {
305 ZF_LOGE("Failed to copy the FDT");
306 ZF_LOGF_IF(ps_free(malloc_ops, block_size, io_fdt->cookie),
307 "Failed to clean-up after a failed operation!");
308 return -1;
309 }
310
311 /* Cut off the bootinfo header from the start of the buffer */
312 ssize_t fdt_size = block_size - sizeof(seL4_BootInfoHeader);
313 void *fdt_start = io_fdt->cookie + sizeof(seL4_BootInfoHeader);
314 memmove(io_fdt->cookie, fdt_start, fdt_size);
315
316 /* Trim off the extra bytes at the end of the FDT */
317 void *fdt_end = io_fdt->cookie + fdt_size;
318 memset(fdt_end, 0, sizeof(seL4_BootInfoHeader));
319 } else {
320 /* No FDT is available so just set the cookie to NULL */
321 io_fdt->cookie = NULL;
Damon Lee8869a2c2019-07-18 14:06:37 +1000322 }
323
Damon Lee8869a2c2019-07-18 14:06:37 +1000324 /* Set the function pointer inside the io_fdt interface */
325 io_fdt->get_fn = sel4platsupport_io_fdt_get;
326
327 return 0;
328}
329
Damon Lee5ac18742019-07-25 13:48:54 +1000330int sel4platsupport_new_io_ops(vspace_t *vspace, vka_t *vka, simple_t *simple, ps_io_ops_t *io_ops)
Alexander Kroh637e0d42015-06-26 13:44:02 +1000331{
Anna Lyonsc28e0d42017-10-04 09:48:23 +1100332 memset(io_ops, 0, sizeof(ps_io_ops_t));
333
Damon Lee5ac18742019-07-25 13:48:54 +1000334 int error = 0;
335
336 /* Initialise the interfaces which do not require memory allocation/need to be initialised first */
Damon Lee2d74ed22019-12-03 10:48:45 +1100337 error = sel4platsupport_new_malloc_ops(&io_ops->malloc_ops);
Damon Lee5ac18742019-07-25 13:48:54 +1000338 if (error) {
339 return error;
Alexander Kroh637e0d42015-06-26 13:44:02 +1000340 }
Anna Lyonsf2887a52016-09-30 16:06:15 +1000341
Damon Lee5ac18742019-07-25 13:48:54 +1000342 /* Now allocate the IO-specific interfaces (the ones that can be found in this file) */
343 error = sel4platsupport_new_io_mapper(vspace, vka, &io_ops->io_mapper);
344 if (error) {
345 return error;
346 }
Kofi Doku Atuahd1ed16a2017-11-15 15:32:07 +1100347
Damon Lee4a474d32019-07-25 13:52:21 +1000348 error = sel4platsupport_new_fdt_ops(&io_ops->io_fdt, simple, &io_ops->malloc_ops);
349 if (error) {
350 free(io_ops->io_mapper.cookie);
351 io_ops->io_mapper.cookie = NULL;
352 return error;
353 }
354
Damon Lee5ac18742019-07-25 13:48:54 +1000355 error = sel4platsupport_new_irq_ops(&io_ops->irq_ops, vka, simple, DEFAULT_IRQ_INTERFACE_CONFIG,
356 &io_ops->malloc_ops);
357 if (error) {
358 free(io_ops->io_mapper.cookie);
359 io_ops->io_mapper.cookie = NULL;
Damon Lee4a474d32019-07-25 13:52:21 +1000360 ssize_t fdt_size = simple_get_extended_bootinfo_length(simple, SEL4_BOOTINFO_HEADER_FDT);
361 if (fdt_size > 0) {
362 /* The FDT is available on this platform and we actually copied it, so we free it */
363 ps_free(&io_ops->malloc_ops, fdt_size, &io_ops->io_fdt.cookie);
364 }
Damon Lee5ac18742019-07-25 13:48:54 +1000365 return error;
366 }
367
368 return 0;
Alexander Kroh637e0d42015-06-26 13:44:02 +1000369}