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#include <virtio/virtio.h> 13#include <virtio/virtqueue.h> 14#include <virtio/virtio_guest.h> 15 16#include <if/virtio_defs.h> 17#include <if/virtio_defs.h> 18 19#include "channel.h" 20#include "debug.h" 21 22 23static struct virtio_binding *virtio_binding; 24 25static iref_t virtio_rpc_svc_iref; 26 27enum virtio_binding_state { 28 RPC_CLIENT_STATE_INVALID, 29 RPC_CLIENT_STATE_BINDING, 30 RPC_CLIENT_STATE_FAILED, 31 RPC_CLIENT_STATE_READY 32}; 33 34static enum virtio_binding_state rpc_client_state = RPC_CLIENT_STATE_INVALID; 35 36 37/** 38 * 39 */ 40static errval_t open_device(uint8_t backend, 41 struct capref *ret_frame) 42{ 43 errval_t err, msg_err; 44 45 VIRTIO_DEBUG_CHAN("open device\n"); 46 47 if (rpc_client_state != RPC_CLIENT_STATE_READY) { 48 /* TODO: error code */ 49 return -1; 50 } 51 52 err = virtio_binding->rpc_tx_vtbl.open(virtio_binding, 53 backend, 54 &msg_err, 55 ret_frame); 56 if (err_is_fail(err)) { 57 return err; 58 } 59 return msg_err; 60} 61 62/** 63 * 64 */ 65static errval_t close_device(void) 66{ 67 errval_t err; 68 69 if (rpc_client_state != RPC_CLIENT_STATE_READY) { 70 /* TODO: error code */ 71 return -1; 72 } 73 74 err = virtio_binding->rpc_tx_vtbl.close(virtio_binding); 75 if (err_is_fail(err)) { 76 return err; 77 } 78 return SYS_ERR_OK; 79} 80 81/** 82 * 83 */ 84static errval_t add_vring(struct virtqueue *vq) 85{ 86 errval_t err, msg_err; 87 88 if (rpc_client_state != RPC_CLIENT_STATE_READY) { 89 /* TODO: error code */ 90 return -1; 91 } 92 93 struct capref frame; 94 virtio_virtqueue_get_vring_cap(vq, &frame); 95 96 uint16_t id = virtio_virtqueue_get_queue_index(vq); 97 98 uint8_t buffers = virtio_virtqueue_has_buffers(vq); 99 100 uint16_t ndesc = virtio_virtqueue_get_num_desc(vq); 101 102 err = virtio_binding->rpc_tx_vtbl.add(virtio_binding, id, ndesc, buffers, frame, &msg_err); 103 if (err_is_fail(err)) { 104 return err; 105 } 106 return msg_err; 107} 108 109/** 110 * 111 */ 112static errval_t extend_vring(uint16_t vq_id, 113 struct capref vbuf) 114{ 115 errval_t err, msg_err; 116 117 if (rpc_client_state != RPC_CLIENT_STATE_READY) { 118 /* TODO: error code */ 119 return -1; 120 } 121 122 err = virtio_binding->rpc_tx_vtbl.extend(virtio_binding, vq_id, vbuf, &msg_err); 123 if (err_is_fail(err)) { 124 return err; 125 } 126 return msg_err; 127} 128 129/** 130 * 131 */ 132static errval_t request_mem(uint64_t size, 133 struct capref *cap) 134{ 135 errval_t err, msg_err; 136 137 if (rpc_client_state != RPC_CLIENT_STATE_READY) { 138 /* TODO: error code */ 139 return -1; 140 } 141 142 err = virtio_binding->rpc_tx_vtbl.req(virtio_binding, size, &msg_err, cap); 143 if (err_is_fail(err)) { 144 return err; 145 } 146 return msg_err; 147} 148 149 150static struct virtio_guest_chan_fn vguest_fc_fn = { 151 .open = open_device, 152 .close = close_device, 153 .add = add_vring, 154 .ext = extend_vring, 155 .req = request_mem, 156}; 157 158static void bind_cb(void *st, errval_t err, struct virtio_binding *b) 159{ 160 if(err_is_fail(err)) { 161 rpc_client_state = RPC_CLIENT_STATE_FAILED; 162 return; 163 } 164 165 VIRTIO_DEBUG_CHAN("Initializing RPC client\n"); 166 virtio_binding = b; 167 virtio_rpc_client_init(virtio_binding); 168 vguest_chan_fn = &vguest_fc_fn; 169 170 rpc_client_state = RPC_CLIENT_STATE_READY; 171} 172 173 174 175 176 177errval_t virtio_guest_flounder_init(char *iface) 178{ 179 errval_t err; 180 181 VIRTIO_DEBUG_CHAN("looking up iface [%s]\n", iface); 182 err = nameservice_blocking_lookup(iface, &virtio_rpc_svc_iref); 183 if (err_is_fail(err)) { 184 return err; 185 } 186 187 VIRTIO_DEBUG_CHAN("initiate binding to iref [%u]\n", virtio_rpc_svc_iref); 188 189 rpc_client_state = RPC_CLIENT_STATE_BINDING; 190 191 err = virtio_bind(virtio_rpc_svc_iref, 192 bind_cb, 193 NULL, 194 get_default_waitset(), 195 IDC_BIND_FLAGS_DEFAULT); 196 197 if (err_is_fail(err)) { 198 return err; 199 } 200 201 VIRTIO_DEBUG_CHAN("Waiting for binding reply\n"); 202 while(rpc_client_state == RPC_CLIENT_STATE_BINDING) { 203 messages_wait_and_handle_next(); 204 } 205 206 if (rpc_client_state == RPC_CLIENT_STATE_FAILED) { 207 VIRTIO_DEBUG_CHAN("Bind failed\n"); 208 return FLOUNDER_ERR_BIND; 209 } 210 211 VIRTIO_DEBUG_CHAN("Host channel ready\n"); 212 213 return SYS_ERR_OK; 214} 215