首页 > 编程知识 正文

ARM64内核系统调用添加方法基于kernel49

时间:2023-05-06 11:01:30 阅读:207087 作者:2803

既上一篇介绍了ARM64内核系统调用详解之后,本篇文章来介绍如何添加自己的系统调用到内核中。

根据上一篇我们知道如下关键的几点:

(1)ARM64的系统调用分为32-bit模式和64-bit模式。

(2)32-bit模式的系统调用syscall定义在头文件arch/arm64/include/asm/unistd32.h

(3)64-bit模式的系统调用syscall定义在头文件include/uapi/asm-generic/unistd.h

(4)默认系统为定义的系统调用号会直接执行一个no implement handler,也就是do_ni_syscall

下面我们就来介绍两种添加自定义系统调用的方法。

第一种方式:

我们以系统调用getpid为例进行讲解。

(1)实现sys_getpid函数体 kernel/sys.c: /** * sys_getpid - return the thread group id of the current process * * Note, despite the name, this returns the tgid not the pid. The tgid and * the pid are identical unless CLONE_THREAD was specified on clone() in * which case the tgid is the same in all threads of the same group. * * This is SMP safe as current->tgid does not change. */ SYSCALL_DEFINE0(getpid) { return task_tgid_vnr(current); }

SYSCALL_DEFINE0的定义如下:

#define SYSCALL_DEFINE0(sname) SYSCALL_METADATA(_##sname, 0); asmlinkage long sys_##sname(void) (2)头文件中声明系统调用函数 include/linux/syscalls.h:asmlinkage long sys_getpid(void); (3)把系统调用函数加入到syscall数组中

64-bit模式系统调用数组添加:

include/uapi/asm-generic/unistd.h:#define __NR_getpid 172__SYSCALL(__NR_getpid, sys_getpid)

32-bit模式系统调用数组添加:

arch/arm64/include/asm/unistd32.h:#define __NR_getpid 20__SYSCALL(__NR_getpid, sys_getpid)

至此我们就完成了一个系统调用的添加了。

第二种方式:

通过前面的介绍我们知道Linux中没有意义的系统调用号都会调用到arch/arm64/kernel/trap.c:do_ni_syscall函数。

那么我们可以考虑在此函数中实现我们新添加的系统调用,使用这种方式添加系统调用就不用再去更改系统调用数组了。

arch/arm64/kernel/trap.c: asmlinkage long do_ni_syscall(struct pt_regs *regs) { #ifdef CONFIG_COMPAT long ret; if (is_compat_task()) { ret = compat_arm_syscall(regs); if (ret != -ENOSYS) return ret; } #endif if (show_unhandled_signals_ratelimited()) { pr_info("%s[%d]: syscall %dn", current->comm, task_pid_nr(current), (int)regs->syscallno); dump_instr("", regs); if (user_mode(regs)) __show_regs(regs); } return sys_ni_syscall(); }

我们可以在此函数的起始处加入一个我们自己的syscall handle函数,并在此函数中处理所有我们要加入的系统调用。

比如:

long custom_add_syscall(struct pt_regs *regs){ unsigned int no; if (is_compat_task()) { no = regs->regs[7]; // regs[7] :32bit program else no = regs->regs[8]; //regs[8] :64bit program return handle_all_add_syscall(regs, no);}

注意一定要区分32-bit和64-bit模式,可以使用is_compat_task()函数来判断是否处于32-bit运行模式。对于32-bit程序,regs[7]中是syscall number,而对于64-bit程序,regs[8]中才是syscall number。得到了syscall number之后,我们可以进一步处理我们要加入的新的syscall了。

整个代码执行流程如下:

查找系统调用表—>表中未定义实际的处理函数—>执行默认的处理函数do_ni_syscall—>执行我们新添加的custom_add_syscall—>在我们的函数中根据系统调用号进一步处理

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。