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#include <assert.h>
14#include <camkes/dataport.h>
15#include <stddef.h>
16#include <stdint.h>
17#include <platsupport/io.h>
18#include <utils/util.h>
19#include <sel4/sel4.h>
20/*? macros.show_includes(me.instance.type.includes) ?*/
21
22/*- set index = me.parent.from_ends.index(me) -*/
23
24/*- set paddr = configuration[me.parent.to_instance.name].get('%s_paddr' % me.parent.to_interface.name) -*/
25/*- if paddr is none -*/
26  /*? raise(TemplateError('Setting %s.%s_paddr that should specify the physical address of an MMIO device is not set' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/
27/*- endif -*/
28/*- if not isinstance(paddr, numbers.Integral) or paddr < 0 -*/
29  /*? raise(TemplateError('Setting %s.%s_paddr that should specify the physical address of an MMIO device does not appear to be a valid address' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/
30/*- endif -*/
31
32/*- set size = configuration[me.parent.to_instance.name].get('%s_size' % me.parent.to_interface.name) -*/
33/*- if size is none -*/
34  /*? raise(TemplateError('Setting %s.%s_size that should specify the size of an MMIO device is not set' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/
35/*- endif -*/
36/*- if not isinstance(size, numbers.Integral) or size <= 0 -*/
37  /*? raise(TemplateError('Setting %s.%s_size that should specify the size of an MMIO device does not appear to be a valid size' % (me.parent.to_instance.name, me.parent.to_interface.name))) ?*/
38/*- endif -*/
39/*- set page_size = macros.get_page_size(size, options.architecture) -*/
40/*- if page_size == 0 -*/
41  /*? raise(TemplateError('Setting %s.%s_size does not meet minimum size requirements. %d must be at least %d and %d aligned' % (me.parent.to_instance.name, me.parent.to_interface.name, size, 4096, 4096))) ?*/
42/*- endif -*/
43/*- set page_size_bits = int(math.log(page_size, 2)) -*/
44
45/*- set cached = configuration[me.parent.to_instance.name].get('%s_hardware_cached' % me.parent.to_interface.name, False) -*/
46
47
48/*- set dataport_symbol_name = "from_%d_%s_data" % (index, me.interface.name) -*/
49struct {
50    char content[ROUND_UP_UNSAFE(/*? macros.dataport_size(me.interface.type) ?*/,
51        SIZE_BITS_TO_BYTES(/*? page_size_bits ?*/))];
52} /*? dataport_symbol_name ?*/
53        ALIGN(/*? page_size ?*/)
54        SECTION("align_/*? page_size_bits ?*/bit")
55        VISIBLE
56        USED;
57/*- set frame_caps = [] -*/
58/*? register_shared_variable('%s_data' % me.parent.name, dataport_symbol_name, size, frame_size=page_size, perm='RW', paddr=paddr, cached=cached, with_mapping_caps=frame_caps) ?*/
59
60
61volatile /*? macros.dataport_type(me.interface.type) ?*/ * /*? me.interface.name ?*/ =
62    (volatile /*? macros.dataport_type(me.interface.type) ?*/ *) & /*? dataport_symbol_name ?*/;
63
64/*- set id = composition.connections.index(me.parent) -*/
65
66int /*? me.interface.name ?*/_wrap_ptr(dataport_ptr_t *p, void *ptr) {
67    /*- set offset = c_symbol('offset') -*/
68    off_t /*? offset ?*/ = (off_t)((uintptr_t)ptr - (uintptr_t)/*? me.interface.name ?*/);
69    if (/*? offset ?*/ < /*? macros.dataport_size(me.interface.type) ?*/) {
70        p->id = /*? id ?*/;
71        p->offset = /*? offset ?*/;
72        return 0;
73    } else {
74        return -1;
75    }
76}
77
78void * /*? me.interface.name ?*/_unwrap_ptr(dataport_ptr_t *p) {
79    if (p->id == /*? id ?*/) {
80        return (void*)((uintptr_t)/*? me.interface.name ?*/ + (uintptr_t)p->offset);
81    } else {
82        return NULL;
83    }
84}
85
86
87/*# Check if we have reserved enough virtual memory for the MMIO. #*/
88static_assert(/*? macros.dataport_size(me.interface.type) ?*/ == /*? size ?*/, "Data type mismatch!");
89
90
91void * /*? me.interface.name ?*/_translate_paddr(
92        uintptr_t paddr, size_t size) {
93    if (paddr >= /*? paddr ?*/ && (paddr + size) <= /*? paddr + size ?*/) {
94        return (void*)/*? me.interface.name ?*/ + (paddr - /*? paddr ?*/);
95    }
96    return NULL;
97}
98
99/*- for cap in frame_caps -*/
100__attribute__((used)) __attribute__((section("_dataport_frames")))
101dataport_frame_t /*? me.interface.name ?*//*? loop.index0 ?*/ = {
102    .paddr = /*? paddr + loop.index0 * page_size ?*/,
103    .cap = /*? cap ?*/,
104    .size = /*? page_size ?*/,
105    .vaddr = (uintptr_t)&(/*? dataport_symbol_name ?*/.content[/*? loop.index0 * page_size ?*/]),
106};
107/*- endfor -*/
108
109/*# We only pull frame_caps from the stash. This is because only one caller of register_shared_variable
110    should pass a frames parameter. By not stashing the frame_objs we ensure that only the original
111    creator passed the frames, and everyone else will still have a None here #*/
112
113/* Flush data corresponding to the dataport-relative address range from the CPU cache */
114int /*? me.interface.name ?*/_flush_cache(size_t start_offset UNUSED, size_t size UNUSED, dma_cache_op_t cache_op UNUSED) {
115    return camkes_dataport_flush_cache(start_offset, size, (uintptr_t) &/*? dataport_symbol_name ?*/.content,
116                                       /*? size ?*/, cache_op);
117}
118