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#pragma once
14
15#include <autoconf.h>
16
17#include <assert.h>
18#include <sel4/sel4.h>
19#include <sel4/macros.h>
20#include <simple/arch/simple.h>
21#include <stdlib.h>
22#include <utils/util.h>
23#include <stdbool.h>
24#include <vka/cspacepath_t.h>
25
26/* Simple does not address initial null caps. */
27#define SIMPLE_NUM_INIT_CAPS (seL4_NumInitialCaps - SIMPLE_SKIPPED_INIT_CAPS)
28
29/**
30 * Get the cap to the physical frame of memory and put it at specified location
31 *
32 * @param data cookie for the underlying implementation
33 *
34 * @param page aligned physical address
35 *
36 * @param size of the region in bits
37 *
38 * @param The path to where to put this cap
39 */
40typedef seL4_Error(*simple_get_frame_cap_fn)(void *data, void *paddr, int size_bits, cspacepath_t *path);
41
42/**
43 * Request mapped address to a region of physical memory.
44 *
45 * Note: This function will only return the mapped virtual address that it knows about. It does not do any mapping its self nor can it guess where mapping functions are going to map.
46 *
47 * @param data cookie for the underlying implementation
48 *
49 * @param page aligned physical address
50 *
51 * @param size of the region in bits
52 *
53 * Returns the virtual address to which this physical address is mapped or NULL if frame is unmapped
54 */
55
56typedef void *(*simple_get_frame_mapping_fn)(void *data, void *paddr, int size_bits);
57
58/**
59 * Request data to a region of physical memory.
60 *
61 * Note: This function will only return the mapped virtual address that it knows about. It does not do any mapping its self nor can it guess where mapping functions are going to map.
62 *
63 * @param data cookie for the underlying implementation
64 *
65 * @param page aligned physical address for the frame
66 *
67 * @param size of the region in bits
68 *
69 * @param cap to the frame gets set. Will return the untyped cap unless the underlying implementation has access to the frame cap. Check with implementation but it should be a frame cap if and only if a vaddr is returned.
70 *
71 * @param (potentially) the offset within the untyped cap that was returned
72 * Returns the vritual address to which this physical address is mapped or NULL if frame is unmapped
73 */
74typedef void *(*simple_get_frame_info_fn)(void *data, void *paddr, int size_bits, seL4_CPtr *cap, seL4_Word *ut_offset);
75
76/**
77 * Assign the vspace to the current threads ASID pool
78 *
79 * @param data cookie for the underlying implementation
80 *
81 * @param vspace to assign
82*/
83typedef seL4_Error(*simple_ASIDPool_assign_fn)(void *data, seL4_CPtr vspace);
84
85/**
86 * Get the total number of caps this library can address
87 *
88 * @param data cookie for the underlying implementation
89*/
90typedef int (*simple_get_cap_count_fn)(void *data);
91
92/**
93 * Get the nth cap that this library can address
94 *
95 * Addressable capabilities are numbered from 0, starting with the initial thread's capabilities,
96 * through caps provided by bootinfo.
97 * Initial capabilities that are null are not addressable, including seL4_CapNull, and other
98 * capabilities depending on the architecture and configuration.
99 *
100 * @param data cookie for the underlying implementation
101 *
102 * @param the nth starting at 0
103*/
104typedef seL4_CPtr(*simple_get_nth_cap_fn)(void *data, int n);
105
106/**
107 * Get the cap to init caps with numbering based on bootinfo.h
108 *
109 * @param data for the underlying implementation
110 *
111 * @param the value of the enum matching in bootinfo.h
112*/
113
114typedef seL4_CPtr(*simple_get_init_cap_fn)(void *data, seL4_CPtr cap);
115
116/**
117 * Get the size of the threads cnode in bits
118 *
119 * @param data for the underlying implementation
120*/
121
122typedef uint8_t (*simple_get_cnode_size_fn)(void *data);
123
124/**
125 * Get the amount of untyped caps available
126 *
127 * @param data for the underlying implementation
128 *
129*/
130
131typedef int (*simple_get_untyped_count_fn)(void *data);
132/**
133 * Get the nth untyped cap that this library can address
134 *
135 * @param data cookie for the underlying implementation
136 *
137 * @param the nth starting at 0
138 *
139 * @param the size of the untyped for the returned cap
140 *
141 * @param the physical address of the returned cap
142*/
143
144typedef seL4_CPtr(*simple_get_nth_untyped_fn)(void *data, int n, size_t *size_bits, uintptr_t *paddr, bool *device);
145
146/**
147 * Get the amount of user image caps available
148 *
149 * @param data for the underlying implementation
150 *
151*/
152
153typedef int (*simple_get_userimage_count_fn)(void *data);
154
155/**
156 * Get the nth untyped cap that this library can address
157 *
158 * @param data cookie for the underlying implementation
159 *
160 * @param the nth starting at 0
161 *
162*/
163
164typedef seL4_CPtr(*simple_get_nth_userimage_fn)(void *data, int n);
165
166/**
167 * Get number of available cores
168 *
169 * @param data for the underlying implementation
170 *
171*/
172
173typedef int (*simple_get_core_count_fn)(void *data);
174
175#ifdef CONFIG_IOMMU
176/**
177 * Get the IO space capability for the specified PCI device and domain ID
178 *
179 * @param data cookie for the underlying implementation
180 * @param domainID domain ID to request
181 * @param deviceID PCI device ID
182 * @param path Path to where to put this cap
183 *
184*/
185typedef seL4_Error(*simple_get_iospace_fn)(void *data, uint16_t domainID, uint16_t deviceID, cspacepath_t *path);
186#endif
187
188/*
189 * Get the sched ctrl for the requested core (0 for uniprocessor).
190 * @return seL4_CapNull if CONFIG_RT is disabled
191 */
192typedef seL4_CPtr(*simple_get_sched_ctrl_fn)(void *data, int core);
193
194
195/**
196 *
197 * Get simple to print all the information it has about its environment
198 */
199typedef void (*simple_print_fn)(void *data);
200
201/**
202 *
203 * Retrieve the length of a particular kind of extended boot information. The information will always
204 * be prefixed with a seL4_BootInfoHeader, which is included in the length
205 *
206 * @param data cookie for the underlying implementation
207 * @param type Type corresponding to a valid 'id' in a seL4_BootInfoHeader
208 *
209 * @return Length of the header or -1 if the type could not be found
210 */
211typedef ssize_t (*simple_get_extended_bootinfo_len_fn)(void *data, seL4_Word type);
212
213/**
214 *
215 * Retrieve a particular kind of extended boot information. The information will always
216 * be prefixed with a seL4_BootInfoHeader, which is included in the length
217 *
218 * @param data cookie for the underlying implementation
219 * @param type Type corresponding to a valid 'id' in a seL4_BootInfoHeader
220 * @param dest Destination to write the information to
221 * @param max_len Maximum length of the destination
222 *
223 * @return Length of the written information or -1 if the type could not be found
224 */
225typedef ssize_t (*simple_get_extended_bootinfo_fn)(void *data, seL4_Word type, void *dest, ssize_t max_len);
226
227typedef struct simple_t {
228    void *data;
229    simple_get_frame_cap_fn frame_cap;
230    simple_get_frame_mapping_fn frame_mapping;
231    simple_get_frame_info_fn frame_info;
232    simple_ASIDPool_assign_fn ASID_assign;
233    simple_get_cap_count_fn cap_count;
234    simple_get_nth_cap_fn nth_cap;
235    simple_get_init_cap_fn init_cap;
236    simple_get_cnode_size_fn cnode_size;
237    simple_get_untyped_count_fn untyped_count;
238    simple_get_nth_untyped_fn nth_untyped;
239    simple_get_userimage_count_fn userimage_count;
240    simple_get_nth_userimage_fn nth_userimage;
241    simple_get_core_count_fn core_count;
242    simple_print_fn print;
243    simple_get_sched_ctrl_fn sched_ctrl;
244    simple_get_extended_bootinfo_len_fn extended_bootinfo_len;
245    simple_get_extended_bootinfo_fn extended_bootinfo;
246    arch_simple_t arch_simple;
247} simple_t;
248
249static inline void *simple_get_frame_info(simple_t *simple, void *paddr, int size_bits, seL4_CPtr *frame_cap,
250                                          seL4_Word *ut_offset)
251{
252    if (!simple) {
253        ZF_LOGE("Simple is NULL");
254        return NULL;
255    }
256    if (!simple->frame_info) {
257        ZF_LOGE("%s not implemented", __FUNCTION__);
258        return NULL;
259    }
260
261    return simple->frame_info(simple->data, paddr, size_bits, frame_cap, ut_offset);
262}
263
264static inline seL4_Error simple_get_frame_cap(simple_t *simple, void *paddr, int size_bits, cspacepath_t *path)
265{
266    if (!simple) {
267        ZF_LOGE("Simple is NULL");
268        return seL4_InvalidArgument;
269    }
270    if (!simple->frame_cap) {
271        ZF_LOGE("%s not implemented", __FUNCTION__);
272        return seL4_InvalidArgument;
273    }
274    return simple->frame_cap(simple->data, paddr, size_bits, path);
275}
276
277static inline void *simple_get_frame_vaddr(simple_t *simple, void *paddr, int size_bits)
278{
279    if (!simple) {
280        ZF_LOGE("Simple is NULL");
281        return NULL;
282    }
283    if (simple->frame_mapping) {
284        return simple->frame_mapping(simple->data, paddr, size_bits);
285    } else {
286        ZF_LOGE("%s not implemented", __FUNCTION__);
287        return NULL;
288    }
289}
290
291static inline seL4_Error SEL4_DEPRECATED("Use simple_get_IRQ_handler")
292simple_get_IRQ_control(simple_t *simple, int irq, cspacepath_t path)
293{
294    if (!simple) {
295        ZF_LOGE("Simple is NULL");
296        return seL4_InvalidArgument;
297    }
298    if (!simple->arch_simple.irq) {
299        ZF_LOGE("%s not implemented", __FUNCTION__);
300        return seL4_InvalidArgument;
301    }
302    return simple->arch_simple.irq(simple->data, irq, path.root, path.capPtr, path.capDepth);
303}
304
305static inline seL4_Error simple_get_IRQ_handler(simple_t *simple, int irq, cspacepath_t path)
306{
307    if (!simple) {
308        ZF_LOGE("Simple is NULL");
309        return seL4_InvalidArgument;
310    }
311    if (!simple->arch_simple.irq) {
312        ZF_LOGE("%s not implemented", __FUNCTION__);
313        return seL4_InvalidArgument;
314    }
315    return simple->arch_simple.irq(simple->data, irq, path.root, path.capPtr, path.capDepth);
316}
317
318static inline seL4_Error simple_ASIDPool_assign(simple_t *simple, seL4_CPtr vspace)
319{
320    if (!simple) {
321        ZF_LOGE("Simple is NULL");
322        return seL4_InvalidArgument;
323    }
324    if (!simple->ASID_assign) {
325        ZF_LOGE("%s not implemented", __FUNCTION__);
326        return seL4_InvalidArgument;
327    }
328
329    return simple->ASID_assign(simple->data, vspace);
330}
331
332static inline
333seL4_Error simple_get_IOPort_cap(simple_t *simple, uint16_t start_port, uint16_t end_port, seL4_Word root,
334                                 seL4_Word dest, seL4_Word depth)
335{
336    if (!simple) {
337        ZF_LOGE("Simple is NULL");
338        return seL4_InvalidArgument;
339    }
340
341    return arch_simple_get_IOPort_cap(&simple->arch_simple, start_port, end_port, root, dest, depth);
342}
343
344static inline int simple_get_cap_count(simple_t *simple)
345{
346    if (!simple) {
347        ZF_LOGE("Simple is NULL");
348        return -1;
349    }
350    if (!simple->cap_count) {
351        ZF_LOGE("%s not implemented", __FUNCTION__);
352    }
353    return simple->cap_count(simple->data);
354}
355
356static inline seL4_CPtr simple_get_nth_cap(simple_t *simple, int n)
357{
358    if (!simple) {
359        ZF_LOGE("Simple is NULL");
360        return seL4_CapNull;
361    }
362
363    if (!simple->nth_cap) {
364        ZF_LOGE("%s not implemented", __FUNCTION__);
365        return seL4_CapNull;
366    }
367
368    return simple->nth_cap(simple->data, n);
369}
370
371static inline int simple_get_cnode_size_bits(simple_t *simple)
372{
373    if (!simple) {
374        ZF_LOGE("Simple is NULL");
375        return -1;
376    }
377    if (!simple->cnode_size) {
378        ZF_LOGE("%s not implemented", __FUNCTION__);
379        return -1;
380    }
381
382    return simple->cnode_size(simple->data);
383}
384
385static inline seL4_CPtr simple_init_cap(simple_t *simple, seL4_CPtr cap)
386{
387    if (!simple) {
388        ZF_LOGE("Simple is NULL");
389        return seL4_CapNull;
390    }
391
392    if (!simple->init_cap) {
393        ZF_LOGE("%s not implemented", __FUNCTION__);
394        return seL4_CapNull;
395    }
396
397    return simple->init_cap(simple->data, cap);
398}
399
400static inline seL4_CPtr simple_get_cnode(simple_t *simple)
401{
402    return simple_init_cap(simple, seL4_CapInitThreadCNode);
403}
404
405static inline seL4_CPtr simple_get_tcb(simple_t *simple)
406{
407    return simple_init_cap(simple, seL4_CapInitThreadTCB);
408}
409
410static inline seL4_CPtr simple_get_sc(UNUSED simple_t *simple)
411{
412#ifdef CONFIG_KERNEL_MCS
413    return simple_init_cap(simple, seL4_CapInitThreadSC);
414#else
415    return seL4_CapNull;
416#endif
417}
418
419static inline seL4_CPtr simple_get_pd(simple_t *simple)
420{
421    return simple_init_cap(simple, seL4_CapInitThreadPD);
422}
423
424static inline seL4_CPtr simple_get_irq_ctrl(simple_t *simple)
425{
426    return simple_init_cap(simple, seL4_CapIRQControl);
427}
428
429static inline seL4_CPtr simple_get_init_cap(simple_t *simple, seL4_CPtr cap)
430{
431    return simple_init_cap(simple, cap);
432}
433
434static inline int simple_get_untyped_count(simple_t *simple)
435{
436    if (!simple) {
437        ZF_LOGE("Simple is NULL");
438        return -1;
439    }
440    if (!simple->untyped_count) {
441        ZF_LOGE("%s not implemented", __FUNCTION__);
442        return -1;
443    }
444
445    return simple->untyped_count(simple->data);
446}
447
448static inline seL4_CPtr simple_get_nth_untyped(simple_t *simple, int n, size_t *size_bits, uintptr_t *paddr,
449                                               bool *device)
450{
451    if (!simple) {
452        ZF_LOGE("Simple is NULL");
453        return seL4_CapNull;
454    }
455    if (!simple->nth_untyped) {
456        ZF_LOGE("%s not implemented", __FUNCTION__);
457        return seL4_CapNull;
458    }
459
460    return simple->nth_untyped(simple->data, n, size_bits, paddr, device);
461}
462
463static inline int simple_get_userimage_count(simple_t *simple)
464{
465    if (!simple) {
466        ZF_LOGE("Simple is NULL");
467        return -1;
468    }
469    if (!simple->userimage_count) {
470        ZF_LOGE("%s not implemented", __FUNCTION__);
471        return -1;
472    }
473
474    return simple->userimage_count(simple->data);
475}
476
477static inline seL4_CPtr simple_get_nth_userimage(simple_t *simple, int n)
478{
479    if (!simple) {
480        ZF_LOGE("Simple is NULL");
481        return seL4_CapNull;
482    }
483    if (!simple->nth_userimage) {
484        ZF_LOGE("%s Not implemented", __FUNCTION__);
485        return seL4_CapNull;
486    }
487    return simple->nth_userimage(simple->data, n);
488}
489
490static inline int simple_get_core_count(simple_t *simple)
491{
492    if (!simple) {
493        ZF_LOGE("Simple is NULL");
494        return -1;
495    }
496    if (!simple->core_count) {
497        ZF_LOGE("%s not implemented", __FUNCTION__);
498        return -1;
499    }
500
501    return simple->core_count(simple->data);
502}
503
504#ifdef CONFIG_IOMMU
505static inline seL4_CPtr simple_get_iospace(simple_t *simple, uint16_t domainID, uint16_t deviceID, cspacepath_t *path)
506{
507    if (!simple) {
508        ZF_LOGE("Simple is NULL");
509        return seL4_CapNull;
510    }
511    if (!simple->arch_simple.iospace) {
512        ZF_LOGE("%s not implemented", __FUNCTION__);
513        return seL4_CapNull;
514    }
515
516    return simple->arch_simple.iospace(simple->data, domainID, deviceID, path);
517}
518#endif
519
520
521#ifdef CONFIG_TK1_SMMU
522static inline seL4_Error simple_get_iospace_cap_count(simple_t *simple, int *count)
523{
524    if (!simple) {
525        ZF_LOGE("Simple is NULL");
526        return seL4_InvalidArgument;
527    }
528    if (!simple->data) {
529        ZF_LOGE("Simple data is NULL");
530        return seL4_InvalidArgument;
531    }
532    if (!count) {
533        ZF_LOGE("NULL pointer");
534        return seL4_InvalidArgument;
535    }
536    if (!simple->arch_simple.iospace_cap_count) {
537        ZF_LOGE("arch %s not implemented", __FUNCTION__);
538        return seL4_IllegalOperation;
539    }
540
541    return simple->arch_simple.iospace_cap_count(simple->data, count);
542}
543
544static inline seL4_CPtr simple_get_nth_iospace_cap(simple_t *simple, int n)
545{
546    if (!simple) {
547        ZF_LOGE("Simple is NULL");
548        return seL4_CapNull;
549    }
550    if (!simple->data) {
551        ZF_LOGE("Simple data is NULL");
552        return seL4_CapNull;
553    }
554    if (!simple->arch_simple.iospace_get_nth_cap) {
555        ZF_LOGE("arch %s not implemented", __FUNCTION__);
556        return seL4_CapNull;
557    }
558
559    return simple->arch_simple.iospace_get_nth_cap(simple->data, n);
560}
561#endif
562
563#ifdef CONFIG_ARM_SMMU
564static inline seL4_CPtr simple_get_sid_ctrl(simple_t *simple)
565{
566    return simple_init_cap(simple, seL4_CapSMMUSIDControl);
567}
568
569static inline seL4_CPtr simple_get_cb_ctrl(simple_t *simple)
570{
571    return simple_init_cap(simple, seL4_CapSMMUCBControl);
572}
573#endif
574
575static inline void simple_print(simple_t *simple)
576{
577    if (!simple) {
578        ZF_LOGE("Simple is NULL");
579        return;
580    }
581    if (!simple->print) {
582        ZF_LOGE("%s not implemented", __FUNCTION__);
583        return;
584    }
585
586    simple->print(simple->data);
587}
588
589static inline seL4_CPtr simple_get_sched_ctrl(simple_t *simple, int core)
590{
591    if (!simple) {
592        ZF_LOGE("Simple is NULL");
593        return seL4_CapNull;
594    }
595    if (!simple->sched_ctrl) {
596        ZF_LOGE("%s not implemented", __FUNCTION__);
597        return seL4_CapNull;
598    }
599    if (core >= simple_get_core_count(simple)) {
600        ZF_LOGE("invalid core");
601        return seL4_CapNull;
602    }
603
604    return simple->sched_ctrl(simple->data, core);
605}
606
607static inline ssize_t simple_get_extended_bootinfo_length(simple_t *simple, seL4_Word type)
608{
609    if (!simple) {
610        ZF_LOGE("Simple is NULL");
611        return -1;
612    }
613    if (!simple->extended_bootinfo_len) {
614        ZF_LOGE("%s not implemented", __FUNCTION__);
615        return -1;
616    }
617    return simple->extended_bootinfo_len(simple->data, type);
618}
619
620static inline ssize_t simple_get_extended_bootinfo(simple_t *simple, seL4_Word type, void *dest, ssize_t max_len)
621{
622    if (!simple) {
623        ZF_LOGE("Simple is NULL");
624        return -1;
625    }
626    if (!simple->extended_bootinfo) {
627        ZF_LOGE("%s not implemented", __FUNCTION__);
628        return -1;
629    }
630    return simple->extended_bootinfo(simple->data, type, dest, max_len);
631}
632
633