blob: 14cb9f090836eda1275d987abbba7a294cf514f5 [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>
14
TrustworthySystemscedc0562014-07-22 14:11:16 +100015#include <sel4platsupport/io.h>
Adrian Danis32095092017-05-25 17:00:35 +100016#ifdef CONFIG_ARCH_ARM
Alexander Kroh637e0d42015-06-26 13:44:02 +100017#include <platsupport/clock.h>
18#include <platsupport/mux.h>
19#endif
TrustworthySystemscedc0562014-07-22 14:11:16 +100020#include <utils/util.h>
Anna Lyons3a9da542016-02-29 14:07:08 +110021#include <vspace/page.h>
TrustworthySystemscedc0562014-07-22 14:11:16 +100022
23#include <vspace/vspace.h>
24#include <vka/capops.h>
25
Matthew Fernandez92702162016-06-10 15:35:43 +100026#include <stdint.h>
TrustworthySystemscedc0562014-07-22 14:11:16 +100027#include <stdlib.h>
28
29typedef struct io_mapping {
TrustworthySystemscedc0562014-07-22 14:11:16 +100030 /* address we returned to the user */
31 void *returned_addr;
32 /* base address of the mapping with respect to the vspace */
33 void *mapped_addr;
Anna Lyonsf2887a52016-09-30 16:06:15 +100034 size_t num_pages;
35 size_t page_size;
36 size_t page_size_bits;
37 /* caps for the mappings (s) */
TrustworthySystemscedc0562014-07-22 14:11:16 +100038 seL4_CPtr *caps;
Anna Lyonsf2887a52016-09-30 16:06:15 +100039 /* allocation cookie for allocation(s) */
40 seL4_Word *alloc_cookies;
TrustworthySystemscedc0562014-07-22 14:11:16 +100041 struct io_mapping *next, *prev;
42} io_mapping_t;
43
44typedef struct sel4platsupport_io_mapper_cookie {
45 vspace_t vspace;
TrustworthySystemscedc0562014-07-22 14:11:16 +100046 vka_t vka;
47 io_mapping_t *head;
48} sel4platsupport_io_mapper_cookie_t;
49
Anna Lyonsf2887a52016-09-30 16:06:15 +100050static void
51free_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
63static io_mapping_t *
64new_node(size_t num_pages)
65{
66 io_mapping_t *ret = calloc(1, sizeof(io_mapping_t));
67
TrustworthySystemscedc0562014-07-22 14:11:16 +100068 if (!ret) {
69 return NULL;
70 }
Anna Lyonsf2887a52016-09-30 16:06:15 +100071
72 ret->caps = calloc(num_pages, sizeof(seL4_CPtr));
73 if (!ret->caps) {
74 free_node(ret);
75 return NULL;
76 }
77
78 ret->alloc_cookies = calloc(num_pages, sizeof(seL4_Word));
79 if (!ret->alloc_cookies) {
80 free_node(ret);
81 return NULL;
82 }
83
84 ret->num_pages = num_pages;
TrustworthySystemscedc0562014-07-22 14:11:16 +100085 return ret;
86}
87
88static void
Anna Lyonsf2887a52016-09-30 16:06:15 +100089destroy_node(vka_t *vka, io_mapping_t *mapping)
90{
91 cspacepath_t path;
92 for (size_t i = 0; i < mapping->num_pages; i++) {
93 /* free the allocation */
94 vka_utspace_free(vka, kobject_get_type(KOBJECT_FRAME, mapping->page_size_bits),
95 mapping->page_size_bits, mapping->alloc_cookies[i]);
96 /* free the caps */
Anna Lyons6899ede2016-10-04 10:05:57 +110097 vka_cspace_make_path(vka, mapping->caps[i], &path);
98 vka_cnode_delete(&path);
99 vka_cspace_free(vka, mapping->caps[i]);
Anna Lyonsf2887a52016-09-30 16:06:15 +1000100 }
101 free_node(mapping);
102}
103
104static void
105insert_node(sel4platsupport_io_mapper_cookie_t *io_mapper, io_mapping_t *node)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000106{
107 node->prev = NULL;
108 node->next = io_mapper->head;
109 if (io_mapper->head) {
110 io_mapper->head->prev = node;
111 }
112 io_mapper->head = node;
113}
114
115static io_mapping_t *
Anna Lyonsf2887a52016-09-30 16:06:15 +1000116find_node(sel4platsupport_io_mapper_cookie_t *io_mapper, void *returned_addr)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000117{
118 io_mapping_t *current;
119 for (current = io_mapper->head; current; current = current->next) {
120 if (current->returned_addr == returned_addr) {
121 return current;
122 }
123 }
124 return NULL;
125}
126
127static void
Anna Lyonsf2887a52016-09-30 16:06:15 +1000128remove_node(sel4platsupport_io_mapper_cookie_t *io_mapper, io_mapping_t *node)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000129{
130 if (node->prev) {
131 node->prev->next = node->next;
132 } else {
133 assert(io_mapper->head == node);
134 io_mapper->head = node->next;
135 }
136 if (node->next) {
137 node->next->prev = node->prev;
138 }
139}
140
TrustworthySystemscedc0562014-07-22 14:11:16 +1000141static void *
Anna Lyonsf2887a52016-09-30 16:06:15 +1000142sel4platsupport_map_paddr_with_page_size(sel4platsupport_io_mapper_cookie_t *io_mapper, uintptr_t paddr, size_t size, size_t page_size_bits, bool cached)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000143{
144
145 vka_t *vka = &io_mapper->vka;
146 vspace_t *vspace = &io_mapper->vspace;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000147
148 /* search at start of page */
149 int page_size = BIT(page_size_bits);
150 uintptr_t start = ROUND_DOWN(paddr, page_size);
Adrian Danis5f4e7d12016-03-03 15:27:15 +1100151 uintptr_t offset = paddr - start;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000152 size += offset;
153
Anna Lyonsf2887a52016-09-30 16:06:15 +1000154 io_mapping_t *mapping = new_node(BYTES_TO_SIZE_BITS_PAGES(size, page_size_bits));
155 assert(mapping->num_pages << page_size_bits >= size);
156 if (!mapping) {
157 ZF_LOGE("Failed to allocate node for %zu pages", mapping->num_pages);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000158 return NULL;
159 }
Anna Lyonsf2887a52016-09-30 16:06:15 +1000160 mapping->page_size_bits = page_size_bits;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000161
Anna Lyonsf2887a52016-09-30 16:06:15 +1000162 seL4_Word type = kobject_get_type(KOBJECT_FRAME, mapping->page_size_bits);
163 /* allocate all of the physical frame caps */
164 for (unsigned int i = 0; i < mapping->num_pages; i++) {
TrustworthySystemscedc0562014-07-22 14:11:16 +1000165 /* allocate a cslot */
Anna Lyonsf2887a52016-09-30 16:06:15 +1000166 int error = vka_cspace_alloc(vka, &mapping->caps[i]);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000167 if (error) {
Anna Lyons67c869c2016-03-30 11:16:41 +1100168 ZF_LOGE("cspace alloc failed");
TrustworthySystemscedc0562014-07-22 14:11:16 +1000169 assert(error == 0);
170 /* we don't clean up as everything has gone to hell */
171 return NULL;
172 }
173
174 /* create a path */
175 cspacepath_t path;
Anna Lyonsf2887a52016-09-30 16:06:15 +1000176 vka_cspace_make_path(vka, mapping->caps[i], &path);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000177
Anna Lyonsf2887a52016-09-30 16:06:15 +1000178 /* allocate the frame */
179 error = vka_utspace_alloc_at(vka, &path, type, page_size_bits, start + (i * page_size),
Anna Lyons6899ede2016-10-04 10:05:57 +1100180 &mapping->alloc_cookies[i]);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000181 if (error) {
182 /* free this slot, and then do general cleanup of the rest of the slots.
183 * this avoids a needless seL4_CNode_Delete of this slot, as there is no
184 * cap in it */
Anna Lyonsf2887a52016-09-30 16:06:15 +1000185 vka_cspace_free(vka, mapping->caps[i]);
186 mapping->num_pages = i;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000187 goto error;
188 }
TrustworthySystemscedc0562014-07-22 14:11:16 +1000189 }
190
191 /* Now map the frames in */
Anna Lyonsf2887a52016-09-30 16:06:15 +1000192 mapping->mapped_addr = vspace_map_pages(vspace, mapping->caps, mapping->alloc_cookies, seL4_AllRights, mapping->num_pages,
Anna Lyons6899ede2016-10-04 10:05:57 +1100193 mapping->page_size_bits, cached);
Anna Lyonsf2887a52016-09-30 16:06:15 +1000194 if (mapping->mapped_addr != NULL) {
195 /* fill out and insert node */
196 mapping->returned_addr = mapping->mapped_addr + offset;
197 insert_node(io_mapper, mapping);
198 return mapping->returned_addr;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000199 }
200error:
Anna Lyonsf2887a52016-09-30 16:06:15 +1000201 destroy_node(vka, mapping);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000202 return NULL;
203}
204
205static void *
Anna Lyonsf2887a52016-09-30 16:06:15 +1000206sel4platsupport_map_paddr(void *cookie, uintptr_t paddr, size_t size, int cached, UNUSED ps_mem_flags_t flags)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000207{
TrustworthySystemscedc0562014-07-22 14:11:16 +1000208 sel4platsupport_io_mapper_cookie_t* io_mapper = (sel4platsupport_io_mapper_cookie_t*)cookie;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000209 int frame_size_index = 0;
210 /* find the largest reasonable frame size */
Anna Lyons3a9da542016-02-29 14:07:08 +1100211 while (frame_size_index + 1 < SEL4_NUM_PAGE_SIZES) {
212 if (size >> sel4_page_sizes[frame_size_index + 1] == 0) {
TrustworthySystemscedc0562014-07-22 14:11:16 +1000213 break;
214 }
215 frame_size_index++;
216 }
Alexander Kroh637e0d42015-06-26 13:44:02 +1000217
TrustworthySystemscedc0562014-07-22 14:11:16 +1000218 /* try mapping in this and all smaller frame sizes until something works */
219 for (int i = frame_size_index; i >= 0; i--) {
Anna Lyons3a9da542016-02-29 14:07:08 +1100220 void *result = sel4platsupport_map_paddr_with_page_size(io_mapper, paddr, size, sel4_page_sizes[i], cached);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000221 if (result) {
222 return result;
223 }
224 }
225
TrustworthySystemscedc0562014-07-22 14:11:16 +1000226 /* shit out of luck */
Anna Lyons67c869c2016-03-30 11:16:41 +1100227 ZF_LOGE("Failed to find a way to map address %p", (void *)paddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000228 return NULL;
229}
230
231static void
Anna Lyonsf2887a52016-09-30 16:06:15 +1000232sel4platsupport_unmap_vaddr(void * cookie, void *vaddr, UNUSED size_t size)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000233{
Anna Lyonsf2887a52016-09-30 16:06:15 +1000234 sel4platsupport_io_mapper_cookie_t* io_mapper = cookie;
TrustworthySystemscedc0562014-07-22 14:11:16 +1000235
Anna Lyonsf2887a52016-09-30 16:06:15 +1000236 vspace_t *vspace = &io_mapper->vspace;
237 vka_t *vka = &io_mapper->vka;
238 io_mapping_t *mapping = find_node(io_mapper, vaddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000239
TrustworthySystemscedc0562014-07-22 14:11:16 +1000240 if (!mapping) {
Anna Lyons67c869c2016-03-30 11:16:41 +1100241 ZF_LOGF("Tried to unmap vaddr %p, which was never mapped in", vaddr);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000242 return;
243 }
TrustworthySystemscedc0562014-07-22 14:11:16 +1000244
Anna Lyonsf2887a52016-09-30 16:06:15 +1000245 /* unmap the pages */
246 vspace_unmap_pages(vspace, mapping->mapped_addr, mapping->num_pages, mapping->page_size_bits,
Alexander Kroh637e0d42015-06-26 13:44:02 +1000247 VSPACE_PRESERVE);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000248
Anna Lyonsf2887a52016-09-30 16:06:15 +1000249 /* clean up the node */
250 remove_node(io_mapper, mapping);
251 destroy_node(vka, mapping);
TrustworthySystemscedc0562014-07-22 14:11:16 +1000252}
253
254int
Anna Lyons76fcd2c2016-10-05 12:21:33 +1100255sel4platsupport_new_io_mapper(vspace_t vspace, vka_t vka, ps_io_mapper_t *io_mapper)
TrustworthySystemscedc0562014-07-22 14:11:16 +1000256{
Anna Lyonsf2887a52016-09-30 16:06:15 +1000257 sel4platsupport_io_mapper_cookie_t *cookie = malloc(sizeof(sel4platsupport_io_mapper_cookie_t));
TrustworthySystemscedc0562014-07-22 14:11:16 +1000258 if (!cookie) {
Anna Lyonsf2887a52016-09-30 16:06:15 +1000259 ZF_LOGE("Failed to allocate %zu bytes", sizeof(sel4platsupport_io_mapper_cookie_t));
TrustworthySystemscedc0562014-07-22 14:11:16 +1000260 return -1;
261 }
Anna Lyonsf2887a52016-09-30 16:06:15 +1000262
263 cookie->vspace = vspace;
264 cookie->vka = vka;
265 io_mapper->cookie = cookie;
266 io_mapper->io_map_fn = sel4platsupport_map_paddr;
267 io_mapper->io_unmap_fn = sel4platsupport_unmap_vaddr;
268
TrustworthySystemscedc0562014-07-22 14:11:16 +1000269 return 0;
270}
Alexander Kroh637e0d42015-06-26 13:44:02 +1000271
272int
Anna Lyons76fcd2c2016-10-05 12:21:33 +1100273sel4platsupport_new_io_ops(vspace_t vspace, vka_t vka, ps_io_ops_t *io_ops)
Alexander Kroh637e0d42015-06-26 13:44:02 +1000274{
Anna Lyons76fcd2c2016-10-05 12:21:33 +1100275 int err = sel4platsupport_new_io_mapper(vspace, vka, &io_ops->io_mapper);
Alexander Kroh637e0d42015-06-26 13:44:02 +1000276 if (err) {
277 return err;
278 }
Adrian Danis32095092017-05-25 17:00:35 +1000279#ifdef CONFIG_ARCH_ARM
Anna Lyonsf2887a52016-09-30 16:06:15 +1000280 clock_sys_init(io_ops, &io_ops->clock_sys);
281 mux_sys_init(io_ops, &io_ops->mux_sys);
Alexander Kroh637e0d42015-06-26 13:44:02 +1000282#endif
Anna Lyonsf2887a52016-09-30 16:06:15 +1000283
284 return err;
Alexander Kroh637e0d42015-06-26 13:44:02 +1000285}
286
287