ฉันลองสิ่งนี้ใน x86_64
แก้ไขกับ 94836ecf1e7378b64d37624fbb81fe48fbd4c772: (เช่นกันที่นี่https://github.com/pskocik/linux/tree/supersyscall )
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183e2f85..8df2e98eb403 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
330 common pkey_alloc sys_pkey_alloc
331 common pkey_free sys_pkey_free
332 common statx sys_statx
+333 common supersyscall sys_supersyscall
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9b06f8..c61c14e3ff4e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -905,5 +905,20 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
asmlinkage long sys_pkey_free(int pkey);
asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
unsigned mask, struct statx __user *buffer);
-
#endif
+
+struct supersyscall_args {
+ unsigned call_nr;
+ long args[6];
+};
+#define SUPERSYSCALL__abort_on_failure 0
+#define SUPERSYSCALL__continue_on_failure 1
+/*#define SUPERSYSCALL__lock_something 2?*/
+
+
+asmlinkage
+long
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags);
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index a076cf1a3a23..56184b84530f 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -732,9 +732,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc)
__SYSCALL(__NR_pkey_free, sys_pkey_free)
#define __NR_statx 291
__SYSCALL(__NR_statx, sys_statx)
+#define __NR_supersyscall 292
+__SYSCALL(__NR_supersyscall, sys_supersyscall)
#undef __NR_syscalls
-#define __NR_syscalls 292
+#define __NR_syscalls (__NR_supersyscall+1)
/*
* All syscalls below here should go away really,
diff --git a/init/Kconfig b/init/Kconfig
index a92f27da4a27..25f30bf0ebbb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2184,4 +2184,9 @@ config ASN1
inform it as to what tags are to be expected in a stream and what
functions to call on what tags.
+config SUPERSYSCALL
+ bool
+ help
+ System call for batching other system calls
+
source "kernel/Kconfig.locks"
diff --git a/kernel/Makefile b/kernel/Makefile
index b302b4731d16..4d86bcf90f90 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
- async.o range.o smpboot.o ucount.o
+ async.o range.o smpboot.o ucount.o supersyscall.o
obj-$(CONFIG_MULTIUSER) += groups.o
diff --git a/kernel/supersyscall.c b/kernel/supersyscall.c
new file mode 100644
index 000000000000..d7fac5d3f970
--- /dev/null
+++ b/kernel/supersyscall.c
@@ -0,0 +1,83 @@
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/compiler.h>
+#include <linux/sched/signal.h>
+
+/*TODO: do this properly*/
+/*#include <uapi/asm-generic/unistd.h>*/
+#ifndef __NR_syscalls
+# define __NR_syscalls (__NR_supersyscall+1)
+#endif
+
+#define uif(Cond) if(unlikely(Cond))
+#define lif(Cond) if(likely(Cond))
+
+
+typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long, unsigned long);
+extern const sys_call_ptr_t sys_call_table[];
+
+static bool
+syscall__failed(unsigned long Ret)
+{
+ return (Ret > -4096UL);
+}
+
+
+static bool
+syscall(unsigned Nr, long A[6])
+{
+ uif (Nr >= __NR_syscalls )
+ return -ENOSYS;
+ return sys_call_table[Nr](A[0], A[1], A[2], A[3], A[4], A[5]);
+}
+
+
+static int
+segfault(void const *Addr)
+{
+ struct siginfo info[1];
+ info->si_signo = SIGSEGV;
+ info->si_errno = 0;
+ info->si_code = 0;
+ info->si_addr = (void*)Addr;
+ return send_sig_info(SIGSEGV, info, current);
+ //return force_sigsegv(SIGSEGV, current);
+}
+
+asmlinkage long /*Ntried*/
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags)
+{
+ int i = 0, nfinished = 0;
+ struct supersyscall_args args; /*7 * sizeof(long) */
+
+ for (i = 0; i<Nargs; i++){
+ long ret;
+
+ uif (0!=copy_from_user(&args, Args+i, sizeof(args))){
+ segfault(&Args+i);
+ return nfinished;
+ }
+
+ ret = syscall(args.call_nr, args.args);
+ nfinished++;
+
+ if ((Flags & 1) == SUPERSYSCALL__abort_on_failure
+ && syscall__failed(ret))
+ return nfinished;
+
+
+ uif (0!=put_user(ret, Rets+1)){
+ segfault(Rets+i);
+ return nfinished;
+ }
+ }
+ return nfinished;
+
+}
+
+
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 8acef8576ce9..c544883d7a13 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -258,3 +258,5 @@ cond_syscall(sys_membarrier);
cond_syscall(sys_pkey_mprotect);
cond_syscall(sys_pkey_alloc);
cond_syscall(sys_pkey_free);
+
+cond_syscall(sys_supersyscall);
และดูเหมือนว่าจะใช้งานได้ - ฉันสามารถเขียน hello to fd 1 และ world to fd 2 ด้วย syscall เพียงอันเดียว:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
int main(int c, char**v)
{
puts("HELLO WORLD:");
long r=0;
struct supersyscall_args args[] = {
{SYS_write, {1, (long)"hello\n", 6 }},
{SYS_write, {2, (long)"world\n", 6 }},
};
long rets[sizeof args / sizeof args[0]];
r = supersyscall(rets,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
puts("");
#if 1
#if SEGFAULT
r = supersyscall(0,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
#endif
#endif
return 0;
}
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags)
{
return syscall(333, Rets, Args, Nargs, Flags);
}
โดยทั่วไปฉันใช้:
long a_syscall(long, long, long, long, long, long);
ในฐานะต้นแบบ syscall สากลซึ่งดูเหมือนจะเป็นสิ่งที่ทำงานบน x86_64 ดังนั้น "syscall" super ของฉันคือ:
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
/*#define SUPERSYSCALL__lock_something 2?*/
asmlinkage
long
sys_supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
ก็จะส่งกลับจำนวน syscalls พยายาม ( ==Nargs
ถ้าSUPERSYSCALL__continue_on_failure
ธงถูกส่งผ่านไปมิฉะนั้น>0 && <=Nargs
) และความล้มเหลวในการคัดลอกระหว่างพื้นที่เมล็ดและพื้นที่ของผู้ใช้จะส่งสัญญาณโดย segfaults -EFAULT
แทนปกติ
สิ่งที่ฉันไม่รู้ก็คือวิธีนี้จะส่งต่อไปยังสถาปัตยกรรมอื่น ๆ แต่มันจะดีถ้ามีสิ่งนี้ในเคอร์เนล
หากเป็นไปได้สำหรับซุ้มประตูทั้งหมดฉันคิดว่าอาจมี wrapper userspace ที่จะให้ความปลอดภัยประเภทผ่านสหภาพและแมโครบางตัว (มันสามารถเลือกสมาชิกสหภาพตามชื่อ syscall และสหภาพทั้งหมดจะได้รับการแปลงเป็นความยาว 6 หรือสิ่งใดก็ตามที่เทียบเท่ากับความยาวของ 6 สถาปัตยกรรม)
batch
syscalls ลงในbatch
syscalls คุณสามารถสร้างทรีเรียกแบบลึกโดยพลการของ syscalls ได้เอง โดยทั่วไปคุณสามารถใส่แอปพลิเคชันทั้งหมดของคุณไว้ใน syscall เดียว