1/* 2 * Copyright 2018, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <camkes.h> 8#include <stdio.h> 9#include <unistd.h> 10#include <string.h> 11#include <virtqueue.h> 12#include <camkes/virtqueue.h> 13#include <utils/util.h> 14 15#define COUNT_LIMIT 20 16 17/* Message to be passed around clients*/ 18typedef struct { 19 int val; 20} payload_t; 21 22/* Each component has a send and recv virtqueue */ 23virtqueue_driver_t send_virtqueue; 24virtqueue_device_t recv_virtqueue; 25 26void handle_send_callback(void); 27 28void send_payload_message(int val) 29{ 30 payload_t data; 31 data.val = val; 32 33 void *alloc_buffer = NULL; 34 35 /* First check if there is data still waiting in the send virtqueue 36 * We need to flush the virtqueue before sending data on it 37 */ 38 if (VQ_DRV_POLL(&send_virtqueue)) { 39 handle_send_callback(); 40 } 41 42 int err = camkes_virtqueue_buffer_alloc(&send_virtqueue, &alloc_buffer, sizeof(payload_t)); 43 if (err) { 44 ZF_LOGE("Client send buffer allocation failed"); 45 return; 46 } 47 48 memcpy(alloc_buffer, (void *)&data, sizeof(payload_t)); 49 50 if (camkes_virtqueue_driver_send_buffer(&send_virtqueue, alloc_buffer, sizeof(payload_t)) != 0) { 51 camkes_virtqueue_buffer_free(&send_virtqueue, alloc_buffer); 52 return; 53 } 54 send_virtqueue.notify(); 55} 56 57void handle_virtqueue_message(void *buffer) 58{ 59 payload_t *data = (payload_t *)buffer; 60 61 printf("Client %d recieved payload value: %d\n", client_id, data->val); 62 63 /* Finish the message passing once we reach COUNT_LIMIT */ 64 if (data->val == COUNT_LIMIT) { 65 return; 66 } 67 68 /* Forward the message with an incremented count */ 69 send_payload_message(data->val + 1); 70} 71 72void handle_recv_callback(void) 73{ 74 void *available_buff = NULL; 75 size_t buf_size = 0; 76 vq_flags_t flag; 77 virtqueue_ring_object_t handle; 78 if (!virtqueue_get_available_buf(&recv_virtqueue, &handle)) { 79 ZF_LOGE("Client virtqueue dequeue failed"); 80 return; 81 } 82 83 while (!camkes_virtqueue_device_gather_buffer(&recv_virtqueue, &handle, &available_buff, &buf_size, &flag)) { 84 /* Process the incoming virtqueue message */ 85 handle_virtqueue_message(available_buff); 86 } 87 88 if (!virtqueue_add_used_buf(&recv_virtqueue, &handle, 0)) { 89 ZF_LOGE("Unable to enqueue used recv buffer"); 90 return; 91 } 92 93 recv_virtqueue.notify(); 94 95} 96 97void handle_send_callback(void) 98{ 99 void *send_buff = NULL; 100 size_t buf_size = 0; 101 uint32_t wr_len = 0; 102 vq_flags_t flag; 103 virtqueue_ring_object_t handle; 104 if (!virtqueue_get_used_buf(&send_virtqueue, &handle, &wr_len)) { 105 ZF_LOGE("Client send dequeue failed"); 106 return; 107 } 108 while (!camkes_virtqueue_driver_gather_buffer(&send_virtqueue, &handle, &send_buff, &buf_size, &flag)) { 109 /* Clean up and free the buffer we allocated */ 110 camkes_virtqueue_buffer_free(&send_virtqueue, send_buff); 111 } 112} 113 114void virtqueue_wait_callback(void) 115{ 116 if (VQ_DEV_POLL(&recv_virtqueue)) { 117 handle_recv_callback(); 118 } 119 120 if (VQ_DRV_POLL(&send_virtqueue)) { 121 handle_send_callback(); 122 } 123} 124 125int run() 126{ 127 /* Initialise send virtqueue */ 128 int err = camkes_virtqueue_driver_init(&send_virtqueue, 0); 129 if (err) { 130 ZF_LOGE("Unable to initialise client send virtqueue"); 131 return 1; 132 } 133 134 /* Initialise recv virtqueue */ 135 err = camkes_virtqueue_device_init(&recv_virtqueue, 1); 136 if (err) { 137 ZF_LOGE("Unable to initialise client recv virtqueue"); 138 return 1; 139 } 140 141 /* Client 0 will send the first message */ 142 if (client_id == 0) { 143 printf("Client 0 sending first message\n"); 144 send_payload_message(1); 145 } 146 147 timeout_periodic(0, 1000 * NS_IN_MS); 148 seL4_Word badge; 149 seL4_CPtr notification = timeout_notification(); 150 while (1) { 151 seL4_Wait(notification, &badge); 152 } 153} 154