实验一:Linux内核编译及添加系统调用
实验一:Linux内核编译及添加系统调用
一、实验目的
- 理解Linux系统处理系统调用的流程
- 增加一个系统调用
二、实验内容
-
nice,可以理解为谦让度,CPU在选择进程时根据优先级prio选择,当nice值越高,可理解为这个进程越是谦让,即优先级越低
-
添加一个系统调用,实现对指定进程的nice值的修改或读取功能,并返回系最新的nice值,即优先级prio。
建议调用原型为:
Int mysetnice(pid_t pid, int flag, int nicevalue,void_userprio,void_usernice)
参数含义:
pid:进程ID
flag:若值为0,表示读取nice值;若值为1表示修改nice值。
prio,nice:指向进程当前优先级及nice值。
返回值:系统调用成功时返回0,失败时返回错误码EFAULT。
-
写一个简单的应用程序测试系统调用
-
深入阅读相关函数源码
三、流程图
四、具体实现
-
安装虚拟机及ubuntu
按指导来问题不大,在可行前提下,分配处理器选择4核或以上
大小分配60G左右!
https://jingyan.baidu.com/article/f96699bb147a73894e3c1b2e.html
-
开启系统,打开terminal,进入管理员模式
打开termintal: ctrl+alt+t
管理员模式: 输入 sudo su 输入用户密码进入管理员模式
-
下载解压内核
下载内核: 输入 wget http://mirrors.ustc.edu.cn/kernel.org/linux/kernel/v4.x/linux-4.4.196.tar.xz
解压内核: 输入 tar -xvJf linux-4.4.196.tar.xz
-
系统调用
装各种包 输入 sudo apt-get install vim libncurses5-dev make openssl libssl-dev bison flex ctags
添加系统调用号 进入内核:cd linux-4.4.196 # 之后的操作都是在这个目录下
编辑调用表:vim arch/x86/entry/syscalls/syscall_64.tbl
输入G (跳末行)上行到300多行 ,输入i (进入编辑模式)
输入如图
按ESC键 退出编辑模式 输入 :wq 保存并退出
申明系统调用 vim include/linux/syscalls.h
输入 G i 添加如下
asmlinkage long sys_mysetnice(pid_t pid,int flag,int nicevalue,void __user * prio,void __user * nice);
按ESC键 退出编辑模式 输入 :wq 保存并退出
实现调用 vim kernel/sys.c
输入 G i 添加如下
SYSCALL_DEFINE5 (mysetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice){
//SYSCALL_DEFINEN中N表示系统调用所需要的参数个数,我们的是5个
struct task_struct *p;//进程结构体指针
struct pid *id;//pid结构体
int m,n;
id=find_get_pid(pid);//通过传入的pid_t pid得到id结构体
p=pid_task(id,PIDTYPE_PID);//通过id得到指定进程,PIDTYPE_PID指的是进程类型的pid
m=task_nice(p); //通过p得到nice值
n=task_prio(p); //通过p得到prio值(优先级)
if(flag==0){//读取
copy_to_user(nice,(void*)&m,sizeof(m));//将m的地址强转为void *类型
copy_to_user(prio,(void*)&n,sizeof(n));
return 0;
}
else if(flag==1){//修改
printk("nice value before modified:%d\n",m);
set_user_nice(p,nicevalue);//修改nice的值
return 0;
}
printk("syscall failed!");
return EFAULT;
}
按ESC键 退出编辑模式 输入 :wq 保存并退出
-
配置编译内核
输入 make mrproper
输入 make clean
输入 make menuconfig
(terminal窗口最大化)
选择Save 回车确定 回车确定 选择Exit
输入 make -j4
(-j4表示4线程编译,耗费较长,无视warning,跳出error可以ctrl+c结束了,出错了就没必要再编译了,看看是否漏掉步骤,根据跳出的error解决)
-
安装内核重启系统
输入 make modules
输入 make modules_install
输入 make install
输入 update-grub2
输入 reboot
重启后 ctrl+alt+t 打开terminal 输入 sudo su 进入管理员模式
输入 uname -a 如果显示的是下载的内核 这里是4.4.196 表明编译成功
-
编写函数测试用
输入 vim exp_1_test.c 新建C文件测试调用
输入i (进入编辑模式)
编写代码如下
#include<stdio.h> #include<unistd.h> #include<sys/syscall.h> #define __NR_mysyscall 326 int main(){ int nice,prio; pid_t id; id=getpid(); printf("----------------read-----------------\n\n"); syscall(__NR_mysyscall,id,0,NULL,&prio,&nice); printf("before modified:pid:%d,prio:%d,nice:%d\r\n",id,prio,nice); printf("-----------------set-------------------\n\n"); printf("syscall(__NR_mysyscall,id,1,-8,&prio,&nice);\n"); syscall(__NR_mysyscall,id,1,-8,&prio,&nice); printf("------------------read-----------------\n\n"); syscall(__NR_mysyscall,id,0,NULL,&prio,&nice); printf("modified:pid:%d,prio:%d,nice:%d\r\n",id,prio,nice); return 0; }
按ESC键 退出编辑模式 输入 :wq 保存并退出
输入 gcc exp_1_test.c 编译C文件
输入 ./a.out 查看结果
-
相关内核源码阅读
输入 cd linux-4.4.196 进入目录
输入 sudo ctags -R * (一些准备工作)
输入 vim kernel/sys.c 就是之前实现调用的
这里以查看set_user_nice函数及nice定义为例,可以此类推
这里光标移动到如图 set_user_nice 函数
输入 ctrl + ] 进入函数 (退出则是c trl +T)
显示如图
光标移动到 MIN_NICE 输入 ctrl + ] 进入
显示如图