分享一下从编译内核到Linux添加系统调用的过程吧。linux
我使用的是ubuntu 16.04 LTS,下载的是4.4.25的内核。
首先要注意硬盘至少须要30g,否则会爆掉...别问我怎么知道的。内存分配的稍微大点就好。ubuntu
内核下载地址浏览器
编译内核其实很简单~测试
咱们先切换到root用户,把下载好的内核压缩文件放到/usr/src下,而后进入这个目录解压ui
xz -d linux-4.4.25.tar.xz tar -xvf linux-4.4.25.tar
而后若是不是第一次编译或者编译出错须要从新编译最好都执行一下make mrproper
执行这条命令须要先安装一个包es5
apt-get install libncurses5-dev
咱们是刚下载的的干净的内核源码包,因此不用执行make mrproper这条命令。firefox
make mrproper -Remove all generated files + config + various back files make clean - Remove most generated files but keep the config and enough build support to build external modules
因此咱们能够知道make mrproper和make clean的区别主要就是前者会删除全部的编译生成文件,然后者会保留配置文件.config,还有足够的扩展模块的支持。因此其实想清除编译残留数据的话执行make clean就能够了。实际上make mrproper一开始就会调用make clean的。code
好了 下面咱们要配置内核选项了进程
make menuconfig
这个就去网上找具体点的吧 选项太多
会出来一个图形界面 配置好exit会提示save便可。内存
以后就是激动人心的编译内核时刻
咱们先安装一个包
apt-get install libssl-dev
生成启动映像文件
make bzImage
而后去看个番什么的等吧 不过可能要多看几集
编译完成以后继续编译模块
make modules
注意咱们一直是在/usr/src/linux-4.4.25这个文件夹下操做的,此次时间就更长了。个人配置通常i5并且是虚拟机,加上编译内核一共可能要几个小时,因此去打会球吧=。=
模块编译好以后的步骤都很快了,
安装模块
make modules_install
而后要创建载入虚拟内存盘的编在内核中的根文件系统镜像
mkinitramfs 4.4.25 -o /boot/initrd-4.4.25.img
配置grub引导
update-grub2
最后重启系统就大功告成了
reboot
最后能够经过uname -a查看内核版本
1.分配系统调用号
先去查看一下系统的调用号使用到多少了,查找一下系统调用表
/usr/src/linux-4.4.25/arch/x86/entry/syscalls/syscall_64.tbl
个人版本使用到了325,因此我新的系统调用用326号。注意文件里要看属于x64的系统调用号。
而后咱们修改/usr/include/asm-generic/unistd.h设置系统调用号
添加
#define __NR_saulcall 326 __SYSYCALL(__NR_saulcall,sys_saulcall)
而且将后面的__NR_syscalls的号加1。
ps: 起名困难症 不过一看到call就想起better call saul~ 就用了这个
2.修改系统调用表,关联调用号与调用的服务例程地址
/usr/src/linux-4.4.25/arch/x86/entry/syscalls/syscall_64.tbl
326 64 saulcall sys_saulcall
3.编写服务例程
要为咱们的服务写程序了
/usr/src/linux-4.4.25/kernel/sys.c
我这里是一个简单的实现读取进程的nice值和修改进程nice值的服务
参数flag为1时修改nice
参数为0时读取nice
SYSCALL_DEFINE3(saulcall, pid_t, pid, int, flag, int, nicevalue){ int error = 0; struct task_struct *p; for(p = &init_task;(p = next_task(p)) != &init_task;){ if(p->pid == pid){ if(flag == 0){ printk("the process's nice = %d",task_nice(p)); } else if(flag == 1){ printk("the process changed to %d",nicevalue); set_user_nice(p,nicevalue); } else { error = -EFAULT; } return error; } } error = -EFAULT; return error; }
SYSCALL_DEFINE3的3即为参数个数,其余就不过多解释了,程序轻喷....
4.从新编译内核
不从新编译没法生效...等吧=。=
5.编写用户态程序测试
下面就能够写程序测试啦
得引入下头文件
#include <linux/unistd.h> #include <sys/syscall.h>
而后能够选择一个进程调用咱们的服务修改或者读取nice值啦,
因为使用了printk,咱们要用dmesg查看输出信息。
可使用top -p pid查看指定进程的信息。
提供一个小demo:
首先咱们能够查找一个指定进程的pid,能够用pgrep加指定进程名,
也能够用top命令显示各个进程资源占用,而后找一个进程的pid来实验咱们的系统调用,比方说我先打开火狐浏览器,而后假设用top命令看到firefox的pid为4325,程序就能够以下来写
#include <linux/unistd.h> #include <sys/syscall.h> int main() { syscall(__NR_saulcall,4325,1,15); // 修改4325进程的nice值为15 return 0; }
再次使用Top查看firefox进程的nice值能够看到已经被更改为咱们想要的数值。
over.