[保姆級教程] 如何在 Linux Kernel (V5.17.7) 中添加一個系統調用(System call)
最近在學習 《linux Kernel Development》,本書用的linux kernel 是v2.6 版本的。看完」系統調用「一節後,想嘗試添加一個系統調用,然後重編一個kernel。經過幾個小時的嘗試,實現了這個小功能,其中也遇到了不少坑,本文主要是記錄分享下如何在Linux Kernel (V5.17.7) 中添加一個系統調用(System call)。
編kernel之前需要注意:
1、修改的kernel是目前最新的release 版本(V5.17.7), 書中v2.6版本的kernel太老了,gcc需要降到4.8版本,否則無法編過。 kernel 發佈地址://www.kernel.org/
2、需要選用大內存,多核的機器編kernel,否則會出現各種異常問題,而且編kernel 很費時間。15GB內存的機器,編不過kernel。換用100GB內存的機器就好了😅
本文主要包含以下幾點內容:
1、環境準備
2、修改kernel
3、rebuild kernel 以及安裝kernel
4、測試結果
1、環境準備
我編kernel的機器是:Ubuntu 20.04.1 LTS,內存180GB, cores: 88
1.1 更新系統的源
sudo apt update && sudo apt upgrade -y
1.2 安裝編譯kernel 需要的依賴
sudo apt install build-essential libncurses-dev libssl-dev libelf-dev bison flex -y
我這裡用的vim,沒有的話也需要安裝:
sudo apt install vim -y
1.3 清除已經安裝的packages
sudo apt clean && sudo apt autoremove -y
1.4 下載kernel code
wget -P ~/ //cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.17.7.tar.xz
tar -xvf ~/linux-5.17.7.tar.xz -C ~/
2、修改kernel
2.1 檢查你自己當前系統的kernel 版本
uname -r
5.11.0-36-generic
重新安裝kernel之後,這個版本號會被修改。
2.2 切換到工作目錄中,然後創建自己的系統調用
cd ~/linux-5.17.7/
mkdir hello
2.3 創建自己的系統調用
vim hello/hello.c
添加代碼。
#include <linux/kernel.h>
#include <linux/syscalls.h>
SYSCALL_DEFINE0(hello)
{
printk("hello_system_call.\n");
return 0;
}
2.4 為你的系統調用創建 Makefile
vim hello/Makefile
添加下面內容:
obj-y := hello.o
2.5 將你的系統調用添加到Kernel 的makefile中
vim Makefile
搜索 core-y, 完成如下添加:
2.6 將系統調用的相應函數原型添加到系統調用的頭文件中
vim include/linux/syscalls.h
添加:
asmlinkage long sys_hello(void);
2.7 在system_table 中為你的系統調用開闢一個新的系統調用號。
vim arch/x86/entry/syscalls/syscall_64.tbl
3、編譯kernel 並安裝
前面的步驟都很簡單,這一步可能會出現各種問題,而且很耗時。
3.1 創建你的.config
這裡一路默認設置就好。
make menuconfig
3.2 查詢你的機器logicl cores 有多少個
nproc
3.3 編譯安裝你的kernel
make -j32
echo $? // make 結束之後記得檢查一下 狀態
###if output is 0 then
sudo make modules_install -j32
echo $?
make install -j32
3.4 查看kernel 是否安裝進去了
sudo update-grub
sudo reboot
4、測試結果
4.1 首先check 你的kernel 換好沒
uname -r
4.2 編一個code 調用你的系統調用
由於系統調用不像普通函數那樣,需要通過sys_call 以及系統調用號才能實現系統調用。創建一個test.c
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define __NR_hello 451
long hello_syscall(void)
{
return syscall(__NR_hello);
}
int main(int argc, char *argv[])
{
long activity;
activity = hello_syscall();
if(activity < 0)
{
perror("Sorry, xxx. Your system call appears to have failed.");
}
else
{
printf("Congratulations, xxx! Your system call is functional. Run the command dmesg in the terminal and find out!\n");
}
return 0;
}
4.3 測試結果
gcc -o test test.c
./test
dmesg // 後面也能看到系統調用打印的信息
Congratulations, yaran! Your system call is functional. Run the command dmesg in the terminal and find out!