linux 添加系统调用的方法(arm架构)

本文详细介绍了Linux系统调用的基本概念,以open系统调用为例,阐述了系统调用的定义、实现过程及其内部工作原理。进一步解释了如何在代码环境中新增系统调用,并通过实例演示了整个新增过程。最后,文章概述了系统调用在Linux内核中的引入方式,以及如何更新系统调用表以确保新系统调用的正常运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在linux中,系统调用是非常重要的一个机制。那么,如何才能在自己的代码环境中增加一项系统调用呢?


首先,以“open”系统调用为例,看看系统调用都需要哪些支持:

1 open系统调用的定义在文件<kernel/fs/open.c>中:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;


        return do_sys_open(AT_FDCWD, filename, flags, mode);
}


SYSCALL_DEFINE3 表示该系统调用有三组参数,其定义如下:

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;


        return do_sys_open(AT_FDCWD, filename, flags, mode);
}


展开可得到:

SYSCALL_DEFINEx(3, _open, const char __user *, filename, int, flags, umode_t, mode)
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;


        return do_sys_open(AT_FDCWD, filename, flags, mode);
}



继续展开,可以得到:

asmlinkage long sys_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode));
static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode));
asmlinkage long SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode))
{ 
    long ret = SYSC_open(__MAP(3,__SC_CAST,const char __user *, filename, int, flags, umode_t, mode));
    __MAP(3,__SC_TEST,const char __user *, filename, int, flags, umode_t, mode);
    __PROTECT(3, ret,__MAP(3,__SC_ARGS,const char __user *, filename, int, flags, umode_t, mode));
    return ret; 
} 
SYSCALL_ALIAS(sys_open, SyS_open); 
static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode))
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;


        return do_sys_open(AT_FDCWD, filename, flags, mode);
}


再根据以下宏定义:

#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_DECL(t, a) t a <<<used to separate the type and param
#define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))
#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
#define __SC_CAST(t, a) (t) a <<<used to forced type change
#define __SC_ARGS(t, a) a <<<only use the param
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long)) <<<used to asert

 

最终可以得到:

asmlinkage long sys_open(const char __user * filename, int flags, umode_t mode);
static inline long SYSC_open(const char __user * filename, int flags, umode_t mode);
asmlinkage long SyS_open(long filename, long flags, long mode))
{ 
    long ret = SYSC_open((const char __user *)filename, (int)flags, (umode_t)mode);
    __MAP3(__SC_TEST,const char __user *, filename, int, flags, umode_t, mode);
    __PROTECT(3, ret,__MAP3(__SC_ARGS,const char __user *, filename, int, flags, umode_t, mode));
    return ret; 
} 
SYSCALL_ALIAS(sys_open, SyS_open); 
static inline long SYSC_open(const char __user * filename, int flags, umode_t mode)
{
        if (force_o_largefile())
                flags |= O_LARGEFILE;


        return do_sys_open(AT_FDCWD, filename, flags, mode);
}


可以看出,实际上该宏做了四件事:

1 声明系统调用接口“sys_open”

2 声明并实现了中间接口“SyS_open”

3 声明了中间接口“SYSC_open”,并由该宏定义之后的代码段实现

4 将“sys_open”和“SyS_open”指向同一位置


2 在文件<arch/arm/include/uapi/asm/unistd.h>中有如下定义:

#define __NR_open                       (__NR_SYSCALL_BASE+  5)

该定义用于将系统调用“sys_open”以系统调用编号引出到用户空间。


3 在文件<arch/arm/kernel/calls.S>中有如下定义:

CALL(sys_open)

该定义是为了告知内核增加了一项系统调用。


4 在文件<arch/arm/include/asm/unistd.h>中有如下定义:

#define __NR_syscalls  (380)

该定义是告知内核一共定义了多少系统调用;当增加新的系统调用时,务必将该数增加。



例子:增加四个系统调用

kernel space:

diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
index 141baa3..acabef1 100644
--- a/arch/arm/include/asm/unistd.h
+++ b/arch/arm/include/asm/unistd.h
@@ -15,7 +15,7 @@
 
 #include <uapi/asm/unistd.h>
 
-#define __NR_syscalls  (380)
+#define __NR_syscalls  (384)
 #define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0)
 
 #define __ARCH_WANT_STAT64
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h
index af33b44..2ac0145 100644
--- a/arch/arm/include/uapi/asm/unistd.h
+++ b/arch/arm/include/uapi/asm/unistd.h
@@ -406,6 +406,10 @@
 #define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
 #define __NR_kcmp (__NR_SYSCALL_BASE+378)
 #define __NR_finit_module (__NR_SYSCALL_BASE+379)
+#define __NR_CustomEvent_open           (__NR_SYSCALL_BASE+380)
+#define __NR_CustomEvent_wait           (__NR_SYSCALL_BASE+381)
+#define __NR_CustomEvent_signal         (__NR_SYSCALL_BASE+382)
+#define __NR_CustomEvent_close          (__NR_SYSCALL_BASE+383)
 
 /*
  * This may need to be greater than __NR_last_syscall+1 in order to
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index c6ca7e3..54cedd5 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -389,6 +389,10 @@
  CALL(sys_process_vm_writev)
  CALL(sys_kcmp)
  CALL(sys_finit_module)
+/* 380 */ CALL(sys_CustomEvent_open)
+ CALL(sys_CustomEvent_wait)
+ CALL(sys_CustomEvent_signal)
+ CALL(sys_CustomEvent_close)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
diff --git a/fs/Makefile b/fs/Makefile
index 4fe6df3..c751b46 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \
  attr.o bad_inode.o file.o filesystems.o namespace.o \
  seq_file.o xattr.o libfs.o fs-writeback.o \
  pnode.o splice.o sync.o utimes.o \
- stack.o fs_struct.o statfs.o
+ stack.o fs_struct.o statfs.o work_queue_test.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 84662ec..dc1605e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -846,4 +846,8 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
 asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
  unsigned long idx1, unsigned long idx2);
 asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
+asmlinkage long sys_CustomEvent_open(long eventNum);
+asmlinkage long sys_CustomEvent_wait(long eventNum);
+asmlinkage long sys_CustomEvent_signal(long eventNum);
+asmlinkage long sys_CustomEvent_close(long eventNum);
 #endif


work_queue_test.c


static long do_CustomEvent_open(long eventNum)
{

......

}


SYSCALL_DEFINE1(CustomEvent_open, long, eventNum)
{
        return do_CustomEvent_open(eventNum);
}

......


user space:

work_queue_test1.c

#include <stdio.h>
#include <stdlib.h>
#include <linux/unistd.h>


int CustomEvent_open(int flag)
{
return syscall(380, flag); <<<此处的380对应系统调用“NR_CustomEvent_open”的编号。
}


int main(int argc, char ** argv)
{
int i;
// if(argc != 2)
// return -1;
i = CustomEvent_open(atoi(argv[1]));
printf("%d\n", i);
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值