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