想要做一次编译linux内核并添加系统调用的实验,于是在网上找了许多教程,没有找到特别合适的,许多命令在作者这里并不适用,现在经过查阅了许多资料终于实验结束,把整个实验的详细过程分享在这里供大家参考。本文中对一些原理性的知识并没有过多的解释,只是无脑的进行下一步吧,如有问题可以一起讨论,谢谢。
本文作者使用的系统是ubuntu16.04,内核版本4.10
将要编译的内核版本是4.4.77,linux内核建议在官方网站进行下载,附上链接Index of /pub/linux/kernel/
下面正式开始编译linux,将想要编译的linux内核下载到本地,将下载的压缩包复制到/usr/src/目录下,之后进行解压
cp linux-4.4.77.tar.gz /usr/src/
tar -xzvf linux-4.4.77.tar.gz
进入文件夹中,进行第一步,添加系统调用。
1.添加系统调用号
vim ./arch/x86/entry/syscalls/syscall_64.tbl
2. 为头文件添加系统调用函数的声明
此处可以看做是c语言编程时要在头文件声明函数,只是此时是在不同文件夹下进行操作
vim ./include/linux/syscalls.h
将下面两行代码添加到文件末尾处
asmlinkage long sys_hello(void);
asmlinkage long sys_mycopy(const char *src_file, const char *copy_file);
到这里头文件已经声明了函数,接下来要在源文件中实现函数的功能
3. 编写函数的功能
asmlinkage long sys_hello(void)
{
printk("hello, world!");
return 1;
}
asmlinkage long sys_mycopy(const char *src_file, const char *copy_file)
{
int infd, outfd, count;
char buf[256];
mm_segment_t fs;
fs=get_fs();
set_fs(get_ds());
if((infd=sys_open(src_file, O_RDONLY, 0)) == -1)
{
return 1;
}
if((outfd=sys_open(copy_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
{
return 2;
}
while((count = sys_read(infd, buf, 256)) > 0)
{
if(sys_write(outfd, buf, count) != count)
return 3;
}
if(count == -1)
return 4;
sys_close(infd);
sys_close(outfd);
set_fs(fs);
return 0;
}
4. 编译linux内核与安装
到这里就可以运行 make menuconfig 命令了,但是值得一提的是,此处遇到了报错,是由于相关的库没有安装,报错中会提示需要安装哪个库,经过总结大概可以直接运行下列命令进行安装,基本可以解决
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc
此时再运行make menuconfig命令,就会有一个图形界面显示
选择save后,exit即可,不需进行其他操作。
之后点击输入make,即可开始编译。此处第一次进行编译时,报错提示空间不足,注意:第一次时分配20G磁盘空间不足,第二次便分配了30G磁盘空间,没有报错,成功运行。此处等待时间较长,和个人电脑配置有关。
下面继续进行两项操作,此处并没有遇到问题,作者直接把命令放在下面(都要使用管理员权限才可以运行)
sudo make modules_install
sudo make install
到这里linux内核编译就已经全部结束了,之后我们要确定引导程序的启动顺序。
5. 修改开机启动引导
这里我们依然需要执行两行命令
update-initramfs -c -k 4.4.77 //这里填写自己刚刚编译过的linux内核的版本
update-grub //这行命令自动寻找/boot/文件夹下的内核版本,并自动添加到grub的配置文件
此时我们进入到/boot/grub/目录下查看grub.cgf,可以看到我们要编译的内核版本已经显示在文件中。
cat /boot/grub/grub.cfg
之后作者reboot启动,但是发现uname -r 后还是linux-4.10 generic,因为开机时没有选择要启动的内核版本,于是继续查看刚刚修改过的grub配置文件,这里作者注意到此文件的上方提示不能修改此文件,它是由grub-mkconfig自动生成的,
作者按照提示找到/etc/default/grub文件,看到对GRUB_DEFAULT的设置以及是否隐藏选择引导启动菜单。因此使用#注释掉两行,之后要使用下面的命令更新,即更新/boot/grub/grub.cfg文件
sudo update-grub
之后再次reboot,进入到grub启动选择界面,选择linux 4.4.77
进入到系统后,再次使用uname -r命令查看,
这里可以看到linux内核版本变为4.4.77,说明已经成功。
6. 检验添加系统调用函数是否成功
#include#include#include#includeint main()
{
long int tmp = syscall(546);
printf("system call sys_hello return %ld\n", tmp);
//此条命令用来执行复制操作,参数1为系统调用函数号,参数2为原文件,参数3为输出文件
//syscall(547,"test.html","resule.html");
return 0;
}
gcc命令进行编译,之后执行
gcc test.c -o test
./test
dmesg //这里需要使用dmesg命令查看printk输出到信息
到这里就全部结束了,本文借鉴了不少大佬的经验,还有许多个人博客的经验,如有侵权,可联系删帖。