From 970ebeef390e98147e0c93d63a66839a58766ed9 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:27 +0900 Subject: [PATCH 01/11] lkl: let atomic ops outsourced This will allow us to reimplpement atomic ops with lock/touch/unlock way if underlying hosts don't support a particular atomic ops. Signed-off-by: Hajime Tazaki --- arch/lkl/include/uapi/asm/host_ops.h | 9 +++ arch/lkl/kernel/Makefile | 2 +- arch/lkl/kernel/atomic.c | 97 ++++++++++++++++++++++++++++ arch/lkl/kernel/cpu.c | 8 +-- arch/lkl/kernel/irq.c | 8 +-- arch/lkl/kernel/setup.c | 2 + 6 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 arch/lkl/kernel/atomic.c diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index 0bf8b2bc4eb1c6..e6908678734303 100644 --- a/arch/lkl/include/uapi/asm/host_ops.h +++ b/arch/lkl/include/uapi/asm/host_ops.h @@ -149,4 +149,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..0021141dba280c 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 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/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..8db6e1cb3e8c2d 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 { 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(); From 12ea48f2797a423c090aae106b9e1432672b0642 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:28 +0900 Subject: [PATCH 02/11] lkl: add signal delivery support This only handles signals right after a system call was invoked. Signed-off-by: Hajime Tazaki --- arch/lkl/include/asm/Kbuild | 1 - arch/lkl/include/asm/signal.h | 3 +++ arch/lkl/kernel/Makefile | 2 +- arch/lkl/kernel/signal.c | 16 ++++++++++++++++ arch/lkl/kernel/syscalls.c | 2 ++ 5 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 arch/lkl/include/asm/signal.h create mode 100644 arch/lkl/kernel/signal.c diff --git a/arch/lkl/include/asm/Kbuild b/arch/lkl/include/asm/Kbuild index edf6aa282af4b8..a17d83bd799d2e 100644 --- a/arch/lkl/include/asm/Kbuild +++ b/arch/lkl/include/asm/Kbuild @@ -53,7 +53,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 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/kernel/Makefile b/arch/lkl/kernel/Makefile index 0021141dba280c..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 atomic.o + syscalls_32.o cpu.o atomic.o signal.o 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; } From f5ad407911fa721b7ea0c996d92a1c8d35171103 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:28 +0900 Subject: [PATCH 03/11] lkl: add irq_{request/release} host_ops entries This allows us to define IRQ related operation outside of the kernel by host_ops implementation. Signed-off-by: Hajime Tazaki --- arch/lkl/include/uapi/asm/host_ops.h | 4 +++ arch/lkl/kernel/irq.c | 39 +++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index e6908678734303..5718a996c247b1 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,9 @@ 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); + long (*gettid)(void); void (*jmp_buf_set)(struct lkl_jmp_buf *jmpb, void (*f)(void)); diff --git a/arch/lkl/kernel/irq.c b/arch/lkl/kernel/irq.c index 8db6e1cb3e8c2d..455f3e3cb8a195 100644 --- a/arch/lkl/kernel/irq.c +++ b/arch/lkl/kernel/irq.c @@ -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"); } From 5a870631e7a45da46a2e1bd698fa9d767bcc899c Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:29 +0900 Subject: [PATCH 04/11] lkl: add getparam host_ops entry This host_ops entry will provide a way to pass any variables (e.g., environmental variables) to an LKL application from the host environment. Signed-off-by: Hajime Tazaki --- arch/lkl/include/uapi/asm/host_ops.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index 5718a996c247b1..3bf26bc7b15882 100644 --- a/arch/lkl/include/uapi/asm/host_ops.h +++ b/arch/lkl/include/uapi/asm/host_ops.h @@ -127,6 +127,8 @@ struct lkl_host_operations { 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)); From 82f73f9dc65753c5f02aa98afda298a3263520a8 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Sat, 11 Feb 2017 23:37:47 +0900 Subject: [PATCH 05/11] lkl: add rump hypercall implementation for frankenlibc build This commit adds an implementation of new host_ops by using rump hypercall (wrapped as an LKL host_ops) provided by rumpkernel project. The rump hypercall implementation is specifically integrated with the one provided by frankenlibc project, which is an alternative way to use rump hypercalls. There are other rump hypercall implementations such as rumprun, NetBSD kernel tree, but this commit only focuses on the frankenlibc integration. The new features covered by this commits ranges in various ways, but here is some highlights. - New thread primitives frankenlibc implements user-space thread implementation based on makecontext(3)&co with non-preemptive (cooperative) scheduler implementation. - LKL specific standard library bind frankenlibc offers cross-compiler build chains to build an LKL application bound to LKL-versioned standard library (i.e., libc). Our musl libc implementation is provided by different repository. So, any application can be built with this toolchain to use LKL instead of host libc. - New host environments support LKLed application now has potentials to run on the platform which rump hypercall implementations support. frankenlibc supports Liunx, FreeBSD, NetBSD, and qemu-arm. Others supposrts run an LKL applications on hypervisors (kvm, xen, etc) The frankenlibc code is located at the following repository, but it will be upstreamed to the original one (justincormack/frankenlibc). https://github.com/libos-nuse/frankenlibc Signed-off-by: Hajime Tazaki --- arch/lkl/Kconfig | 3 + arch/lkl/Makefile | 32 +- arch/lkl/defconfig | 1 + arch/lkl/include/asm/Kbuild | 2 + arch/lkl/kernel/console.c | 87 ++++- tools/lkl/Makefile | 39 ++- tools/lkl/lib/Build | 17 +- tools/lkl/lib/fs.c | 6 +- tools/lkl/lib/net.c | 6 +- tools/lkl/lib/rump-host.c | 672 ++++++++++++++++++++++++++++++++++++ tools/lkl/lib/rump.c | 234 +++++++++++++ tools/lkl/lib/rump.h | 20 ++ tools/lkl/lib/utils.c | 4 + tools/lkl/lib/virtio.h | 3 + tools/lkl/lib/virtio_net.c | 15 + tools/lkl/tests/boot.c | 2 +- 16 files changed, 1124 insertions(+), 19 deletions(-) create mode 100644 tools/lkl/lib/rump-host.c create mode 100644 tools/lkl/lib/rump.c create mode 100644 tools/lkl/lib/rump.h diff --git a/arch/lkl/Kconfig b/arch/lkl/Kconfig index 67cf0a6cb0628d..b37b23517aa7bc 100644 --- a/arch/lkl/Kconfig +++ b/arch/lkl/Kconfig @@ -45,6 +45,9 @@ config 64BIT config BIG_ENDIAN def_bool n +config TTY + def_bool n + config GENERIC_CSUM def_bool y diff --git a/arch/lkl/Makefile b/arch/lkl/Makefile index 84efa7564d9f27..7eeb7d34efa48e 100644 --- a/arch/lkl/Makefile +++ b/arch/lkl/Makefile @@ -21,9 +21,39 @@ 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/ @@ -31,7 +61,7 @@ core-y += arch/lkl/mm/ 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..8d0667580b8bf0 100644 --- a/arch/lkl/defconfig +++ b/arch/lkl/defconfig @@ -31,6 +31,7 @@ CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_XFS_FS=y CONFIG_XFS_POSIX_ACL=y +CONFIG_ISO9660_FS=y CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y # CONFIG_FILE_LOCKING is not set diff --git a/arch/lkl/include/asm/Kbuild b/arch/lkl/include/asm/Kbuild index a17d83bd799d2e..2015a6a84b95bd 100644 --- a/arch/lkl/include/asm/Kbuild +++ b/arch/lkl/include/asm/Kbuild @@ -72,4 +72,6 @@ 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/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/tools/lkl/Makefile b/tools/lkl/Makefile index f055632fb66222..3e239721fe20af 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: @@ -37,8 +40,8 @@ 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) @@ -49,6 +52,8 @@ ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64 elf32-i386 elf64-x86-64-freebsd e 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 +78,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 +120,19 @@ 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 + +endif TEST_TARGETS := test valgrind gdb @@ -147,12 +167,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 +210,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/fs.c b/tools/lkl/lib/fs.c index b56a5a3d29dc4e..ba194470f17757 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) { 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.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..66ae233dbb545d --- /dev/null +++ b/tools/lkl/lib/rump.h @@ -0,0 +1,20 @@ +/* + * 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; + +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.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/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; From 499ba64ca3648bf9a5af393d822f6a30c32a350c Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:31 +0900 Subject: [PATCH 06/11] lkl: fix arm-none-eabi- build with frankenlibc qemu-arm support with frankenlibc & lkl is limited at this moment: no network (virtio-net) is not supported yet, etc. Signed-off-by: Hajime Tazaki --- arch/lkl/Makefile | 5 +++++ tools/lkl/Makefile | 9 +++++---- tools/lkl/lib/endian.h | 10 ++++++++++ tools/lkl/lib/virtio.c | 4 ++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/arch/lkl/Makefile b/arch/lkl/Makefile index 7eeb7d34efa48e..30fc5367ddcdc7 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 diff --git a/tools/lkl/Makefile b/tools/lkl/Makefile index 3e239721fe20af..b5f3b29d5af742 100644 --- a/tools/lkl/Makefile +++ b/tools/lkl/Makefile @@ -22,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 := @@ -44,11 +44,12 @@ export CFLAGS += -I$(OUTPUT)/include -Iinclude -Wall -g -O2 -Wextra \ -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 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/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]; From 75bae623f1ff3bd39a9944cce45dba03119e3017 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:32 +0900 Subject: [PATCH 07/11] lkl: add experimental rump syscall proxy support The code is not built as-is but put an implementation using rump syscall proxy which makes an LKL application communicate with outside of the process. Signed-off-by: Hajime Tazaki --- arch/lkl/include/asm/Kbuild | 1 - arch/lkl/include/asm/thread_info.h | 1 + arch/lkl/include/asm/uaccess.h | 70 ++++++++++++++++++++++++++++++ tools/lkl/lib/rump-sysproxy.c | 29 +++++++++++++ tools/lkl/lib/rump.h | 3 ++ 5 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 arch/lkl/include/asm/uaccess.h create mode 100644 tools/lkl/lib/rump-sysproxy.c diff --git a/arch/lkl/include/asm/Kbuild b/arch/lkl/include/asm/Kbuild index 2015a6a84b95bd..d2a6eb9316b8b7 100644 --- a/arch/lkl/include/asm/Kbuild +++ b/arch/lkl/include/asm/Kbuild @@ -70,7 +70,6 @@ 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 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/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.h b/tools/lkl/lib/rump.h index 66ae233dbb545d..76d6b92e28ab6c 100644 --- a/tools/lkl/lib/rump.h +++ b/tools/lkl/lib/rump.h @@ -15,6 +15,9 @@ 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); From badf2bd2b99819182b49e8f850d5481221597867 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:33 +0900 Subject: [PATCH 08/11] lkl: add rumpun unikernel support for LKL This commit offers an integration with rumprun unikernel. It is only tested with qemu-system-x86_64 but it potentially works fine with x86 baremetal machines as well as xen hypervior. An initial PCI device support is also implemented by relying on exposed virtual devices from hyperviros: virtio-net device is tested for the moment. The rumprun repository to support lkl build is not upstreamed yet - you can try with the following repository before it will be in. https://github.com/libos-nuse/rumprun Signed-off-by: Hajime Tazaki --- arch/lkl/Kconfig | 6 + arch/lkl/Makefile | 1 + arch/lkl/defconfig | 4 + arch/lkl/drivers/Makefile | 13 ++ arch/lkl/drivers/pci_user.h | 43 ++++++ arch/lkl/drivers/rumpdev_pci.c | 263 +++++++++++++++++++++++++++++++++ arch/lkl/include/asm/Kbuild | 3 +- arch/lkl/include/asm/dma.h | 12 ++ arch/lkl/include/asm/pci.h | 10 ++ tools/lkl/Makefile | 6 + tools/lkl/lib/fs.c | 6 + tools/lkl/lib/iomem.c | 85 +++++++++++ 12 files changed, 450 insertions(+), 2 deletions(-) create mode 100644 arch/lkl/drivers/Makefile create mode 100644 arch/lkl/drivers/pci_user.h create mode 100644 arch/lkl/drivers/rumpdev_pci.c create mode 100644 arch/lkl/include/asm/dma.h create mode 100644 arch/lkl/include/asm/pci.h diff --git a/arch/lkl/Kconfig b/arch/lkl/Kconfig index b37b23517aa7bc..4e2dd2e6f4bceb 100644 --- a/arch/lkl/Kconfig +++ b/arch/lkl/Kconfig @@ -61,6 +61,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 30fc5367ddcdc7..dedabebfe5bbc8 100644 --- a/arch/lkl/Makefile +++ b/arch/lkl/Makefile @@ -62,6 +62,7 @@ endif core-y += arch/lkl/kernel/ core-y += arch/lkl/mm/ +core-y += arch/lkl/drivers/ all: lkl.o diff --git a/arch/lkl/defconfig b/arch/lkl/defconfig index 8d0667580b8bf0..1cb5db2e2545ad 100644 --- a/arch/lkl/defconfig +++ b/arch/lkl/defconfig @@ -94,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 d2a6eb9316b8b7..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 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/tools/lkl/Makefile b/tools/lkl/Makefile index b5f3b29d5af742..a8447f9e4cbe4d 100644 --- a/tools/lkl/Makefile +++ b/tools/lkl/Makefile @@ -133,6 +133,12 @@ else 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 diff --git a/tools/lkl/lib/fs.c b/tools/lkl/lib/fs.c index ba194470f17757..e0d4fb77c17fab 100644 --- a/tools/lkl/lib/fs.c +++ b/tools/lkl/lib/fs.c @@ -76,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; } From 5f9d30229e5e23a2b94c1876a338f0966110fdbb Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:34 +0900 Subject: [PATCH 09/11] lkl: work around for arm build failure (Issue #229) Signed-off-by: Hajime Tazaki --- arch/lkl/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/lkl/Kconfig b/arch/lkl/Kconfig index 4e2dd2e6f4bceb..b5b6a4fe749445 100644 --- a/arch/lkl/Kconfig +++ b/arch/lkl/Kconfig @@ -45,6 +45,9 @@ config 64BIT config BIG_ENDIAN def_bool n +config KALLSYMS_BASE_RELATIVE + def_bool n + config TTY def_bool n From f82b29491d2a175b5912a947c1142aab85f60b40 Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Fri, 10 Feb 2017 17:33:51 +0900 Subject: [PATCH 10/11] lkl: temporary disabled btrfs Signed-off-by: Hajime Tazaki --- arch/lkl/defconfig | 4 ++-- tools/lkl/tests/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/lkl/defconfig b/arch/lkl/defconfig index 1cb5db2e2545ad..d9047fd7668871 100644 --- a/arch/lkl/defconfig +++ b/arch/lkl/defconfig @@ -32,8 +32,8 @@ CONFIG_EXT4_FS_SECURITY=y CONFIG_XFS_FS=y CONFIG_XFS_POSIX_ACL=y CONFIG_ISO9660_FS=y -CONFIG_BTRFS_FS=y -CONFIG_BTRFS_FS_POSIX_ACL=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 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 From 95be33af7d91823a7a21d1bed41cd780ced0499c Mon Sep 17 00:00:00 2001 From: Hajime Tazaki Date: Mon, 13 Feb 2017 17:20:11 +0900 Subject: [PATCH 11/11] Revert "device core: Remove deprecated create_singlethread_workqueue" This reverts commit 2c507e464f79 ("device core: Remove deprecated create_singlethread_workqueue"). This is a temporary fix for qemu-arm hangs on the following command that schedule_work() triggers (?) dead-lock that nanosleep on hello->main() never returns. $ qemu-system-arm -M versatilepb -m 512M -nographic -serial null \ -semihosting -kernel rumpobj/tests/hello This should be fixed in a transparent way in a future. Signed-off-by: Hajime Tazaki --- drivers/base/dd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) 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);