1/* 2 * Copyright (c) 2014 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <barrelfish/barrelfish.h> 11#include <barrelfish/nameservice_client.h> 12 13#include <virtio/virtio.h> 14#include <virtio/virtio_device.h> 15#include <virtio/virtqueue_host.h> 16#include <virtio/virtio_host.h> 17 18#include <if/virtio_defs.h> 19#include <if/virtio_defs.h> 20 21#include "channel.h" 22#include "device.h" 23#include "debug.h" 24 25static uint8_t device_open = 0x0; 26 27static iref_t virtio_rpc_svc_iref; 28 29enum virtio_rpc_host_state { 30 RPC_HOST_STATE_INVALID, 31 RPC_HOST_STATE_EXPORTING, 32 RPC_HOST_STATE_FAILED, 33 RPC_HOST_STATE_READY 34}; 35 36static enum virtio_rpc_host_state rpc_client_state = RPC_HOST_STATE_INVALID; 37 38/* -------------------- virtio_open() --------------------------------------- */ 39 40struct open_response_state 41{ 42 struct virtio_binding *b; 43 errval_t err; 44 struct capref frame; 45}; 46 47struct open_response_state open_err_st; 48 49static void virtio_open_response_cb(void *a) 50{ 51 if (a != &open_err_st) { 52 free(a); 53 } 54} 55 56static void virtio_open_response(void *a) 57{ 58 errval_t err; 59 struct open_response_state *st = a; 60 61 struct event_closure txcont = MKCONT(virtio_open_response_cb, st); 62 err = virtio_open_response__tx(st->b, txcont, st->err, st->frame); 63 if (err_is_fail(err)) { 64 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 65 txcont = MKCONT(virtio_open_response, st); 66 err = st->b->register_send(st->b, get_default_waitset(), txcont); 67 if (err_is_fail(err)) { 68 DEBUG_ERR(err, "register send failed\n"); 69 free(st); 70 } 71 } else { 72 DEBUG_ERR(err, "sending reply failed\n"); 73 free(st); 74 } 75 } 76} 77 78static void virtio_open_call__rx(struct virtio_binding *_binding, 79 uint8_t backend) 80{ 81 errval_t err; 82 83 VIRTIO_DEBUG_CHAN("Received device_open rpc call\n"); 84 85 if (device_open) { 86 open_err_st.err = VIRTIO_ERR_DEVICE_STATUS; 87 virtio_open_response(&open_err_st); 88 return; 89 } else { 90 device_open = 0x1; 91 } 92 93 assert(_binding->st); 94 95 struct virtio_device *vdev = _binding->st; 96 97 struct open_response_state *st = malloc(sizeof(struct open_response_state)); 98 if (st == NULL) { 99 device_open = 0x0; 100 open_err_st.err = LIB_ERR_MALLOC_FAIL; 101 virtio_open_response(&open_err_st); 102 return; 103 } 104 105 assert(vdev->cb_h); 106 assert(vdev->cb_h->open); 107 108 err = vdev->cb_h->open(vdev, backend, &st->frame); 109 if (err_is_fail(err)) { 110 device_open = 0x0; 111 open_err_st.err = err; 112 virtio_open_response(&open_err_st); 113 } 114 115 st->b = _binding; 116 st->err = err; 117 118 virtio_open_response(st); 119} 120 121/* -------------------- virtio_close() -------------------------------------- */ 122 123static void virtio_close_response(void *a) 124{ 125 126} 127 128static void virtio_close_call__rx(struct virtio_binding *_binding) 129{ 130 virtio_close_response(_binding); 131} 132 133/* -------------------- virtio_add() ---------------------------------------- */ 134 135struct add_response_state 136{ 137 struct virtio_binding *b; 138 errval_t err; 139}; 140 141struct open_response_state add_err_st; 142 143static void virtio_add_response_cb(void *a) 144{ 145 if (a != &add_err_st) { 146 free(a); 147 } 148} 149 150static void virtio_add_response(void *a) 151{ 152 errval_t err; 153 struct add_response_state *st = a; 154 155 struct event_closure txcont = MKCONT(virtio_add_response_cb, st); 156 err = virtio_add_response__tx(st->b, txcont, st->err); 157 if (err_is_fail(err)) { 158 if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 159 txcont = MKCONT(virtio_add_response, st); 160 err = st->b->register_send(st->b, get_default_waitset(), txcont); 161 if (err_is_fail(err)) { 162 DEBUG_ERR(err, "virtio_add_response: register send failed\n"); 163 free(st); 164 } 165 } else { 166 DEBUG_ERR(err, "virtio_add_response: sending reply failed\n"); 167 free(st); 168 } 169 } 170} 171 172static void virtio_add_call__rx(struct virtio_binding *_binding, 173 uint16_t vq_id, 174 uint16_t ndesc, 175 uint8_t has_buffers, 176 struct capref vring) 177{ 178 VIRTIO_DEBUG_CHAN("Received virtq_add rpc call\n"); 179 180 if (!_binding->st) { 181 /* cannot open a device twice! */ 182 add_err_st.err = VIRTIO_ERR_DEVICE_STATUS; 183 virtio_open_response(&add_err_st); 184 return; 185 } 186 187 struct open_response_state *st = malloc(sizeof(struct open_response_state)); 188 if (st == NULL) { 189 add_err_st.err = LIB_ERR_MALLOC_FAIL; 190 virtio_open_response(&add_err_st); 191 return; 192 } 193 194 struct virtio_device *vdev = _binding->st; 195 196 assert(vdev->cb_h); 197 assert(vdev->cb_h->add); 198 199 st->b = _binding; 200 201 st->err = virtio_vq_host_init_vring(vdev, vring, vq_id, ndesc, has_buffers); 202 if (err_is_fail(st->err)) { 203 virtio_add_response(st); 204 return; 205 } 206 207 st->b = _binding; 208 st->err = vdev->cb_h->add(vdev,vring, ndesc, has_buffers, vq_id); 209 210 virtio_add_response(st); 211} 212 213 214/* -------------------- virtio_ext() ---------------------------------------- */ 215 216static void virtio_ext_response(void *a) 217{ 218 219} 220 221static void virtio_extend_call__rx(struct virtio_binding *_binding, 222 uint16_t vq_id, 223 struct capref vbuf) 224{ 225 virtio_ext_response(_binding); 226} 227 228/* -------------------- virtio_req() ---------------------------------------- */ 229 230static void virtio_req_response(void *a) 231{ 232 233} 234 235static void virtio_req_call__rx(struct virtio_binding *_binding, 236 uint64_t size) 237{ 238 virtio_req_response(_binding); 239} 240 241 242 243 244struct virtio_rx_vtbl s_rx_vtbl = { 245 .open_call = virtio_open_call__rx, 246 .close_call = virtio_close_call__rx, 247 .add_call = virtio_add_call__rx, 248 .extend_call = virtio_extend_call__rx, 249 .req_call = virtio_req_call__rx, 250}; 251 252 253static errval_t connect_cb(void *st, struct virtio_binding *b) 254{ 255 VIRTIO_DEBUG_CHAN("New guest connection\n"); 256 257 /* 258 * this would be the point where we should initialize a new VirtIO device, 259 * however we support just one device at this stage. 260 * 261 * We assign the current device as the binding state. 262 */ 263 b->st = st; 264 265 b->rx_vtbl = s_rx_vtbl; 266 267 return SYS_ERR_OK; 268} 269 270static void export_cb(void *st, errval_t err, iref_t iref) 271{ 272 if (err_is_fail(err)) { 273 rpc_client_state = RPC_HOST_STATE_FAILED; 274 DEBUG_ERR(err, "Export failed"); 275 return; 276 } 277 278 struct virtio_device *vdev = st; 279 280 virtio_rpc_svc_iref = iref; 281 282 VIRTIO_DEBUG_CHAN("Registering [%s] with iref [%u]\n", vdev->hc_iface, iref); 283 err = nameservice_register(vdev->hc_iface, iref); 284 if (err_is_fail(err)) { 285 DEBUG_ERR(err, "nameservice_register failed"); 286 rpc_client_state = RPC_HOST_STATE_FAILED; 287 return; 288 } 289 290 rpc_client_state = RPC_HOST_STATE_READY; 291} 292 293 294 295 296errval_t virtio_host_flounder_init(struct virtio_device *vdev) 297{ 298 errval_t err; 299 300 VIRTIO_DEBUG_CHAN("initiate exporting service\n"); 301 302 rpc_client_state = RPC_HOST_STATE_EXPORTING; 303 304 err = virtio_export(vdev, 305 export_cb, connect_cb, 306 get_default_waitset(), 307 IDC_BIND_FLAGS_DEFAULT); 308 309 if (err_is_fail(err)) { 310 return err; 311 } 312 313 VIRTIO_DEBUG_CHAN("Waiting for export reply\n"); 314 while(rpc_client_state == RPC_HOST_STATE_EXPORTING) { 315 messages_wait_and_handle_next(); 316 } 317 318 if (rpc_client_state == RPC_HOST_STATE_FAILED) { 319 VIRTIO_DEBUG_CHAN("Export failed\n"); 320 return FLOUNDER_ERR_BIND; 321 } 322 323 VIRTIO_DEBUG_CHAN("Service ready\n"); 324 325 return SYS_ERR_OK; 326} 327