From: Kyle Milka <[email protected]> We were able to get Linux to send a packet to the virtio device. Used linux/lguest.c as a starting point and virtio_lguest_console.c for finding the names of our version of the functions. This included adding the network device struct and transmit and receive functions.
Bug:29178446 Change-Id: I840c0acc617d238fb2b24b5662ee76f615bc743f Signed-off-by: Kyle Milka <[email protected]> --- tests/vmm/vmrunkernel.c | 64 ++++++++++++++++++-- user/vmm/include/vmm/virtio_mmio.h | 3 + user/vmm/include/vmm/virtio_net.h | 8 ++- user/vmm/include/vmm/vmm.h | 5 +- user/vmm/virtio.c | 5 ++ user/vmm/virtio_net.c | 120 +++++++++++++++++++++++++++++++++++++ 6 files changed, 197 insertions(+), 8 deletions(-) create mode 100644 user/vmm/virtio_net.c diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c index 6dd66a4..410b8a1 100644 --- a/tests/vmm/vmrunkernel.c +++ b/tests/vmm/vmrunkernel.c @@ -27,6 +27,7 @@ #include <vmm/virtio_ids.h> #include <vmm/virtio_config.h> #include <vmm/virtio_console.h> +#include <vmm/virtio_net.h> #include <vmm/virtio_lguest_console.h> #include <vmm/sched.h> @@ -206,14 +207,15 @@ void timer_thread(void *arg) // FIXME. volatile int consdata = 0; -static void virtio_poke_guest(void) +static void virtio_cons_poke_guest(void) { set_posted_interrupt(0xE5); ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0); } static struct virtio_mmio_dev cons_mmio_dev = { - .poke_guest = virtio_poke_guest + .poke_guest = virtio_cons_poke_guest, + .irq = 32 }; static struct virtio_console_config cons_cfg; @@ -223,7 +225,7 @@ static struct virtio_vq_dev cons_vqdev = { .name = "console", .dev_id = VIRTIO_ID_CONSOLE, .dev_feat = ((uint64_t)1 << VIRTIO_F_VERSION_1) - | (1 << VIRTIO_RING_F_INDIRECT_DESC) + | (1 << VIRTIO_RING_F_INDIRECT_DESC) , .num_vqs = 2, .cfg = &cons_cfg, @@ -246,6 +248,52 @@ static struct virtio_vq_dev cons_vqdev = { } }; +/* Sends an interrupt to the guest. */ +static void virtio_net_poke_guest(void) +{ + set_posted_interrupt(0xE6); + ros_syscall(SYS_vmm_poke_guest, 0, 0, 0, 0, 0, 0); +} + +static struct virtio_mmio_dev net_mmio_dev = { + .poke_guest = virtio_net_poke_guest, + .irq = 29 +}; + +static struct virtio_net_config net_cfg = { + .mac = {0xec, 0xb1, 0xd7, 0x42, 0x90, 0xbf}, + .max_virtqueue_pairs = 1 +}; +static struct virtio_net_config net_cfg_d = { + .mac = {0xec, 0xb1, 0xd7, 0x42, 0x90, 0xbf}, + .max_virtqueue_pairs = 1 +}; + +static struct virtio_vq_dev net_vqdev = { + .name = "network", + .dev_id = VIRTIO_ID_NET, + .dev_feat = ((uint64_t)1 << VIRTIO_F_VERSION_1 | 1 << VIRTIO_NET_F_MAC), + + .num_vqs = 2, + .cfg = &net_cfg, + .cfg_d = &net_cfg_d, + .cfg_sz = sizeof(struct virtio_net_config), + .transport_dev = &net_mmio_dev, + .vqs = { + { + .name = "net_receiveq", + .qnum_max = 64, + .srv_fn = net_receiveq_fn, + .vqdev = &net_vqdev + }, + { + .name = "net_transmitq", + .qnum_max = 64, + .srv_fn = net_transmitq_fn, + .vqdev = &net_vqdev + }, + } +}; void lowmem() { __asm__ __volatile__ (".section .lowmem, \"aw\"\n\tlow: \n\t.=0x1000\n\t.align 0x100000\n\t.previous\n"); @@ -585,6 +633,10 @@ int main(int argc, char **argv) cons_mmio_dev.vqdev = &cons_vqdev; vm->virtio_mmio_devices[VIRTIO_MMIO_CONSOLE_DEV] = &cons_mmio_dev; + net_mmio_dev.addr = cons_mmio_dev.addr + PGSIZE; + net_mmio_dev.vqdev = &net_vqdev; + vm->virtio_mmio_devices[VIRTIO_MMIO_NETWORK_DEV] = &net_mmio_dev; + /* Set the kernel command line parameters */ a += 4096; cmdline = a; @@ -602,8 +654,10 @@ int main(int argc, char **argv) if (vm->virtio_mmio_devices[i] == NULL) continue; /* Append all the virtio mmio base addresses. */ - len = snprintf(cmdlinep, cmdlinesz, " virtio_mmio.device=1K@0x%llx:32", - vm->virtio_mmio_devices[i]->addr); + len = snprintf(cmdlinep, cmdlinesz, + " virtio_mmio.device=1K@0x%llx:%lld", + vm->virtio_mmio_devices[i]->addr, + vm->virtio_mmio_devices[i]->irq); if (len >= cmdlinesz) { fprintf(stderr, "Too many arguments to the linux command line."); exit(1); diff --git a/user/vmm/include/vmm/virtio_mmio.h b/user/vmm/include/vmm/virtio_mmio.h index f0b8979..afd079e 100644 --- a/user/vmm/include/vmm/virtio_mmio.h +++ b/user/vmm/include/vmm/virtio_mmio.h @@ -212,6 +212,9 @@ struct virtio_mmio_dev { // The generic vq device contained by this mmio transport struct virtio_vq_dev *vqdev; + + // The specific irq number for this device. + uint64_t irq; }; // Sets the VIRTIO_MMIO_INT_VRING bit in the interrupt status diff --git a/user/vmm/include/vmm/virtio_net.h b/user/vmm/include/vmm/virtio_net.h index 31b8f54..a73e646 100644 --- a/user/vmm/include/vmm/virtio_net.h +++ b/user/vmm/include/vmm/virtio_net.h @@ -27,7 +27,6 @@ #include <stdint.h> #include <vmm/virtio_ids.h> #include <vmm/virtio_config.h> -#include <linux/if_ether.h> /* The feature bitmap for virtio net */ #define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ @@ -61,6 +60,10 @@ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ +#ifndef ETH_ALEN +#define ETH_ALEN 6 /* Length of a MAC address (48 bits) */ +#endif + struct virtio_net_config { /* The config defining mac address (if VIRTIO_NET_F_MAC) */ uint8_t mac[ETH_ALEN]; @@ -239,3 +242,6 @@ struct virtio_net_ctrl_mq { */ #define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5 #define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0 + +void net_receiveq_fn(void *_vq); +void net_transmitq_fn(void *_vq); diff --git a/user/vmm/include/vmm/vmm.h b/user/vmm/include/vmm/vmm.h index fbc12b7..d5416fe 100644 --- a/user/vmm/include/vmm/vmm.h +++ b/user/vmm/include/vmm/vmm.h @@ -10,12 +10,13 @@ #include <vmm/sched.h> /* The listing of VIRTIO MMIO devices. We currently only expect to have 2, - * console and network. Only the console is implemented right now.*/ + * console and network. Only the console is fully implemented right now.*/ enum { VIRTIO_MMIO_CONSOLE_DEV, + VIRTIO_MMIO_NETWORK_DEV, /* This should always be the last entry. */ - VIRTIO_MMIO_MAX_NUM_DEV = 2, + VIRTIO_MMIO_MAX_NUM_DEV, }; /* Structure to encapsulate all of the bookkeeping for a VM. */ diff --git a/user/vmm/virtio.c b/user/vmm/virtio.c index 165cb47..f64d1e2 100644 --- a/user/vmm/virtio.c +++ b/user/vmm/virtio.c @@ -32,6 +32,11 @@ const char *virtio_validate_feat(struct virtio_vq_dev *vqdev, uint64_t feat) case VIRTIO_ID_CONSOLE: // No interdependent features for the console. break; + case VIRTIO_ID_NET: + // There is no "mandatory" feature bit that we always want to have, + // either the device can set its own MAC Address (as it does now) + // or the driver can set it using a controller thread. + break; case 0: return "Invalid device id (0x0)! On the MMIO transport, this value indicates that the device is a system memory map with placeholder devices at static, well known addresses. In any case, this is not something you validate features for."; default: diff --git a/user/vmm/virtio_net.c b/user/vmm/virtio_net.c new file mode 100644 index 0000000..6b6f670 --- /dev/null +++ b/user/vmm/virtio_net.c @@ -0,0 +1,120 @@ +/* Virtio helper functions from linux/tools/lguest/lguest.c + * + * Copyright (C) 1991-2016, the Linux Kernel authors + * Copyright (c) 2016 Google Inc. + * + * Author: + * Rusty Russell <[email protected]> + * Kyle Milka <[email protected]> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * The code from lguest.c has been modified for Akaros. + * + * Original linux/tools/lguest/lguest.c: + * https://github.com/torvalds/linux/blob/v4.5/tools/lguest/lguest.c + * most recent hash on the file as of v4.5 tag: + * e523caa601f4a7c2fa1ecd040db921baf7453798 + */ + +#include <stdlib.h> +#include <vmm/virtio.h> +#include <vmm/virtio_mmio.h> + +/* net_receiveq_fn receives packets from the virtio networking device through + * the _vq virtio queue. + * + * TODO(kmilka): Not working until we have networking capabilities. + */ +void net_receiveq_fn(void *_vq) +{ + struct virtio_vq *vq = _vq; + uint32_t head; + uint32_t olen, ilen; + uint32_t num_read; + struct iovec *iov; + + if (!vq) + VIRTIO_DEV_ERRX(vq->vqdev, + "\n %s:%d\n" + " Virtio device: (not sure which one): Error, device behavior.\n" + " The device must provide a valid virtio_vq as an argument to %s." + , __FILE__, __LINE__, __func__); + + iov = malloc(vq->qnum_max * sizeof(struct iovec)); + + if (vq->qready == 0x0) { + free(iov); + VIRTIO_DEV_ERRX(vq->vqdev, + "The service function for queue '%s' was launched before the driver set QueueReady to 0x1." + , vq->name); + } + + while (1) { + head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen); + + if (olen) { + free(iov); + VIRTIO_DRI_ERRX(vq->vqdev, + "The driver placed a device-readable buffer in the console device's receiveq.\n" + " See virtio-v1.0-cs04 s5.3.6.1 Device Operation"); + } + /* Grab actual external packet + * num_read = readv(0, iov, ilen); + * if (num_read <= 0) + * wait forever since we dont actually have + * something from the network */ + while (1); + + virtio_add_used_desc(vq, head, num_read); + + virtio_mmio_set_vring_irq(vq->vqdev->transport_dev); + if (!((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest) { + free(iov); + VIRTIO_DEV_ERRX(vq->vqdev, + "The 'poke_guest' function pointer was not set."); + } + ((struct virtio_mmio_dev*)vq->vqdev->transport_dev)->poke_guest(); + } + + free(iov); +} + +/* net_receiveq_fn transmits packets from the virtio networking device through + * the _vq virtio queue. + * + * TODO(kmilka): At this point we can receive packets from the guest, but still + * can not transmit a packet until we have networking capabilities. + */ +void net_transmitq_fn(void *_vq) +{ + struct virtio_vq *vq = _vq; + uint32_t head; + uint32_t olen, ilen; + struct iovec *iov; + + iov = malloc(vq->qnum_max * sizeof(struct iovec)); + + while (1) { + head = virtio_next_avail_vq_desc(vq, iov, &olen, &ilen); + + if (ilen) { + free(iov); + VIRTIO_DRI_ERRX(vq->vqdev, + "The driver placed a device-writeable buffer in the network device's transmitq.\n" + " See virtio-v1.0-cs04 s5.3.6.1 Device Operation"); + } + + virtio_add_used_desc(vq, head, 0); + } + + free(iov); +} -- 2.8.0.rc3.226.g39d4020 -- You received this message because you are subscribed to the Google Groups "Akaros" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
