如何向内核添加系统调用(syscall),并进行编译和测试?
syscall我的示例方法之一会将内容打印Hello world到内核缓冲区。
第二个方法是获取进程的 PID 并将elapsed time其打印到内核缓冲区,这在我的另一个教程中有所介绍:
1. 设置环境
我更倾向于获取root并执行这些步骤,以root避免过程中出现权限错误。如果您不想以 root 用户身份执行这些步骤,您可以直接使用sudo需要 root 权限的命令。
su -
root输入密码后将切换到该用户root。然后,您可以先使用以下命令检查操作系统当前内核版本:
uname -r
我这里会打印出这些4.19.0-6-amd64信息。接下来,我们需要获取内核源代码。我将使用比我当前版本稍新的版本(4.20.1),使用以下wget命令。
wget https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/linux-4.20.1.tar.xz
这将下载源代码4.20.1。这可能需要一些时间,大约2-3分钟,具体取决于您的网络速度。
使用以下命令提取压缩内核代码
tar -xvf linux-4.20.1.tar.xz
它会创建一个名为“文件夹”的文件夹linux-4.20.1.tar.xz,并将压缩代码解压到该文件夹中。
现在我们将把目录切换到新的内核代码。
cd linux-4.20.1
2. 向内核添加“Hello world”系统调用
我喜欢在添加新的系统调用时,为自己的文件创建一个新文件夹。
mkdir hello && cd hello
之后,我将创建一个 C 文件来实现我的系统调用。我倾向于vim hello.c创建并编辑该文件,然后插入以下 C 代码。
#include <linux/kernel.h>
asmlinkage long sys_hello(void)
{
//printk prints to the kernel’s log file.
printk("Hello world\n");
return 0;
}
我们需要Makefile在hello目录中创建一个文件。
vim Makefile
然后插入以下内容:
:= hello.o
然后,进入父目录(内核源代码主目录):
cd ..
我们需要将新的系统调用目录添加到 `<path>` 中Makefile,这样它也会编译我们的系统调用。为此,请core-y在 `<path>` 中搜索 `<path> Makefile`,然后找到 `<path>`。
在 vim 中,按下 ESC 键后可以进行搜索/core-y。
+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/
``` line and add `hello/` to the end of this line.
As a result, the line should be looking like this:
```core-y
+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/ hello/
下一步是将新的系统调用添加到系统调用表中。
如果您使用的是 32 位系统,则需要修改syscall_32.tbl文件。
vim arch/x86/entry/syscalls/syscall_32.tbl
对于 64 位系统,请进行更改syscall_64.tbl。
vim arch/x86/entry/syscalls/syscall_64.tbl
我将继续使用我的 64 位操作系统,我的步骤也会相应调整。
我们需要在添加系统调用时保持表的结构。因此,我们将把代码行添加到行尾。我的最后一个系统调用有编号547,所以我将使用548,你也应该使用N+1。
我的系统调用数据:
64 hello sys_hello
示例文件:
546 ... ... ...
547 ... ... ...
548 64 hello sys_hello
现在,我们需要将系统调用方法签名添加syscalls到头文件中syscalls.h。
vim include/linux/syscalls.h
然后,在文档末尾的 #endif 语句之前添加以下行:
asmlinkage long sys_hello(void);
3. 编译内核
编译之前,您需要安装一些软件包。请在终端中输入以下命令来安装所需的软件包:
apt-get install gcc &&
apt-get install libncurses5-dev &&
apt-get install bison &&
apt-get install flex &&
apt-get install libssl-dev &&
apt-get install libelf-dev &&
apt-get update &&
apt-get upgrade &&
apt-get make
现在,您可以通过执行以下命令,使用配置菜单来配置内核:
make menuconfig
重要提示:输入此命令时,建议您最大化终端屏幕。否则,可能会出现错误,并且不会弹出窗口。
使用上述命令配置 Linux 内核后,会弹出一个包含
菜单列表的窗口,您可以从中选择要配置的项目。如果您不熟悉配置,请检查文件系统菜单,确认是否已选择“ext4”。如果未选择,请选中并保存配置。
或者:您可以直接执行以下命令并使用默认配置。
make defconfig
现在,我们终于可以使用以下命令编译内核了:
sudo make
在我的单核虚拟机上,编译耗时 40 分钟到 1 小时。作为替代方案,您可以在虚拟机设置中增加虚拟机的核心数,并使用参数指定分配给虚拟机的核心数-jn。n
就我而言,我使用了以下 occmand 命令来处理 8 核虚拟机,这使得编译时间从 20 秒缩短到 1 分钟:
make -j8
4. 安装我们的内核
编译成功后,要安装/更新内核,请使用以下命令:
make modules_install install
该命令会在/boot/目录下创建一些文件,并automatically在 grub.cfg 文件中添加一个条目。
要检查条目是否正确添加,请检查目录下的文件/boot/。如果您已按步骤操作且未出现任何错误,除了其他文件外,您还会在该目录中找到以下文件。
5. 在新内核中测试我们的系统调用
现在我们只需要重启系统:
shutdown -r now
计算机重启后,在grub高级选项中,可以看到有 2 个选项(不包括恢复模式选项)。
计算机重启后,您可以运行以下命令来检查内核版本:
uname -r
4.20.1安装内核后,我的操作系统会打印出这条信息。
检查内核版本后,我们将syscall用一个简单的 C 程序进行测试。
vim hello_test.c
将以下 C 代码插入到hello_test.c文件中:
#include <stdio.h>
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <unistd.h>
int main()
{
long int helloCheck = syscall(548);
printf("System call sys_hello returned %ld\n", helloCheck);
return 0;
}
然后编译并运行它:
gcc hello_test.c -o hello.o && ./hello.o
System call sys_hello returned 0如果执行过程中没有问题,它会打印相关信息。现在我们可以使用Hello world以下命令检查内核日志缓冲区,看看我们的代码是否在那里:
dmesg
它会打印大量的行,最后我们应该会看到我们的Hello world。
[ ........] ...
[ ........] ...
[ ........] ...
[ 2.858022] IPv6: ADDRCONF(NETDEV_UP): enp0s3: link is not ready
[ 2.858144] ip (1443) used greatest stack depth: 12424 bytes left
[ 2.860434] Adding 10483708k swap on /dev/sda5. Priority:-2 extents:1 across:10483708k
[ 3.391290] hrtimer: interrupt took 4499049 ns
[ 4.887969] e1000: enp0s3 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX
[ 4.888216] IPv6: ADDRCONF(NETDEV_CHANGE): enp0s3: link becomes ready
[ 306.497742] Hello world
我们可以观察到,我们的信息Hello world被打印到了内核日志缓冲区。所以它成功了!
错误修复
Debian证书问题
第一次尝试时,我遇到了如下错误:
make[1]: *** No rule to make target 'debian/certs/debian-uefi-certs.pem', needed by 'certs/x509_certificate_list'. Stop.
make: *** [Makefile:1055: certs] Error 2
- 解决方案 -
我在debian.org 的 bug 报告区找到了这个问题的解决方案。该问题由Heinrich Schuchardt报告如下:
Debian 内核目前使用 CONFIG_SYSTEM_TRUSTED_KEYS="debian/certs benh@debian.org.cert.pem "构建。
这是通过以下链接引入的:https://alioth-lists-archive.debian.net/pipermail/kernel-svn-changes/2016-April/022904.html。距离 Ben 的贡献已经过去两年了,但我们仍然没有使用内核模块签名(配置中未设置 CONFIG_MODULE_SIG)。
由于内核无需信任 Ben 的证书,请删除此设置。
此致
海因里希·舒哈特
因此,我已清除CONFIG_SYSTEM_TRUSTED_KEYS配置文件中的配置。
在linux-4.20.1我的内核源代码目录中,有一个名为 `.config` 的文件,.config其中存储了内核的配置信息。我使用以下命令打开了它:
vim .config
然后搜索CONFIG_SYSTEM_TRUSTED_KEYS并更改
CONFIG_SYSTEM_TRUSTED_KEYS="debian/certs benh@debian.org.cert.pem"
变成这样:
CONFIG_SYSTEM_TRUSTED_KEYS=""
然后保存并关闭文件,再次尝试编译,就没有出现问题了。
由于这篇文章已经很长了,第二个例子我会在另一篇文章中发表。
请在下方留言提出您的问题和反馈意见。
文章来源:https://dev.to/omergulen/how-to-add-system-call-syscall-to-the-kernel-compile-and-test-it-3e6p