Linux添加系统调用
1.设计目的
Linux 是开源操作系统,用户可以根据自身系统需要裁剪、修改内核,定制出功能更加
合适、运行效率更高的系统,因此,编译 linux 内核是进行内核开发的必要基本功。
在系统中根据需要添加新的系统调用是修改内核的一种常用手段,通过本次实验,读
者应理解 linux 系统处理系统调用的流程以及增加系统调用的方法。
2.内容要求
(1)添加一个系统调用,实现对指定进程的 nice 值的修改或读取功能,并返回进程最
新的 nice 值及优先级 prio。建议调用原型为:
int mysetnice(pid_t pid, int flag, int nicevalue, void __user * prio, void __user * nice);
参数含义:
pid:进程 ID。
flag:若值为 0,表示读取 nice 值;若值为 1,表示修改 nice 值。
Prio、nice:进程当前优先级及 nice 值。
返回值:系统调用成功时返回 0,失败时返回错误码 EFAULT。
(2)写一个简单的应用程序测试(1)中添加的系统调用。
(3)若程序中调用了 linux 的内核函数,要求深入阅读相关函数源码。
一、准备
我使用的是ubuntu 16.04 LTS,下载的是4.13.12的内核。
下载链接:https://www.kernel.org/
首先要注意硬盘至少需要40G,不然会爆掉…别问我怎么知道的。内存分配的稍微大点就好。
二、编译内核
编译内核其实很简单~
我们先切换到root用户,把下载好的内核压缩文件放到/usr/src下,然后进入这个目录解压
xz -d linux-4.4.25.tar.xz
tar -xvf linux-4.4.25.tar
- 1
- 2
然后如果不是第一次编译或者编译出错需要重新编译最好都执行一下make mrproper
执行这条命令需要先安装一个包
apt-get install libncurses5-dev
- 1
我们是刚下载的的干净的内核源码包,所以不用执行make mrproper这条命令。
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
- 1
- 2
- 3
所以我们可以知道make mrproper和make clean的区别主要就是前者会删除所有的编译生成文件,而后者会保留配置文件.config,还有足够的扩展模块的支持。所以其实想清除编译残留数据的话执行make clean就可以了。实际上make mrproper一开始就会调用make clean的。
好了 下面我们要配置内核选项了
make menuconfig
- 1
这个就去网上找具体点的吧 选项太多
会出来一个图形界面 配置好exit会提示save即可。
之后就是激动人心的编译内核时刻
我们先安装一个包
apt-get install libssl-dev
- 1
生成启动映像文件
make bzImage
- 1
然后去看个番什么的等吧 不过可能要多看几集
编译完成之后继续编译模块
make modules
- 1
注意我们一直是在/usr/src/linux-4.4.25这个文件夹下操作的,这次时间就更长了。我的配置一般i5而且是虚拟机,加上编译内核一共可能要几个小时,所以去打会球吧=。=
模块编译好之后的步骤都很快了,
安装模块
make modules_install
- 1
然后要建立载入虚拟内存盘的编在内核中的根文件系统镜像
mkinitramfs 4.4.25 -o /boot/initrd-4.4.25.img
- 1
配置grub引导
update-grub2
- 1
最后重启系统就大功告成了
reboot
- 1
最后可以通过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)
```
- 1
- 2
- 3
- 4
- 5
并且将后面的__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_zwhsyscall
- 1
3.编写服务例程
要为我们的服务写程序了
/usr/src/linux-4.4.25/kernel/sys.c
我这里是一个简单的实现读取进程的nice值和修改进程nice值的服务
参数flag为1时修改nice
参数为0时读取nice
SYSCALL_DEFINE3(setmynice, 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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
SYSCALL_DEFINE3的3即为参数个数,其他就不过多解释了,程序轻喷….
4.重新编译内核
不重新编译无法生效…等吧=。=
5.编写用户态程序测试
下面就可以写程序测试啦
得引入下头文件
#include<linux/unistd.h>
#include<sys/syscall.h>
- 1
- 2
然后可以选择一个进程调用我们的服务修改或者读取nice值啦,
由于使用了printk,我们要用dmesg查看输出信息。
可以使用top -p pid查看指定进程的信息。
over.