1/*
2 * Copyright 2018, 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/*- from 'global-endpoint.template.c' import allocate_cap with context -*/
14
15#include <sel4/sel4.h>
16#include <camkes/dataport.h>
17#include <camkes.h>
18#include <camkes/virtqueue_template.h>
19#include <virtqueue.h>
20
21/*- if len(me.parent.to_ends) != 1 -*/
22    /*? raise(Exception('%s must only have 1 to end' % (me.parent.name))) ?*/
23/*- endif -*/
24/*- set to_end = me.parent.to_ends[0] -*/
25
26/*- set all_connection_ends = me.parent.from_ends -*/
27
28/*- set interface_name =  me.interface.type.name -*/
29
30/*- if interface_name == "VirtQueueDrv" -*/
31    /*- set end_string = "drv" -*/
32    /*- set other_end_string = "dev" -*/
33/*- else -*/
34    /*- set end_string = "dev" -*/
35    /*- set other_end_string = "drv" -*/
36/*- endif -*/
37
38/*- set topology = configuration[to_end.instance.name].get("%s_topology" % to_end.interface.name, []) -*/
39/*- if len(topology) == 0 -*/
40    /*- if len(all_connection_ends) > 2 -*/
41        /*? raise(Exception("%s: Has more than 2 ends and could not find 'topology' definition describing how to connect them." % (me.parent.name))) ?*/
42    /*- else -*/
43        /*- do topology.append({}) -*/
44        /*- for end in all_connection_ends -*/
45            /*- if end == me -*/
46                /*- do topology[0].update({end_string: str(end)}) -*/
47            /*- else -*/
48                /*- do topology[0].update({other_end_string: str(end)}) -*/
49            /*- endif -*/
50        /*- endfor -*/
51
52    /*- endif -*/
53/*- endif -*/
54
55/*- set topology_entry = [] -*/
56
57/*- for entry in topology -*/
58    /*- if entry[end_string] == "%s.%s" % (me.instance.name, me.interface.name) -*/
59        /*- do topology_entry.append(entry) -*/
60    /*- endif -*/
61/*- endfor -*/
62
63/*- if len(topology_entry) != 1 -*/
64    /*? raise(Exception('Could not find topology entry for: %s.%s' % (me.instance.name, me.interface.name))) ?*/
65/*- endif -*/
66
67/*# Check that there is a valid interface on the other end of the topology from us #*/
68/*- set other_interface_name = topology_entry[0][other_end_string] -*/
69/*- set other_interface = [0] -*/
70/*- for c in all_connection_ends -*/
71  /*- if str(c) == other_interface_name -*/
72    /*- do other_interface.__setitem__(0, c) -*/
73  /*- endif -*/
74/*- endfor -*/
75/*- if other_interface[0] == 0 -*/
76    /*? raise(TemplateError('Interface %s is not present in connection.' % (other_interface_name))) ?*/
77/*- endif -*/
78/*- set other_interface = other_interface[0] -*/
79/*- set queue_length = configuration[me.parent.name].get("queue_length", 256) -*/
80/*- if queue_length is none or not isinstance(queue_length, six.integer_types) -*/
81    /*? raise(Exception('%s.queue_length must be set to a number' % (me.parent.name))) ?*/
82/*- endif -*/
83
84
85/*# Create shared memory region between the two interfaces #*/
86/*- set shmem_size = configuration[me.instance.name].get("%s_shmem_size" % me.interface.name, 8192) -*/
87/*- if shmem_size != configuration[other_interface.instance.name].get("%s_shmem_size" % other_interface.interface.name, 8192) -*/
88    /*? raise(TemplateError('Setting %s.%s_shmem_size does not match size configuration from other side: %d vs. %d' % (me.instance.name, me.interface.name, shmem_size, configuration[other_interface.instance.name].get("%s_shmem_size" % other_interface.interface.name, 4096)))) ?*/
89/*- endif -*/
90/*- if end_string == 'drv' -*/
91    /*- set shmem_symbol = '%s_%s_data' % (str(me), other_interface_name) -*/
92/*- else -*/
93    /*- set shmem_symbol = '%s_%s_data' % (other_interface_name, str(me)) -*/
94/*- endif -*/
95/*- set shmem_symbol = shmem_symbol.replace('.', '_') -*/
96/*- set page_size = macros.get_page_size(shmem_size, options.architecture) -*/
97/*- if page_size == 0 -*/
98  /*? raise(TemplateError('Setting %s.%s_shmem_size does not meet minimum size and alignment requirements. %d must be at least %d and %d aligned' % (me.instance.name, me.interface.name, size, 4096, 4096))) ?*/
99/*- endif -*/
100
101/*? macros.shared_buffer_symbol(sym=shmem_symbol, shmem_size=shmem_size, page_size=page_size) ?*/
102/*? register_shared_variable(shmem_symbol, shmem_symbol, shmem_size, frame_size=page_size) ?*/
103
104size_t /*? me.interface.name ?*/_get_size(void) {
105    return sizeof(/*? shmem_symbol ?*/);
106}
107
108
109/*# We need to create a notification badge of their notificaion in our cspace #*/
110/*- do allocate_cap(other_interface, is_reader=False) -*/
111/*- set notification = pop('notification') -*/
112
113/*- set disable_optimizations = configuration[me.interface.name].get("disable_optimizations", 0) -*/
114
115/*- if configuration[me.instance.name].get('single_threaded', 0) and disable_optimizations != 1 -*/
116extern seL4_CPtr signal_to_send;
117static void /*? me.interface.name ?*/_notify(void) {
118    if (signal_to_send) {
119        seL4_Signal(signal_to_send);
120    }
121    signal_to_send = /*? notification ?*/;
122
123}
124/*- else -*/
125static void /*? me.interface.name ?*/_notify(void) {
126    seL4_Signal(/*? notification ?*/);
127}
128
129/*- endif -*/
130
131/*# We need to get the badge that they will signal us on #*/
132/*- do allocate_cap(me, is_reader=True) -*/
133/*- set notification = pop('notification') -*/
134/*- set badge = pop('badge') -*/
135
136static seL4_CPtr /*? me.interface.name ?*/_notification(void) {
137    return /*? notification ?*/;
138}
139
140seL4_Word /*? me.interface.name ?*/_notification_badge(void) {
141    return /*? badge ?*/;
142}
143
144/*- set interface_name =  me.interface.type.name -*/
145
146/*- set queue_id = macros.virtqueue_get_client_id(composition, me, configuration) -*/
147/*- if queue_id is none or not isinstance(queue_id, six.integer_types) -*/
148  /*? raise(Exception('%s.%s_id must be set to a number' % (me.instance.name, me.interface.name))) ?*/
149/*- endif -*/
150
151//This is called by camkes runtime during init.
152static void __attribute__((constructor)) register_connector(void) {
153/*- if interface_name == "VirtQueueDrv" -*/
154    camkes_virtqueue_channel_register(/*? queue_id ?*/, "/*? me.interface.name ?*/", /*? queue_length ?*/, /*? me.interface.name ?*/_get_size(), (volatile void *) &/*? shmem_symbol ?*/,  /*? me.interface.name ?*/_notify, /*? me.interface.name ?*/_notification(), /*? me.interface.name ?*/_notification_badge(), VIRTQUEUE_DRIVER);
155/*- else -*/
156    camkes_virtqueue_channel_register(/*? queue_id ?*/, "/*? me.interface.name ?*/", /*? queue_length ?*/, /*? me.interface.name ?*/_get_size(), (volatile void *) &/*? shmem_symbol ?*/,  /*? me.interface.name ?*/_notify, /*? me.interface.name ?*/_notification(), /*? me.interface.name ?*/_notification_badge(), VIRTQUEUE_DEVICE);
157/*- endif -*/
158}
159