最近在學習 《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 釋出地址:https://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 ~/ https://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!