下载内核 首先,到官网(https://www.kernel.org/ )下载内核。
因为之前编译过一次内核,所以这次没有选择最新的 5.11.11
版本。
下载完之后,直接拖进虚拟机的任意一个目录即可。
解压内核压缩包 进入刚刚放置内核文件的目录,右键解压,或者在命令行解压
1 $ tar -Jxvf linux-5.11.11.tar.xz
注意,tar -Jxvf
的 J
要大写。
然后,将解压好的文件从当前目录移动到 /usr/src/
目录下
1 $ sudo mv linux-5.10.27/ /usr/src/
安装相关依赖 安装前,先执行以下命令
1 2 $ sudo apt-get update $ sudo apt-get upgrade
然后,依次安装下面的依赖
1 2 3 4 5 6 7 8 9 $ sudo apt-get install libncurses5-dev openssl libssl-dev $ sudo apt-get install build-essential openssl $ sudo apt-get install pkg-config $ sudo apt-get install libc6-dev $ sudo apt-get install bison $ sudo apt-get install flex $ sudo apt-get install libelf-dev $ sudo apt-get install zlibc minizip $ sudo apt-get install libidn11-dev libidn11
如果以前有安装过这些依赖,则跳过这一步。
添加自定义的系统调用 进入相关目录
1 $ cd /usr/src/linux-5.10.27/
打开可以向其中添加自定义系统调用号的文件
1 $ sudo gedit arch /x86/entry/syscalls/syscall_64.tbl
如图所示,442 和 443 是自己添加的系统调用的调用号
保存后关闭窗口。
需要注意的一点是,这里的第三列的内容是和后面的 sys_
后面的内容是一致的,千万不要把它们搞错了!我就是因为这个问题导致后面内核编译到最后一步时,报了一个找不到我自己定义的函数的引用。
还有,这里使用 sudo gedit
会报一些 warning,这个不要理会,这个是 gedit 本身的问题,它在命令行调用就会出现这样的警告。
然后输入命令
1 $ sudo gedit include/linux/syscalls.h
编辑文件,添加函数声明,这里的函数声明应该与上一步定义的系统调用中的函数一致
添加系统调用的函数定义
1 $ sudo gedit kernel/sys.c
1 2 3 4 5 6 7 8 9 10 11 12 SYSCALL_DEFINE0(first) { printk("My first system call\n" ); return 0 ; } SYSCALL_DEFINE1(second, int , number) { printk("My second system call\n" ); printk("The number you enter is %d\n" , number); return number; }
这里的两个函数就是自己增加的系统调用。
使用虚拟机的朋友,建议在这里拍一个快照。
编译内核 首先,输入以下命令并执行
1 2 sudo make mrpropersudo make clean
注意,这里因为执行了 clean
,所以下面的编译时间会有点长,大概五十分钟到一个小时不等。
然后执行以下命令,进入图形配置界面
这里我们直接 Save,然后退出即可,然后开始编译
-j4
表示将编译工作分成 4 个 jobs,每一个 job 分别在单独的核上运行。当然,前提是我们的机器得是多核的才行。比如,我的机器是 4 核的,这里就用 -j4
。
以上表示编译好了(只要最后不报错,就是编译成功了)。
1 $ sudo make modules_install
以上表示模块安装成功。
最后执行 reboot
(即重启),然后开机检查内核版本,发现变成了我们安装的 5.11.11
。
检验添加的系统调用
然后写入以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <linux/kernel.h> #include <sys/syscall.h> #include <unistd.h> #include <stdio.h> int main () { printf ("System call sys_first return %ld\n" , syscall(442 )); long temp; temp = syscall(443 , 2 ); printf ("System call sys_second return %ld\n" , temp); return 0 ; }
1 2 $ sudo gcc -o test test.c $ sudo ./test
运行结果如下
再输入命令
查看系统进程,可以看到系统调用的输出
可以发现,这里打印了我们之前 printk
中的语句。
到这里,就大功告成了。
参考:操作系统作业:Ubuntu编译一个新内核以及添加系统调用