diff --git a/arch/lkl/Makefile b/arch/lkl/Makefile index 05c7897b42e3a1..1793487efb513d 100644 --- a/arch/lkl/Makefile +++ b/arch/lkl/Makefile @@ -22,15 +22,22 @@ LDFLAGS_vmlinux += -r LKL_ENTRY_POINTS := lkl_start_kernel lkl_sys_halt lkl_syscall lkl_trigger_irq \ lkl_get_free_irq lkl_put_irq +SYSCALL_TBL_HDR = arch/lkl/include/generated/asm/syscall_table.h +UNISTD_HDR = arch/lkl/include/asm/unistd.h + core-y += arch/lkl/kernel/ all: lkl.o lkl.o: vmlinux - $(OBJCOPY) -R .eh_frame -R .syscall_defs $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) vmlinux lkl.o + $(OBJCOPY) -R .eh_frame $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) vmlinux lkl.o + +quiet_cmd_syscall_tbl = TBL $< + cmd_syscall_tbl = $< systbl $(UNISTD_HDR) $@ -arch/lkl/include/generated/uapi/asm/syscall_defs.h: vmlinux - $(OBJCOPY) -j .syscall_defs -O binary --set-section-flags .syscall_defs=alloc $< $@ +$(SYSCALL_TBL_HDR): arch/lkl/scripts/make_syscall_tbl.sh $(UNISTD_HDR) + @mkdir -p arch/lkl/include/generated/asm/ + $(call cmd,syscall_tbl) install: lkl.o __headers arch/lkl/include/generated/uapi/asm/syscall_defs.h @echo " INSTALL $(INSTALL_PATH)/lib/lkl.o" @@ -39,6 +46,8 @@ install: lkl.o __headers arch/lkl/include/generated/uapi/asm/syscall_defs.h $(subst -j,-j$(NPROC),$(findstring -j,$(MAKEFLAGS))) \ $(INSTALL_PATH)/include +archheaders: $(SYSCALL_TBL_HDR) + archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/lkl/include/asm/unistd.h b/arch/lkl/include/asm/unistd.h index 234f93d8e8478c..3431f9aef30fb7 100644 --- a/arch/lkl/include/asm/unistd.h +++ b/arch/lkl/include/asm/unistd.h @@ -24,3 +24,83 @@ __ASCII_MAP(x, __SC_ASCII, __VA_ARGS__) ")\\n\"\n" \ ".ascii \"#endif\\n\"\n" \ ".section .text\n"); + +/* + * Unsupported system calls due to lack of support in LKL (e.g. related to + * virtual memory, signal, user processes). We also only support 64bit version + * of system calls where we have two version to keep the same API across 32 and + * 64 bit hosts. + */ + +#define __IGNORE_restart_syscall +#define __IGNORE_exit +#define __IGNORE_fork +#define __IGNORE_execve +#define __IGNORE_ptrace +#define __IGNORE_alarm +#define __IGNORE_pause +#define __IGNORE_kill +#define __IGNORE_brk +#define __IGNORE_uselib +#define __IGNORE_swapon +#define __IGNORE_mmap +#define __IGNORE_munmap +#define __IGNORE_swapoff +#define __IGNORE_clone +#define __IGNORE_mprotect +#define __IGNORE_init_module +#define __IGNORE_quotactl +#define __IGNORE_msync +#define __IGNORE_mlock +#define __IGNORE_munlock +#define __IGNORE_mlockall +#define __IGNORE_munlockall +#define __IGNORE_mremap +#define __IGNORE_rt_sigreturn +#define __IGNORE_rt_sigaction +#define __IGNORE_rt_sigprocmask +#define __IGNORE_rt_sigpending +#define __IGNORE_rt_sigtimedwait +#define __IGNORE_rt_sigqueueinfo +#define __IGNORE_rt_sigsuspend +#define __IGNORE_sigaltstack +#define __IGNORE_vfork +#define __IGNORE_mincore +#define __IGNORE_madvise +#define __IGNORE_getdents /* we use the 64 bit counter part instead */ +#define __IGNORE_tkill +#define __IGNORE_exit_group +#define __IGNORE_remap_file_pages +#define __IGNORE_fstatfs /* we use the 64 bit counter part instead */ +#define __IGNORE_mbind +#define __IGNORE_get_mempolicy +#define __IGNORE_set_mempolicy +#define __IGNORE_mq_open +#define __IGNORE_mq_unlink +#define __IGNORE_mq_timedsend +#define __IGNORE_mq_timedreceive +#define __IGNORE_mq_getsetattr +#define __IGNORE_kexec_load +#define __IGNORE_migrate_pages +#define __IGNORE_unshare +#define __IGNORE_set_robust_list +#define __IGNORE_get_robust_list +#define __IGNORE_sync_file_range +#define __IGNORE_vmsplice +#define __IGNORE_move_pages +#define __IGNORE_mq_notify +#define __IGNORE_delete_module +#define __IGNORE_signalfd4 +#define __IGNORE_preadv /* we use the 64 bit counter part instead */ +#define __IGNORE_pwritev /* we use the 64 bit counter part instead */ +#define __IGNORE_rt_tgsigqueueinfo +#define __IGNORE_perf_event_open +#define __IGNORE_setns +#define __IGNORE_process_vm_readv +#define __IGNORE_process_vm_writev +#define __IGNORE_kcmp +#define __IGNORE_finit_module +#define __IGNORE_seccomp +#define __IGNORE_memfd_create +#define __IGNORE_bpf +#define __IGNORE_execveat diff --git a/arch/lkl/kernel/Makefile b/arch/lkl/kernel/Makefile index 47036c0ed2d3e5..f3ae562f97c08f 100644 --- a/arch/lkl/kernel/Makefile +++ b/arch/lkl/kernel/Makefile @@ -1,3 +1,13 @@ -extra-y := vmlinux.lds +SYSCALL_DEFS_HDR := ../include/generated/uapi/asm/syscall_defs.h +UNISTD_HDR = arch/lkl/include/asm/unistd.h +extra-y := vmlinux.lds $(SYSCALL_DEFS_HDR) obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o mem.o console.o + + +quiet_cmd_syscall_def = CALL $< + cmd_syscall_def = $< sysdef $(UNISTD_HDR) arch/lkl/include/generated/uapi/asm/syscall_defs.h + +arch/lkl/kernel/$(SYSCALL_DEFS_HDR): arch/lkl/scripts/make_syscall_tbl.sh $(UNISTD_HDR) + @mkdir -p arch/lkl/include/generated/uapi/asm/ + $(call cmd,syscall_def) diff --git a/arch/lkl/kernel/syscalls.c b/arch/lkl/kernel/syscalls.c index 011116a31fdf73..8d46f152789cdf 100644 --- a/arch/lkl/kernel/syscalls.c +++ b/arch/lkl/kernel/syscalls.c @@ -19,6 +19,8 @@ typedef long (*syscall_handler_t)(long arg1, ...); syscall_handler_t syscall_table[__NR_syscalls] = { [0 ... __NR_syscalls - 1] = (syscall_handler_t)sys_ni_syscall, #include + /* override __IGNORE-ed syscalls */ +#include }; static struct syscall_queue { diff --git a/arch/lkl/scripts/make_syscall_tbl.sh b/arch/lkl/scripts/make_syscall_tbl.sh new file mode 100755 index 00000000000000..5266f31c4105dc --- /dev/null +++ b/arch/lkl/scripts/make_syscall_tbl.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +#set -x + +# requires: bash-4.0 (hashtable), cpp, grep, sed, cat + +## +## Usage: $0 +## ARGV[0]: (OPT: "systbl" oe "sysdef") +## ARGV[1]: (IN: asm/unistd.h) +## ARGV[2]: (OUT: syscall_table.h(systbl) or syscall_defs.h (sysdef)) +## + +mode=$1 +in=$2 +out=$3 + +if [ "$mode" != "systbl" ] && [ "$mode" != "sysdef" ] ; then + echo "Usage: $0 [systbl|sysdef] (unistd.h) (output file)" + exit +fi + +echo "" > $out + +# obtain the blacklist of syscall +declare -A ignore_syscall + +## +## step 1: create ignored syscall table entries based on +## +while read def nr ; do + name=$(echo $nr | sed "s/__IGNORE_/__NR_/") + ignore_syscall[$name]="ignored" + +if [ $mode = "systbl" ] ; then + cat << EOF >> $out +#define __SYSCALL_STE_${name}(nr,sym) [nr] = (syscall_handler_t)sys_ni_syscall, +__SYSCALL_STE_${name}(${name},dummy) +EOF +fi +done < <(${CROSS_COMPILE}cpp ${LINUXINCLUDE} -dM -fdirectives-only $in | grep '__IGNORE_') + +## +## stop if systbl is specified +## +if [ $mode = "systbl" ] ; then + exit +fi + + +## +## step 2-1: grep SYSCALL_DEFINE in whole tree with specific +## directories ($SYSCALL_DIRS) +## +SYSCALL_DIRS="block drivers/pci drivers/char fs init ipc kernel mm net" +SYSCALL_FILES=$(find ${SYSCALL_DIRS} -name \*.c | \ + xargs grep -E "^SYSCALL_DEFINE[0-6]" -l) + +## +## step 2-2: dump lkl syscall definitions from preprocessor's ouptut +## +set -f +for file in ${SYSCALL_FILES} ; +do + while read syscall; do + func=$(echo $syscall | sed "s/SYSCALL_DEFINE.*(\([^,]*\).*/\1/") + #echo "syscall= "$syscall + #echo "func= "$func + + # 0) pull the system call name + funcname=$(echo $func | sed "s/(.*//" | sed "s/long sys_//") + #echo "funcname ="$funcname + + # 1) skip if the syscall is unsupported + if [ "${ignore_syscall[__NR_$funcname]}" = "ignored" ] ; then + #echo $funcname " ignore= " "${ignore_syscall[__NR_$funcname]}" + continue + fi + + # 2) count the number of argument + func_l=/$func/ + IFS=',' + set -- $func_l + argc=0 + if [ $(echo $func | sed "s/.*(//") != "void)" ] ; then + argc=`expr $(($#-1)) + 1` + fi + #echo "argc = $argc" + IFS=' ' + + # 3) pull arg name template + args=$(echo $func | sed "s/.*(/(/" | sed "s/__lkl__kernel_//g"\ + | sed "s/lkl_//g" | sed "s/[()]//g") + OIFS="$IFS"; IFS=',' + arg=($args); IFS="$OIFS" + #echo "arg ="$arg > /dev/stdout + + param="" + for i in {1..6} ; do + if [ $i -gt ${argc} ] ; then + break + fi + if [ $i -ne 1 ] ; then + param="${param}, " + fi + nparam=$(echo ${arg[$((i-1))]} | \ + sed "s/\(.*\) \(.*\)$/\1, \2/") + param="${param}${nparam}" + done + #echo ${param} > /dev/stdout + IFS=' ' + + # 4) give a template based on funcname, args + cat << EOF >> $out + +#ifdef __NR_$funcname +SYSCALL_DEFINE$argc(_$funcname, $param); +#endif /* __NR_$funcname */ +EOF + done < <(${CROSS_COMPILE}cpp -P ${LINUXINCLUDE} $file 2>/dev/null \ + | grep "long sys_" | sed "s/^; / /" \ + | sed "s/\(.*\) __attribute.*/\1/" | grep -vE ";|,$") +done diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index a0ff156814759b..10970d3452b550 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -181,7 +181,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; #define SYSCALL_DEFINE0(sname) \ SYSCALL_METADATA(_##sname, 0); \ - __SYSCALL_DEFINE_ARCH(0, _##sname); \ asmlinkage long sys_##sname(void) #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) @@ -193,7 +192,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; #define SYSCALL_DEFINEx(x, sname, ...) \ SYSCALL_METADATA(sname, x, __VA_ARGS__) \ - __SYSCALL_DEFINE_ARCH(x, sname, __VA_ARGS__) \ __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c index 3dfa3ed2a70496..0dfa89fd60210d 100644 --- a/tools/lkl/tests/boot.c +++ b/tools/lkl/tests/boot.c @@ -420,6 +420,19 @@ static int test_umount(char *str, int len) return 0; } +static int test_syscall(char *str, int len) +{ + long ret, params[6]; + + ret = lkl_syscall(__lkl__NR_fork, params); + + snprintf(str, len, "%ld", ret); + if (ret == -LKL_ENOSYS) + return 1; + + return 0; +} + static struct cl_option *find_short_opt(char name) { struct cl_option *opt; @@ -516,6 +529,7 @@ int main(int argc, char **argv) TEST(opendir); TEST(getdents64); TEST(umount); + TEST(syscall); lkl_sys_halt();