1/* 2 * Copyright 2019, 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 <sel4/sel4.h> 16#include <virtqueue.h> 17#include <stddef.h> 18#include <inttypes.h> 19 20/* Max camkes virtqueue id */ 21#define MAX_CAMKES_VIRTQUEUE_ID 100 22 23/* 24 * Represents a shared window between two components 25 * that can be used as a basis for a virtqueue. This 26 * primary purpose of this structure is to encapsulate 27 * the shared memory buffer and role of the component 28 * (DEVICE or DRIVER) when using this channel 29 * for virtqueue-based communication. 30 * 31 * It is expected that a CAmkES connection template will 32 * register a single virtqueue channel. 33 */ 34 35typedef enum virtqueue_role { 36 VIRTQUEUE_UNASSIGNED, 37 VIRTQUEUE_DRIVER, 38 VIRTQUEUE_DEVICE 39} virtqueue_role_t; 40 41typedef struct virtqueue_channel { 42 volatile void *channel_buffer; 43 size_t channel_buffer_size; 44 unsigned queue_len; 45 void (*notify)(void); 46 seL4_CPtr recv_notification; 47 seL4_Word recv_badge; 48 virtqueue_role_t role; 49 uint8_t buffer_allocated; 50 const char *interface_name; 51} camkes_virtqueue_channel_t; 52 53/* 54 * Global array that contains all the registered virtqueue channels for a 55 * component. Virtqueue channels are stored in the array based on their 56 * configured id 57 */ 58extern camkes_virtqueue_channel_t camkes_virtqueue_channels[MAX_CAMKES_VIRTQUEUE_ID + 1]; 59 60/* The number of virtqueue channels registered to a component */ 61extern int num_registered_virtqueue_channels; 62 63/** 64 * @brief Convert a string name to a camkes virtqueue channel id. 65 * 66 * When a camkes virtqueue is registered, a numeric ID and a string name are provided 67 * to identify it with. This function translates from the string name to numerical ID. 68 * 69 * @param[in] interface_name The interface name 70 * 71 * @return Returns a valid ID or -1 on error. 72 */ 73int camkes_virtqueue_get_id_from_name(const char *interface_name); 74 75/* Initialise a virtqueue_driver_t object from a registered virtqueue channel 76 * @param virtqueue_driver_t Pointer to set with the allocated virtqueue_driver_t object 77 * @param camkes_virtqueue_id The unique id of the registered virtqueue channel. This 78 * indexes into the 'camkes_virtqueue_channels' array 79 * @param recv_notification Capability to notification object for receiving events on. 80 * @param recv_badge Badge value that received notifications will have. 81 * If recv_notification or recv_badge are NULL then they won't be returned. 82 * @return Positive 0 on success, -1 on error 83 */ 84int camkes_virtqueue_driver_init_with_recv(virtqueue_driver_t *driver, unsigned int camkes_virtqueue_id, 85 seL4_CPtr *recv_notification, seL4_CPtr *recv_badge); 86 87static inline int camkes_virtqueue_driver_init(virtqueue_driver_t *driver, unsigned int camkes_virtqueue_id) 88{ 89 return camkes_virtqueue_driver_init_with_recv(driver, camkes_virtqueue_id, NULL, NULL); 90} 91 92/* Initialise a virtqueue_device_t object from a registered virtqueue channel 93 * @param virtqueue_device_t Pointer to set with the allocated virtqueue_device_t object 94 * @param camkes_virtqueue_id The unique id of the registered virtqueue channel. This 95 * indexes into the 'camkes_virtqueue_channels' array 96 * @param recv_notification Capability to notification object for receiving events on. 97 * @param recv_badge Badge value that received notifications will have. 98 * If recv_notification or recv_badge are NULL then they won't be returned. 99 * @return Positive 0 on success, -1 on error 100 */ 101int camkes_virtqueue_device_init_with_recv(virtqueue_device_t *device, unsigned int camkes_virtqueue_id, 102 seL4_CPtr *recv_notification, seL4_CPtr *recv_badge); 103 104static inline int camkes_virtqueue_device_init(virtqueue_device_t *device, unsigned int camkes_virtqueue_id) 105{ 106 return camkes_virtqueue_device_init_with_recv(device, camkes_virtqueue_id, NULL, NULL); 107} 108 109/* Allocates a virtqueue buffer that the given 'virtqueue_driver_t' can use to communicate with 110 * @param virtqueue_driver_t Pointer to the virtqueue_driver_t object we are allocating a buffer for 111 * @param buffer A pointer to set with the allocated region of memory 112 * @param alloc_size Size of memory to allocate 113 * @return Positive 0 on success, -1 on error 114 */ 115int camkes_virtqueue_buffer_alloc(virtqueue_driver_t *virtqueue, void **buf, size_t alloc_size); 116 117/* Frees a virtqueue buffer that the given 'virtqueue_driver_t' is using 118 * @param virtqueue_driver_t Pointer to the virtqueue object we are free a buffer for 119 * @param buffer A pointer to the allocated region of memory we wish to free 120 */ 121void camkes_virtqueue_buffer_free(virtqueue_driver_t *virtqueue, void *buffer); 122 123/* Convert an offset in shared memory to a pointer in the device vspace 124 * @param virtqueue the device side virtqueue 125 * @param offset the offset to convert 126 * @return the converted pointer 127 */ 128void *camkes_virtqueue_device_offset_to_buffer(virtqueue_device_t *virtqueue, uintptr_t offset); 129 130/* Convert an offset in shared memory to a pointer in the driver vspace 131 * @param virtqueue the driver side virtqueue 132 * @param offset the offset to convert 133 * @return the converted pointer 134 */ 135void *camkes_virtqueue_driver_offset_to_buffer(virtqueue_driver_t *virtqueue, uintptr_t offset); 136 137/* Send exactly one buffer to the virtqueue (add it to the available ring). Performs the pointer 138 * to offset conversion. Doesn't notify the other side. Doesn't scatter the buffer, so the scatterlist 139 * will only contain one buffer. 140 * @param vq the driver side virtqueue 141 * @param buffer a pointer (in driver vspace) to the buffer to send 142 * @param size the size of the buffer 143 * @return 0 on success, -1 on fail 144 */ 145int camkes_virtqueue_driver_send_buffer(virtqueue_driver_t *vq, void *buffer, size_t size); 146 147/* Scatter and send one buffer (add to the available ring). Performs the pointer to offset conversion. 148 * Doesn't notify the other side. Scatters the buffer into chunks of BLOCK_SIZE, so the buffer can have 149 * an arbitrary size, and the scatterlist will contain several buffers. 150 * @param vq the driver side virtqueue 151 * @param buffer the buffer to add 152 * @param size the size of the buffer 153 * @return 0 on success, -1 on fail 154 */ 155int camkes_virtqueue_driver_scatter_send_buffer(virtqueue_driver_t *vq, void *buffer, size_t size); 156 157/* Takes a handle (obtained from a get_used_buffer invocation), iterates through all the buffers in 158 * the scatterlist and copies them into the buffer given as parameter. Once each buffer has been copied, 159 * it gets freed. 160 * @param vq the driver side virtqueue 161 * @param handle the iterator on the used ring object 162 * @param buffer a pointer to the buffer to copy into 163 * @param size the size of the buffer we're passing 164 * @return 0 on success, -1 on fail 165 */ 166int camkes_virtqueue_driver_gather_copy_buffer(virtqueue_driver_t *vq, virtqueue_ring_object_t *handle, 167 void *buffer, size_t size); 168 169/* Takes a handle (obtained from a get_available_buffer), iterates through all the buffers in the scatterlist 170 * and scatter-copies the content of the buffer passed as parameter into them. Then move the ring object into 171 * the used buffer ring. 172 * @param vq the device side virtqueue 173 * @param handle the iterator on the available ring object 174 * @param buffer a pointer to the buffer to copy from 175 * @param size the size of the buffer we're passing 176 * @return 0 on success, -1 on fail 177 */ 178int camkes_virtqueue_device_scatter_copy_buffer(virtqueue_device_t *vq, virtqueue_ring_object_t *handle, 179 void *buffer, size_t size); 180 181/* Takes a handle (obtained from a get_used_buffer invocation), iterates through all the buffers in 182 * the scatterlist and copies them into the buffer given as parameter. Then adds the object onto the 183 * used list. 184 * @param vq the device side virtqueue 185 * @param handle the iterator on the available ring object 186 * @param buffer a pointer to the buffer to copy from 187 * @param size the size of the buffer we're passing 188 * @return 0 on success, -1 on fail 189 */ 190int camkes_virtqueue_device_gather_copy_buffer(virtqueue_device_t *vq, virtqueue_ring_object_t *handle, 191 void *buffer, size_t size); 192 193/* Performs one iteration on the scatterlist pointed by the given handle: returns the next buffer in the list. 194 * @param vq the driver side virtqueue 195 * @param handle the iterator on the used ring object 196 * @param buffer a pointer to the address of the buffer to be returned 197 * @param size a pointer to the size of the buffer to be returned 198 * @param flag a pointer to the flag of the buffer getting returned 199 * @return 0 on success, -1 on fail 200 */ 201int camkes_virtqueue_driver_gather_buffer(virtqueue_driver_t *vq, virtqueue_ring_object_t *handle, 202 void **buffer, unsigned *size, vq_flags_t *flag); 203 204/* Performs one iteration on the scatterlist pointed by the given handle: returns the next buffer in the list. 205 * @param vq the device side virtqueue 206 * @param handle the iterator on the available ring object 207 * @param buffer a pointer to the address of the buffer to be returned 208 * @param size a pointer to the size of the buffer to be returned 209 * @param flag a pointer to the flag of the buffer getting returned 210 * @return 0 on success, -1 on fail 211 */ 212int camkes_virtqueue_device_gather_buffer(virtqueue_device_t *vq, virtqueue_ring_object_t *handle, 213 void **buffer, unsigned *size, vq_flags_t *flag); 214 215/* Returns the number of registered virtqueue channels 216 * @return Number of registered virtqueue channels 217 */ 218int camkes_virtqueue_channel_num(void); 219