diff --git a/arch/lkl/Kconfig b/arch/lkl/Kconfig index 67cf0a6cb0628d..b5b6a4fe749445 100644 --- a/arch/lkl/Kconfig +++ b/arch/lkl/Kconfig @@ -45,6 +45,12 @@ config 64BIT config BIG_ENDIAN def_bool n +config KALLSYMS_BASE_RELATIVE + def_bool n + +config TTY + def_bool n + config GENERIC_CSUM def_bool y @@ -58,6 +64,12 @@ config RWSEM_GENERIC_SPINLOCK bool default y +config PCI + bool "PCI support" + select NO_GENERIC_PCI_IOPORT_MAP + select GENERIC_PCI_IOMAP + default y + source init/Kconfig source net/Kconfig diff --git a/arch/lkl/Makefile b/arch/lkl/Makefile index 84efa7564d9f27..dedabebfe5bbc8 100644 --- a/arch/lkl/Makefile +++ b/arch/lkl/Makefile @@ -14,6 +14,11 @@ else $(error Unrecognized platform: $(OUTPUT_FORMAT)) endif +ifeq ($(OUTPUT_FORMAT),elf32-littlearm) +CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork -mfpu=vfp +KBUILD_CFLAGS += $(CFLAGS_ABI) +endif + ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64-freebsd)) NPROC=$(shell sysctl -n hw.ncpu) else @@ -21,17 +26,48 @@ NPROC=$(shell nproc) endif LDFLAGS_vmlinux += -r + +ifeq ($(buildrump),yes) +# objcopy trick is taken from rumpkernel +GCCSYMBOLS=__umoddi3|__udivdi3|__aeabi_idiv|__aeabi_idivmod|__aeabi_llsl +GCCSYMBOLS:=$(GCCSYMBOLS)|__aeabi_llsr|__aeabi_uidiv|__aeabi_uidivmod|__aeabi_uldivmod +GCCATOMIC=__sync_synchronize|__sync_fetch_and_sub_4|__sync_fetch_and_add_4 +GCCATOMIC:=$(GCCATOMIC)|__sync_fetch_and_and_4|__sync_fetch_and_or_4 +VMLINUX_SYMS=__start___ex_table|__stop___ex_table|boot_cmdline +EXP_SYMRENAME=rump|RUMP|bmk_|lib_|nuse_|lkl_|__tls|__initcall_start +EXP_SYMRENAME:=$(EXP_SYMRENAME)|__initcall_end|__gcov|_end|_GLOBAL_OFFSET_TABLE|__assert13 +EXP_SYMRENAME:=$(EXP_SYMRENAME)|${GCCSYMBOLS}|${GCCATOMIC}'${_SYMQUIRK}' +EXP_SYMRENAME:=$(EXP_SYMRENAME)${RUMP_SYM_NORENAME:D|${RUMP_SYM_NORENAME}}|${VMLINUX_SYMS} + +define make_ns_symbols + ${Q}echo " OBJCPY " $1 $2; \ + ${NM} -go $1 | awk ' \ + $$NF!~/^'${_PQ}'(${EXP_SYMRENAME})/ \ + {s=$$NF;sub(/^'${_PQ}'/, "&rumpns_", s); print $$NF, s}'\ + | sort | uniq > $2.renametab; \ + $(OBJCOPY) -R .eh_frame -L __start___ex_table \ + -L __stop___ex_table --preserve-dates \ + --redefine-syms $2.renametab $1 $2; \ + rm -f $2.renametab +endef +else LKL_ENTRY_POINTS := lkl_start_kernel lkl_sys_halt lkl_syscall lkl_trigger_irq \ lkl_get_free_irq lkl_put_irq lkl_create_syscall_thread \ lkl_stop_syscall_thread lkl_is_running +define make_ns_symbols + $(OBJCOPY) -R .eh_frame -R .syscall_defs $(foreach sym,$(LKL_ENTRY_POINTS),\ + -G$(prefix)$(sym)) vmlinux lkl.o +endef +endif core-y += arch/lkl/kernel/ core-y += arch/lkl/mm/ +core-y += arch/lkl/drivers/ all: lkl.o lkl.o: vmlinux - $(OBJCOPY) -R .eh_frame -R .syscall_defs $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) vmlinux lkl.o + $(call make_ns_symbols,vmlinux,lkl.o) arch/lkl/include/generated/uapi/asm/syscall_defs.h: vmlinux $(OBJCOPY) -j .syscall_defs -O binary --set-section-flags .syscall_defs=alloc $< $@ diff --git a/arch/lkl/defconfig b/arch/lkl/defconfig index f91380beee7c38..d9047fd7668871 100644 --- a/arch/lkl/defconfig +++ b/arch/lkl/defconfig @@ -31,8 +31,9 @@ CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_XFS_FS=y CONFIG_XFS_POSIX_ACL=y -CONFIG_BTRFS_FS=y -CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_ISO9660_FS=y +#CONFIG_BTRFS_FS=y +#CONFIG_BTRFS_FS_POSIX_ACL=y # CONFIG_FILE_LOCKING is not set # CONFIG_DNOTIFY is not set # CONFIG_INOTIFY_USER is not set @@ -93,3 +94,7 @@ CONFIG_DEBUG_INFO=y CONFIG_DEBUG_INFO_REDUCED=y # CONFIG_ENABLE_WARN_DEPRECATED is not set # CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_PCI=y +CONFIG_NET_CORE=y +CONFIG_VIRTIO_PCI=y +CONFIG_GENERIC_IOMAP=y diff --git a/arch/lkl/drivers/Makefile b/arch/lkl/drivers/Makefile new file mode 100644 index 00000000000000..7ab5e390de7420 --- /dev/null +++ b/arch/lkl/drivers/Makefile @@ -0,0 +1,13 @@ + +obj-y = rumpdev_pci.o + +# need to build with +librumpdev_linux_pci.a: ${RUMP_BMK_PCI_HYPERCALLS} + rm -f $@ + $(AR) rc $@ ${RUMP_BMK_PCI_HYPERCALLS} + +install: librumpdev_linux_pci.a + install -D librumpdev_linux_pci.a ${DESTDIR}/lib/ + + +.PHONY: ${RUMP_BMK_PCI_HYPERCALLS} diff --git a/arch/lkl/drivers/pci_user.h b/arch/lkl/drivers/pci_user.h new file mode 100644 index 00000000000000..92cd5c601bf45c --- /dev/null +++ b/arch/lkl/drivers/pci_user.h @@ -0,0 +1,43 @@ +/* Reused from src-netbsd/sys/rump/dev/lib/libpci/pci_user.h */ +/* + * Possible userfeature macro flags: + * + * RUMPCOMP_USERFEATURE_PCI_DMAFREE: + * Support free'ing DMA memory. If not, panic() when free() is called. + * + * RUMPCOMP_USERFEATURE_PCI_IOSPACE + * Support for PCI I/O space. If yes, rumpcomp_pci_iospace_init() + * must be provided. + */ + + +void *rumpcomp_pci_map(unsigned long addr, unsigned long len); +int rumpcomp_pci_confread(unsigned int bus, unsigned int dev, + unsigned int fun, int reg, unsigned int *value); +int rumpcomp_pci_confwrite(unsigned int bus, unsigned int dev, + unsigned int fun, int reg, unsigned int value); +int rumpcomp_pci_irq_map(unsigned int bus, unsigned int device, + unsigned int fun, int intrline, unsigned int cookie); +void *rumpcomp_pci_irq_establish(unsigned int cookie, + int (*handler)(void *), void *data); + +/* XXX: needs work: support boundary-restricted allocations */ +int rumpcomp_pci_dmalloc(size_t size, size_t align, + unsigned long *pap, unsigned long *vap); +#ifdef RUMPCOMP_USERFEATURE_PCI_DMAFREE +void rumpcomp_pci_dmafree(unsigned long mem, size_t size); +#endif + +struct rumpcomp_pci_dmaseg { + unsigned long ds_pa; + unsigned long ds_len; + unsigned long ds_vacookie; +}; +int rumpcomp_pci_dmamem_map(struct rumpcomp_pci_dmaseg *dss, size_t nseg, + size_t totlen, void **vap); + +unsigned long rumpcomp_pci_virt_to_mach(void *virt); + +#ifdef RUMPCOMP_USERFEATURE_PCI_IOSPACE +int rumpcomp_pci_iospace_init(void); +#endif diff --git a/arch/lkl/drivers/rumpdev_pci.c b/arch/lkl/drivers/rumpdev_pci.c new file mode 100644 index 00000000000000..5f0755010b0fbb --- /dev/null +++ b/arch/lkl/drivers/rumpdev_pci.c @@ -0,0 +1,263 @@ +/* + * rumprun PCI access (reused from src-netbsd/.../rumpdev_pci.c) + */ + +/* + * Copyright (c) 2013 Antti Kantee. 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. + * + * 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 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 +#include +#include +#include +#include +#include +#include +#include + +#include "pci_user.h" + +struct rump_pci_sysdata { + int domain; /* PCI domain */ +}; + +/* stubs: should not called */ +int __weak rumpcomp_pci_confread(unsigned int bus, unsigned int dev, + unsigned int fun, + int reg, unsigned int *value) +{ + return 0; +} + +int __weak rumpcomp_pci_confwrite(unsigned int bus, unsigned int dev, + unsigned int fun, + int reg, unsigned int value) +{ + return 0; +} + +void * __weak rumpcomp_pci_map(unsigned long addr, unsigned long len) +{ + return NULL; +} + +int __weak rumpcomp_pci_irq_map(unsigned int bus, unsigned int device, + unsigned int fun, + int intrline, unsigned int cookie) +{ + return 0; +} + +void * __weak rumpcomp_pci_irq_establish(unsigned int cookie, + int (*handler)(void *), void *data) +{ + return NULL; +} + +void __iomem *__pci_ioport_map(struct pci_dev *dev, + unsigned long port, unsigned int nr) +{ + /* XXX: no care at the moment */ + return rumpcomp_pci_map(port, nr); +} + +/* from arch/x86/pci/common.c */ +void pcibios_fixup_bus(struct pci_bus *b) +{ + pci_read_bridge_bases(b); +} + +/* from arch/x86/pci/i386.c */ +resource_size_t +pcibios_align_resource(void *data, const struct resource *res, + resource_size_t size, resource_size_t align) +{ + return 0; +} + +/* from drivers/pci/access.c + * + * @bus: PCI bus to scan + * @devfn: slot number to scan (must have zero function.) + */ +void *rump_pci_map_bus(struct pci_bus *bus, unsigned int devfn, int where) +{ + unsigned long addr; + + addr = (1 << 31) | (bus->number << 16) | (PCI_SLOT(devfn) << 11) | + (PCI_FUNC(devfn) << 8) | (where & 0xfc); + + /* FIXME: length? */ + return rumpcomp_pci_map(addr, 0); +} + +int rump_pci_generic_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + + rumpcomp_pci_confread(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, val); + if (size <= 2) + *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1); + + return PCIBIOS_SUCCESSFUL; +} + +int rump_pci_generic_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 mask, tmp; + + if (size == 4) { + rumpcomp_pci_confwrite(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, val); + return PCIBIOS_SUCCESSFUL; + } + + mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); + + /* This brings the way much overhead though I picked this + * code from access.c.. maybe should come up with single + * write method to avoid that. + */ + + rumpcomp_pci_confread(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, &tmp); + tmp &= mask; + tmp |= val << ((where & 0x3) * 8); + + rumpcomp_pci_confwrite(bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn), where, tmp); + + return PCIBIOS_SUCCESSFUL; +} + + +#ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH +#include +#include +#include +#include + +void * +pciide_machdep_compat_intr_establish(device_t dev, + const struct pci_attach_args *pa, int chan, + int (*func)(void *), void *arg) +{ + pci_intr_handle_t ih; + struct pci_attach_args mypa = *pa; + + mypa.pa_intrline = PCIIDE_COMPAT_IRQ(chan); + if (pci_intr_map(&mypa, &ih) != 0) + return NULL; + return rumpcomp_pci_irq_establish(ih, func, arg); +} + +__strong_alias(pciide_machdep_compat_intr_disestablish, pci_intr_disestablish); +#endif /* __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH */ + + +/* from drivers/pci/xen-pcifront.c */ +static int pci_lib_claim_resource(struct pci_dev *dev, void *data) +{ + int i; + struct resource *r; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + r = &dev->resource[i]; + + if (!r->parent && r->start && r->flags) { + dev_info(&dev->dev, "claiming resource %s/%d\n", + pci_name(dev), i); + if (pci_claim_resource(dev, i)) { + dev_err(&dev->dev, + "Could not claim resource %s/%d!", + pci_name(dev), i); + } + } + } + + return 0; +} + +static int rump_trigger_irq(void *arg) +{ + struct irq_data *data = arg; + + lkl_trigger_irq(data->irq); + return 0; +} + +int rump_pci_irq_request(struct irq_data *data) +{ + int ret, int_irq; + struct irq_desc *desc = irq_to_desc(data->irq); + const char *name = desc->name ? desc->name : "null"; /* XXX */ + + static int intr[5] = {9, 10, 11, 14, 15}; + static int intnum; + + /* setup IRQ */ + int_irq = lkl_get_free_irq(name); + + ret = rumpcomp_pci_irq_map(0, 0, 0, intr[intnum++], int_irq); + rumpcomp_pci_irq_establish(int_irq, rump_trigger_irq, data); + + return 0; +} + +void rump_pci_irq_release(struct irq_data *data) +{ + /* XXX: NOP */ +} + +struct pci_ops rump_pci_root_ops = { + .map_bus = rump_pci_map_bus, + .read = rump_pci_generic_read, + .write = rump_pci_generic_write, +}; + + +static int __init rump_pci_init(void) +{ + struct pci_bus *bus; + struct rump_pci_sysdata *sd; + int busnum = 0; + + sd = kzalloc(sizeof(*sd), GFP_KERNEL); + if (!sd) + return -1; + + pr_info("PCI: root bus %02x: using default resources\n", busnum); + bus = pci_scan_bus(busnum, &rump_pci_root_ops, sd); + if (!bus) { + kfree(sd); + return -1; + } + pci_walk_bus(bus, pci_lib_claim_resource, NULL); + pci_bus_add_devices(bus); + + return 0; +} +subsys_initcall(rump_pci_init); diff --git a/arch/lkl/include/asm/Kbuild b/arch/lkl/include/asm/Kbuild index edf6aa282af4b8..b2b2db0e565963 100644 --- a/arch/lkl/include/asm/Kbuild +++ b/arch/lkl/include/asm/Kbuild @@ -13,7 +13,6 @@ generic-y += current.h generic-y += delay.h generic-y += device.h generic-y += div64.h -generic-y += dma.h generic-y += emergency-restart.h generic-y += errno.h generic-y += exec.h @@ -39,7 +38,7 @@ generic-y += msgbuf.h generic-y += page.h generic-y += param.h generic-y += parport.h -generic-y += pci.h +generic-y += pci_iomap.h generic-y += percpu.h generic-y += pgalloc.h generic-y += poll.h @@ -53,7 +52,6 @@ generic-y += segment.h generic-y += sembuf.h generic-y += serial.h generic-y += shmbuf.h -generic-y += signal.h generic-y += simd.h generic-y += sizes.h generic-y += socket.h @@ -71,6 +69,7 @@ generic-y += tlb.h generic-y += tlbflush.h generic-y += topology.h generic-y += trace_clock.h -generic-y += uaccess.h generic-y += unaligned.h +generic-y += vga.h generic-y += word-at-a-time.h +header-y += syscalls.h diff --git a/arch/lkl/include/asm/dma.h b/arch/lkl/include/asm/dma.h new file mode 100644 index 00000000000000..a5b7cc63df7080 --- /dev/null +++ b/arch/lkl/include/asm/dma.h @@ -0,0 +1,12 @@ +#ifndef _ASM_LKL_DMA_H +#define _ASM_LKL_DMA_H + +#include + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* _ASM_LKL_DMA_H */ diff --git a/arch/lkl/include/asm/pci.h b/arch/lkl/include/asm/pci.h new file mode 100644 index 00000000000000..5dc008570e148e --- /dev/null +++ b/arch/lkl/include/asm/pci.h @@ -0,0 +1,10 @@ +#ifndef _ASM_LKL_PCI_H +#define _ASM_LKL_PCI_H + +#include + +# define pcibios_assign_all_busses() 0 +#define PCIBIOS_MIN_IO 0x1000 +#define PCIBIOS_MIN_MEM 0x10000000 + +#endif /* _ASM_LKL_PCI_H */ diff --git a/arch/lkl/include/asm/signal.h b/arch/lkl/include/asm/signal.h new file mode 100644 index 00000000000000..f638d0371155f4 --- /dev/null +++ b/arch/lkl/include/asm/signal.h @@ -0,0 +1,3 @@ +void do_signal(struct pt_regs *regs); + +#include diff --git a/arch/lkl/include/asm/thread_info.h b/arch/lkl/include/asm/thread_info.h index de00569f158e4c..63c37957320cad 100644 --- a/arch/lkl/include/asm/thread_info.h +++ b/arch/lkl/include/asm/thread_info.h @@ -22,6 +22,7 @@ struct thread_info { bool dead; lkl_thread_t tid; struct task_struct *prev_sched; + void *rump_client; /* for syscall proxy */ unsigned long stackend; }; diff --git a/arch/lkl/include/asm/uaccess.h b/arch/lkl/include/asm/uaccess.h new file mode 100644 index 00000000000000..a7875448ac35e4 --- /dev/null +++ b/arch/lkl/include/asm/uaccess.h @@ -0,0 +1,70 @@ +#ifndef _ASM_LKL_UACCESS_H +#define _ASM_LKL_UACCESS_H + +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_SYSPROXY +#include +#endif + +#define __access_ok(addr, size) (1) + +/* handle rump remote client */ +static inline __must_check long __copy_from_user(void *to, + const void __user *from, unsigned long n) +{ + int error = 0; + struct thread_info *ti; + + ti = current_thread_info(); + + if (unlikely(from == NULL && n)) + return -EFAULT; + + if (!ti->rump_client) { + memcpy(to, from, n); + } else if (n) { +#ifdef ENABLE_SYSPROXY + error = rumpuser_sp_copyin(ti->rump_client, from, to, n); +#else + ; +#endif + } + + return error; +} +#define __copy_from_user(to, from, n) __copy_from_user(to, from, n) + +static inline __must_check long __copy_to_user(void __user *to, + const void *from, unsigned long n) +{ + int error = 0; + struct thread_info *ti; + + ti = current_thread_info(); + + if (unlikely(to == NULL && n)) + return -EFAULT; + + if (!ti->rump_client) { + memcpy(to, from, n); + } else if (n) { +#ifdef ENABLE_SYSPROXY + error = rumpuser_sp_copyout(ti->rump_client, from, to, n); +#else + ; +#endif + } + + return error; +} +#define __copy_to_user(to, from, n) __copy_to_user(to, from, n) + +#include + +#endif /* _ASM_LKL_UACCESS_H */ diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index 0bf8b2bc4eb1c6..3bf26bc7b15882 100644 --- a/arch/lkl/include/uapi/asm/host_ops.h +++ b/arch/lkl/include/uapi/asm/host_ops.h @@ -5,6 +5,7 @@ struct lkl_mutex; struct lkl_sem; struct lkl_tls_key; +struct irq_data; typedef unsigned long lkl_thread_t; struct lkl_jmp_buf { unsigned long buf[32]; @@ -123,6 +124,11 @@ struct lkl_host_operations { int (*iomem_access)(const volatile void *addr, void *val, int size, int write); + int (*irq_request)(struct irq_data *data); + void (*irq_release)(struct irq_data *data); + + int (*getparam)(const char *name, void *buf, int buflen); + long (*gettid)(void); void (*jmp_buf_set)(struct lkl_jmp_buf *jmpb, void (*f)(void)); @@ -149,4 +155,13 @@ int lkl_is_running(void); int lkl_printf(const char *, ...); void lkl_bug(const char *, ...); +/* atomic ops */ +int lkl__sync_fetch_and_sub(int *ptr, int value); +int lkl__sync_fetch_and_add(int *ptr, int value); +long lkl__sync_fetch_and_or(long *ptr, long value); +long lkl__sync_fetch_and_and(long *ptr, long value); +void lkl__sync_synchronize(void); +void atomic_ops_init(void); +void atomic_ops_cleanup(void); + #endif diff --git a/arch/lkl/kernel/Makefile b/arch/lkl/kernel/Makefile index ef489f2f717618..d6da491095edf6 100644 --- a/arch/lkl/kernel/Makefile +++ b/arch/lkl/kernel/Makefile @@ -1,4 +1,4 @@ extra-y := vmlinux.lds obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o console.o \ - syscalls_32.o cpu.o + syscalls_32.o cpu.o atomic.o signal.o diff --git a/arch/lkl/kernel/atomic.c b/arch/lkl/kernel/atomic.c new file mode 100644 index 00000000000000..a1129e40ee3cdb --- /dev/null +++ b/arch/lkl/kernel/atomic.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#if defined(__ARMEL__) +static void *atomic_lock; + +long lkl__sync_fetch_and_or(long *ptr, long value) +{ + lkl_ops->sem_down(atomic_lock); + *ptr = value; + lkl_ops->sem_up(atomic_lock); + return 0; +} + +long lkl__sync_fetch_and_and(long *ptr, long value) +{ + int tmp; + + lkl_ops->sem_down(atomic_lock); + tmp = *ptr; + *ptr *= value; + lkl_ops->sem_up(atomic_lock); + return tmp; +} + +int lkl__sync_fetch_and_add(int *ptr, int value) +{ + int tmp; + + lkl_ops->sem_down(atomic_lock); + tmp = *ptr; + *ptr += value; + lkl_ops->sem_up(atomic_lock); + return tmp; +} + +int lkl__sync_fetch_and_sub(int *ptr, int value) +{ + int tmp; + + lkl_ops->sem_down(atomic_lock); + tmp = *ptr; + *ptr -= value; + lkl_ops->sem_up(atomic_lock); + return tmp; +} + +void lkl__sync_synchronize(void) +{ +} + +void atomic_ops_init(void) +{ + atomic_lock = lkl_ops->sem_alloc(1); +} + +void atomic_ops_cleanup(void) +{ + lkl_ops->sem_free(atomic_lock); +} + +#else +long lkl__sync_fetch_and_or(long *ptr, long value) +{ + return __sync_fetch_and_or(ptr, value); +} + +long lkl__sync_fetch_and_and(long *ptr, long value) +{ + return __sync_fetch_and_and(ptr, value); +} + +int lkl__sync_fetch_and_add(int *ptr, int value) +{ + return __sync_fetch_and_add(ptr, value); +} + +int lkl__sync_fetch_and_sub(int *ptr, int value) +{ + return __sync_fetch_and_sub(ptr, value); +} + +void lkl__sync_synchronize(void) +{ + return __sync_synchronize(); +} + +void atomic_ops_init(void) +{ +} + +void atomic_ops_cleanup(void) +{ +} +#endif + diff --git a/arch/lkl/kernel/console.c b/arch/lkl/kernel/console.c index bd3a686810daed..9d273e556cb8d1 100644 --- a/arch/lkl/kernel/console.c +++ b/arch/lkl/kernel/console.c @@ -1,10 +1,31 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include static void console_write(struct console *con, const char *str, unsigned len) { + static char buf[256]; + static int verbose; + + /* when console isn't NULL (not called from file_write() */ + if (con && !verbose) { + if (!lkl_ops->getparam) + verbose = 1; + else if (lkl_ops->getparam("RUMP_VERBOSE", buf, sizeof(buf)) + == 0) + if (*buf != 0) + verbose = 1; + } + + if (con && !verbose) + return; + if (lkl_ops->print) lkl_ops->print(str, len); } @@ -39,3 +60,67 @@ int __init lkl_console_init(void) } core_initcall(lkl_console_init); +static ssize_t file_write(struct file *fp, const char __user *s, + size_t n, loff_t *off) +{ + console_write(NULL, s, n); + return n; +} + +static ssize_t file_read(struct file *file, char __user *buf, size_t size, + loff_t *ppos) +{ + int err = 0; +#ifdef TO_BE_IMPLEMENTED + /* need to use iovread in host_ops (not directly from rump hypercall) */ + struct rumpuser_iovec iov; + ssize_t ret; + + iov.iov_base = buf; + iov.iov_len = size; + + err = rumpuser_iovread(0, &iov, 1, 0, &ret); + if (err == 0) + return ret; + +#endif + return -err; +} + +static const struct file_operations lkl_stdio_fops = { + .owner = THIS_MODULE, + .write = file_write, + .read = file_read, +}; + +static int __init lkl_stdio_init(void) +{ + int err; + + /* prepare /dev/console */ + err = register_chrdev(TTYAUX_MAJOR, "console", &lkl_stdio_fops); + if (err < 0) { + pr_err("can't register lkl stdio console.\n"); + return err; + } + + return 0; +} +/* should be _before_ default_rootfs creation (noinitramfs.c) */ +fs_initcall(lkl_stdio_init); + +static int __init lkl_memdev_init(void) +{ + int err; + + /* prepare /dev/null */ + err = sys_mknod((const char __user __force *) "/dev/null", + S_IFCHR | 0600, new_encode_dev(MKDEV(MEM_MAJOR, 3))); + if (err < 0) { + pr_err("can't register /dev/null.\n"); + return err; + } + + return 0; +} +device_initcall(lkl_memdev_init); diff --git a/arch/lkl/kernel/cpu.c b/arch/lkl/kernel/cpu.c index 2c315262a935e3..dbc47f8b6f76a9 100644 --- a/arch/lkl/kernel/cpu.c +++ b/arch/lkl/kernel/cpu.c @@ -66,7 +66,7 @@ static int __cpu_try_get_lock(int n) { lkl_thread_t self; - if (__sync_fetch_and_add(&cpu.shutdown_gate, n) >= MAX_THREADS) + if (lkl__sync_fetch_and_add(&cpu.shutdown_gate, n) >= MAX_THREADS) return -2; lkl_ops->mutex_lock(cpu.lock); @@ -89,7 +89,7 @@ static void __cpu_try_get_unlock(int lock_ret, int n) { if (lock_ret >= -1) lkl_ops->mutex_unlock(cpu.lock); - __sync_fetch_and_sub(&cpu.shutdown_gate, n); + lkl__sync_fetch_and_sub(&cpu.shutdown_gate, n); } void lkl_cpu_change_owner(lkl_thread_t owner) @@ -173,7 +173,7 @@ int lkl_cpu_try_run_irq(int irq) void lkl_cpu_shutdown(void) { - __sync_fetch_and_add(&cpu.shutdown_gate, MAX_THREADS); + lkl__sync_fetch_and_add(&cpu.shutdown_gate, MAX_THREADS); } void lkl_cpu_wait_shutdown(void) @@ -184,7 +184,7 @@ void lkl_cpu_wait_shutdown(void) static void lkl_cpu_cleanup(bool shutdown) { - while (__sync_fetch_and_add(&cpu.shutdown_gate, 0) > MAX_THREADS) + while (lkl__sync_fetch_and_add(&cpu.shutdown_gate, 0) > MAX_THREADS) ; if (shutdown) diff --git a/arch/lkl/kernel/irq.c b/arch/lkl/kernel/irq.c index 4e374e564ee3d1..455f3e3cb8a195 100644 --- a/arch/lkl/kernel/irq.c +++ b/arch/lkl/kernel/irq.c @@ -27,14 +27,14 @@ static inline unsigned long test_and_clear_irq_index_status(void) { if (!irq_index_status) return 0; - return __sync_fetch_and_and(&irq_index_status, 0); + return lkl__sync_fetch_and_and(&irq_index_status, 0); } static inline unsigned long test_and_clear_irq_status(int index) { if (!&irq_status[index]) return 0; - return __sync_fetch_and_and(&irq_status[index], 0); + return lkl__sync_fetch_and_and(&irq_status[index], 0); } void set_irq_pending(int irq) @@ -42,8 +42,8 @@ void set_irq_pending(int irq) int index = irq / IRQ_STATUS_BITS; int bit = irq % IRQ_STATUS_BITS; - __sync_fetch_and_or(&irq_status[index], BIT(bit)); - __sync_fetch_and_or(&irq_index_status, BIT(index)); + lkl__sync_fetch_and_or(&irq_status[index], BIT(bit)); + lkl__sync_fetch_and_or(&irq_index_status, BIT(index)); } static struct irq_info { @@ -174,12 +174,49 @@ void arch_local_irq_restore(unsigned long flags) irqs_enabled = flags; } +static int lkl_irq_request_resource(struct irq_data *data) +{ + if (!lkl_ops->irq_request) + return 0; + + return lkl_ops->irq_request(data); +} + +static void lkl_irq_release_resource(struct irq_data *data) +{ + if (!lkl_ops->irq_release) + return; + + return lkl_ops->irq_release(data); +} + +static void noop(struct irq_data *data) { } +static unsigned int noop_ret(struct irq_data *data) +{ + return 0; +} + +struct irq_chip dummy_lkl_irq_chip = { + .name = "lkl_dummy", + .irq_startup = noop_ret, + .irq_shutdown = noop, + .irq_enable = noop, + .irq_disable = noop, + .irq_ack = noop, + .irq_mask = noop, + .irq_unmask = noop, + .irq_request_resources = lkl_irq_request_resource, + .irq_release_resources = lkl_irq_release_resource, + .flags = IRQCHIP_SKIP_SET_WAKE, +}; + void init_IRQ(void) { int i; for (i = 0; i < NR_IRQS; i++) - irq_set_chip_and_handler(i, &dummy_irq_chip, handle_simple_irq); + irq_set_chip_and_handler(i, &dummy_lkl_irq_chip, + handle_simple_irq); pr_info("lkl: irqs initialized\n"); } diff --git a/arch/lkl/kernel/setup.c b/arch/lkl/kernel/setup.c index a7206d03a9f2bd..cca6ea3a9ece81 100644 --- a/arch/lkl/kernel/setup.c +++ b/arch/lkl/kernel/setup.c @@ -43,6 +43,7 @@ void __init setup_arch(char **cl) static void __init lkl_run_kernel(void *arg) { + atomic_ops_init(); threads_init(); lkl_cpu_get(); start_kernel(); @@ -132,6 +133,7 @@ long lkl_sys_halt(void) syscalls_cleanup(); threads_cleanup(); + atomic_ops_cleanup(); /* Shutdown the clockevents source. */ tick_suspend_local(); free_mem(); diff --git a/arch/lkl/kernel/signal.c b/arch/lkl/kernel/signal.c new file mode 100644 index 00000000000000..62f0e64830b068 --- /dev/null +++ b/arch/lkl/kernel/signal.c @@ -0,0 +1,16 @@ +#include + +static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) +{ + ksig->ka.sa.sa_handler(ksig->sig); +} + +void do_signal(struct pt_regs *regs) +{ + struct ksignal ksig; + + while (get_signal(&ksig)) { + /* Whee! Actually deliver the signal. */ + handle_signal(&ksig, regs); + } +} diff --git a/arch/lkl/kernel/syscalls.c b/arch/lkl/kernel/syscalls.c index fb8e8d59b14bf2..77510dee826a52 100644 --- a/arch/lkl/kernel/syscalls.c +++ b/arch/lkl/kernel/syscalls.c @@ -15,6 +15,7 @@ #include #include #include +#include static asmlinkage long sys_virtio_mmio_device_add(long base, long size, unsigned int irq); @@ -44,6 +45,7 @@ static long run_syscall(long no, long *params) params[4], params[5]); task_work_run(); + do_signal(NULL); return ret; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index d76cd97a98b6ba..a90224eab2b242 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -51,6 +51,7 @@ static DEFINE_MUTEX(deferred_probe_mutex); static LIST_HEAD(deferred_probe_pending_list); static LIST_HEAD(deferred_probe_active_list); +static struct workqueue_struct *deferred_wq; static atomic_t deferred_trigger_count = ATOMIC_INIT(0); /* @@ -174,7 +175,7 @@ static void driver_deferred_probe_trigger(void) * Kick the re-probe thread. It may already be scheduled, but it is * safe to kick it again. */ - schedule_work(&deferred_probe_work); + queue_work(deferred_wq, &deferred_probe_work); } /** @@ -210,10 +211,14 @@ void device_unblock_probing(void) */ static int deferred_probe_initcall(void) { + deferred_wq = create_singlethread_workqueue("deferwq"); + if (WARN_ON(!deferred_wq)) + return -ENOMEM; + driver_deferred_probe_enable = true; driver_deferred_probe_trigger(); /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(&deferred_probe_work); + flush_workqueue(deferred_wq); return 0; } late_initcall(deferred_probe_initcall); @@ -477,7 +482,8 @@ int driver_probe_done(void) void wait_for_device_probe(void) { /* wait for the deferred probe workqueue to finish */ - flush_work(&deferred_probe_work); + if (driver_deferred_probe_enable) + flush_workqueue(deferred_wq); /* wait for the known devices to complete their probing */ wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); diff --git a/tools/lkl/Makefile b/tools/lkl/Makefile index f055632fb66222..a8447f9e4cbe4d 100644 --- a/tools/lkl/Makefile +++ b/tools/lkl/Makefile @@ -10,6 +10,9 @@ else Q = @ endif +OUTPUT_FORMAT=$(shell $(LD) -r -print-output-format) +RUMP_PREFIX?= +RUMP_INCLUDE?=$(RUMP_PREFIX)/ # default target all: @@ -19,7 +22,7 @@ all: # cross toolchain does not use prefixed names CC := $(CROSS_COMPILE)gcc LD := $(CROSS_COMPILE)$(LD) -AR := $(CROSS_COMPILE)$(AR) +AR := $(CROSS_COMPILE)ar export CC LD AR EXESUF := @@ -37,18 +40,21 @@ export srctree # Target build configuration export CFLAGS += -I$(OUTPUT)/include -Iinclude -Wall -g -O2 -Wextra \ - -Wno-unused-parameter \ - -Wno-missing-field-initializers -fno-strict-aliasing + -Wno-missing-field-initializers -fno-strict-aliasing \ + -Wno-unused-parameter -U_FORTIFY_SOURCE -fno-stack-protector OUTPUT_FORMAT = $(shell $(LD) -r -print-output-format) +OUTPUT_DEF = $(shell echo | $(CC) -dM -E -) ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64 elf32-i386 elf64-x86-64-freebsd elf32-littlearm)) - OUTPUT_DEF = $(shell echo | $(CC) -dM -E -) - CFLAGS += -fPIC -pthread - ifeq (,$(filter $(OUTPUT_DEF),__ANDROID__)) + CFLAGS += -fPIC + ifeq (,$(filter $(OUTPUT_DEF),__ANDROID__ __ARMEL__)) + CFLAGS += -pthread LDLIBS += -lrt -lpthread endif export CONFIG_AUTO_LKL_POSIX_HOST=y + export CONFIG_AUTO_LKL_VIRTIO=y + export CONFIG_AUTO_LKL_VIRTIO_NET=y CFLAGS += -DCONFIG_AUTO_LKL_POSIX_HOST # Intel DPDK configuration @@ -73,6 +79,8 @@ else ifneq (,$(filter $(OUTPUT_FORMAT),pe-i386)) EXESUF := .exe SOSUF := .dll export CONFIG_AUTO_LKL_NT_HOST=y + export CONFIG_AUTO_LKL_VIRTIO=y + export CONFIG_AUTO_LKL_VIRTIO_NET=n CFLAGS += -DCONFIG_AUTO_LKL_NT_HOST else $(error Unrecognized platform: $(OUTPUT_FORMAT)) @@ -113,6 +121,25 @@ ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64-freebsd)) $(OUTPUT)cptofs$(EXESUF): LDLIBS += -largp endif +# if there is no rumpuser.h, then skip build +ifeq (,$(wildcard $(RUMP_INCLUDE)/rump/rumpuser.h)) +else + buildrump=yes + KOPT+="buildrump="$(buildrump) + export CONFIG_AUTO_LKL_RUMP_HOST=y + export CONFIG_AUTO_LKL_POSIX_HOST=n + export CONFIG_AUTO_LKL_VIRTIO=y + export CONFIG_AUTO_LKL_VIRTIO_NET=y + CFLAGS += -I$(RUMP_INCLUDE) -DRUMPUSER -DLIBRUMPUSER -D_KERNEL + CFLAGS += -UCONFIG_AUTO_LKL_POSIX_HOST + +# if rumprun=yes, then skip virtio-host build +ifeq ($(rumprun),yes) + CFLAGS += -DRUMPRUN + export CONFIG_AUTO_LKL_VIRTIO=n + export CONFIG_AUTO_LKL_VIRTIO_NET=n +endif +endif TEST_TARGETS := test valgrind gdb @@ -147,12 +174,18 @@ $(OUTPUT)cpfromfs$(EXESUF): cptofs$(EXESUF) # arm-android neither for the moment ifneq (,$(filter $(OUTPUT_FORMAT),pe-i386)) all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) -else ifneq (,$(filter $(OUTPUT_DEF),__ANDROID__)) + install: headers_install libraries_install programs_install +else ifneq (,$(wildcard $(RUMP_INCLUDE)/rump/rumpuser.h)) + ALL_LIBRARIES := $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) + all: $(ALL_LIBRARIES) + install: headers_install libraries_install +else ifneq (,$(filter $(OUTPUT_DEF),__ANDROID__ __ARMEL__)) all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) -else ifneq (,$(filter $(OUTPUT_FORMAT),elf32-littlearm)) - all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) $(ALL_PROGRAMS) + install: headers_install libraries_install programs_install else + ALL_LIBRARIES := $(ALL_LIBRARIES) $(OUTPUT)liblkl-hijack$(SOSUF) all: $(ALL_PROGRAMS) $(ALL_LIBRARIES) + install: headers_install libraries_install programs_install endif clean: @@ -184,9 +217,6 @@ programs_install: $(ALL_PROGRAMS) install -d $(DESTDIR)$(PREFIX)/bin ; \ install -m 755 $(ALL_PROGRAMS) $(DESTDIR)$(PREFIX)/bin -install: headers_install libraries_install programs_install - - FORCE: ; .PHONY: all clean $(TEST_TARGETS) FORCE .PHONY: headers_install libraries_install programs_install install diff --git a/tools/lkl/lib/Build b/tools/lkl/lib/Build index 468878b0049fa6..4186ce15ef151b 100644 --- a/tools/lkl/lib/Build +++ b/tools/lkl/lib/Build @@ -8,15 +8,22 @@ lkl-y += net.o lkl-y += jmp_buf.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += posix-host.o lkl-$(CONFIG_AUTO_LKL_NT_HOST) += nt-host.o +lkl-$(CONFIG_AUTO_LKL_RUMP_HOST) += rump.o +lkl-$(CONFIG_AUTO_LKL_RUMP_HOST) += rump-host.o lkl-y += utils.o -lkl-y += virtio_blk.o -lkl-y += virtio.o -lkl-y += dbg.o -lkl-y += dbg_handler.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net.o +lkl-$(CONFIG_AUTO_LKL_VIRTIO) += virtio_blk.o +lkl-$(CONFIG_AUTO_LKL_VIRTIO) += virtio.o +lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += dbg.o +lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += dbg_handler.o +lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET) += virtio_net.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_fd.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_tap.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_raw.o lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_macvtap.o lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_DPDK) += virtio_net_dpdk.o lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_VDE) += virtio_net_vde.o + +# for frankenlibc +CFLAGS_rump-host.o = -I$(RUMP_PREFIX)/../platform/include \ + -I$(RUMP_PREFIX)/../franken/include \ + -DCONFIG_AUTO_LKL_POSIX_HOST diff --git a/tools/lkl/lib/endian.h b/tools/lkl/lib/endian.h index c95bc2bc853408..83da8e2d0c6171 100644 --- a/tools/lkl/lib/endian.h +++ b/tools/lkl/lib/endian.h @@ -3,6 +3,16 @@ #if defined(__FreeBSD__) #include +#elif defined(__ARMEL__) +#include +#define le16toh(x) (x) +#define le32toh(x) (x) +#define le64toh(x) (x) +#define htole16(x) htons(x) +#define htole32(x) htonl(x) +#define htobe16(x) htons(x) +#define htobe32(x) htonl(x) +#define be32toh(x) ntohl(x) #elif defined(__ANDROID__) #include #define le16toh(x) letoh16(x) diff --git a/tools/lkl/lib/fs.c b/tools/lkl/lib/fs.c index b56a5a3d29dc4e..e0d4fb77c17fab 100644 --- a/tools/lkl/lib/fs.c +++ b/tools/lkl/lib/fs.c @@ -1,11 +1,13 @@ #include #include #include -#include #include - #include "virtio.h" +#ifdef RUMPUSER +#include "rump.h" +#endif + #define MAX_FSTYPE_LEN 50 int lkl_mount_fs(char *fstype) { @@ -74,6 +76,12 @@ static int get_node_with_prefix(const char *path, const char *prefix, return ret; } +/* rumprun doesn't build virtio.o (of lkl) so stub it */ +uint32_t __attribute__((weak)) virtio_get_num_bootdevs(void) +{ + return 0; +} + static int encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid) { int ret; diff --git a/tools/lkl/lib/iomem.c b/tools/lkl/lib/iomem.c index 90545b901165df..3fd2e9e5f0d67d 100644 --- a/tools/lkl/lib/iomem.c +++ b/tools/lkl/lib/iomem.c @@ -55,6 +55,9 @@ void unregister_iomem(void *base) void *lkl_ioremap(long addr, int size) { +#ifdef RUMPRUN + return (void *)addr; +#else int index = IOMEM_ADDR_TO_INDEX(addr); struct iomem_region *iomem = &iomem_regions[index]; @@ -65,10 +68,91 @@ void *lkl_ioremap(long addr, int size) return IOMEM_INDEX_TO_ADDR(index); return NULL; +#endif } int lkl_iomem_access(const volatile void *addr, void *res, int size, int write) { + /* FIXME: should be transparent with platform/ */ +#ifdef RUMPRUN + uint16_t mem = (unsigned long)addr; + int ret = 0; + + if (write) { + if (size == 1) { +#ifdef __x86_64__ + uint8_t v = *(uint8_t *)res; + + asm volatile("outb %0, %1" :: "a"(v), "d"(mem)); +#elif __arm__ +#endif + return 0; + } else if (size == 2) { +#ifdef __x86_64__ + uint16_t v = *(uint16_t *)res; + + asm volatile("out %0, %1" :: "a"(v), "d"(mem)); +#elif __arm__ +#endif + return 0; + } else if (size == 4) { +#ifdef __x86_64__ + uint32_t v = *(uint32_t *)res; + + asm volatile("outl %0, %1" :: "a"(v), "d"(mem)); +#elif __arm__ +#endif + return 0; + } else if (size == 8) { +#ifdef __x86_64__ + lkl_printf("not implemented yet\n"); + lkl_host_ops.panic(); +#elif __arm__ +#endif + } else { + lkl_printf("not implemented yet\n"); + lkl_host_ops.panic(); + } + } else { + if (size == 1) { +#ifdef __x86_64__ + uint8_t v; + + asm volatile("inb %1,%0" : "=a"(v) : "d"(mem)); + *(uint8_t *)res = v; +#elif __arm__ +#endif + return 0; + } else if (size == 2) { +#ifdef __x86_64__ + uint16_t v; + + asm volatile("in %1,%0" : "=a"(v) : "d"(mem)); + *(uint16_t *)res = v; +#elif __arm__ +#endif + return 0; + } else if (size == 4) { +#ifdef __x86_64__ + uint32_t v; + + asm volatile("inl %1,%0" : "=a"(v) : "d"(mem)); + *(uint32_t *)res = v; +#elif __arm__ +#endif + return 0; + } else if (size == 8) { +#ifdef __x86_64__ + lkl_printf("not implemented yet\n"); + lkl_host_ops.panic(); +#elif __arm__ +#endif + } else { + lkl_printf("not implemented yet\n"); + lkl_host_ops.panic(); + } + } +#else /* !RUMPRUN */ int index = IOMEM_ADDR_TO_INDEX(addr); struct iomem_region *iomem = &iomem_regions[index]; int offset = IOMEM_ADDR_TO_OFFSET(addr); @@ -83,5 +167,6 @@ int lkl_iomem_access(const volatile void *addr, void *res, int size, int write) else ret = iomem->ops->read(iomem->data, offset, res, size); +#endif return ret; } diff --git a/tools/lkl/lib/net.c b/tools/lkl/lib/net.c index ffd1f43ac9522e..b52e185ac2295b 100644 --- a/tools/lkl/lib/net.c +++ b/tools/lkl/lib/net.c @@ -1,8 +1,12 @@ -#include #include +#include #include "endian.h" #include +#ifdef RUMPUSER +#include "rump.h" +#endif + static inline void set_sockaddr(struct lkl_sockaddr_in *sin, unsigned int addr, unsigned short port) { diff --git a/tools/lkl/lib/rump-host.c b/tools/lkl/lib/rump-host.c new file mode 100644 index 00000000000000..fd577cc40eb886 --- /dev/null +++ b/tools/lkl/lib/rump-host.c @@ -0,0 +1,672 @@ +/* + * Rump hypercall interface for LKL + * Copyright (c) 2015 Hajime Tazaki + * + * Author: Hajime Tazaki + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "iomem.h" +#include "jmp_buf.h" +#include "rump.h" + + +/* FIXME */ +#define BIT(x) (1ULL << x) +#define NSEC_PER_SEC 1000000000L +#define container_of(ptr, type, member) \ + (type *)((char *)(ptr) - __builtin_offsetof(type, member)) + +/* FIXME */ +int *__errno(void); +#undef errno +#define errno (*__errno()) + + +/* console */ +static void rump_print(const char *str, int len) +{ + while (len-- > 0) { + rumpuser_putchar(*str); + str++; + } +} + + +/* semaphore/mutex */ +struct rumpuser_sem { + struct rumpuser_mtx *lock; + int count; + struct rumpuser_cv *cond; +}; + +struct lkl_mutex { + struct rumpuser_mtx *mutex; +}; + +struct lkl_sem { + struct rumpuser_sem sem; +}; + +static struct lkl_sem *rump_sem_alloc(int count) +{ + struct lkl_sem *sem; + + rumpuser_malloc(sizeof(*sem), 0, (void **)&sem); + if (!sem) + return NULL; + + rumpuser_mutex_init(&sem->sem.lock, RUMPUSER_MTX_SPIN); + sem->sem.count = count; + rumpuser_cv_init(&sem->sem.cond); + + return sem; +} + +static void rump_sem_free(struct lkl_sem *_sem) +{ + struct rumpuser_sem *sem = (struct rumpuser_sem *)&_sem->sem; + + rumpuser_cv_destroy(sem->cond); + rumpuser_mutex_destroy(sem->lock); + rumpuser_free(sem, 0); +} + +static void rump_sem_up(struct lkl_sem *_sem) +{ + struct rumpuser_sem *sem = (struct rumpuser_sem *)&_sem->sem; + + rumpuser_mutex_enter(sem->lock); + sem->count++; + if (sem->count > 0) + rumpuser_cv_signal(sem->cond); + rumpuser_mutex_exit(sem->lock); +} + +static void rump_sem_down(struct lkl_sem *_sem) +{ + struct rumpuser_sem *sem = (struct rumpuser_sem *)&_sem->sem; + + rumpuser_mutex_enter(sem->lock); + while (sem->count <= 0) + rumpuser_cv_wait(sem->cond, sem->lock); + sem->count--; + rumpuser_mutex_exit(sem->lock); +} + +static struct lkl_mutex *rump_mutex_alloc(int recursive) +{ + struct lkl_mutex *_mutex; + + rumpuser_malloc(sizeof(*_mutex), 0, (void **)&_mutex); + if (!_mutex) + return NULL; + + rumpuser_mutex_init(&_mutex->mutex, RUMPUSER_MTX_SPIN); + + return _mutex; +} + +static void rump_mutex_lock(struct lkl_mutex *_mutex) +{ + rumpuser_mutex_enter(_mutex->mutex); +} + +static void rump_mutex_unlock(struct lkl_mutex *_mutex) +{ + rumpuser_mutex_exit(_mutex->mutex); +} + +static void rump_mutex_free(struct lkl_mutex *_mutex) +{ + rumpuser_mutex_destroy(_mutex->mutex); + rumpuser_free(_mutex, 0); +} + +/* XXX: dummy TLS */ +struct lkl_tls_key { + unsigned int *key; +}; +static struct lkl_tls_key *rump_tls_alloc(void (*destructor)(void *)) +{ + return NULL; +} + +static void rump_tls_free(struct lkl_tls_key *key) +{ +} + +static int rump_tls_set(struct lkl_tls_key *key, void *data) +{ + rumpuser_curlwpop(RUMPUSER_LWP_SET, (struct lwp *)data); + return 0; +} + +static void *rump_tls_get(struct lkl_tls_key *key) +{ + return rumpuser_curlwp(); +} + + +/* memory */ +static void *rump_mem_alloc(size_t size) +{ + void *mem; + + rumpuser_malloc(size, 0, (void **)&mem); + return mem; +} + +static void rump_mem_free(void *mem) +{ + rumpuser_free(mem, 0); +} + +/* thread */ +static lkl_thread_t rump_thread_create(void (*fn)(void *), void *arg) +{ + void *thrid; + int ret; + + ret = rumpuser_thread_create((void * (*)(void *))fn, arg, + "lkl_thr", 1, 1, -1, &thrid); + if (ret) + return 0; + + return (lkl_thread_t) thrid; +} + +static void rump_thread_detach(void) +{ + /* NOP */ +} + +static void rump_thread_exit(void) +{ + rumpuser_thread_exit(); +} + +static int rump_thread_join(lkl_thread_t tid) +{ + return rumpuser_thread_join((void *)tid); +} + +static lkl_thread_t rump_thread_self(void) +{ + return (lkl_thread_t)rumpuser_thread_self(); +} + +static int rump_thread_equal(lkl_thread_t a, lkl_thread_t b) +{ + return a == b; +} + +/* time/timer */ +static bool threads_are_go; +static struct rumpuser_mtx *thrmtx; +static struct rumpuser_cv *thrcv; + +struct thrdesc { + void (*f)(void *); + void *arg; + int canceled; + void *thrid; + struct timespec timeout; + struct rumpuser_mtx *mtx; + struct rumpuser_cv *cv; +}; + +static void *rump_timer_trampoline(void *arg) +{ + struct thrdesc *td = arg; + void (*f)(void *); + void *thrarg; + int err; + + /* from src-netbsd/sys/rump/librump/rumpkern/thread.c */ + /* don't allow threads to run before all CPUs have fully attached */ + if (!threads_are_go) { + rumpuser_mutex_enter_nowrap(thrmtx); + while (!threads_are_go) + rumpuser_cv_wait_nowrap(thrcv, thrmtx); + rumpuser_mutex_exit(thrmtx); + } + + f = td->f; + thrarg = td->arg; + if (td->timeout.tv_sec != 0 || td->timeout.tv_nsec != 0) { + rumpuser_mutex_enter(td->mtx); + err = rumpuser_cv_timedwait(td->cv, td->mtx, + td->timeout.tv_sec, + td->timeout.tv_nsec); + if (td->canceled) { + if (!td->thrid) + rumpuser_free(td, 0); + goto end; + } + rumpuser_mutex_exit(td->mtx); + /* FIXME: we should not use rumpuser__errtrans here + * 60==ETIMEDOUT(netbsd), rumpuser__errtrans(ETIMEDOUT)) + */ + if (err && err != 60) + goto end; + } + + f(thrarg); + + rumpuser_thread_exit(); +end: + return arg; +} + +static void rump_timer_cancel(void *timer) +{ + struct thrdesc *td = timer; + + if (td->canceled) + return; + + td->canceled = 1; + rumpuser_mutex_enter(td->mtx); + rumpuser_cv_signal(td->cv); + rumpuser_mutex_exit(td->mtx); + + rumpuser_mutex_destroy(td->mtx); + rumpuser_cv_destroy(td->cv); + + if (td->thrid) + rumpuser_thread_join(td->thrid); + + rumpuser_free(td, 0); +} + +/* from src-netbsd/sys/rump/librump/rumpkern/thread.c */ +static void rump_thread_allow(struct lwp *l) +{ + rumpuser_mutex_enter(thrmtx); + if (l == NULL) + threads_are_go = true; + + rumpuser_cv_broadcast(thrcv); + rumpuser_mutex_exit(thrmtx); +} + +static unsigned long long time_ns(void) +{ + struct timespec ts; + + rumpuser_clock_gettime(RUMPUSER_CLOCK_RELWALL, (int64_t *)&ts.tv_sec, + &ts.tv_nsec); + + return ((unsigned long long) ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec; +} + +static void *timer_alloc(void (*fn)(void *), void *arg) +{ + struct thrdesc *td; + + rumpuser_malloc(sizeof(*td), 0, (void **)&td); + + memset(td, 0, sizeof(*td)); + td->f = fn; + td->arg = arg; + + rumpuser_mutex_init(&td->mtx, RUMPUSER_MTX_SPIN); + rumpuser_cv_init(&td->cv); + + return td; +} + +static int timer_set_oneshot(void *_timer, unsigned long ns) +{ + int ret; + struct thrdesc *td = _timer; + + td->timeout = (struct timespec){ .tv_sec = ns / NSEC_PER_SEC, + .tv_nsec = ns % NSEC_PER_SEC}; + ret = rumpuser_thread_create(rump_timer_trampoline, td, "timer", + 0, 0, -1, &td->thrid); + + return ret ? -1 : 0; +} + +static void timer_free(void *_timer) +{ + rump_timer_cancel(_timer); +} + +static void panic(void) +{ + rumpuser_exit(RUMPUSER_PANIC); +} + +struct lkl_host_operations lkl_host_ops = { + .panic = panic, + .thread_create = rump_thread_create, + .thread_detach = rump_thread_detach, + .thread_exit = rump_thread_exit, + .thread_join = rump_thread_join, + .thread_self = rump_thread_self, + .thread_equal = rump_thread_equal, + .sem_alloc = rump_sem_alloc, + .sem_free = rump_sem_free, + .sem_up = rump_sem_up, + .sem_down = rump_sem_down, + .mutex_alloc = rump_mutex_alloc, + .mutex_free = rump_mutex_free, + .mutex_lock = rump_mutex_lock, + .mutex_unlock = rump_mutex_unlock, + .tls_alloc = rump_tls_alloc, + .tls_free = rump_tls_free, + .tls_set = rump_tls_set, + .tls_get = rump_tls_get, + .time = time_ns, + .timer_alloc = timer_alloc, + .timer_set_oneshot = timer_set_oneshot, + .timer_free = timer_free, + .print = rump_print, + .mem_alloc = rump_mem_alloc, + .mem_free = rump_mem_free, + .ioremap = lkl_ioremap, + .iomem_access = lkl_iomem_access, + .jmp_buf_set = jmp_buf_set, + .jmp_buf_longjmp = jmp_buf_longjmp, + .irq_request = rump_pci_irq_request, + .irq_release = rump_pci_irq_release, + .getparam = (int (*)(const char *, void *, int))rumpuser_getparam, +#ifndef RUMPRUN + .virtio_devices = lkl_virtio_devs, +#endif +}; + + +/* entry/exit points */ +char *boot_cmdline; +static char buf[256]; +static int verbose; + +int rump_init(void) +{ + if (rumpuser_init(RUMPUSER_VERSION, &hyp) != 0) { + rumpuser_dprintf("rumpuser init failed\n"); + return -EINVAL; + } + + rumpuser_mutex_init(&thrmtx, RUMPUSER_MTX_SPIN); + rumpuser_cv_init(&thrcv); + threads_are_go = false; + + if (rumpuser_getparam("LKL_BOOT_CMDLINE", buf, sizeof(buf)) == 0) + boot_cmdline = buf; + else + boot_cmdline = "mem=100M"; + + + lkl_start_kernel(&lkl_host_ops, boot_cmdline); + + rump_thread_allow(NULL); + /* FIXME: rumprun doesn't have sysproxy. + * maybe outsourced and linked -lsysproxy for hijack case ? + */ +#ifdef ENABLE_SYSPROXY + rump_sysproxy_init(); +#endif + if (rumpuser_getparam("RUMP_VERBOSE", buf, sizeof(buf)) == 0) { + if (*buf != 0) + verbose = 1; + } + + if (verbose) + rumpuser_dprintf("rumpuser started.\n"); + return 0; +} + +void rump_exit(void) +{ + if (verbose) + rumpuser_dprintf("rumpuser finishing.\n"); + +#ifdef ENABLE_SYSPROXY + rump_sysproxy_fini(); +#endif + rumpuser_exit(0); +} + +/* stub calls */ +#define RUMP_TEMP_STUB +#ifdef RUMP_TEMP_STUB +enum rump_etfs_type { + RUMP_ETFS_REG, + RUMP_ETFS_BLK, + RUMP_ETFS_CHR, + RUMP_ETFS_DIR, + RUMP_ETFS_DIR_SUBDIRS +}; + +void rump_boot_setsigmodel(int rump_sigmodel) +{ +} + +int rump_pub_etfs_register(const char *key, const char *hostpath, + enum rump_etfs_type ftype) +{ + return 0; +} + +int rump_pub_etfs_register_withsize(const char *key, const char *hostpath, + enum rump_etfs_type ftype, uint64_t begin, + uint64_t size) +{ + return 0; +} + +int rump___sysimpl_mount50(const char *str, const char *str2, int i, + void *p, size_t s) +{ + return 0; +} + +int rump___sysimpl_dup2(int i, int j) +{ + return 0; +} + +int rump___sysimpl_socket30(int i, int j, int k) +{ + return 0; +} + +int rump___sysimpl_unmount(const char *str, int i) +{ + return 0; +} + +void __assert13(const char *file, int line, const char *function, + const char *failedexpr) +{ +} + +int rump___sysimpl_close(int fd) +{ + return -1; +} + +int rump___sysimpl_ioctl(int fd, u_long com, void *data) +{ + return -1; +} + +int rump___sysimpl_mkdir(const char *path, mode_t mode) +{ + return -1; +} + +int rump___sysimpl_open(const char *name, int flags, ...) +{ + return -1; +} + +#endif /* RUMP_TEMP_STUB */ + +#ifndef RUMPRUN +static int fd_get_capacity(struct lkl_disk disk, unsigned long long *res) +{ + off_t off; + + off = lseek(disk.fd, 0, SEEK_END); + if (off < 0) + return -1; + + *res = off; + return 0; +} + +static int blk_request(struct lkl_disk disk, struct lkl_blk_req *req) +{ + int err = 0; + struct iovec *iovec = (struct iovec *)req->buf; + + /* TODO: handle short reads/writes */ + switch (req->type) { + case LKL_DEV_BLK_TYPE_READ: + err = preadv(disk.fd, iovec, req->count, req->sector * 512); + break; + case LKL_DEV_BLK_TYPE_WRITE: + err = pwritev(disk.fd, iovec, req->count, req->sector * 512); + break; + case LKL_DEV_BLK_TYPE_FLUSH: + case LKL_DEV_BLK_TYPE_FLUSH_OUT: + err = fsync(disk.fd); + break; + default: + return LKL_DEV_BLK_STATUS_UNSUP; + } + + if (err < 0) + return LKL_DEV_BLK_STATUS_IOERR; + + return LKL_DEV_BLK_STATUS_OK; +} + +struct lkl_dev_blk_ops lkl_dev_blk_ops = { + .get_capacity = fd_get_capacity, + .request = blk_request, +}; + +struct lkl_netdev_rumpfd { + struct lkl_netdev dev; + /* TAP device */ + int fd; +}; + +static int rump_net_tx(struct lkl_netdev *nd, + struct iovec *iov, int cnt) +{ + struct lkl_netdev_rumpfd *nd_rumpfd = + container_of(nd, struct lkl_netdev_rumpfd, dev); + int ret; + + do { + ret = writev(nd_rumpfd->fd, iov, cnt); + } while (ret == -1 && (errno == EINTR)); + + if (ret < 0) + lkl_perror("write to rump fd netdev fails", errno); + + return ret; +} + +static int rump_net_rx(struct lkl_netdev *nd, + struct iovec *iov, int cnt) +{ + struct lkl_netdev_rumpfd *nd_rumpfd = + container_of(nd, struct lkl_netdev_rumpfd, dev); + int ret; + + do { + ret = readv(nd_rumpfd->fd, iov, cnt); + } while (ret == -1 && errno == EINTR); + + if (ret <= 0) + return -1; + + return ret; +} + +static int rump_net_poll(struct lkl_netdev *nd) +{ + struct lkl_netdev_rumpfd *nd_rumpfd = + container_of(nd, struct lkl_netdev_rumpfd, dev); + struct pollfd pfd = { + .fd = nd_rumpfd->fd, + .events = POLLIN | POLLPRI | POLLOUT + }; + int ret = 0; + + + while (1) { + int err = poll(&pfd, 1, -1); + + if (err < 0 && errno == EINTR) + continue; + if (err > 0) + break; + } + + if (pfd.revents & (POLLHUP | POLLNVAL)) + return -1; + + if (pfd.revents & POLLIN) + ret |= LKL_DEV_NET_POLL_RX; + if (pfd.revents & POLLOUT) + ret |= LKL_DEV_NET_POLL_TX; + + return ret; +} + +struct lkl_dev_net_ops rumpfd_ops = { + .tx = rump_net_tx, + .rx = rump_net_rx, + .poll = rump_net_poll, +}; + +struct lkl_netdev *lkl_netdev_rumpfd_create(const char *ifname, int fd, + struct lkl_netdev_args *args) +{ + struct lkl_netdev_rumpfd *nd; + char offload[8]; + + nd = (struct lkl_netdev_rumpfd *) + malloc(sizeof(struct lkl_netdev_rumpfd)); + if (!nd) { + lkl_printf("tap: failed to allocate memory\n"); + return NULL; + } + + memset(args, 0, sizeof(struct lkl_netdev_args)); + nd->fd = fd; + nd->dev.ops = &rumpfd_ops; + + if (rumpuser_getparam("LKL_OFFLOAD", offload, sizeof(offload)) == 0) { + args->offload = BIT(LKL_VIRTIO_NET_F_GUEST_CSUM) | + BIT(LKL_VIRTIO_NET_F_GUEST_TSO4) | + BIT(LKL_VIRTIO_NET_F_MRG_RXBUF) | + BIT(LKL_VIRTIO_NET_F_CSUM) | + BIT(LKL_VIRTIO_NET_F_HOST_TSO4); + nd->dev.has_vnet_hdr = 1; + } + + return (struct lkl_netdev *)nd; +} +#endif diff --git a/tools/lkl/lib/rump-sysproxy.c b/tools/lkl/lib/rump-sysproxy.c new file mode 100644 index 00000000000000..194cb91bdbbb08 --- /dev/null +++ b/tools/lkl/lib/rump-sysproxy.c @@ -0,0 +1,29 @@ +/* + * Rump system call proxy interface for Linux + * Copyright (c) 2015 Hajime Tazaki + * + * Author: Hajime Tazaki + */ + +#include +#include +#include + +#ifdef ENABLE_SYSPROXY +#include "rump.h" + +int rump_init_server(const char *url) +{ + return rumpuser_sp_init(url, "Linux", UTS_RELEASE, "libos"); +} + +void rump_sysproxy_init(void) +{ + rump_init_server("unix:///tmp/rump-server"); +} + +void rump_sysproxy_fini(void) +{ + rumpuser_sp_fini(NULL); +} +#endif diff --git a/tools/lkl/lib/rump.c b/tools/lkl/lib/rump.c new file mode 100644 index 00000000000000..f2aa1d580f790d --- /dev/null +++ b/tools/lkl/lib/rump.c @@ -0,0 +1,234 @@ +/* + * Rump hypercall interface for Linux + * Copyright (c) 2015 Hajime Tazaki + * + * Author: Hajime Tazaki + */ + +#include +#include + +#include "rump.h" + +#include +#include + +static struct lwp *rump_lkl_lwproc_curlwp(void); +static int rump_lkl_lwproc_newlwp(pid_t pid); +static void rump_lkl_lwproc_switch(struct lwp *newlwp); +static void rump_lkl_lwproc_release(void); +static int rump_lkl_lwproc_rfork(void *priv, int flags, const char *comm); + +void +rump_schedule(void) +{ +} + +void +rump_unschedule(void) +{ +} + +int +rump_daemonize_begin(void) +{ + return 0; +} + +int +rump_daemonize_done(int error) +{ + return 0; +} + + +int +rump_pub_lwproc_rfork(int arg1) +{ + int rv = 0; + + rump_schedule(); +// rv = rump_lkl_lwproc_rfork(arg1); + rump_unschedule(); + + return rv; +} + +int +rump_pub_lwproc_newlwp(pid_t arg1) +{ + int rv; + + rump_schedule(); + rv = rump_lkl_lwproc_newlwp(arg1); + rump_unschedule(); + + return rv; +} + +void +rump_pub_lwproc_switch(struct lwp *arg1) +{ + + rump_schedule(); + rump_lkl_lwproc_switch(arg1); + rump_unschedule(); +} + +void +rump_pub_lwproc_releaselwp(void) +{ + + rump_schedule(); + rump_lkl_lwproc_release(); + rump_unschedule(); +} + +struct lwp * +rump_pub_lwproc_curlwp(void) +{ + struct lwp *rv; + + rump_schedule(); + rv = rump_lkl_lwproc_curlwp(); + rump_unschedule(); + + return rv; +} + +int +rump_syscall(int num, void *data, size_t dlen, long *retval) +{ + int ret = 0; + + ret = lkl_syscall(num, (long *)data); + /* FIXME: need better err translation */ + if (ret < 0) { + retval[0] = -ret; + ret = -1; + } + return ret; +} + + +static int +rump_lkl_hyp_syscall(int num, void *arg, long *retval) +{ + return rump_syscall(num, arg, 0, retval); +} + +static int +rump_lkl_lwproc_rfork(void *priv, int flags, const char *comm) +{ +#ifdef ENABLE_SYSPROXY + /* FIXME: needs new task_struct instead of get_current() */ + struct thread_info *ti = task_thread_info(get_current()); + + /* store struct spc_client */ + ti->rump_client = priv; + + rumpuser_curlwpop(RUMPUSER_LWP_CREATE, (struct lwp *)ti); + rumpuser_curlwpop(RUMPUSER_LWP_SET, (struct lwp *)ti); +#endif + return 0; +} + +static void +rump_lkl_lwproc_release(void) +{ + struct thread_info *ti = (struct thread_info *)rumpuser_curlwp(); + + rumpuser_curlwpop(RUMPUSER_LWP_CLEAR, (struct lwp *)ti); +} + +static void +rump_lkl_lwproc_switch(struct lwp *newlwp) +{ + struct thread_info *ti = (struct thread_info *)rumpuser_curlwp(); + + rumpuser_curlwpop(RUMPUSER_LWP_CLEAR, (struct lwp *)ti); + rumpuser_curlwpop(RUMPUSER_LWP_SET, (struct lwp *)ti); +} + +/* find rump_task created by rfork */ +static int +rump_lkl_lwproc_newlwp(pid_t pid) +{ +#ifdef FIXME + /* find rump_task */ + struct thread_info *ti = NULL; + struct task_struct *p; + + for_each_process(p) { + if (p->pid == pid) { + ti = task_thread_info(p); + break; + } + } + + if (!ti) { + pr_warn("newlwp: could not find pid %d\n", pid); + ti = current_thread_info(); + /* FIXME */ +// return ESRCH; + } + + /* set to currnet */ + rumpuser_curlwpop(RUMPUSER_LWP_SET, (struct lwp *)ti); + +#endif /* FIXME */ + return 0; +} + +static struct lwp * +rump_lkl_lwproc_curlwp(void) +{ + return rumpuser_curlwp(); +} + +static void +rump_lkl_hyp_lwpexit(void) +{ + struct thread_info *ti = (struct thread_info *)rumpuser_curlwp(); + + rumpuser_curlwpop(RUMPUSER_LWP_DESTROY, (struct lwp *)ti); +#ifdef FIXME + free_thread_info(ti); +#endif +} + +static pid_t +rump_lkl_hyp_getpid(void) +{ +#ifdef FIXME + struct thread_info *ti = (struct thread_info *)rumpuser_curlwp(); + + return ti->task->pid; +#endif + return -1; +} + +static void rump_lkl_user_unschedule(int nlocks, int *countp, + void *interlock) {} +static void rump_lkl_user_schedule(int nlocks, void *interlock) {} +static void rump_lkl_hyp_execnotify(const char *comm) {} + +const struct rumpuser_hyperup hyp = { + .hyp_schedule = rump_schedule, + .hyp_unschedule = rump_unschedule, + .hyp_backend_unschedule = rump_lkl_user_unschedule, + .hyp_backend_schedule = rump_lkl_user_schedule, + + .hyp_lwproc_switch = rump_lkl_lwproc_switch, + .hyp_lwproc_release = rump_lkl_lwproc_release, + .hyp_lwproc_newlwp = rump_lkl_lwproc_newlwp, + .hyp_lwproc_curlwp = rump_lkl_lwproc_curlwp, + + .hyp_getpid = rump_lkl_hyp_getpid, + .hyp_syscall = rump_lkl_hyp_syscall, + .hyp_lwproc_rfork = rump_lkl_lwproc_rfork, + .hyp_lwpexit = rump_lkl_hyp_lwpexit, + .hyp_execnotify = rump_lkl_hyp_execnotify, +}; + + diff --git a/tools/lkl/lib/rump.h b/tools/lkl/lib/rump.h new file mode 100644 index 00000000000000..76d6b92e28ab6c --- /dev/null +++ b/tools/lkl/lib/rump.h @@ -0,0 +1,23 @@ +/* + * Rump hypercall interface for Linux + * Copyright (c) 2015 Hajime Tazaki + * + * Author: Hajime Tazaki + */ + +#define __dead +#define __printflike(x, y) +#include + +struct irq_data; + +void rump_sysproxy_init(void); +void rump_sysproxy_fini(void); + +extern const struct rumpuser_hyperup hyp; +#ifdef ENABLE_SYSPROXY +extern struct rump_sysproxy_ops rump_sysproxy_ops; +#endif + +int rump_pci_irq_request(struct irq_data *data); +void rump_pci_irq_release(struct irq_data *data); diff --git a/tools/lkl/lib/utils.c b/tools/lkl/lib/utils.c index af69b1511356d1..3740648a78be13 100644 --- a/tools/lkl/lib/utils.c +++ b/tools/lkl/lib/utils.c @@ -3,6 +3,10 @@ #include #include +#ifdef RUMPUSER +#include "rump.h" +#endif + static const char * const lkl_err_strings[] = { "Success", "Operation not permitted", diff --git a/tools/lkl/lib/virtio.c b/tools/lkl/lib/virtio.c index 5e1cecba943d5f..51cf69a95f56cb 100644 --- a/tools/lkl/lib/virtio.c +++ b/tools/lkl/lib/virtio.c @@ -66,6 +66,10 @@ struct _virtio_req { }; +#if defined(__ARMEL__) +#define __sync_synchronize(x) lkl__sync_synchronize(x) +#endif + static inline uint16_t virtio_get_used_event(struct virtio_queue *q) { return q->avail->ring[q->num]; diff --git a/tools/lkl/lib/virtio.h b/tools/lkl/lib/virtio.h index e0113789ce88ca..50faa50bfb4d17 100644 --- a/tools/lkl/lib/virtio.h +++ b/tools/lkl/lib/virtio.h @@ -89,4 +89,7 @@ void virtio_set_queue_max_merge_len(struct virtio_dev *dev, int q, int len); #define container_of(ptr, type, member) \ (type *)((char *)(ptr) - __builtin_offsetof(type, member)) +/* XXX: must be provided by another way */ +void franken_recv_thread(int fd, void *thrid); + #endif /* _LKL_LIB_VIRTIO_H */ diff --git a/tools/lkl/lib/virtio_net.c b/tools/lkl/lib/virtio_net.c index a06c2135ad2c62..25cdfb1b577623 100644 --- a/tools/lkl/lib/virtio_net.c +++ b/tools/lkl/lib/virtio_net.c @@ -258,6 +258,21 @@ int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args* args) if (dev->poll_tid == 0) goto out_cleanup_dev; + /* XXX: only for rump: need to use this semantics for franken_poll(2) */ +#ifdef LIBRUMPUSER + { + struct lkl_netdev_rumpfd { + struct lkl_netdev dev; + /* TAP device */ + int fd; + }; + + struct lkl_netdev_rumpfd *nd_rumpfd = + container_of(nd, struct lkl_netdev_rumpfd, dev); + franken_recv_thread(nd_rumpfd->fd, (void *)dev->poll_tid); + } +#endif /* LIBRUMPUSER */ + ret = dev_register(dev); if (ret < 0) goto out_cleanup_dev; diff --git a/tools/lkl/tests/Makefile b/tools/lkl/tests/Makefile index fbe1f8451120b5..4c41700109f648 100644 --- a/tools/lkl/tests/Makefile +++ b/tools/lkl/tests/Makefile @@ -27,7 +27,7 @@ endef QUICK?=0 VALGRIND_TEXT?=0 -FS_TYPES?=ext4 btrfs vfat xfs +FS_TYPES?=ext4 vfat xfs # The hijack tests are very time consuming, so run with `QUICK=1 make # test` if you want to stick to the unit tests diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index 8b9a392cfe5551..4a3c34f2cfa735 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -180,7 +180,7 @@ int test_creat(char *str, int len) snprintf(str, len, "%ld", ret); - if (ret == 0) + if (ret == 3) /* 0/1/2 are already opened */ return TEST_SUCCESS; return TEST_FAILURE;