vhost_user_rng.c 5.22 KB
Newer Older
1
/*
2
 * Based on vhost-user-rng of QEMU project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
 *
 * Copyright (c) 2021 Mathieu Poirier <mathieu.poirier@linaro.org>
 *
 * Copyright (c) 2022 Virtual Open Systems SAS.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <sys/param.h>

/* Project header files */
#include "vhost_loopback.h"
#include "vhost_user_rng.h"

#ifdef DEBUG
#define DBG(...) printf("vhost-user-rng: " __VA_ARGS__)
#else
#define DBG(...)
#endif /* DEBUG */

static void vu_rng_start(VirtIODevice *vdev)
{
    VHostUserRNG *rng = vdev->vhrng;
    VirtioBus *k = vdev->vbus;
    int ret;
    int i;

    /* TODO: This might be deleted in future */
    if (!k->set_guest_notifiers) {
        DBG("binding does not support guest notifiers\n");
        return;
    }

    ret = vhost_dev_enable_notifiers(rng->vhost_dev, vdev);
    if (ret < 0) {
        DBG("Error enabling host notifiers: %d\n", ret);
        return;
    }

    ret = k->set_guest_notifiers(vdev, rng->vhost_dev->nvqs, true);
    if (ret < 0) {
        DBG("Error binding guest notifier: %d\n", ret);
        return;
    }

    rng->vhost_dev->acked_features = vdev->guest_features;

    ret = vhost_dev_start(rng->vhost_dev, vdev);
    if (ret < 0) {
        DBG("Error starting vhost-user-rng: %d\n", ret);
        return;
    }

    /*
     * guest_notifier_mask/pending not used yet, so just unmask
     * everything here. virtio-pci will do the right thing by
     * enabling/disabling irqfd.
     */
    for (i = 0; i < rng->vhost_dev->nvqs; i++) {
        vhost_virtqueue_mask(rng->vhost_dev, vdev, i, false);
    }

}

/* TODO: We need to implement this function in a future release */
static void vu_rng_stop(VirtIODevice *vdev)
{
    VHostUserRNG *rng = vdev->vhrng;
}


static uint64_t vu_rng_get_features(VirtIODevice *vdev,
                                    uint64_t requested_features)
{
    /* No feature bits used yet */
    return requested_features;
}

/* TODO: We need to implement this function in a future release */
static void vu_rng_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask)
{
    VHostUserRNG *rng = vdev->vhrng;

    /* vhost_virtqueue_mask(&rng->vhost_dev, vdev, idx, mask); */
}

/* TODO: We need to implement this function in a future release */
static bool vu_rng_guest_notifier_pending(VirtIODevice *vdev, int idx)
{
    VHostUserRNG *rng = vdev->vhrng;

    /* return vhost_virtqueue_pending(&rng->vhost_dev, idx); */
    return 1;
}

static void vu_rng_set_status(VirtIODevice *vdev, uint8_t status)
{
    VHostUserRNG *rng = vdev->vhrng;
    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;

    if (rng->vhost_dev->started == should_start) {
        DBG("rng->vhost_dev->started != should_start\n");
        return;
    }

    if (should_start) {
        vu_rng_start(vdev);
    } else {
        DBG("vu_rng_stop(vdev)\n");
        /* TODO: Add vu_rng_stop(vdev); when this function is implemented */
    }
}

134 135 136
static void virtio_dev_class_init(VirtIODevice *vdev)
{
    vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass));
137 138 139 140 141 142 143 144
    vdev->vdev_class->parent = vdev;
    vdev->vdev_class->set_status = vu_rng_set_status;
    vdev->vdev_class->get_features = vu_rng_get_features;
    vdev->vdev_class->guest_notifier_mask = vu_rng_guest_notifier_mask;
    vdev->vdev_class->guest_notifier_pending = vu_rng_guest_notifier_pending;
}


145 146 147
void vhost_user_rng_init(VirtIODevice *vdev)
{
    VHostUserRNG *vhrng = (VHostUserRNG *)malloc(sizeof(VHostUserRNG));
148 149 150 151 152
    vdev->vhrng = vhrng;
    vhrng->parent = vdev;
    vhrng->req_vq = vdev->vq;
    vhrng->vhost_dev = dev;

153 154
    virtio_dev_class_init(vdev);
    virtio_loopback_bus_init(vdev->vbus);
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
}

static void vu_rng_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    /*
     * Not normally called; it's the daemon that handles the queue;
     * however virtio's cleanup path can call this.
     */
    DBG("vu_rng_handle_output\n");
}


void vhost_user_rng_realize(void)
{
    virtio_dev_init(global_vdev, "virtio-rng", 4, 0);

    /* This needs to be change to vhost-user-rng init */
    vhost_user_rng_init(global_vdev);

    global_vdev->vq = virtio_add_queue(global_vdev, 4, vu_rng_handle_output);

    global_vdev->host_features = 0x39000000;

178
    proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy));
179 180 181 182 183 184
    *proxy = (VirtIOMMIOProxy) {
        .legacy = 1,
    };

    /* Virtqueues conf */
    dev->nvqs = 1;
185 186
    dev->vqs = (struct vhost_virtqueue *)malloc(dev->nvqs *
                                                sizeof(struct vhost_virtqueue));
187 188 189

    vhost_dev_init(dev);
}