@@ -141,7 +141,7 @@ do_uml_steps: &do_uml_steps
if [ $CIRCLE_STAGE = "i386_uml" ] || [ $CIRCLE_STAGE = "i386_uml_on_x86_64" ]; then
exit 0
fi
- ./linux rootfstype=hostfs ro mem=1g loglevel=10 init="/bin/bash -c exit" || export RETVAL=$?
+ ./linux rootfstype=hostfs ro mem=1g loglevel=10 veth0=tap,tap0,0xc803 init="/bin/bash -c exit" || export RETVAL=$?
# SIGABRT=6 => 128+6
if [ $RETVAL != "134" ]; then
exit 1
@@ -45,9 +45,6 @@ config MMU
bool
default y
-config NO_IOMEM
- def_bool y
-
config ISA
bool
@@ -182,9 +179,6 @@ config MMAPPER
This driver allows a host file to be used as emulated IO memory inside
UML.
-config NO_DMA
- def_bool y
-
config PGTABLE_LEVELS
int
default 3 if 3_LEVEL_PGTABLES
@@ -147,3 +147,6 @@ archclean:
-o -name '*.gcov' \) -type f -print | xargs rm -f
export HEADER_ARCH SUBARCH USER_CFLAGS CFLAGS_NO_HARDENING OS DEV_NULL_PATH
+
+core-y += $(srctree)/tools/lkl/lib/
+KBUILD_CPPFLAGS += -I$(srctree)/$(ARCH_DIR)/lkl/include -I$(srctree)/$(ARCH_DIR)/
@@ -70,3 +70,8 @@ CONFIG_NLS=y
CONFIG_DEBUG_INFO=y
CONFIG_FRAME_WARN=1024
CONFIG_DEBUG_KERNEL=y
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_VIRTIO_NET=y
@@ -5,6 +5,7 @@ generic-y += compat.h
generic-y += current.h
generic-y += delay.h
generic-y += device.h
+generic-y += dma-mapping.h
generic-y += emergency-restart.h
generic-y += exec.h
generic-y += extable.h
@@ -2,11 +2,15 @@
#ifndef _ASM_UM_IO_H
#define _ASM_UM_IO_H
+#ifndef CONFIG_HAS_IOMEM
#define ioremap ioremap
static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
{
return (void __iomem *)(unsigned long)offset;
}
+#else
+#include <lkl/include/asm/io.h>
+#endif
#define iounmap iounmap
static inline void iounmap(void __iomem *addr)
@@ -13,6 +13,7 @@
#include <asm/mman.h>
#include <linux/uaccess.h>
#include <asm/unistd.h>
+#include <linux/platform_device.h>
long old_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
@@ -26,3 +27,55 @@ long old_mmap(unsigned long addr, unsigned long len,
out:
return err;
}
+
+SYSCALL_DEFINE3(virtio_mmio_device_add, long, base, long, size, unsigned int,
+ irq)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ struct resource res[] = {
+ [0] = {
+ .start = base,
+ .end = base + size - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = irq,
+ .end = irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ pdev = platform_device_alloc("virtio-mmio", PLATFORM_DEVID_AUTO);
+ if (!pdev) {
+ dev_err(&pdev->dev,
+ "%s: Unable to device alloc for virtio-mmio\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Unable to add resources for %s%d\n", __func__,
+ pdev->name, pdev->id);
+ goto exit_device_put;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "%s: Unable to add %s%d\n", __func__,
+ pdev->name, pdev->id);
+ goto exit_release_pdev;
+ }
+
+ return pdev->id;
+
+exit_release_pdev:
+ platform_device_del(pdev);
+exit_device_put:
+ platform_device_put(pdev);
+
+ return ret;
+}
@@ -2,8 +2,10 @@
#ifndef _ASM_LKL_IRQ_H
#define _ASM_LKL_IRQ_H
+#ifndef CONFIG_UML
#define IRQ_STATUS_BITS (sizeof(long) * 8)
#define NR_IRQS ((int)(IRQ_STATUS_BITS * IRQ_STATUS_BITS))
+#endif
void run_irqs(void);
void set_irq_pending(int irq);
@@ -11,9 +11,14 @@ obj-y = execvp.o file.o helper.o irq.o main.o mem.o process.o \
umid.o user_syms.o util.o drivers/ skas/
obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o
+obj-y += lkl_dev.o
+
+CFLAGS_lkl_dev.o:=-I$(srctree)/tools/lkl/include -Wno-undef
USER_OBJS := $(user-objs-y) elf_aux.o execvp.o file.o helper.o irq.o \
main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
tty.o umid.o util.o
+USER_OBJS += lkl_dev.o
+
include arch/um/scripts/Makefile.rules
new file mode 100644
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdlib.h>
+#include <string.h>
+#include <init.h>
+#include <os.h>
+#include <kern_util.h>
+#include <errno.h>
+
+#include <lkl.h>
+#include <lkl_host.h>
+
+extern struct lkl_host_operations lkl_host_ops;
+struct lkl_host_operations *lkl_ops = &lkl_host_ops;
+
+static struct lkl_netdev *nd;
+
+int __init uml_netdev_prepare(char *iftype, char *ifparams, char *ifoffload)
+{
+ int offload = 0;
+
+ if (ifoffload)
+ offload = strtol(ifoffload, NULL, 0);
+
+ if ((strcmp(iftype, "tap") == 0)) {
+ nd = lkl_netdev_tap_create(ifparams, offload);
+#ifdef notyet
+ } else if ((strcmp(iftype, "macvtap") == 0)) {
+ nd = lkl_netdev_macvtap_create(ifparams, offload);
+#endif
+ } else {
+ if (offload) {
+ lkl_printf("WARN: %s isn't supported on %s\n",
+ "LKL_HIJACK_OFFLOAD",
+ iftype);
+ lkl_printf(
+ "WARN: Disabling offload features.\n");
+ }
+ offload = 0;
+ }
+#ifdef notyet
+ if (strcmp(iftype, "raw") == 0)
+ nd = lkl_netdev_raw_create(ifparams);
+#endif
+
+ return 0;
+}
+
+
+int __init uml_netdev_add(void)
+{
+ if (nd)
+ lkl_netdev_add(nd, NULL);
+
+ return 0;
+}
+__initcall(uml_netdev_add);
+
+static int __init lkl_eth_setup(char *str, int *niu)
+{
+ char *end, *iftype, *ifparams, *ifoffload;
+ int devid, err = -EINVAL;
+
+ /* veth */
+ devid = strtoul(str, &end, 0);
+ if (end == str) {
+ os_warn("Bad device number\n");
+ return err;
+ }
+
+ /* = */
+ str = end;
+ if (*str != '=') {
+ os_warn("Expected '=' after device number\n");
+ return err;
+ }
+ str++;
+
+ /* <iftype> */
+ iftype = str;
+
+ /* <ifparams> */
+ ifparams = strchr(str, ',');
+ if (ifparams == NULL) {
+ os_warn("failed to parse ifparams\n");
+ return -1;
+ }
+ *ifparams = '\0';
+ ifparams++;
+
+ str = ifparams;
+ /* <offload> */
+ ifoffload = strchr(str, ',');
+ *ifoffload = '\0';
+ ifoffload++;
+
+ os_info("str=%s, iftype=%s, ifparams=%s, offload=%s\n",
+ str, iftype, ifparams, ifoffload);
+
+ /* preparation */
+ uml_netdev_prepare(iftype, ifparams, ifoffload);
+
+ return 1;
+}
+
+__uml_setup("veth", lkl_eth_setup,
+"veth[0-9]+=<iftype>,<ifparams>,<offload>\n"
+" Configure a network device.\n\n"
+);
+
+/* stub functions */
+int lkl_is_running(void)
+{
+ return 1;
+}
+
+
+void lkl_put_irq(int i, const char *user)
+{
+}
+
+/* XXX */
+static int free_irqs[2] = {5, 13};
+int lkl_get_free_irq(const char *user)
+{
+ static int irq_idx;
+ return free_irqs[irq_idx++];
+}
+
+int lkl_trigger_irq(int irq)
+{
+ do_IRQ(irq, NULL);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,33 @@
+CFLAGS_posix-host.o += -D_FILE_OFFSET_BITS=64 -Wno-error=incompatible-pointer-types
+
+USER_CFLAGS += -I$(srctree)/tools/lkl/include \
+ -Wno-strict-prototypes -Wno-undef \
+ -Wframe-larger-than=20480 -O0 -g
+
+USER_OBJS += fs.o iomem.o net.o jmp_buf.o virtio.o virtio_net.o \
+ virtio_net_fd.o virtio_net_tap.o utils.o posix-host.o \
+ ../../perf/pmu-events/jsmn.o
+
+#obj-y += fs.o
+obj-y += iomem.o
+#obj-y += net.o
+obj-y += jmp_buf.o
+obj-y += posix-host.o
+#obj-$(LKL_HOST_CONFIG_NT) += nt-host.o
+obj-y += utils.o
+#obj-y += virtio_blk.o
+obj-y += virtio.o
+#obj-y += dbg.o
+#obj-y += dbg_handler.o
+obj-y += virtio_net.o
+obj-y += virtio_net_fd.o
+obj-y += virtio_net_tap.o
+#obj-$(LKL_HOST_CONFIG_VIRTIO_NET) += virtio_net_raw.o
+#obj-$(LKL_HOST_CONFIG_VIRTIO_NET_MACVTAP) += virtio_net_macvtap.o
+#obj-$(LKL_HOST_CONFIG_VIRTIO_NET_DPDK) += virtio_net_dpdk.o
+#obj-$(LKL_HOST_CONFIG_VIRTIO_NET_VDE) += virtio_net_vde.o
+#obj-$(LKL_HOST_CONFIG_VIRTIO_NET) += virtio_net_pipe.o
+obj-y += ../../perf/pmu-events/jsmn.o
+#obj-y += config.o
+
+include arch/um/scripts/Makefile.rules
@@ -306,10 +306,12 @@ static void timer_free(void *_timer)
timer_delete(timer);
}
+#ifndef __arch_um__
static void panic(void)
{
assert(0);
}
+#endif
static long _gettid(void)
{
@@ -321,7 +323,9 @@ static long _gettid(void)
}
struct lkl_host_operations lkl_host_ops = {
+#ifndef __arch_um__
.panic = panic,
+#endif
.thread_create = thread_create,
.thread_detach = thread_detach,
.thread_exit = thread_exit,
@@ -46,6 +46,12 @@
lkl_host_ops.panic(); \
} while (0)
+#ifdef __arch_um__
+extern unsigned long uml_physmem;
+#else
+static unsigned long uml_physmem;
+#endif
+
struct virtio_queue {
uint32_t num_max;
uint32_t num;
@@ -216,7 +222,8 @@ static void add_dev_buf_from_vring_desc(struct virtio_req *req,
{
struct iovec *buf = &req->buf[req->buf_count++];
- buf->iov_base = (void *)(uintptr_t)le64toh(vring_desc->addr);
+ buf->iov_base = (void *)(uintptr_t)le64toh(vring_desc->addr)
+ + uml_physmem;
buf->iov_len = le32toh(vring_desc->len);
if (!(buf->iov_base && buf->iov_len))
@@ -304,8 +311,10 @@ void virtio_process_queue(struct virtio_dev *dev, uint32_t qidx)
if (!q->ready)
return;
+#ifndef __arch_um__
if (dev->ops->acquire_queue)
dev->ops->acquire_queue(dev, qidx);
+#endif
while (q->last_avail_idx != le16toh(q->avail->idx)) {
/*
@@ -319,8 +328,10 @@ void virtio_process_queue(struct virtio_dev *dev, uint32_t qidx)
virtio_set_avail_event(q, q->avail->idx);
}
+#ifndef __arch_um__
if (dev->ops->release_queue)
dev->ops->release_queue(dev, qidx);
+#endif
}
static inline uint32_t virtio_read_device_features(struct virtio_dev *dev)
@@ -406,7 +417,7 @@ static inline void set_ptr_low(void **ptr, uint32_t val)
uint64_t tmp = (uintptr_t)*ptr;
tmp = (tmp & 0xFFFFFFFF00000000) | val;
- *ptr = (void *)(long)tmp;
+ *ptr = (void *)(long)tmp + uml_physmem;
}
static inline void set_ptr_high(void **ptr, uint32_t val)
@@ -579,6 +590,7 @@ int virtio_dev_setup(struct virtio_dev *dev, int queues, int num_max)
int virtio_dev_cleanup(struct virtio_dev *dev)
{
+#ifndef __arch_um__
char devname[100];
long fd, ret;
long mount_ret;
@@ -622,6 +634,7 @@ int virtio_dev_cleanup(struct virtio_dev *dev)
lkl_put_irq(dev->irq, "virtio");
unregister_iomem(dev->base);
lkl_host_ops.mem_free(dev->queue);
+#endif
return 0;
}
@@ -87,6 +87,28 @@ void virtio_req_complete(struct virtio_req *req, uint32_t len);
void virtio_process_queue(struct virtio_dev *dev, uint32_t qidx);
void virtio_set_queue_max_merge_len(struct virtio_dev *dev, int q, int len);
+#ifdef __arch_um__
+//#include <irq_kern.h>
+#include <irq_user.h>
+enum irqreturn {
+ IRQ_HANDLED = (1 << 0),
+ IRQ_WAKE_THREAD = (1 << 1),
+};
+
+typedef enum irqreturn irqreturn_t;
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
+#define IRQF_SHARED 0x00000080
+
+extern int um_request_irq(unsigned int irq, int fd, int type,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+ void *dev_id);
+
+long sys_virtio_mmio_device_add(long base, long size, unsigned int irq);
+#define lkl_sys_virtio_mmio_device_add sys_virtio_mmio_device_add
+#endif /* __arch_um__ */
+
#define container_of(ptr, type, member) \
(type *)((char *)(ptr) - __builtin_offsetof(type, member))
@@ -2,6 +2,7 @@
#include <string.h>
#include <lkl_host.h>
#include "virtio.h"
+#include "virtio_net_fd.h"
#include "endian.h"
#include <lkl/linux/virtio_net.h>
@@ -212,9 +213,23 @@ static struct lkl_mutex **init_queue_locks(int num_queues)
return ret;
}
+#ifdef __arch_um__
+static irqreturn_t um_virtio_intr(int irq, void *dev_id)
+{
+ struct virtio_dev *dev = dev_id;
+
+ virtio_process_queue(dev, 0);
+ return 0;
+}
+#endif
+
int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args *args)
{
struct virtio_net_dev *dev;
+#ifdef __arch_um__
+ struct lkl_netdev_fd *nd_fd =
+ container_of(nd, struct lkl_netdev_fd, dev);
+#endif
int ret = -LKL_ENOMEM;
dev = lkl_host_ops.mem_alloc(sizeof(*dev));
@@ -252,16 +267,22 @@ int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args *args)
if (ret)
goto out_free;
+#ifdef __arch_um__
+ um_request_irq(dev->dev.irq, nd_fd->fd_rx, IRQ_READ, um_virtio_intr,
+ IRQF_SHARED, "virtio", dev);
+#endif
+
/*
* We may receive upto 64KB TSO packet so collect as many descriptors as
* there are available up to 64KB in total len.
*/
if (dev->dev.device_features & BIT(LKL_VIRTIO_NET_F_MRG_RXBUF))
virtio_set_queue_max_merge_len(&dev->dev, RX_QUEUE_IDX, 65536);
-
+#ifndef __arch_um__
dev->poll_tid = lkl_host_ops.thread_create(poll_thread, dev);
if (dev->poll_tid == 0)
goto out_cleanup_dev;
+#endif
ret = dev_register(dev);
if (ret < 0)
@@ -280,6 +301,7 @@ int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args *args)
return ret;
}
+#ifndef __arch_um__
/* Return 0 for success, -1 for failure. */
void lkl_netdev_remove(int id)
{
@@ -315,6 +337,7 @@ void lkl_netdev_remove(int id)
free_queue_locks(dev->queue_locks, NUM_QUEUES);
lkl_host_ops.mem_free(dev);
}
+#endif
void lkl_netdev_free(struct lkl_netdev *nd)
{
@@ -25,28 +25,6 @@
#include "virtio.h"
#include "virtio_net_fd.h"
-struct lkl_netdev_fd {
- struct lkl_netdev dev;
- /* file-descriptor based device */
- int fd_rx;
- int fd_tx;
- /*
- * Controlls the poll mask for fd. Can be acccessed concurrently from
- * poll, tx, or rx routines but there is no need for syncronization
- * because:
- *
- * (a) TX and RX routines set different variables so even if they update
- * at the same time there is no race condition
- *
- * (b) Even if poll and TX / RX update at the same time poll cannot
- * stall: when poll resets the poll variable we know that TX / RX will
- * run which means that eventually the poll variable will be set.
- */
- int poll_tx, poll_rx;
- /* controle pipe */
- int pipe[2];
-};
-
static int fd_net_tx(struct lkl_netdev *nd, struct iovec *iov, int cnt)
{
int ret;
@@ -4,6 +4,28 @@
struct ifreq;
+struct lkl_netdev_fd {
+ struct lkl_netdev dev;
+ /* file-descriptor based device */
+ int fd_rx;
+ int fd_tx;
+ /*
+ * Controlls the poll mask for fd. Can be acccessed concurrently from
+ * poll, tx, or rx routines but there is no need for syncronization
+ * because:
+ *
+ * (a) TX and RX routines set different variables so even if they update
+ * at the same time there is no race condition
+ *
+ * (b) Even if poll and TX / RX update at the same time poll cannot
+ * stall: when poll resets the poll variable we know that TX / RX will
+ * run which means that eventually the poll variable will be set.
+ */
+ int poll_tx, poll_rx;
+ /* controle pipe */
+ int pipe[2];
+};
+
/**
* lkl_register_netdev_linux_fdnet - register a file descriptor-based network
* device as a NIC
This also expands supporting virtio-mmio driver, which involves multiple addition to Kbuild file as well. Signed-off-by: Hajime Tazaki <thehajime@gmail.com> --- .circleci/config.yml | 2 +- arch/um/Kconfig | 6 -- arch/um/Makefile.um | 3 + arch/um/configs/x86_64_defconfig | 5 ++ arch/um/include/asm/Kbuild | 1 + arch/um/include/asm/io.h | 4 + arch/um/kernel/syscall.c | 53 ++++++++++++ arch/um/lkl/include/asm/irq.h | 2 + arch/um/os-Linux/Makefile | 5 ++ arch/um/os-Linux/lkl_dev.c | 134 +++++++++++++++++++++++++++++++ tools/lkl/lib/Makefile | 33 ++++++++ tools/lkl/lib/posix-host.c | 4 + tools/lkl/lib/virtio.c | 17 +++- tools/lkl/lib/virtio.h | 22 +++++ tools/lkl/lib/virtio_net.c | 25 +++++- tools/lkl/lib/virtio_net_fd.c | 22 ----- tools/lkl/lib/virtio_net_fd.h | 22 +++++ 17 files changed, 328 insertions(+), 32 deletions(-) create mode 100644 arch/um/os-Linux/lkl_dev.c create mode 100644 tools/lkl/lib/Makefile