+++ /dev/null
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Cristian Banu <cristb@gmail.com>
- *
- * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <uk/config.h>
-#include <uk/alloc.h>
-#include <uk/assert.h>
-#include <uk/essentials.h>
-#include <uk/errptr.h>
-#include <uk/list.h>
-#if CONFIG_LIBUKSCHED
-#include <uk/thread.h>
-#endif
-#include <uk/9pdev.h>
-#include <uk/9preq.h>
-#include <uk/9pdev_trans.h>
-#include <uk/plat/spinlock.h>
-#if defined(__i386__) || defined(__x86_64__)
-#include <xen-x86/mm.h>
-#include <xen-x86/irq.h>
-#elif defined(__aarch64__)
-#include <xen-arm/mm.h>
-#else
-#error "Unsupported architecture"
-#endif
-#include <uk/xenbus/xenbus.h>
-
-#include "9pfront_xb.h"
-
-#define DRIVER_NAME "xen-9pfront"
-
-static struct uk_alloc *a;
-static UK_LIST_HEAD(p9front_device_list);
-static __spinlock p9front_device_list_lock;
-
-struct p9front_header {
- uint32_t size;
- uint8_t type;
- uint16_t tag;
-} __packed;
-
-static void p9front_recv(struct p9front_dev_ring *ring);
-
-#if CONFIG_LIBUKSCHED
-
-static __noreturn void p9front_bh_handler(void *arg)
-{
- struct p9front_dev_ring *ring = arg;
-
- while (1) {
- uk_waitq_wait_event(&ring->bh_wq,
- UK_READ_ONCE(ring->data_avail));
- p9front_recv(ring);
- }
-}
-
-#endif
-
-static void p9front_recv(struct p9front_dev_ring *ring)
-{
- struct p9front_dev *p9fdev = ring->dev;
- evtchn_port_t evtchn = ring->evtchn;
- RING_IDX cons, prod, masked_cons, masked_prod;
- int ring_size, rc;
- struct p9front_header hdr;
- struct uk_9preq *req;
- uint32_t buf_cnt, zc_buf_cnt;
-
- ring_size = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
-
- while (1) {
- cons = ring->intf->in_cons;
- prod = ring->intf->in_prod;
- xen_rmb();
-
- if (xen_9pfs_queued(prod, cons, ring_size) < sizeof(hdr)) {
-#if CONFIG_LIBUKSCHED
- UK_WRITE_ONCE(ring->data_avail, false);
-#endif
- notify_remote_via_evtchn(evtchn);
- return;
- }
-
- masked_prod = xen_9pfs_mask(prod, ring_size);
- masked_cons = xen_9pfs_mask(cons, ring_size);
-
- xen_9pfs_read_packet(&hdr, ring->data.in, sizeof(hdr),
- masked_prod, &masked_cons, ring_size);
-
- req = uk_9pdev_req_lookup(p9fdev->p9dev, hdr.tag);
- if (PTRISERR(req)) {
- uk_pr_warn("Found invalid tag=%u\n", hdr.tag);
- cons += hdr.size;
- xen_mb();
- ring->intf->in_cons = cons;
- continue;
- }
-
- masked_cons = xen_9pfs_mask(cons, ring_size);
-
- /*
- * Compute amount of data to read into request buffer and into
- * zero-copy buffer.
- */
- buf_cnt = hdr.size;
- if (hdr.type != UK_9P_RERROR && req->recv.zc_buf)
- buf_cnt = MIN(buf_cnt, req->recv.zc_offset);
- zc_buf_cnt = hdr.size - buf_cnt;
-
- xen_9pfs_read_packet(req->recv.buf, ring->data.in, buf_cnt,
- masked_prod, &masked_cons, ring_size);
- xen_9pfs_read_packet(req->recv.zc_buf, ring->data.in,
- zc_buf_cnt, masked_prod, &masked_cons,
- ring_size);
- cons += hdr.size;
- xen_mb();
- ring->intf->in_cons = cons;
-
- rc = uk_9preq_receive_cb(req, hdr.size);
- if (rc)
- uk_pr_warn("Could not receive reply: %d\n", rc);
-
- /* Release reference held by uk_9pdev_req_lookup(). */
- uk_9preq_put(req);
- }
-}
-
-static void p9front_handler(evtchn_port_t evtchn,
- struct __regs *regs __unused,
- void *arg)
-{
- struct p9front_dev_ring *ring = arg;
-
- UK_ASSERT(ring);
- UK_ASSERT(ring->evtchn == evtchn);
-
- /*
- * A new interrupt means that there is a response to be received, which
- * means that a previously sent request has been removed from the out
- * ring. Thus, the API can be notified of the possibility of retrying to
- * send requests blocked on ENOSPC errors.
- */
- if (ring->dev->p9dev)
- uk_9pdev_xmit_notify(ring->dev->p9dev);
-#if CONFIG_LIBUKSCHED
- UK_WRITE_ONCE(ring->data_avail, true);
- uk_waitq_wake_up(&ring->bh_wq);
-#else
- p9front_recv(ring);
-#endif
-}
-
-static void p9front_free_dev_ring(struct p9front_dev *p9fdev, int idx)
-{
- struct p9front_dev_ring *ring = &p9fdev->rings[idx];
- int i;
-
- UK_ASSERT(ring->initialized);
-
- if (ring->bh_thread_name)
- free(ring->bh_thread_name);
- uk_sched_thread_terminate(ring->bh_thread);
- unbind_evtchn(ring->evtchn);
- for (i = 0; i < (1 << p9fdev->ring_order); i++)
- gnttab_end_access(ring->intf->ref[i]);
- uk_pfree(a, ring->data.in,
- 1ul << (p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT));
- gnttab_end_access(ring->ref);
- uk_pfree(a, ring->intf, 1);
- ring->initialized = false;
-}
-
-static void p9front_free_dev_rings(struct p9front_dev *p9fdev)
-{
- int i;
-
- for (i = 0; i < p9fdev->nb_rings; i++) {
- if (!p9fdev->rings[i].initialized)
- continue;
- p9front_free_dev_ring(p9fdev, i);
- }
-
- uk_free(a, p9fdev->rings);
-}
-
-static int p9front_allocate_dev_ring(struct p9front_dev *p9fdev, int idx)
-{
- struct xenbus_device *xendev = p9fdev->xendev;
- struct p9front_dev_ring *ring;
- int rc, i;
- void *data_bytes;
-
- /* Sanity checks. */
- UK_ASSERT(idx >= 0 && idx < p9fdev->nb_rings);
-
- ring = &p9fdev->rings[idx];
- UK_ASSERT(!ring->initialized);
-
- ukarch_spin_init(&ring->spinlock);
- ring->dev = p9fdev;
-
- /* Allocate ring intf page. */
- ring->intf = uk_palloc(a, 1);
- if (!ring->intf) {
- rc = -ENOMEM;
- goto out;
- }
- memset(ring->intf, 0, PAGE_SIZE);
-
- /* Grant access to the allocated page to the backend. */
- ring->ref = gnttab_grant_access(xendev->otherend_id,
- virt_to_mfn(ring->intf), 0);
- UK_ASSERT(ring->ref != GRANT_INVALID_REF);
-
- /* Allocate memory for the data. */
- data_bytes = uk_palloc(a, 1ul << (p9fdev->ring_order +
- XEN_PAGE_SHIFT - PAGE_SHIFT));
- if (!data_bytes) {
- rc = -ENOMEM;
- goto out_free_intf;
- }
- memset(data_bytes, 0, XEN_FLEX_RING_SIZE(p9fdev->ring_order) * 2);
-
- /* Grant refs to the entire data. */
- for (i = 0; i < (1 << p9fdev->ring_order); i++) {
- ring->intf->ref[i] = gnttab_grant_access(xendev->otherend_id,
- virt_to_mfn(data_bytes) + i, 0);
- UK_ASSERT(ring->intf->ref[i] != GRANT_INVALID_REF);
- }
-
- ring->intf->ring_order = p9fdev->ring_order;
- ring->data.in = data_bytes;
- ring->data.out = data_bytes + XEN_FLEX_RING_SIZE(p9fdev->ring_order);
-
-#if CONFIG_LIBUKSCHED
- /* Allocate bottom-half thread. */
- ring->data_avail = false;
- uk_waitq_init(&ring->bh_wq);
-
- rc = asprintf(&ring->bh_thread_name, DRIVER_NAME"-recv-%s-%u",
- p9fdev->tag, idx);
- ring->bh_thread = uk_sched_thread_create(uk_sched_current(),
- p9front_bh_handler, ring,
- ring->bh_thread_name);
- if (PTRISERR(ring->bh_thread)) {
- rc = PTR2ERR(ring->bh_thread);
- ring->bh_thread = NULL;
- goto out_free_grants;
- }
-#endif
-
- /* Allocate event channel. */
- rc = evtchn_alloc_unbound(xendev->otherend_id, p9front_handler, ring,
- &ring->evtchn);
- if (rc) {
- uk_pr_err(DRIVER_NAME": Error creating evt channel: %d\n", rc);
- goto out_free_thread;
- }
-
- unmask_evtchn(ring->evtchn);
-
- /* Mark ring as initialized. */
- ring->initialized = true;
-
- return 0;
-
-out_free_thread:
- if (ring->bh_thread_name)
- free(ring->bh_thread_name);
- uk_sched_thread_terminate(ring->bh_thread);
-out_free_grants:
- for (i = 0; i < (1 << p9fdev->ring_order); i++)
- gnttab_end_access(ring->intf->ref[i]);
- uk_pfree(a, data_bytes,
- 1ul << (p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT));
-out_free_intf:
- gnttab_end_access(ring->ref);
- uk_pfree(a, ring->intf, 1);
-out:
- return rc;
-}
-
-static int p9front_allocate_dev_rings(struct p9front_dev *p9fdev)
-{
- int rc, i;
-
- p9fdev->rings = uk_calloc(a, p9fdev->nb_rings, sizeof(*p9fdev->rings));
- if (!p9fdev->rings) {
- rc = -ENOMEM;
- goto out;
- }
-
- for (i = 0; i < p9fdev->nb_rings; i++) {
- rc = p9front_allocate_dev_ring(p9fdev, i);
- if (rc)
- goto out_free;
- }
-
- return 0;
-
-out_free:
- p9front_free_dev_rings(p9fdev);
-out:
- return rc;
-}
-
-static int p9front_connect(struct uk_9pdev *p9dev,
- const char *device_identifier,
- const char *mount_args __unused)
-{
- struct p9front_dev *p9fdev = NULL;
- int rc = 0;
- int found = 0;
-
- ukarch_spin_lock(&p9front_device_list_lock);
- uk_list_for_each_entry(p9fdev, &p9front_device_list, _list) {
- if (!strcmp(p9fdev->tag, device_identifier)) {
- if (p9fdev->p9dev != NULL) {
- rc = -EBUSY;
- goto out;
- }
- found = 1;
- break;
- }
- }
-
- if (!found) {
- rc = -ENODEV;
- goto out;
- }
-
- /* The msize is given by the size of the flex ring. */
- p9dev->max_msize = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
-
- p9fdev->p9dev = p9dev;
- p9dev->priv = p9fdev;
- rc = 0;
- found = 1;
-
-out:
- ukarch_spin_unlock(&p9front_device_list_lock);
- return rc;
-}
-
-static int p9front_disconnect(struct uk_9pdev *p9dev __unused)
-{
- struct p9front_dev *p9fdev;
-
- UK_ASSERT(p9dev);
- p9fdev = p9dev->priv;
-
- ukarch_spin_lock(&p9front_device_list_lock);
- p9fdev->p9dev = NULL;
- ukarch_spin_unlock(&p9front_device_list_lock);
-
- return 0;
-}
-
-static int p9front_request(struct uk_9pdev *p9dev,
- struct uk_9preq *req)
-{
- struct p9front_dev *p9fdev;
- struct p9front_dev_ring *ring;
- int ring_idx, ring_size;
- RING_IDX masked_prod, masked_cons, prod, cons;
-
- UK_ASSERT(p9dev);
- UK_ASSERT(req);
- UK_ASSERT(req->state == UK_9PREQ_READY);
-
- p9fdev = p9dev->priv;
-
- ring_size = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
-
- ring_idx = req->tag % p9fdev->nb_rings;
- ring = &p9fdev->rings[ring_idx];
-
- /* Protect against concurrent writes to the out ring. */
- ukarch_spin_lock(&ring->spinlock);
- cons = ring->intf->out_cons;
- prod = ring->intf->out_prod;
- xen_mb();
-
- masked_prod = xen_9pfs_mask(prod, ring_size);
- masked_cons = xen_9pfs_mask(cons, ring_size);
-
- if (ring_size - xen_9pfs_queued(prod, cons, ring_size) <
- req->xmit.size + req->xmit.zc_size) {
- ukarch_spin_unlock(&ring->spinlock);
- return -ENOSPC;
- }
-
- xen_9pfs_write_packet(ring->data.out, req->xmit.buf, req->xmit.size,
- &masked_prod, masked_cons, ring_size);
- xen_9pfs_write_packet(ring->data.out, req->xmit.zc_buf, req->xmit.zc_size,
- &masked_prod, masked_cons, ring_size);
- req->state = UK_9PREQ_SENT;
- xen_wmb();
- prod += req->xmit.size + req->xmit.zc_size;
- ring->intf->out_prod = prod;
-
- ukarch_spin_unlock(&ring->spinlock);
- notify_remote_via_evtchn(ring->evtchn);
-
- return 0;
-}
-
-static const struct uk_9pdev_trans_ops p9front_trans_ops = {
- .connect = p9front_connect,
- .disconnect = p9front_disconnect,
- .request = p9front_request
-};
-
-static struct uk_9pdev_trans p9front_trans = {
- .name = "xen",
- .ops = &p9front_trans_ops,
- .a = NULL /* Set below. */
-};
-
-
-static int p9front_drv_init(struct uk_alloc *drv_allocator)
-{
- if (!drv_allocator)
- return -EINVAL;
-
- a = drv_allocator;
- p9front_trans.a = a;
-
- return uk_9pdev_trans_register(&p9front_trans);
-}
-
-static int p9front_add_dev(struct xenbus_device *xendev)
-{
- struct p9front_dev *p9fdev;
- int rc;
-
- p9fdev = uk_calloc(a, 1, sizeof(*p9fdev));
- if (!p9fdev) {
- rc = -ENOMEM;
- goto out;
- }
-
- p9fdev->xendev = xendev;
- rc = p9front_xb_init(p9fdev);
- if (rc)
- goto out_free;
-
- uk_pr_info("Initialized 9pfront dev: tag=%s,maxrings=%d,maxorder=%d\n",
- p9fdev->tag, p9fdev->nb_max_rings, p9fdev->max_ring_page_order);
-
- p9fdev->nb_rings = MIN(CONFIG_LIBXEN_9PFRONT_NB_RINGS,
- p9fdev->nb_max_rings);
- p9fdev->ring_order = MIN(CONFIG_LIBXEN_9PFRONT_RING_ORDER,
- p9fdev->max_ring_page_order);
-
- rc = p9front_allocate_dev_rings(p9fdev);
- if (rc) {
- uk_pr_err(DRIVER_NAME": Could not initialize device rings: %d\n",
- rc);
- goto out_free;
- }
-
- rc = p9front_xb_connect(p9fdev);
- if (rc) {
- uk_pr_err(DRIVER_NAME": Could not connect: %d\n", rc);
- goto out_free_rings;
- }
-
- rc = 0;
- ukarch_spin_lock(&p9front_device_list_lock);
- uk_list_add(&p9fdev->_list, &p9front_device_list);
- ukarch_spin_unlock(&p9front_device_list_lock);
-
- uk_pr_info(DRIVER_NAME": Connected 9pfront dev: tag=%s,rings=%d,order=%d\n",
- p9fdev->tag, p9fdev->nb_rings, p9fdev->ring_order);
-
- goto out;
-
-out_free_rings:
- p9front_free_dev_rings(p9fdev);
-out_free:
- uk_free(a, p9fdev);
-out:
- return rc;
-}
-
-static const xenbus_dev_type_t p9front_devtypes[] = {
- xenbus_dev_9pfs,
-};
-
-static struct xenbus_driver p9front_driver = {
- .device_types = p9front_devtypes,
- .init = p9front_drv_init,
- .add_dev = p9front_add_dev
-};
-
-XENBUS_REGISTER_DRIVER(&p9front_driver);
+++ /dev/null
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Cristian Banu <cristb@gmail.com>
- *
- * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
-
-#ifndef __9PFRONT_H__
-#define __9PFRONT_H__
-
-#include <string.h>
-#include <uk/config.h>
-#include <uk/essentials.h>
-#include <uk/list.h>
-#include <uk/plat/spinlock.h>
-#if CONFIG_LIBUKSCHED
-#include <uk/sched.h>
-#endif
-#include <xen/io/9pfs.h>
-#include <common/events.h>
-#include <common/gnttab.h>
-
-struct p9front_dev_ring {
- /* Backpointer to the p9front device. */
- struct p9front_dev *dev;
- /* The 9pfs data interface, as dedfined by the xen headers. */
- struct xen_9pfs_data_intf *intf;
- /* The 9pfs data, as defined by the xen headers. */
- struct xen_9pfs_data data;
- /* The event channel for this ring. */
- evtchn_port_t evtchn;
- /* Grant reference for the interface. */
- grant_ref_t ref;
- /* Per-ring spinlock. */
- __spinlock spinlock;
- /* Tracks if this ring was initialized. */
- bool initialized;
-#if CONFIG_LIBUKSCHED
- /* Tracks if there is any data available on this ring. */
- bool data_avail;
- /* Bottom-half thread. */
- struct uk_thread *bh_thread;
- /* Bottom-half thread name. */
- char *bh_thread_name;
- /* Wait-queue on which the thread waits for available data. */
- struct uk_waitq bh_wq;
-#endif
-};
-
-struct p9front_dev {
- /* Xenbus device. */
- struct xenbus_device *xendev;
- /* 9P API device. */
- struct uk_9pdev *p9dev;
- /* Entry within the 9pfront device list. */
- struct uk_list_head _list;
- /* Number of maximum rings, read from xenstore. */
- int nb_max_rings;
- /* Maximum ring page order, read from xenstore. */
- int max_ring_page_order;
- /* Mount tag for this device, read from xenstore. */
- char *tag;
- /* Number of rings to use. */
- int nb_rings;
- /* Ring page order. */
- int ring_order;
- /* Device data rings. */
- struct p9front_dev_ring *rings;
-};
-
-#endif /* __9PFRONT_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Cristian Banu <cristb@gmail.com>
- *
- * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
-
-#ifndef __9PFRONT_XB_H__
-#define __9PFRONT_XB_H__
-
-#include "9pfront.h"
-
-/**
- * Reads device information from the xenstore, such as the mount tag
- * and details about the device rings.
- *
- * @param p9fdev
- * 9P frontend device
- * @return
- * - (0): Successful.
- * - (-EINVAL): Invalid data.
- * - (< 0): Error while reading.
- */
-int p9front_xb_init(struct p9front_dev *p9fdev);
-
-/**
- * Connects to the backend by setting up the communication between
- * frontend and backend.
- *
- * @param p9fdev
- * 9P frontend device
- * @return
- * - (0): Successful.
- * - (< 0): Error while committing XenStore transaction.
- */
-int p9front_xb_connect(struct p9front_dev *p9fdev);
-
-#endif /* __9PFRONT_XB_H__ */
+++ /dev/null
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Cristian Banu <cristb@gmail.com>
- *
- * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
- */
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <uk/config.h>
-#include <uk/assert.h>
-#include <uk/essentials.h>
-#include <uk/errptr.h>
-#include <uk/xenbus/xs.h>
-#include <uk/xenbus/client.h>
-
-#include "9pfront_xb.h"
-
-static int xs_read_backend_info(struct xenbus_device *xendev)
-{
- int rc, val;
- char *path = NULL;
-
- /* Read backend id. */
- rc = asprintf(&path, "%s/backend-id", xendev->nodename);
- if (rc <= 0) {
- uk_pr_err("Failed to allocate format path: %d\n", rc);
- goto out;
- }
-
- rc = xs_read_integer(XBT_NIL, path, &val);
- if (rc)
- goto out;
- xendev->otherend_id = (domid_t)val;
-
- /* Read backend path. */
- xendev->otherend = xs_read(XBT_NIL, xendev->nodename, "backend");
- if (PTRISERR(xendev->otherend)) {
- rc = PTR2ERR(xendev->otherend);
- xendev->otherend = NULL;
- }
-
-out:
- free(path);
- return rc;
-}
-
-static int xs_read_backend_ring_info(struct xenbus_device *xendev,
- int *nb_max_rings,
- int *max_ring_page_order)
-{
- int rc;
- char *int_str;
-
- /* Read max-rings. */
- int_str = xs_read(XBT_NIL, xendev->otherend, "max-rings");
- if (PTRISERR(int_str)) {
- rc = PTR2ERR(int_str);
- uk_pr_err("Error: %d\n", rc);
- goto out;
- }
-
- *nb_max_rings = strtol(int_str, NULL, 10);
- free(int_str);
-
- /* Read max-ring-page-order. */
- int_str = xs_read(XBT_NIL, xendev->otherend, "max-ring-page-order");
- if (PTRISERR(int_str)) {
- rc = PTR2ERR(int_str);
- uk_pr_err("Error: %d\n", rc);
- goto out;
- }
-
- *max_ring_page_order = strtol(int_str, NULL, 10);
- free(int_str);
- rc = 0;
-
-out:
- return rc;
-}
-
-int p9front_xb_init(struct p9front_dev *p9fdev)
-{
- struct xenbus_device *xendev;
- char *versions;
- int rc;
-
- UK_ASSERT(p9fdev != NULL);
-
- xendev = p9fdev->xendev;
- UK_ASSERT(xendev != NULL);
-
- /* Read backend node and backend id. */
- rc = xs_read_backend_info(xendev);
- if (rc) {
- uk_pr_err("Error initializing backend node and id.\n");
- goto out;
- }
-
- /* Check versions string. */
- versions = xs_read(XBT_NIL, xendev->otherend, "versions");
- if (PTRISERR(versions)) {
- uk_pr_err("Error reading backend version information.\n");
- rc = PTR2ERR(versions);
- goto out;
- }
-
- if (strcmp(versions, "1")) {
- uk_pr_err("Backend does not support xen protocol version 1.\n");
- free(versions);
- rc = -EINVAL;
- goto out;
- }
- free(versions);
-
- /* Read ring information. */
- rc = xs_read_backend_ring_info(xendev, &p9fdev->nb_max_rings,
- &p9fdev->max_ring_page_order);
- if (rc) {
- uk_pr_err("Error reading backend ring information.\n");
- goto out;
- }
-
- /* Read tag. */
- p9fdev->tag = xs_read(XBT_NIL, xendev->nodename, "tag");
- if (PTRISERR(p9fdev->tag)) {
- uk_pr_err("Error reading 9pfs mount tag.\n");
- rc = PTR2ERR(p9fdev->tag);
- p9fdev->tag = NULL;
- }
-
-out:
- return rc;
-}
-
-static int xs_write_ring(struct p9front_dev *p9fdev,
- int i,
- xenbus_transaction_t xbt)
-{
- struct xenbus_device *xendev = p9fdev->xendev;
- struct p9front_dev_ring *ring = &p9fdev->rings[i];
- char *path;
- int rc;
-
- rc = asprintf(&path, "ring-ref%u", i);
- if (rc < 0)
- goto out;
-
- rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->ref);
- if (rc < 0)
- goto out_path;
-
- free(path);
- rc = asprintf(&path, "event-channel-%u", i);
- if (rc < 0)
- goto out;
-
- rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->evtchn);
- if (rc < 0)
- goto out_path;
-
- rc = 0;
-
-out_path:
- free(path);
-out:
- return rc;
-}
-
-static void xs_delete_ring(struct p9front_dev *p9fdev,
- int i,
- xenbus_transaction_t xbt)
-{
- struct xenbus_device *xendev = p9fdev->xendev;
- int rc;
- char *path;
-
- rc = asprintf(&path, "%s/ring-ref%u", xendev->nodename, i);
- if (rc < 0)
- return;
- xs_rm(xbt, path);
- free(path);
-
- rc = asprintf(&path, "%s/event-channel-%u", xendev->nodename, i);
- if (rc < 0)
- return;
- xs_rm(xbt, path);
- free(path);
-}
-
-static int p9front_xb_front_init(struct p9front_dev *p9fdev,
- xenbus_transaction_t xbt)
-{
- int i, rc;
- struct xenbus_device *xendev = p9fdev->xendev;
-
- /*
- * Assert that the p9fdev ring information has been properly
- * configured before attempting to connect.
- */
- UK_ASSERT(p9fdev->nb_rings != 0 && p9fdev->nb_rings <= 9);
- UK_ASSERT(p9fdev->ring_order != 0);
-
- /*
- * Assert that the p9fdev rings have been initialized.
- */
- UK_ASSERT(p9fdev->rings != NULL);
-
- /* Write version... */
- rc = xs_printf(xbt, xendev->nodename, "version", "%u", 1);
- if (rc < 0)
- goto out;
-
- /* ... and num-rings... */
- rc = xs_printf(xbt, xendev->nodename, "num-rings", "%u",
- p9fdev->nb_rings);
- if (rc < 0)
- goto out;
-
- /* ... and each ring. */
- for (i = 0; i < p9fdev->nb_rings; i++) {
- rc = xs_write_ring(p9fdev, i, xbt);
- if (rc)
- goto out;
- }
-
-out:
- return rc;
-}
-
-static void p9front_xb_front_fini(struct p9front_dev *p9fdev,
- xenbus_transaction_t xbt)
-{
- int i;
-
- for (i = 0; i < p9fdev->nb_rings; i++)
- xs_delete_ring(p9fdev, i, xbt);
-}
-
-static int be_watch_start(struct xenbus_device *xendev, const char *path)
-{
- struct xenbus_watch *watch;
-
- watch = xs_watch_path(XBT_NIL, path);
- if (PTRISERR(watch))
- return PTR2ERR(watch);
-
- xendev->otherend_watch = watch;
-
- return 0;
-}
-
-static int be_watch_stop(struct xenbus_device *xendev)
-{
- return xs_unwatch(XBT_NIL, xendev->otherend_watch);
-}
-
-#define WAIT_BE_STATE_CHANGE_WHILE_COND(state_cond) \
- do { \
- rc = xs_read_integer(XBT_NIL, be_state_path, \
- (int *) &be_state); \
- if (rc) \
- goto out; \
- while (!rc && (state_cond)) \
- rc = uk_xenbus_wait_for_state_change(be_state_path, \
- &be_state, xendev->otherend_watch); \
- if (rc) \
- goto out; \
- } while (0)
-
-static int p9front_xb_wait_be_connect(struct p9front_dev *p9fdev)
-{
- struct xenbus_device *xendev = p9fdev->xendev;
- char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
- XenbusState be_state;
- int rc;
-
- sprintf(be_state_path, "%s/state", xendev->otherend);
-
- rc = be_watch_start(xendev, be_state_path);
- if (rc)
- goto out;
-
- WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateConnected);
-
- if (be_state != XenbusStateConnected) {
- uk_pr_err("Backend not available, state=%s\n",
- uk_xenbus_state_to_str(be_state));
- be_watch_stop(xendev);
- goto out;
- }
-
- rc = uk_xenbus_switch_state(XBT_NIL, xendev, XenbusStateConnected);
- if (rc)
- goto out;
-
-out:
- return rc;
-}
-
-int p9front_xb_connect(struct p9front_dev *p9fdev)
-{
- struct xenbus_device *xendev;
- xenbus_transaction_t xbt;
- int rc;
-
- UK_ASSERT(p9fdev != NULL);
-
- xendev = p9fdev->xendev;
- UK_ASSERT(xendev != NULL);
-
-again:
- rc = xs_transaction_start(&xbt);
- if (rc)
- goto abort_transaction;
-
- rc = p9front_xb_front_init(p9fdev, xbt);
- if (rc)
- goto abort_transaction;
-
- rc = uk_xenbus_switch_state(xbt, xendev, XenbusStateInitialised);
- if (rc)
- goto abort_transaction;
-
- rc = xs_transaction_end(xbt, 0);
- if (rc == -EAGAIN)
- goto again;
-
- rc = p9front_xb_wait_be_connect(p9fdev);
- if (rc)
- p9front_xb_front_fini(p9fdev, XBT_NIL);
-
- return rc;
-
-abort_transaction:
- xs_transaction_end(xbt, 1);
- return rc;
-}
+++ /dev/null
-menuconfig LIBXEN_9PFRONT
- bool "Xenbus 9pfront Driver"
- select LIBXENBUS
- select LIBXENHEADERS
- depends on PLAT_XEN
- depends on LIBUK9P
- help
- Driver for 9pfs devices
-
-config LIBXEN_9PFRONT_NB_RINGS
- int "Xen 9P ring number"
- default 2
- depends on LIBXEN_9PFRONT
- help
- Number of rings to allocate.
- Will be clamped to the maximum value allowed by the backend.
-
-config LIBXEN_9PFRONT_RING_ORDER
- int "Xen 9P ring order"
- default 6
- depends on LIBXEN_9PFRONT
- help
- Ring order for xen 9P devices. Orders of 0, 1, 2, ..., 9 will
- create rings of size 4K, 8K, 16K, ..., 2M respectively.
- Will be clamped to the maximum value allowed by the backend.
+++ /dev/null
-$(eval $(call addlib_s,libxen9pfront,$(CONFIG_LIBXEN_9PFRONT)))
-
-LIBXEN9PFRONT_CFLAGS-y += $(LIBXENPLAT_CFLAGS-y)
-LIBXEN9PFRONT_CINCLUDES-y += $(LIBXENPLAT_CINCLUDES-y)
-LIBXEN9PFRONT_CINCLUDES-y += $(LIBXENBUS_CINCLUDES-y)
-LIBXEN9PFRONT_SRCS-y += $(LIBXEN9PFRONT_BASE)/9pfront.c
-LIBXEN9PFRONT_SRCS-y += $(LIBXEN9PFRONT_BASE)/9pfront_xs.c
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@gmail.com>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ */
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <uk/config.h>
+#include <uk/alloc.h>
+#include <uk/assert.h>
+#include <uk/essentials.h>
+#include <uk/errptr.h>
+#include <uk/list.h>
+#if CONFIG_LIBUKSCHED
+#include <uk/thread.h>
+#endif
+#include <uk/9pdev.h>
+#include <uk/9preq.h>
+#include <uk/9pdev_trans.h>
+#include <uk/plat/spinlock.h>
+#if defined(__i386__) || defined(__x86_64__)
+#include <xen-x86/mm.h>
+#include <xen-x86/irq.h>
+#elif defined(__aarch64__)
+#include <xen-arm/mm.h>
+#else
+#error "Unsupported architecture"
+#endif
+#include <uk/xenbus/xenbus.h>
+
+#include "9pfront_xb.h"
+
+#define DRIVER_NAME "xen-9pfront"
+
+static struct uk_alloc *a;
+static UK_LIST_HEAD(p9front_device_list);
+static __spinlock p9front_device_list_lock;
+
+struct p9front_header {
+ uint32_t size;
+ uint8_t type;
+ uint16_t tag;
+} __packed;
+
+static void p9front_recv(struct p9front_dev_ring *ring);
+
+#if CONFIG_LIBUKSCHED
+
+static __noreturn void p9front_bh_handler(void *arg)
+{
+ struct p9front_dev_ring *ring = arg;
+
+ while (1) {
+ uk_waitq_wait_event(&ring->bh_wq,
+ UK_READ_ONCE(ring->data_avail));
+ p9front_recv(ring);
+ }
+}
+
+#endif
+
+static void p9front_recv(struct p9front_dev_ring *ring)
+{
+ struct p9front_dev *p9fdev = ring->dev;
+ evtchn_port_t evtchn = ring->evtchn;
+ RING_IDX cons, prod, masked_cons, masked_prod;
+ int ring_size, rc;
+ struct p9front_header hdr;
+ struct uk_9preq *req;
+ uint32_t buf_cnt, zc_buf_cnt;
+
+ ring_size = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
+
+ while (1) {
+ cons = ring->intf->in_cons;
+ prod = ring->intf->in_prod;
+ xen_rmb();
+
+ if (xen_9pfs_queued(prod, cons, ring_size) < sizeof(hdr)) {
+#if CONFIG_LIBUKSCHED
+ UK_WRITE_ONCE(ring->data_avail, false);
+#endif
+ notify_remote_via_evtchn(evtchn);
+ return;
+ }
+
+ masked_prod = xen_9pfs_mask(prod, ring_size);
+ masked_cons = xen_9pfs_mask(cons, ring_size);
+
+ xen_9pfs_read_packet(&hdr, ring->data.in, sizeof(hdr),
+ masked_prod, &masked_cons, ring_size);
+
+ req = uk_9pdev_req_lookup(p9fdev->p9dev, hdr.tag);
+ if (PTRISERR(req)) {
+ uk_pr_warn("Found invalid tag=%u\n", hdr.tag);
+ cons += hdr.size;
+ xen_mb();
+ ring->intf->in_cons = cons;
+ continue;
+ }
+
+ masked_cons = xen_9pfs_mask(cons, ring_size);
+
+ /*
+ * Compute amount of data to read into request buffer and into
+ * zero-copy buffer.
+ */
+ buf_cnt = hdr.size;
+ if (hdr.type != UK_9P_RERROR && req->recv.zc_buf)
+ buf_cnt = MIN(buf_cnt, req->recv.zc_offset);
+ zc_buf_cnt = hdr.size - buf_cnt;
+
+ xen_9pfs_read_packet(req->recv.buf, ring->data.in, buf_cnt,
+ masked_prod, &masked_cons, ring_size);
+ xen_9pfs_read_packet(req->recv.zc_buf, ring->data.in,
+ zc_buf_cnt, masked_prod, &masked_cons,
+ ring_size);
+ cons += hdr.size;
+ xen_mb();
+ ring->intf->in_cons = cons;
+
+ rc = uk_9preq_receive_cb(req, hdr.size);
+ if (rc)
+ uk_pr_warn("Could not receive reply: %d\n", rc);
+
+ /* Release reference held by uk_9pdev_req_lookup(). */
+ uk_9preq_put(req);
+ }
+}
+
+static void p9front_handler(evtchn_port_t evtchn,
+ struct __regs *regs __unused,
+ void *arg)
+{
+ struct p9front_dev_ring *ring = arg;
+
+ UK_ASSERT(ring);
+ UK_ASSERT(ring->evtchn == evtchn);
+
+ /*
+ * A new interrupt means that there is a response to be received, which
+ * means that a previously sent request has been removed from the out
+ * ring. Thus, the API can be notified of the possibility of retrying to
+ * send requests blocked on ENOSPC errors.
+ */
+ if (ring->dev->p9dev)
+ uk_9pdev_xmit_notify(ring->dev->p9dev);
+#if CONFIG_LIBUKSCHED
+ UK_WRITE_ONCE(ring->data_avail, true);
+ uk_waitq_wake_up(&ring->bh_wq);
+#else
+ p9front_recv(ring);
+#endif
+}
+
+static void p9front_free_dev_ring(struct p9front_dev *p9fdev, int idx)
+{
+ struct p9front_dev_ring *ring = &p9fdev->rings[idx];
+ int i;
+
+ UK_ASSERT(ring->initialized);
+
+ if (ring->bh_thread_name)
+ free(ring->bh_thread_name);
+ uk_sched_thread_terminate(ring->bh_thread);
+ unbind_evtchn(ring->evtchn);
+ for (i = 0; i < (1 << p9fdev->ring_order); i++)
+ gnttab_end_access(ring->intf->ref[i]);
+ uk_pfree(a, ring->data.in,
+ 1ul << (p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT));
+ gnttab_end_access(ring->ref);
+ uk_pfree(a, ring->intf, 1);
+ ring->initialized = false;
+}
+
+static void p9front_free_dev_rings(struct p9front_dev *p9fdev)
+{
+ int i;
+
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ if (!p9fdev->rings[i].initialized)
+ continue;
+ p9front_free_dev_ring(p9fdev, i);
+ }
+
+ uk_free(a, p9fdev->rings);
+}
+
+static int p9front_allocate_dev_ring(struct p9front_dev *p9fdev, int idx)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ struct p9front_dev_ring *ring;
+ int rc, i;
+ void *data_bytes;
+
+ /* Sanity checks. */
+ UK_ASSERT(idx >= 0 && idx < p9fdev->nb_rings);
+
+ ring = &p9fdev->rings[idx];
+ UK_ASSERT(!ring->initialized);
+
+ ukarch_spin_init(&ring->spinlock);
+ ring->dev = p9fdev;
+
+ /* Allocate ring intf page. */
+ ring->intf = uk_palloc(a, 1);
+ if (!ring->intf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ring->intf, 0, PAGE_SIZE);
+
+ /* Grant access to the allocated page to the backend. */
+ ring->ref = gnttab_grant_access(xendev->otherend_id,
+ virt_to_mfn(ring->intf), 0);
+ UK_ASSERT(ring->ref != GRANT_INVALID_REF);
+
+ /* Allocate memory for the data. */
+ data_bytes = uk_palloc(a, 1ul << (p9fdev->ring_order +
+ XEN_PAGE_SHIFT - PAGE_SHIFT));
+ if (!data_bytes) {
+ rc = -ENOMEM;
+ goto out_free_intf;
+ }
+ memset(data_bytes, 0, XEN_FLEX_RING_SIZE(p9fdev->ring_order) * 2);
+
+ /* Grant refs to the entire data. */
+ for (i = 0; i < (1 << p9fdev->ring_order); i++) {
+ ring->intf->ref[i] = gnttab_grant_access(xendev->otherend_id,
+ virt_to_mfn(data_bytes) + i, 0);
+ UK_ASSERT(ring->intf->ref[i] != GRANT_INVALID_REF);
+ }
+
+ ring->intf->ring_order = p9fdev->ring_order;
+ ring->data.in = data_bytes;
+ ring->data.out = data_bytes + XEN_FLEX_RING_SIZE(p9fdev->ring_order);
+
+#if CONFIG_LIBUKSCHED
+ /* Allocate bottom-half thread. */
+ ring->data_avail = false;
+ uk_waitq_init(&ring->bh_wq);
+
+ rc = asprintf(&ring->bh_thread_name, DRIVER_NAME"-recv-%s-%u",
+ p9fdev->tag, idx);
+ ring->bh_thread = uk_sched_thread_create(uk_sched_current(),
+ p9front_bh_handler, ring,
+ ring->bh_thread_name);
+ if (PTRISERR(ring->bh_thread)) {
+ rc = PTR2ERR(ring->bh_thread);
+ ring->bh_thread = NULL;
+ goto out_free_grants;
+ }
+#endif
+
+ /* Allocate event channel. */
+ rc = evtchn_alloc_unbound(xendev->otherend_id, p9front_handler, ring,
+ &ring->evtchn);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Error creating evt channel: %d\n", rc);
+ goto out_free_thread;
+ }
+
+ unmask_evtchn(ring->evtchn);
+
+ /* Mark ring as initialized. */
+ ring->initialized = true;
+
+ return 0;
+
+out_free_thread:
+ if (ring->bh_thread_name)
+ free(ring->bh_thread_name);
+ uk_sched_thread_terminate(ring->bh_thread);
+out_free_grants:
+ for (i = 0; i < (1 << p9fdev->ring_order); i++)
+ gnttab_end_access(ring->intf->ref[i]);
+ uk_pfree(a, data_bytes,
+ 1ul << (p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT));
+out_free_intf:
+ gnttab_end_access(ring->ref);
+ uk_pfree(a, ring->intf, 1);
+out:
+ return rc;
+}
+
+static int p9front_allocate_dev_rings(struct p9front_dev *p9fdev)
+{
+ int rc, i;
+
+ p9fdev->rings = uk_calloc(a, p9fdev->nb_rings, sizeof(*p9fdev->rings));
+ if (!p9fdev->rings) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ rc = p9front_allocate_dev_ring(p9fdev, i);
+ if (rc)
+ goto out_free;
+ }
+
+ return 0;
+
+out_free:
+ p9front_free_dev_rings(p9fdev);
+out:
+ return rc;
+}
+
+static int p9front_connect(struct uk_9pdev *p9dev,
+ const char *device_identifier,
+ const char *mount_args __unused)
+{
+ struct p9front_dev *p9fdev = NULL;
+ int rc = 0;
+ int found = 0;
+
+ ukarch_spin_lock(&p9front_device_list_lock);
+ uk_list_for_each_entry(p9fdev, &p9front_device_list, _list) {
+ if (!strcmp(p9fdev->tag, device_identifier)) {
+ if (p9fdev->p9dev != NULL) {
+ rc = -EBUSY;
+ goto out;
+ }
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ rc = -ENODEV;
+ goto out;
+ }
+
+ /* The msize is given by the size of the flex ring. */
+ p9dev->max_msize = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
+
+ p9fdev->p9dev = p9dev;
+ p9dev->priv = p9fdev;
+ rc = 0;
+ found = 1;
+
+out:
+ ukarch_spin_unlock(&p9front_device_list_lock);
+ return rc;
+}
+
+static int p9front_disconnect(struct uk_9pdev *p9dev __unused)
+{
+ struct p9front_dev *p9fdev;
+
+ UK_ASSERT(p9dev);
+ p9fdev = p9dev->priv;
+
+ ukarch_spin_lock(&p9front_device_list_lock);
+ p9fdev->p9dev = NULL;
+ ukarch_spin_unlock(&p9front_device_list_lock);
+
+ return 0;
+}
+
+static int p9front_request(struct uk_9pdev *p9dev,
+ struct uk_9preq *req)
+{
+ struct p9front_dev *p9fdev;
+ struct p9front_dev_ring *ring;
+ int ring_idx, ring_size;
+ RING_IDX masked_prod, masked_cons, prod, cons;
+
+ UK_ASSERT(p9dev);
+ UK_ASSERT(req);
+ UK_ASSERT(req->state == UK_9PREQ_READY);
+
+ p9fdev = p9dev->priv;
+
+ ring_size = XEN_FLEX_RING_SIZE(p9fdev->ring_order);
+
+ ring_idx = req->tag % p9fdev->nb_rings;
+ ring = &p9fdev->rings[ring_idx];
+
+ /* Protect against concurrent writes to the out ring. */
+ ukarch_spin_lock(&ring->spinlock);
+ cons = ring->intf->out_cons;
+ prod = ring->intf->out_prod;
+ xen_mb();
+
+ masked_prod = xen_9pfs_mask(prod, ring_size);
+ masked_cons = xen_9pfs_mask(cons, ring_size);
+
+ if (ring_size - xen_9pfs_queued(prod, cons, ring_size) <
+ req->xmit.size + req->xmit.zc_size) {
+ ukarch_spin_unlock(&ring->spinlock);
+ return -ENOSPC;
+ }
+
+ xen_9pfs_write_packet(ring->data.out, req->xmit.buf, req->xmit.size,
+ &masked_prod, masked_cons, ring_size);
+ xen_9pfs_write_packet(ring->data.out, req->xmit.zc_buf, req->xmit.zc_size,
+ &masked_prod, masked_cons, ring_size);
+ req->state = UK_9PREQ_SENT;
+ xen_wmb();
+ prod += req->xmit.size + req->xmit.zc_size;
+ ring->intf->out_prod = prod;
+
+ ukarch_spin_unlock(&ring->spinlock);
+ notify_remote_via_evtchn(ring->evtchn);
+
+ return 0;
+}
+
+static const struct uk_9pdev_trans_ops p9front_trans_ops = {
+ .connect = p9front_connect,
+ .disconnect = p9front_disconnect,
+ .request = p9front_request
+};
+
+static struct uk_9pdev_trans p9front_trans = {
+ .name = "xen",
+ .ops = &p9front_trans_ops,
+ .a = NULL /* Set below. */
+};
+
+
+static int p9front_drv_init(struct uk_alloc *drv_allocator)
+{
+ if (!drv_allocator)
+ return -EINVAL;
+
+ a = drv_allocator;
+ p9front_trans.a = a;
+
+ return uk_9pdev_trans_register(&p9front_trans);
+}
+
+static int p9front_add_dev(struct xenbus_device *xendev)
+{
+ struct p9front_dev *p9fdev;
+ int rc;
+
+ p9fdev = uk_calloc(a, 1, sizeof(*p9fdev));
+ if (!p9fdev) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p9fdev->xendev = xendev;
+ rc = p9front_xb_init(p9fdev);
+ if (rc)
+ goto out_free;
+
+ uk_pr_info("Initialized 9pfront dev: tag=%s,maxrings=%d,maxorder=%d\n",
+ p9fdev->tag, p9fdev->nb_max_rings, p9fdev->max_ring_page_order);
+
+ p9fdev->nb_rings = MIN(CONFIG_LIB9PFRONT_NB_RINGS,
+ p9fdev->nb_max_rings);
+ p9fdev->ring_order = MIN(CONFIG_LIB9PFRONT_RING_ORDER,
+ p9fdev->max_ring_page_order);
+
+ rc = p9front_allocate_dev_rings(p9fdev);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Could not initialize device rings: %d\n",
+ rc);
+ goto out_free;
+ }
+
+ rc = p9front_xb_connect(p9fdev);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Could not connect: %d\n", rc);
+ goto out_free_rings;
+ }
+
+ rc = 0;
+ ukarch_spin_lock(&p9front_device_list_lock);
+ uk_list_add(&p9fdev->_list, &p9front_device_list);
+ ukarch_spin_unlock(&p9front_device_list_lock);
+
+ uk_pr_info(DRIVER_NAME": Connected 9pfront dev: tag=%s,rings=%d,order=%d\n",
+ p9fdev->tag, p9fdev->nb_rings, p9fdev->ring_order);
+
+ goto out;
+
+out_free_rings:
+ p9front_free_dev_rings(p9fdev);
+out_free:
+ uk_free(a, p9fdev);
+out:
+ return rc;
+}
+
+static const xenbus_dev_type_t p9front_devtypes[] = {
+ xenbus_dev_9pfs,
+};
+
+static struct xenbus_driver p9front_driver = {
+ .device_types = p9front_devtypes,
+ .init = p9front_drv_init,
+ .add_dev = p9front_add_dev
+};
+
+XENBUS_REGISTER_DRIVER(&p9front_driver);
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@gmail.com>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ */
+
+#ifndef __9PFRONT_H__
+#define __9PFRONT_H__
+
+#include <string.h>
+#include <uk/config.h>
+#include <uk/essentials.h>
+#include <uk/list.h>
+#include <uk/plat/spinlock.h>
+#if CONFIG_LIBUKSCHED
+#include <uk/sched.h>
+#endif
+#include <xen/io/9pfs.h>
+#include <common/events.h>
+#include <common/gnttab.h>
+
+struct p9front_dev_ring {
+ /* Backpointer to the p9front device. */
+ struct p9front_dev *dev;
+ /* The 9pfs data interface, as dedfined by the xen headers. */
+ struct xen_9pfs_data_intf *intf;
+ /* The 9pfs data, as defined by the xen headers. */
+ struct xen_9pfs_data data;
+ /* The event channel for this ring. */
+ evtchn_port_t evtchn;
+ /* Grant reference for the interface. */
+ grant_ref_t ref;
+ /* Per-ring spinlock. */
+ __spinlock spinlock;
+ /* Tracks if this ring was initialized. */
+ bool initialized;
+#if CONFIG_LIBUKSCHED
+ /* Tracks if there is any data available on this ring. */
+ bool data_avail;
+ /* Bottom-half thread. */
+ struct uk_thread *bh_thread;
+ /* Bottom-half thread name. */
+ char *bh_thread_name;
+ /* Wait-queue on which the thread waits for available data. */
+ struct uk_waitq bh_wq;
+#endif
+};
+
+struct p9front_dev {
+ /* Xenbus device. */
+ struct xenbus_device *xendev;
+ /* 9P API device. */
+ struct uk_9pdev *p9dev;
+ /* Entry within the 9pfront device list. */
+ struct uk_list_head _list;
+ /* Number of maximum rings, read from xenstore. */
+ int nb_max_rings;
+ /* Maximum ring page order, read from xenstore. */
+ int max_ring_page_order;
+ /* Mount tag for this device, read from xenstore. */
+ char *tag;
+ /* Number of rings to use. */
+ int nb_rings;
+ /* Ring page order. */
+ int ring_order;
+ /* Device data rings. */
+ struct p9front_dev_ring *rings;
+};
+
+#endif /* __9PFRONT_H__ */
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@gmail.com>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ */
+
+#ifndef __9PFRONT_XB_H__
+#define __9PFRONT_XB_H__
+
+#include "9pfront.h"
+
+/**
+ * Reads device information from the xenstore, such as the mount tag
+ * and details about the device rings.
+ *
+ * @param p9fdev
+ * 9P frontend device
+ * @return
+ * - (0): Successful.
+ * - (-EINVAL): Invalid data.
+ * - (< 0): Error while reading.
+ */
+int p9front_xb_init(struct p9front_dev *p9fdev);
+
+/**
+ * Connects to the backend by setting up the communication between
+ * frontend and backend.
+ *
+ * @param p9fdev
+ * 9P frontend device
+ * @return
+ * - (0): Successful.
+ * - (< 0): Error while committing XenStore transaction.
+ */
+int p9front_xb_connect(struct p9front_dev *p9fdev);
+
+#endif /* __9PFRONT_XB_H__ */
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Cristian Banu <cristb@gmail.com>
+ *
+ * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <uk/config.h>
+#include <uk/assert.h>
+#include <uk/essentials.h>
+#include <uk/errptr.h>
+#include <uk/xenbus/xs.h>
+#include <uk/xenbus/client.h>
+
+#include "9pfront_xb.h"
+
+static int xs_read_backend_info(struct xenbus_device *xendev)
+{
+ int rc, val;
+ char *path = NULL;
+
+ /* Read backend id. */
+ rc = asprintf(&path, "%s/backend-id", xendev->nodename);
+ if (rc <= 0) {
+ uk_pr_err("Failed to allocate format path: %d\n", rc);
+ goto out;
+ }
+
+ rc = xs_read_integer(XBT_NIL, path, &val);
+ if (rc)
+ goto out;
+ xendev->otherend_id = (domid_t)val;
+
+ /* Read backend path. */
+ xendev->otherend = xs_read(XBT_NIL, xendev->nodename, "backend");
+ if (PTRISERR(xendev->otherend)) {
+ rc = PTR2ERR(xendev->otherend);
+ xendev->otherend = NULL;
+ }
+
+out:
+ free(path);
+ return rc;
+}
+
+static int xs_read_backend_ring_info(struct xenbus_device *xendev,
+ int *nb_max_rings,
+ int *max_ring_page_order)
+{
+ int rc;
+ char *int_str;
+
+ /* Read max-rings. */
+ int_str = xs_read(XBT_NIL, xendev->otherend, "max-rings");
+ if (PTRISERR(int_str)) {
+ rc = PTR2ERR(int_str);
+ uk_pr_err("Error: %d\n", rc);
+ goto out;
+ }
+
+ *nb_max_rings = strtol(int_str, NULL, 10);
+ free(int_str);
+
+ /* Read max-ring-page-order. */
+ int_str = xs_read(XBT_NIL, xendev->otherend, "max-ring-page-order");
+ if (PTRISERR(int_str)) {
+ rc = PTR2ERR(int_str);
+ uk_pr_err("Error: %d\n", rc);
+ goto out;
+ }
+
+ *max_ring_page_order = strtol(int_str, NULL, 10);
+ free(int_str);
+ rc = 0;
+
+out:
+ return rc;
+}
+
+int p9front_xb_init(struct p9front_dev *p9fdev)
+{
+ struct xenbus_device *xendev;
+ char *versions;
+ int rc;
+
+ UK_ASSERT(p9fdev != NULL);
+
+ xendev = p9fdev->xendev;
+ UK_ASSERT(xendev != NULL);
+
+ /* Read backend node and backend id. */
+ rc = xs_read_backend_info(xendev);
+ if (rc) {
+ uk_pr_err("Error initializing backend node and id.\n");
+ goto out;
+ }
+
+ /* Check versions string. */
+ versions = xs_read(XBT_NIL, xendev->otherend, "versions");
+ if (PTRISERR(versions)) {
+ uk_pr_err("Error reading backend version information.\n");
+ rc = PTR2ERR(versions);
+ goto out;
+ }
+
+ if (strcmp(versions, "1")) {
+ uk_pr_err("Backend does not support xen protocol version 1.\n");
+ free(versions);
+ rc = -EINVAL;
+ goto out;
+ }
+ free(versions);
+
+ /* Read ring information. */
+ rc = xs_read_backend_ring_info(xendev, &p9fdev->nb_max_rings,
+ &p9fdev->max_ring_page_order);
+ if (rc) {
+ uk_pr_err("Error reading backend ring information.\n");
+ goto out;
+ }
+
+ /* Read tag. */
+ p9fdev->tag = xs_read(XBT_NIL, xendev->nodename, "tag");
+ if (PTRISERR(p9fdev->tag)) {
+ uk_pr_err("Error reading 9pfs mount tag.\n");
+ rc = PTR2ERR(p9fdev->tag);
+ p9fdev->tag = NULL;
+ }
+
+out:
+ return rc;
+}
+
+static int xs_write_ring(struct p9front_dev *p9fdev,
+ int i,
+ xenbus_transaction_t xbt)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ struct p9front_dev_ring *ring = &p9fdev->rings[i];
+ char *path;
+ int rc;
+
+ rc = asprintf(&path, "ring-ref%u", i);
+ if (rc < 0)
+ goto out;
+
+ rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->ref);
+ if (rc < 0)
+ goto out_path;
+
+ free(path);
+ rc = asprintf(&path, "event-channel-%u", i);
+ if (rc < 0)
+ goto out;
+
+ rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->evtchn);
+ if (rc < 0)
+ goto out_path;
+
+ rc = 0;
+
+out_path:
+ free(path);
+out:
+ return rc;
+}
+
+static void xs_delete_ring(struct p9front_dev *p9fdev,
+ int i,
+ xenbus_transaction_t xbt)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ int rc;
+ char *path;
+
+ rc = asprintf(&path, "%s/ring-ref%u", xendev->nodename, i);
+ if (rc < 0)
+ return;
+ xs_rm(xbt, path);
+ free(path);
+
+ rc = asprintf(&path, "%s/event-channel-%u", xendev->nodename, i);
+ if (rc < 0)
+ return;
+ xs_rm(xbt, path);
+ free(path);
+}
+
+static int p9front_xb_front_init(struct p9front_dev *p9fdev,
+ xenbus_transaction_t xbt)
+{
+ int i, rc;
+ struct xenbus_device *xendev = p9fdev->xendev;
+
+ /*
+ * Assert that the p9fdev ring information has been properly
+ * configured before attempting to connect.
+ */
+ UK_ASSERT(p9fdev->nb_rings != 0 && p9fdev->nb_rings <= 9);
+ UK_ASSERT(p9fdev->ring_order != 0);
+
+ /*
+ * Assert that the p9fdev rings have been initialized.
+ */
+ UK_ASSERT(p9fdev->rings != NULL);
+
+ /* Write version... */
+ rc = xs_printf(xbt, xendev->nodename, "version", "%u", 1);
+ if (rc < 0)
+ goto out;
+
+ /* ... and num-rings... */
+ rc = xs_printf(xbt, xendev->nodename, "num-rings", "%u",
+ p9fdev->nb_rings);
+ if (rc < 0)
+ goto out;
+
+ /* ... and each ring. */
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ rc = xs_write_ring(p9fdev, i, xbt);
+ if (rc)
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+static void p9front_xb_front_fini(struct p9front_dev *p9fdev,
+ xenbus_transaction_t xbt)
+{
+ int i;
+
+ for (i = 0; i < p9fdev->nb_rings; i++)
+ xs_delete_ring(p9fdev, i, xbt);
+}
+
+static int be_watch_start(struct xenbus_device *xendev, const char *path)
+{
+ struct xenbus_watch *watch;
+
+ watch = xs_watch_path(XBT_NIL, path);
+ if (PTRISERR(watch))
+ return PTR2ERR(watch);
+
+ xendev->otherend_watch = watch;
+
+ return 0;
+}
+
+static int be_watch_stop(struct xenbus_device *xendev)
+{
+ return xs_unwatch(XBT_NIL, xendev->otherend_watch);
+}
+
+#define WAIT_BE_STATE_CHANGE_WHILE_COND(state_cond) \
+ do { \
+ rc = xs_read_integer(XBT_NIL, be_state_path, \
+ (int *) &be_state); \
+ if (rc) \
+ goto out; \
+ while (!rc && (state_cond)) \
+ rc = uk_xenbus_wait_for_state_change(be_state_path, \
+ &be_state, xendev->otherend_watch); \
+ if (rc) \
+ goto out; \
+ } while (0)
+
+static int p9front_xb_wait_be_connect(struct p9front_dev *p9fdev)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
+ XenbusState be_state;
+ int rc;
+
+ sprintf(be_state_path, "%s/state", xendev->otherend);
+
+ rc = be_watch_start(xendev, be_state_path);
+ if (rc)
+ goto out;
+
+ WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateConnected);
+
+ if (be_state != XenbusStateConnected) {
+ uk_pr_err("Backend not available, state=%s\n",
+ uk_xenbus_state_to_str(be_state));
+ be_watch_stop(xendev);
+ goto out;
+ }
+
+ rc = uk_xenbus_switch_state(XBT_NIL, xendev, XenbusStateConnected);
+ if (rc)
+ goto out;
+
+out:
+ return rc;
+}
+
+int p9front_xb_connect(struct p9front_dev *p9fdev)
+{
+ struct xenbus_device *xendev;
+ xenbus_transaction_t xbt;
+ int rc;
+
+ UK_ASSERT(p9fdev != NULL);
+
+ xendev = p9fdev->xendev;
+ UK_ASSERT(xendev != NULL);
+
+again:
+ rc = xs_transaction_start(&xbt);
+ if (rc)
+ goto abort_transaction;
+
+ rc = p9front_xb_front_init(p9fdev, xbt);
+ if (rc)
+ goto abort_transaction;
+
+ rc = uk_xenbus_switch_state(xbt, xendev, XenbusStateInitialised);
+ if (rc)
+ goto abort_transaction;
+
+ rc = xs_transaction_end(xbt, 0);
+ if (rc == -EAGAIN)
+ goto again;
+
+ rc = p9front_xb_wait_be_connect(p9fdev);
+ if (rc)
+ p9front_xb_front_fini(p9fdev, XBT_NIL);
+
+ return rc;
+
+abort_transaction:
+ xs_transaction_end(xbt, 1);
+ return rc;
+}
--- /dev/null
+menuconfig LIB9PFRONT
+ bool "9pfront: Xen 9pfs volumes"
+ select LIBXENBUS
+ select LIBXENHEADERS
+ depends on PLAT_XEN
+ depends on LIBUK9P
+ help
+ Xen driver for 9pfs volumes
+
+if LIB9PFRONT
+config LIB9PFRONT_NB_RINGS
+ int "Number of rings"
+ default 2
+ help
+ Number of rings to allocate.
+ Will be clamped to the maximum value allowed by the backend.
+
+config LIB9PFRONT_RING_ORDER
+ int "Ring size order"
+ default 6
+ help
+ Ring order for xen 9P devices. Orders of 0, 1, 2, ..., 9 will
+ create rings of size 4K, 8K, 16K, ..., 2M respectively.
+ Will be clamped to the maximum value allowed by the backend.
+endif
--- /dev/null
+$(eval $(call addlib_s,lib9pfront,$(CONFIG_LIB9PFRONT)))
+
+# FIXME: Extra includes should be removed
+LIB9PFRONT_CFLAGS-y += $(LIBXENPLAT_CFLAGS-y)
+LIB9PFRONT_CINCLUDES-y += $(LIBXENPLAT_CINCLUDES-y)
+LIB9PFRONT_CINCLUDES-y += $(LIBXENBUS_CINCLUDES-y)
+LIB9PFRONT_SRCS-y += $(LIB9PFRONT_BASE)/9pfront.c
+LIB9PFRONT_SRCS-y += $(LIB9PFRONT_BASE)/9pfront_xs.c
--- /dev/null
+# No public symbols
UK_DRIV_XEN_BASE := $(UK_DRIV_BASE)/xen
$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/xenheaders))
-$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/9p))
+$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/9pfront))
$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/blk))
$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/net))
$(eval $(call import_lib,$(UK_DRIV_XEN_BASE)/xenbus))
select HAVE_INTCTLR
imply LIBUKINTCTLR_GICV3 if ARCH_ARM_64
imply LIBXEN_NETFRONT if LIBUKNETDEV
- imply LIBXEN_9PFRONT if LIBUK9P
+ imply LIB9PFRONT if LIBUK9P
imply LIBXEN_BLKFRONT if LIBUKBLKDEV
imply LIBXEN_CONSOLE
help