创建简单的Kernel System Call

本篇是接着上一篇<编译Linux Kernel – Version 4.9.13>写的。

1. 创建system call 源文件

在下载了kernel的源代码并且解压后,进入根目录下的kernel文件夹,在里面创建文件hello.c

#include 
#include 
#include 
#include 

asmlinkage long sys_hello(long a, long b){
	long sum = a + b;
	printk("hello world\n");
	printk("the sum is %d\n",sum);
	return 0;
	//return -EINVAL;
}

解释

  1. asmlinkage 是所有定义system call需要使用的关键字
  2. sys_ 是所有 system call 函数的约定命名前缀
  3. kernel中能调用的函数和 user space的不一样
  4. linux/kernel.h 头文件能够使用 printk,他会在 kernel log内打印内容,使用 sudo dmesg 查看
  5. linux/errno.h 中包含了错误代码,system call的约定是:
    1. 如果调用成功则返回0, 如果调用失败则返回负数;
    2. 这个system call的wrapper函数会将这个负数 变正,并且用它来设置 user space 的errno,然后返回-1
  6. 剩下的两个头文件暂时没用找,但是在之后和module配合调用的时候需要

2. 添加Makefile内容

在同目录(kernel文件夹)中的Makefile内添加编译目标,保证编译kernel的时候能够产生我们hello这个system call的目标文件:

obj-y := hello.o

因为本来的Makefile内已经有了很多指定的编译目标文件,所以直接在后面添加上我们的hello.o, 大概结果是:

创建简单的Kernel System Call_第1张图片

2.0 如果源文件没有放在kernel文件夹下

网上有些教程,是在 kernel根目录下创建一个文件夹,叫做 hello, 内部写这个 hello.c。 这样的话,需要的操作和上面有点不一样:

  1. 需要告诉内核,编译的时候把这个文件夹的内容包括进来
  2. 不需要更改kernel文件夹下的Makefile,而是在hello这个目录中创建单独的 Makefile

上面第一条, 在kernel根目录下的Makefile中,找到core-y这么一行,加上刚才hello的目录路径:

在这里插入图片描述
上面第二条,在 刚才创建的hello文件夹中,创建Makefile,内容写上

obj-y := hello.o

3. 添加系统头文件 system call 原型

在内核根目录下的include/linux文件夹中的syscalls.h 的最后面、#endif 之间,添加我们system call的原型:

...
asmlinkage long sys_pkey_alloc....;
// 在这添加自己的 prototype
asmlinkage long sys_hello(long a, long b);
#endif

创建简单的Kernel System Call_第2张图片

解释:

  1. asmlinkage is a key word used to indicate that all parameters of the function would be available on the stack.

4. 添加system call table条目

想要最终能够调用添加的system call,需要在对应机器的 architecture 的 system call table中添加,并且指定 system call 的编号。 所有system call 最终被调用的时候都是通过指定的编号来找到的。

我的机器是x86_64架构的,可以在uname -a中查看到。

在内核根目录下的arch 文件夹下有很多不同的 architecture文件夹,如果需要让自己的system call能够在某个architecture的系统中调用,就需要在对应的文件夹下的 systme call table中添加。

以本机来说: arch/x86/entry/syscalls 中的 syscall_64.tbl 中添加:

400	common	hello	sys_hello    

创建简单的Kernel System Call_第3张图片

解释:

  1. 上面400开头的那一句就是添加的内容,说明添加的system call的编号是400,记住这个编号

5. 重新编译内核并且安装

运行前可以先确定已经安装了需要的工具:

sudo apt-get install gcc
sudo apt-get install libncurses5-dev
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install libssl-dev
sudo apt-get install libelf-dev
sudo apt-get update
sudo apt-get upgrade

然后回到linux根目录,运行(前提是之前已经有了.config,之前那篇文章有讲,使用make olddefconfig

make -jN   # N 代表执行编译的内核数,数字越大编译越快

sudo make module_install    # 如果之前执行过一次完整的编译内核并且安装,这里不需要重新编译内核
sudo make install  # 这句话一定要执行

编译结束后重新启动(一定要重启)

sudo reboot

6. 在用户空间中测试

写一个新的文件:testhello.c

#include 
#include 
#include 
#include 
int main()
{
         long result = syscall(400, 12, 30);
         printf("The result is %ld\n", result);
         return 0;
}

然后

gcc testhello.c -o testhello
./testhello

The result is 0

检查系统log

sudo dmesg

创建简单的Kernel System Call_第4张图片

解释:

  1. syscall 函数可以用来调用 system call,第一个参数是 system call 编号,之后可以传入对应的system call 的参数

大功告成!!

你可能感兴趣的:(创建简单的Kernel System Call)