@@ -28,6 +28,7 @@ config UMMODE_LIB
depends on !SMP
select UACCESS_MEMCPY
select ARCH_THREAD_STACK_ALLOCATOR
+ select ARCH_HAS_SYSCALL_WRAPPER
help
This mode switches a mode to build a library of UML (Linux
Kernel Library/LKL). If this is Y, the build only generates,
@@ -1,2 +1,18 @@
KBUILD_CFLAGS += -fno-builtin -fPIC
ELF_FORMAT=$(shell $(LD) -r -print-output-format)
+
+INSTALL_PATH ?= $(objtree)/tools/um
+SYSCALL_DEFS_H := $(objtree)/$(HOST_DIR)/include/generated/uapi/asm/syscall_defs.h
+REPLACED_SYSCALL_DEFS_H := $(INSTALL_PATH)/include/lkl/asm/syscall_defs.h
+
+um_headers_install: $(REPLACED_SYSCALL_DEFS_H) scripts_unifdef
+
+$(REPLACED_SYSCALL_DEFS_H): $(SYSCALL_DEFS_H) $(srctree)/$(ARCH_DIR)/scripts/headers_install.py
+ $(Q)$(srctree)/$(ARCH_DIR)/scripts/headers_install.py \
+ $(INSTALL_PATH)/include
+
+$(objtree)/$(HOST_DIR)/include/generated/uapi/asm/syscall_defs.h: vmlinux
+ $(Q)$(OBJCOPY) -j .syscall_defs -O binary --set-section-flags \
+ .syscall_defs=alloc $< $@
+ $(Q) export tmpfile=$(shell mktemp); \
+ sed 's/\x0//g' $@ > $$tmpfile; mv $$tmpfile $@ ; rm -f $$tmpfile
new file mode 100644
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __UM_SYSCALL_WRAPPER_H
+#define __UM_SYSCALL_WRAPPER_H
+
+#define __SC_ASCII(t, a) #t "," #a
+
+#define __ASCII_MAP0(m, ...)
+#define __ASCII_MAP1(m, t, a) m(t, a)
+#define __ASCII_MAP2(m, t, a, ...) m(t, a) "," __ASCII_MAP1(m, __VA_ARGS__)
+#define __ASCII_MAP3(m, t, a, ...) m(t, a) "," __ASCII_MAP2(m, __VA_ARGS__)
+#define __ASCII_MAP4(m, t, a, ...) m(t, a) "," __ASCII_MAP3(m, __VA_ARGS__)
+#define __ASCII_MAP5(m, t, a, ...) m(t, a) "," __ASCII_MAP4(m, __VA_ARGS__)
+#define __ASCII_MAP6(m, t, a, ...) m(t, a) "," __ASCII_MAP5(m, __VA_ARGS__)
+#define __ASCII_MAP(n, ...) __ASCII_MAP##n(__VA_ARGS__)
+
+#ifdef __MINGW32__
+#define SECTION_ATTRS "n0"
+#else
+#define SECTION_ATTRS "a"
+#endif
+
+#define __SYSCALL_DEFINE_ARCH(x, name, ...) \
+ asm(".section .syscall_defs,\"" SECTION_ATTRS "\"\n" \
+ ".ascii \"#ifdef __NR" #name "\\n\"\n" \
+ ".ascii \"SYSCALL_DEFINE" #x "(" #name "," \
+ __ASCII_MAP(x, __SC_ASCII, __VA_ARGS__) ")\\n\"\n" \
+ ".ascii \"#endif\\n\"\n" \
+ ".section .text\n")
+
+#define SYSCALL_DEFINE0(sname) \
+ SYSCALL_METADATA(_##sname, 0); \
+ __SYSCALL_DEFINE_ARCH(0, _##sname); \
+ asmlinkage long sys_##sname(void); \
+ ALLOW_ERROR_INJECTION(sys_##sname, ERRNO); \
+ asmlinkage long sys_##sname(void)
+
+#define __SYSCALL_DEFINEx(x, name, ...) \
+ __SYSCALL_DEFINE_ARCH(x, name, __VA_ARGS__); \
+ __diag_push(); \
+ __diag_ignore(GCC, 8, "-Wattribute-alias", \
+ "Type aliasing is used to sanitize syscall arguments");\
+ asmlinkage long sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \
+ __attribute__((alias(__stringify(__se_sys##name)))); \
+ ALLOW_ERROR_INJECTION(sys##name, ERRNO); \
+ static inline long __do_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)); \
+ asmlinkage long __se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)); \
+ asmlinkage long __se_sys##name(__MAP(x, __SC_LONG, __VA_ARGS__)) \
+ { \
+ long ret = __do_sys##name(__MAP(x, __SC_CAST, __VA_ARGS__)); \
+ __MAP(x, __SC_TEST, __VA_ARGS__); \
+ __PROTECT(x, ret, __MAP(x, __SC_ARGS, __VA_ARGS__)); \
+ return ret; \
+ } \
+ __diag_pop(); \
+ static inline long __do_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__))
+
+#endif /* __UM_SYSCALL_WRAPPER_H */
new file mode 100644
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+int syscalls_init(void);
+void syscalls_cleanup(void);
+long lkl_syscall(long no, long *params);
+void wakeup_idle_host_task(void);
+
+#define sys_mmap sys_ni_syscall
+#define sys_rt_sigreturn sys_ni_syscall
+#define sys_arch_prctl sys_ni_syscall
+#define sys_iopl sys_ni_syscall
+#define sys_ioperm sys_ni_syscall
+#define sys_clone sys_ni_syscall
+
+int run_syscalls(void);
new file mode 100644
@@ -0,0 +1,6 @@
+# UAPI Header export list
+
+generated-y += syscall_defs.h
+
+# generated-y file is parsed by special user headers handling
+# see arch/um/script/headers_install.py
@@ -2,7 +2,10 @@
#ifndef __UM_LIBMODE_UAPI_BITSPERLONG_H
#define __UM_LIBMODE_UAPI_BITSPERLONG_H
-#ifdef CONFIG_64BIT
+/* need to add new arch defines here, as we cannot use CONFIG_64BIT here
+ * to avoid CONFIG leaks to userspace
+ */
+#if defined(__x86_64__)
#define __BITS_PER_LONG 64
#else
#define __BITS_PER_LONG 32
@@ -2,10 +2,12 @@
#ifndef __UM_LIBMODE_UAPI_BYTEORDER_H
#define __UM_LIBMODE_UAPI_BYTEORDER_H
-#if defined(CONFIG_BIG_ENDIAN)
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#include <linux/byteorder/big_endian.h>
-#else
+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#include <linux/byteorder/little_endian.h>
+#else
+#error "cannot detect endian of the target"
#endif
#endif
@@ -200,4 +200,47 @@ void lkl_jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void));
*/
void lkl_jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val);
+/**
+ * lkl_tls_alloc - allocate a thread local storage key
+ *
+ * @destructor: a destructor called upon termination. if this is not NULL it
+ * will be called when a thread terminates with its argument set to the current
+ * thread local storage value
+ *
+ * Return: non-NULL address of allocated struct lkl_tls_key if successful;
+ * otherwise NULL
+ *
+ */
+struct lkl_tls_key *lkl_tls_alloc(void (*destructor)(void *));
+
+/**
+ * lkl_tls_free - frees a thread local storage key
+ *
+ * @key: lkl_tls_key to be freed
+ *
+ */
+void lkl_tls_free(struct lkl_tls_key *key);
+
+/**
+ * lkl_tls_set - associate data to the thread local storage key
+ *
+ * @key: lkl_tls_key to be configured
+ * @data: the value associated with the @key
+ *
+ * Return: 0 if successful
+ *
+ */
+int lkl_tls_set(struct lkl_tls_key *key, void *data);
+
+/**
+ * lkl_tls_get - obtain the value associated with tls
+ *
+ * @key: lkl_tls_key to be queried
+ *
+ * Return: data associated with the thread local storage key or NULL
+ * on error
+ *
+ */
+void *lkl_tls_get(struct lkl_tls_key *key);
+
#endif
new file mode 100644
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __UM_LIBMODE_UAPI_SYSCALLS_H
+#define __UM_LIBMODE_UAPI_SYSCALLS_H
+
+#include <linux/types.h>
+
+typedef __kernel_uid32_t qid_t;
+typedef __kernel_fd_set fd_set;
+typedef __kernel_mode_t mode_t;
+typedef unsigned short umode_t;
+typedef __u32 nlink_t;
+typedef __kernel_off_t off_t;
+typedef __kernel_pid_t pid_t;
+typedef __kernel_key_t key_t;
+typedef __kernel_suseconds_t suseconds_t;
+typedef __kernel_timer_t timer_t;
+typedef __kernel_clockid_t clockid_t;
+typedef __kernel_mqd_t mqd_t;
+typedef __kernel_uid32_t uid_t;
+typedef __kernel_gid32_t gid_t;
+typedef __kernel_uid16_t uid16_t;
+typedef __kernel_gid16_t gid16_t;
+typedef unsigned long uintptr_t;
+
+typedef __kernel_loff_t loff_t;
+typedef __kernel_size_t size_t;
+typedef __kernel_ssize_t ssize_t;
+typedef __kernel_time_t time_t;
+typedef __kernel_clock_t clock_t;
+typedef __u32 u32;
+typedef __s32 s32;
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __kernel_long_t __kernel_old_time_t;
+
+#define __user
+
+#include <asm/unistd.h>
+/* Temporary undefine system calls that don't have data types defined in UAPI
+ * headers
+ */
+#undef __NR_kexec_load
+#undef __NR_getcpu
+#undef __NR_sched_getattr
+#undef __NR_sched_setattr
+#undef __NR_sched_setparam
+#undef __NR_sched_getparam
+#undef __NR_sched_setscheduler
+#undef __NR_name_to_handle_at
+#undef __NR_open_by_handle_at
+
+/* deprecated system calls */
+#undef __NR_access
+#undef __NR_chmod
+#undef __NR_chown
+#undef __NR_lchown
+#undef __NR_open
+#undef __NR_creat
+#undef __NR_readlink
+#undef __NR_pipe
+#undef __NR_mknod
+#undef __NR_mkdir
+#undef __NR_rmdir
+#undef __NR_unlink
+#undef __NR_symlink
+#undef __NR_link
+#undef __NR_rename
+#undef __NR_getdents
+#undef __NR_select
+#undef __NR_poll
+#undef __NR_dup2
+#undef __NR_sysfs
+#undef __NR_ustat
+#undef __NR_inotify_init
+#undef __NR_epoll_create
+#undef __NR_epoll_wait
+#undef __NR_signalfd
+#undef __NR_eventfd
+
+#undef __NR_umount
+#define __NR_umount __NR_umount2
+
+#if defined(__x86_64__)
+#define __NR_newfstat __NR3264_fstat
+#define __NR_newfstatat __NR3264_fstatat
+#endif
+
+#include <linux/time.h>
+#include <linux/times.h>
+#include <linux/timex.h>
+#include <linux/capability.h>
+#define __KERNEL__ /* to pull in S_ definitions */
+#include <linux/stat.h>
+#undef __KERNEL__
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <asm/statfs.h>
+#include <asm/stat.h>
+#include <linux/bpf.h>
+#include <linux/msg.h>
+#include <linux/resource.h>
+#include <linux/sysinfo.h>
+#include <linux/shm.h>
+#include <linux/aio_abi.h>
+#include <linux/socket.h>
+#include <linux/perf_event.h>
+#include <linux/sem.h>
+#include <linux/futex.h>
+#include <linux/poll.h>
+#include <linux/mqueue.h>
+#include <linux/eventpoll.h>
+#include <linux/uio.h>
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+#include <linux/utime.h>
+#include <asm/socket.h>
+#include <linux/icmp.h>
+#include <linux/ip.h>
+
+/* Define data structures used in system calls that are not defined in UAPI
+ * headers
+ */
+struct sockaddr {
+ unsigned short int sa_family;
+ char sa_data[14];
+};
+
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+#define __UAPI_DEF_IF_IFREQ 1
+#define __UAPI_DEF_IF_IFMAP 1
+#include <linux/if.h>
+#define __UAPI_DEF_IN_IPPROTO 1
+#define __UAPI_DEF_IN_ADDR 1
+#define __UAPI_DEF_IN6_ADDR 1
+#define __UAPI_DEF_IP_MREQ 1
+#define __UAPI_DEF_IN_PKTINFO 1
+#define __UAPI_DEF_SOCKADDR_IN 1
+#define __UAPI_DEF_IN_CLASS 1
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/sockios.h>
+#include <linux/route.h>
+#include <linux/ipv6_route.h>
+#include <linux/ipv6.h>
+#include <linux/netlink.h>
+#include <linux/neighbour.h>
+#include <linux/rtnetlink.h>
+#include <linux/fib_rules.h>
+
+#include <linux/kdev_t.h>
+#include <linux/virtio_blk.h>
+#include <linux/virtio_net.h>
+#include <linux/virtio_ring.h>
+#include <linux/pkt_sched.h>
+#include <linux/io_uring.h>
+#include <linux/utsname.h>
+
+struct user_msghdr {
+ void __user *msg_name;
+ int msg_namelen;
+ struct iovec __user *msg_iov;
+ __kernel_size_t msg_iovlen;
+ void __user *msg_control;
+ __kernel_size_t msg_controllen;
+ unsigned int msg_flags;
+};
+
+typedef __u32 key_serial_t;
+
+struct mmsghdr {
+ struct user_msghdr msg_hdr;
+ unsigned int msg_len;
+};
+
+struct linux_dirent64 {
+ u64 d_ino;
+ s64 d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[0];
+};
+
+struct linux_dirent {
+ unsigned long d_ino;
+ unsigned long d_off;
+ unsigned short d_reclen;
+ char d_name[1];
+};
+
+struct ustat {
+ __kernel_daddr_t f_tfree;
+ __kernel_ino_t f_tinode;
+ char f_fname[6];
+ char f_fpack[6];
+};
+
+struct __aio_sigset;
+struct clone_args;
+
+typedef __kernel_rwf_t rwf_t;
+
+/**
+ * lkl_syscall() - issue LKL system calls
+ *
+ * @no: system call number
+ * @params: parameters of system calls
+ *
+ * Return: 0 if there is no error; otherwise non-zero value returns.
+ *
+ * The function is an entry point of LKL system call.
+ */
+long lkl_syscall(long no, long *params);
+
+/**
+ * lkl_sys_halt() - terminate LKL kernel
+ *
+ * Return: 0 if there is no error; otherwise non-zero value returns.
+ *
+ * The function requests the termination of LKL kernel.
+ */
+long lkl_sys_halt(void);
+
+#define __MAP0(m, ...)
+#define __MAP1(m, t, a) m(t, a)
+#define __MAP2(m, t, a, ...) m(t, a), __MAP1(m, __VA_ARGS__)
+#define __MAP3(m, t, a, ...) m(t, a), __MAP2(m, __VA_ARGS__)
+#define __MAP4(m, t, a, ...) m(t, a), __MAP3(m, __VA_ARGS__)
+#define __MAP5(m, t, a, ...) m(t, a), __MAP4(m, __VA_ARGS__)
+#define __MAP6(m, t, a, ...) m(t, a), __MAP5(m, __VA_ARGS__)
+#define __MAP(n, ...) __MAP##n(__VA_ARGS__)
+
+#define __SC_LONG(t, a) (long)(a)
+#define __SC_TABLE(t, a) {sizeof(t), (long long)(a)}
+#define __SC_DECL(t, a) t a
+
+#define LKL_SYSCALL0(name) \
+ static inline long lkl_sys##name(void) \
+ { \
+ long params[6]; \
+ return lkl_syscall(__lkl__NR##name, params); \
+ }
+
+#if __BITS_PER_LONG == 32
+#define LKL_SYSCALLx(x, name, ...) \
+ static inline \
+ long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \
+ { \
+ struct { \
+ unsigned int size; \
+ long long value; \
+ } lkl_params[x] = { __MAP(x, __SC_TABLE, __VA_ARGS__) }; \
+ long sys_params[6], i, k; \
+ for (i = k = 0; i < x && k < 6; i++, k++) { \
+ if (lkl_params[i].size > sizeof(long) && \
+ k + 1 < 6) { \
+ sys_params[k] = \
+ (long)(lkl_params[i].value & (-1UL)); \
+ k++; \
+ sys_params[k] = \
+ (long)(lkl_params[i].value >> \
+ __BITS_PER_LONG); \
+ } else { \
+ sys_params[k] = (long)(lkl_params[i].value); \
+ } \
+ } \
+ return lkl_syscall(__lkl__NR##name, sys_params); \
+ }
+#else
+#define LKL_SYSCALLx(x, name, ...) \
+ static inline \
+ long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \
+ { \
+ long lkl_params[6] = { __MAP(x, __SC_LONG, __VA_ARGS__) }; \
+ return lkl_syscall(__lkl__NR##name, lkl_params); \
+ }
+#endif
+
+#define SYSCALL_DEFINE0(name, ...) LKL_SYSCALL0(name)
+#define SYSCALL_DEFINE1(name, ...) LKL_SYSCALLx(1, name, __VA_ARGS__)
+#define SYSCALL_DEFINE2(name, ...) LKL_SYSCALLx(2, name, __VA_ARGS__)
+#define SYSCALL_DEFINE3(name, ...) LKL_SYSCALLx(3, name, __VA_ARGS__)
+#define SYSCALL_DEFINE4(name, ...) LKL_SYSCALLx(4, name, __VA_ARGS__)
+#define SYSCALL_DEFINE5(name, ...) LKL_SYSCALLx(5, name, __VA_ARGS__)
+#define SYSCALL_DEFINE6(name, ...) LKL_SYSCALLx(6, name, __VA_ARGS__)
+
+#if __BITS_PER_LONG == 32
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
+#endif
+
+#include <asm/syscall_defs.h>
+
+#if __BITS_PER_LONG == 32
+#pragma GCC diagnostic pop
+#endif
+
+#endif
new file mode 100644
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __UM_LIBMODE_UAPI_UNISTD_H
+#define __UM_LIBMODE_UAPI_UNISTD_H
+
+#define __ARCH_WANT_NEW_STAT
+#include <asm/bitsperlong.h>
+
+#if __BITS_PER_LONG == 64
+#define __ARCH_WANT_SYS_NEWFSTATAT
+#endif
+
+#include <asm-generic/unistd.h>
+
+
+#endif
new file mode 100644
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
+#undef CONFIG_ARCH_HAS_SYSCALL_WRAPPER
+#include <linux/syscalls.h>
+#define CONFIG_ARCH_HAS_SYSCALL_WRAPPER
+#endif
+
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/jhash.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/net.h>
+#include <linux/task_work.h>
+
+#include <asm/host_ops.h>
+#include <asm/syscalls.h>
+#include <asm/cpu.h>
+#include <asm/sched.h>
+#include <kern_util.h>
+#include <os.h>
+
+typedef long (*syscall_handler_t)(long arg1, ...);
+
+#undef __SYSCALL
+#define __SYSCALL(nr, sym)[nr] = (syscall_handler_t)sym,
+
+syscall_handler_t syscall_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls - 1] = (syscall_handler_t)sys_ni_syscall,
+#undef __UM_LIBMODE_UAPI_UNISTD_H
+#include <asm/unistd.h>
+
+#if __BITS_PER_LONG == 32
+#include <asm/unistd_32.h>
+#endif
+};
+
+
+static long run_syscall(long no, long *params)
+{
+ long ret;
+
+ if (no < 0 || no >= __NR_syscalls)
+ return -ENOSYS;
+
+ ret = syscall_table[no](params[0], params[1], params[2], params[3],
+ params[4], params[5]);
+
+ task_work_run();
+
+ return ret;
+}
+
+
+#define CLONE_FLAGS (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | \
+ CLONE_SIGHAND | SIGCHLD)
+
+static int host_task_id;
+static struct task_struct *host0;
+
+static int new_host_task(struct task_struct **task)
+{
+ pid_t pid;
+
+ switch_to_host_task(host0);
+
+ pid = kernel_thread(host_task_stub, NULL, CLONE_FLAGS);
+ if (pid < 0)
+ return pid;
+
+ rcu_read_lock();
+ *task = find_task_by_pid_ns(pid, &init_pid_ns);
+ rcu_read_unlock();
+
+ host_task_id++;
+
+ snprintf((*task)->comm, sizeof((*task)->comm), "host%d", host_task_id);
+
+ return 0;
+}
+static void exit_task(void)
+{
+ do_exit(0);
+}
+
+static void del_host_task(void *arg)
+{
+ struct task_struct *task = (struct task_struct *)arg;
+ struct thread_info *ti = task_thread_info(task);
+
+ if (lkl_cpu_get() < 0)
+ return;
+
+ switch_to_host_task(task);
+ host_task_id--;
+ set_ti_thread_flag(ti, TIF_SCHED_JB);
+ lkl_jmp_buf_set(&ti->task->thread.arch.sched_jb, exit_task);
+}
+
+static struct lkl_tls_key *task_key;
+
+long lkl_syscall(long no, long *params)
+{
+ struct task_struct *task = host0;
+ long ret;
+
+ ret = lkl_cpu_get();
+ if (ret < 0)
+ return ret;
+
+ task = lkl_tls_get(task_key);
+ if (!task) {
+ ret = new_host_task(&task);
+ if (ret)
+ goto out;
+ lkl_tls_set(task_key, task);
+ }
+
+ switch_to_host_task(task);
+
+ ret = run_syscall(no, params);
+
+ if (no == __NR_reboot) {
+ thread_sched_jb();
+ return ret;
+ }
+
+out:
+ lkl_cpu_put();
+
+ return ret;
+}
+
+static struct task_struct *idle_host_task;
+
+/* called from idle, don't failed, don't block */
+void wakeup_idle_host_task(void)
+{
+ if (!need_resched() && idle_host_task)
+ wake_up_process(idle_host_task);
+}
+
+static int idle_host_task_loop(void *unused)
+{
+ struct thread_info *ti = task_thread_info(current);
+
+ snprintf(current->comm, sizeof(current->comm), "idle_host_task");
+ set_thread_flag(TIF_HOST_THREAD);
+ idle_host_task = current;
+
+ for (;;) {
+ lkl_cpu_put();
+ lkl_sem_down(ti->task->thread.arch.sched_sem);
+ if (idle_host_task == NULL) {
+ lkl_thread_exit();
+ return 0;
+ }
+ schedule_tail(ti->task->thread.prev_sched);
+ }
+}
+
+int syscalls_init(void)
+{
+ snprintf(current->comm, sizeof(current->comm), "host0");
+ set_thread_flag(TIF_HOST_THREAD);
+ host0 = current;
+
+ task_key = lkl_tls_alloc(del_host_task);
+ if (!task_key)
+ return -1;
+
+ if (kernel_thread(idle_host_task_loop, NULL, CLONE_FLAGS) < 0) {
+ lkl_tls_free(task_key);
+ return -1;
+ }
+
+ return 0;
+}
+
+void syscalls_cleanup(void)
+{
+ if (idle_host_task) {
+ struct thread_info *ti = task_thread_info(idle_host_task);
+
+ idle_host_task = NULL;
+ lkl_sem_up(ti->task->thread.arch.sched_sem);
+ lkl_thread_join(ti->task->thread.arch.tid);
+ }
+
+ lkl_tls_free(task_key);
+}
new file mode 100755
@@ -0,0 +1,200 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+import re, os, sys, argparse, multiprocessing, fnmatch
+
+srctree = os.environ["srctree"]
+objtree = os.environ["objtree"]
+header_paths = [ "include/uapi/", "arch/um/lkl/include/uapi/",
+ "arch/um/lkl/include/generated/uapi/" ]
+
+headers = set()
+includes = set()
+
+def relpath2abspath(relpath):
+ if "generated" in relpath:
+ return objtree + "/" + relpath
+ else:
+ return srctree + "/" + relpath
+
+def find_headers(path):
+ headers.add(path)
+ f = open(relpath2abspath(path))
+ for l in f.readlines():
+ m = re.search("#\s*include <(.*)>", l)
+ try:
+ i = m.group(1)
+ for p in header_paths:
+ if os.access(relpath2abspath(p + i), os.R_OK):
+ if p + i not in headers:
+ includes.add(i)
+ headers.add(p + i)
+ find_headers(p + i)
+ except:
+ pass
+ f.close()
+
+def has_lkl_prefix(w):
+ return w.startswith("lkl") or w.startswith("_lkl") or w.startswith("__lkl") \
+ or w.startswith("LKL") or w.startswith("_LKL") or w.startswith("__LKL")
+
+def find_symbols(regexp, store):
+ for h in headers:
+ f = open(h)
+ for l in f.readlines():
+ m = regexp.search(l)
+ if not m:
+ continue
+ for e in reversed(m.groups()):
+ if e:
+ if not has_lkl_prefix(e):
+ store.add(e)
+ break
+ f.close()
+
+def find_ml_symbols(regexp, store):
+ for h in headers:
+ for i in regexp.finditer(open(h).read()):
+ for j in reversed(i.groups()):
+ if j:
+ if not has_lkl_prefix(j):
+ store.add(j)
+ break
+
+def find_enums(block_regexp, symbol_regexp, store):
+ for h in headers:
+ # remove comments
+ content = re.sub(re.compile("(\/\*(\*(?!\/)|[^*])*\*\/)", re.S|re.M), " ", open(h).read())
+ # remove preprocesor lines
+ clean_content = ""
+ for l in content.split("\n"):
+ if re.match("\s*#", l):
+ continue
+ clean_content += l + "\n"
+ for i in block_regexp.finditer(clean_content):
+ for j in reversed(i.groups()):
+ if j:
+ for k in symbol_regexp.finditer(j):
+ for l in k.groups():
+ if l:
+ if not has_lkl_prefix(l):
+ store.add(l)
+ break
+
+def lkl_prefix(w):
+ r = ""
+
+ if w.startswith("__"):
+ r = "__"
+ elif w.startswith("_"):
+ r = "_"
+
+ if w.isupper():
+ r += "LKL"
+ else:
+ r += "lkl"
+
+ if not w.startswith("_"):
+ r += "_"
+
+ r += w
+
+ return r
+
+def replace(h):
+ content = open(h).read()
+ for i in includes:
+ search_str = "(#[ \t]*include[ \t]*[<\"][ \t]*)" + i + "([ \t]*[>\"])"
+ replace_str = "\\1" + "lkl/" + i + "\\2"
+ content = re.sub(search_str, replace_str, content)
+ tmp = ""
+ for w in re.split("(\W+)", content):
+ if w in defines:
+ w = lkl_prefix(w)
+ tmp += w
+ content = tmp
+ for s in structs:
+ search_str = "(\W?struct\s+)" + s + "(\W)"
+ replace_str = "\\1" + lkl_prefix(s) + "\\2"
+ content = re.sub(search_str, replace_str, content, flags = re.MULTILINE)
+ for s in unions:
+ search_str = "(\W?union\s+)" + s + "(\W)"
+ replace_str = "\\1" + lkl_prefix(s) + "\\2"
+ content = re.sub(search_str, replace_str, content, flags = re.MULTILINE)
+ open(h, 'w').write(content)
+
+parser = argparse.ArgumentParser(description='install lkl headers')
+parser.add_argument('path', help='path to install to', )
+args = parser.parse_args()
+
+find_headers("arch/um/lkl/include/uapi/asm/syscalls.h")
+headers.add("arch/um/lkl/include/uapi/asm/host_ops.h")
+
+if 'LKL_INSTALL_ADDITIONAL_HEADERS' in os.environ:
+ with open(os.environ['LKL_INSTALL_ADDITIONAL_HEADERS'], 'rU') as f:
+ for line in f.readlines():
+ line = line.split('#', 1)[0].strip()
+ if line != '':
+ headers.add(line)
+
+new_headers = set()
+
+for h in headers:
+ h = relpath2abspath(h)
+ dir = os.path.dirname(h)
+ out_dir = args.path + "/" + re.sub("(" + srctree + "/arch/um/lkl/include/uapi/|"
+ + srctree + "/include/uapi/|"
+ + "arch/um/lkl/include/generated/uapi/|"
+ + "include/generated/uapi/|"
+ + "include/generated)(.*)", "lkl/\\2", dir)
+ try:
+ os.makedirs(out_dir)
+ except:
+ pass
+ print(" INSTALL %s" % (out_dir + "/" + os.path.basename(h)))
+ os.system(srctree+"/scripts/headers_install.sh %s %s" % (os.path.abspath(h),
+ out_dir + "/" + os.path.basename(h)))
+ new_headers.add(out_dir + "/" + os.path.basename(h))
+
+headers = new_headers
+
+defines = set()
+structs = set()
+unions = set()
+
+p = re.compile("#[ \t]*define[ \t]*(\w+)")
+find_symbols(p, defines)
+p = re.compile("typedef.*(\(\*(\w+)\)\(.*\)\s*|\W+(\w+)\s*|\s+(\w+)\(.*\)\s*);")
+find_symbols(p, defines)
+p = re.compile("typedef\s+(struct|union)\s+\w*\s*{[^\\{\}]*}\W*(\w+)\s*;", re.M|re.S)
+find_ml_symbols(p, defines)
+defines.add("siginfo_t")
+defines.add("sigevent_t")
+p = re.compile("struct\s+(\w+)\s*\{")
+find_symbols(p, structs)
+structs.add("iovec")
+p = re.compile("union\s+(\w+)\s*\{")
+find_symbols(p, unions)
+p = re.compile("static\s+__inline__(\s+\w+)+\s+(\w+)\([^)]*\)\s")
+find_symbols(p, defines)
+p = re.compile("static\s+__always_inline(\s+\w+)+\s+(\w+)\([^)]*\)\s")
+find_symbols(p, defines)
+p = re.compile("enum\s+(\w*)\s*{([^}]*)}", re.M|re.S)
+q = re.compile("(\w+)\s*(,|=[^,]*|$)", re.M|re.S)
+find_enums(p, q, defines)
+
+# needed for i386
+defines.add("__NR_stime")
+
+def process_header(h):
+ print(" REPLACE %s" % h)
+ replace(h)
+
+# use num of processors determined by os.cpu_count()
+p = multiprocessing.Pool(None)
+try:
+ p.map_async(process_header, headers).wait(999999)
+ p.close()
+except:
+ p.terminate()
+finally:
+ p.join()
@@ -24,7 +24,11 @@ TMPFILE=$OUTFILE.tmp
trap 'rm -f $OUTFILE $TMPFILE' EXIT
# SPDX-License-Identifier with GPL variants must have "WITH Linux-syscall-note"
-if [ -n "$(sed -n -e "/SPDX-License-Identifier:.*GPL-/{/WITH Linux-syscall-note/!p}" $INFILE)" ]; then
+#
+# ARCH=um with library mode exposes uapi headers but applications may be linked
+# statically, thus this GPL exception doesn't apply to.
+if [ -n "$(sed -n -e "/SPDX-License-Identifier:.*GPL-/{/WITH Linux-syscall-note/!p}" $INFILE)" ] &&
+ [ "$SRCARCH" != "um" ]; then
echo "error: $INFILE: missing \"WITH Linux-syscall-note\" for SPDX-License-Identifier" >&2
exit 1
fi