|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 3/5] plat/kvm: KVM Balloon Driver
From: Cason Schindler <cason.j.schindler@xxxxxxxxx>
Add balloon driver to interface with KVM through virtio balloon device.
Implement inflate and deflate API calls.
Signed-off-by: Cason Schindler <cason.j.schindler@xxxxxxxxx>
Signed-off-by: Jack Raney <raney.jack99@xxxxxxxxx>
---
plat/kvm/memory.c | 390 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 390 insertions(+)
diff --git a/plat/kvm/memory.c b/plat/kvm/memory.c
index 1d9269e..c4417ed 100644
--- a/plat/kvm/memory.c
+++ b/plat/kvm/memory.c
@@ -178,3 +178,393 @@ int _ukplat_mem_mappings_init(void)
{
return 0;
}
+
+
+/*
+ * front-end driver for kvm virtio balloon driver
+ * putting relative includes here because should really
+ * be in its own file
+ */
+
+
+#include <inttypes.h>
+#include <uk/alloc.h>
+#include <uk/sglist.h>
+#include <uk/list.h>
+#include <uk/assert.h>
+//#include <uk/mutex.h>
+#include <virtio/virtio_ids.h>
+#include <virtio/virtio_bus.h>
+#include <virtio/virtqueue.h>
+
+#define DRIVER_NAME "virtio-balloon"
+#define VTBALLOON_PAGES_PER_REQUEST 256
+
+static struct uk_alloc *a;
+
+static struct virtio_balloon_device *global_vb;
+
+/* pages given to hypervisor (in the balloon) */
+struct balloon_pages {
+
+ uint32_t num_pages; /* # pages in balloon */
+
+};
+
+/* temporary storage for pages with which we are either
+ * inflating or deflating the balloon
+ */
+struct transport_pages {
+
+ uint32_t num_pages; /* # of pages in pages */
+ uint32_t *pages;
+
+};
+
+/* wrapper for virtio device */
+struct virtio_balloon_device {
+
+ struct virtio_dev *vdev;
+
+ struct virtqueue *inflate_vq, *deflate_vq;
+
+ __u16 infvq_id;
+ __u16 defvq_id;
+
+ char* tag;
+
+ struct balloon_pages *balloon;
+
+ struct transport_pages *transport;
+
+ uint64_t features;
+ uint32_t flags;
+
+ //uk_mutex lock;
+
+};
+
+static void clear_transport(struct virtio_balloon_device* vb)
+{
+ int num = vb->transport->num_pages;
+ for (int i = 0; i < num; i++) {
+ (vb->transport->pages)[i] = 0;
+ vb->transport->num_pages -= 1;
+ }
+}
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2011, Bryan Venteicher <bryanv@xxxxxxxxxxx>
+ * All rights reserved.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* The above copyright notice applies only to the below function,
+ * vtballoon_send_page_frames, which is based on FreeBSD's function
+ * of the same name.
+ */
+
+static void vtballoon_send_page_frames(struct virtio_balloon_device *vb,
+ struct virtqueue *vq, int npages)
+{
+
+ struct uk_sglist sg;
+ struct uk_sglist_seg segs[1];
+ int c;
+
+ uk_sglist_init(&sg, 1, segs);
+
+ uk_sglist_append(&sg, vb->transport->pages, npages * sizeof(uint32_t));
+
+ void* vq_cookie;
+ virtqueue_buffer_enqueue(vq, &vq_cookie, &sg, 1, 0);
+
+ virtqueue_host_notify(vq);
+
+ __u32 len = 0;
+ /* wait on KVM to respond. Need a safer method for this */
+ while ((c = virtqueue_buffer_dequeue(vq, &vq_cookie, &len)) < 0);
+
+}
+
+/**
+ * this is equivalent to leaking from the balloon and
+ * increasing memory reservation for guest
+ */
+static int deflate_balloon(uintptr_t *pages_to_guest, uint32_t num)
+{
+ /* get pages_to_guest from the balloon and tell host we are using them
now */
+
+ /* check if device is ready */
+ if (!global_vb)
+ return -ENXIO;
+
+ struct virtio_balloon_device *vb = global_vb;
+
+ //uk_mutex_lock(vb->lock);
+
+ clear_transport(vb);
+
+ if (vb->balloon->num_pages < num) num = vb->balloon->num_pages;
+
+ for (uint32_t i = 0; i < num; i++) {
+ uint32_t page = pages_to_guest[i];
+ vb->transport->pages[i] = page; /* put page in temp array for
host */
+ vb->balloon->num_pages -= 1;
+ vb->transport->num_pages += 1;
+ }
+
+ int num_pages_taken = vb->transport->num_pages;
+
+ if (vb->transport->num_pages != 0) {
+ vtballoon_send_page_frames(vb, vb->deflate_vq,
vb->transport->num_pages);
+ }
+
+ //uk_mutex_unlock(vb->lock);
+
+ return num_pages_taken;
+}
+
+/**
+ * this is equivalent to filling the balloon and
+ * decreasing memory reservation for guest
+ */
+static int inflate_balloon(uintptr_t *pages_to_host, uint32_t num)
+{
+ /* need to put pages_to_host in the balloon for the host to use */
+
+ /* check if device is ready */
+ if (!global_vb)
+ return -ENXIO;
+
+ struct virtio_balloon_device *vb = global_vb;
+
+ //uk_mutex_lock(vb->lock);
+
+ clear_transport(vb);
+
+ for (uint32_t i = 0; i < num; i++) {
+ uint32_t page = pages_to_host[i] / __PAGE_SIZE;
+ vb->transport->pages[i] = page; /* put page in temp array for
host */
+ vb->balloon->num_pages += 1;
+ vb->transport->num_pages += 1;
+ }
+
+ int num_pages_given = vb->transport->num_pages;
+
+ if (vb->transport->num_pages != 0) {
+ vtballoon_send_page_frames(vb, vb->inflate_vq,
vb->transport->num_pages);
+ }
+
+ //uk_mutex_unlock(vb->lock);
+
+ return num_pages_given;
+}
+
+
+static inline void virtio_balloon_feature_set(struct virtio_balloon_device *vb)
+{
+ vb->features = 0;
+ vb->flags = 0;
+ vb->vdev->features = 0;
+}
+
+static int virtio_balloon_vq_alloc(struct virtio_balloon_device *vb)
+{
+ int vq_avail = 0;
+ int rc = 0;
+ __u16 qdesc_size[2];
+
+ vq_avail = virtio_find_vqs(vb->vdev, 2, &(qdesc_size[0]));
+ if (unlikely(vq_avail != 2)) {
+ uk_pr_err(DRIVER_NAME": Expected: %d queues, found %d\n",
+ 2, vq_avail);
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ vb->infvq_id = 0;
+ vb->defvq_id = 1;
+
+ vb->inflate_vq = virtio_vqueue_setup(
+ vb->vdev, vb->infvq_id,
qdesc_size[0], NULL, a); /* no callback */
+ vb->inflate_vq->priv = vb;
+
+ if (unlikely(PTRISERR(vb->inflate_vq))) {
+ uk_pr_err(DRIVER_NAME": Failed to set up virtqueue %"PRIu16"\n",
+ vb->infvq_id);
+ rc = PTR2ERR(vb->inflate_vq);
+ }
+
+ vb->deflate_vq = virtio_vqueue_setup(
+ vb->vdev, vb->defvq_id,
qdesc_size[1], NULL, a); /* no callback */
+ vb->deflate_vq->priv = vb;
+
+ if (unlikely(PTRISERR(vb->deflate_vq))) {
+ uk_pr_err(DRIVER_NAME": Failed to set up virtqueue %"PRIu16"\n",
+ vb->defvq_id);
+ rc = PTR2ERR(vb->deflate_vq);
+ }
+
+exit:
+ return rc;
+}
+
+static int virtio_balloon_start(struct virtio_balloon_device *vb)
+{
+
+ virtqueue_intr_enable(vb->inflate_vq);
+ virtqueue_intr_enable(vb->deflate_vq);
+ virtio_dev_drv_up(vb->vdev);
+ uk_pr_info(DRIVER_NAME": %s started\n", vb->tag);
+
+ return 0;
+}
+
+static int virtio_balloon_add_dev(struct virtio_dev *vdev)
+{
+
+ struct virtio_balloon_device *vbdev;
+ int rc = 0;
+
+ UK_ASSERT(vdev != NULL);
+
+ vbdev = uk_calloc(a, 1, sizeof(*vbdev));
+
+ if (!vbdev) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ int tag_len = 30;
+ vbdev->tag = uk_calloc(a, 1, sizeof(tag_len));
+ vbdev->tag = "VIRTIO_BALLOON_DRV_DEV";
+
+ //uk_mutex_init(&vbdev->lock);
+
+ vbdev->vdev = vdev;
+ virtio_balloon_feature_set(vbdev);
+ rc = virtio_balloon_vq_alloc(vbdev);
+ if (rc) {
+ goto err_out;
+ }
+
+ vbdev->transport = uk_calloc(a, 1, sizeof(struct transport_pages));
+ if (!(vbdev->transport)) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ vbdev->transport->pages =
+ uk_calloc(a, 1, VTBALLOON_PAGES_PER_REQUEST *
sizeof(uint32_t));
+ if (!(vbdev->transport->pages)) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ vbdev->balloon = uk_calloc(a, 1, sizeof(struct balloon_pages));
+
+ rc = virtio_balloon_start(vbdev);
+ if (rc) {
+ goto err_out;
+ }
+
+exit:
+ global_vb = vbdev; /* initialize global vb */
+ /* initial alloc and free to trigger ballon init */
+ void* alc = uk_palloc(a, 0);
+ uk_pfree(a, alc, 0);
+ return rc;
+err_out:
+ uk_free(a, vbdev->transport->pages);
+ uk_free(a, vbdev->transport);
+ uk_free(a, vbdev->balloon);
+ uk_free(a, vbdev);
+ goto exit;
+
+}
+
+static int virtio_balloon_drv_init(struct uk_alloc *drv_allocator)
+{
+ /* driver initialization */
+ if (!drv_allocator) {
+ return -EINVAL;
+ }
+
+ a = drv_allocator;
+ return 0;
+
+}
+
+static const struct virtio_dev_id vballoon_dev_id[] = {
+ {VIRTIO_ID_BALLOON},
+ {VIRTIO_ID_INVALID} /* List Terminator */
+};
+
+static struct virtio_driver virtio_balloon_driver = {
+ .dev_ids = vballoon_dev_id,
+ .init = virtio_balloon_drv_init,
+ .add_dev = virtio_balloon_add_dev
+};
+VIRTIO_BUS_REGISTER_DRIVER(&virtio_balloon_driver);
+
+
+/* memory.c inflation and deflation API function implementations: */
+
+/**
+ * number of pages is 2^order
+ */
+int get_num_pages(int order)
+{
+ int num_pages = 1;
+ for (int i = 0; i < order; i++) num_pages *= 2;
+ return num_pages;
+}
+
+/**
+ * fill addresses for page range starting at first_page
+ */
+void fill_page_array(uintptr_t *pages_array, void* first_page, int num_pages)
+{
+ uint64_t current_pg = (uint64_t) first_page;
+ for (int i = 0; i < num_pages; i++) {
+ pages_array[i] = current_pg;
+ current_pg += __PAGE_SIZE;
+ }
+}
+
+/**
+ * call driver inflate_balloon
+ * returns number of pages actually put into balloon or < 0 on error
+ */
+int ukplat_inflate(void* page, int order)
+{
+ int num_pages = get_num_pages(order);
+ uintptr_t pages_to_host[num_pages];
+ fill_page_array(pages_to_host, page, num_pages);
+
+ return inflate_balloon(pages_to_host, num_pages);
+}
+
+/**
+ * call driver deflate_balloon
+ * returns number of pages actually taken from balloon or < 0 on error
+ */
+int ukplat_deflate(void* page, int order)
+{
+ int num_pages = get_num_pages(order);
+ uintptr_t pages_to_guest[num_pages];
+ fill_page_array(pages_to_guest, page, num_pages);
+
+ return deflate_balloon(pages_to_guest, num_pages);
+}
--
2.24.0
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |