实验要求:添加一个系统调用,实现对指定进程的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

一看到这个实验要求,就产生了很多困惑,通过大量的查阅资料和阅读源码弄懂了个大概
(1)进程nice值是什么?
   进程nice值可以调整该进程的优先级。int类型,值从-20到+19,负值表示调整到高优先级,0表示不调整优先级,正值表示调整到低优先级
(2)pid_t是什么类型?

//linux4.16.2源码中是这么写的
typedef __kernel_pid_t  pid_t;
typedef int     __kernel_pid_t;

那为什么不直接声明为int类型呢?为了在不同平台间可移植性好一些。
(3)void __user* 又是什么类型?
(void __user *)arg 指的是arg值是一个用户空间的地址,不能直接进行拷贝等,要使用例如copy_from_user,copy_to_user等函数。
大概意思就是在内核函数里,拷贝这种类型的数据要用copy_from_user,copy_to_user函数
copy_to_user函数原型:

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);

(4)EFAULT是什么?

#define EFAULT  14  /* Bad address */

再通过一张图来了解下系统调用的原理:

用户调用系统调用时,会执行一条访管指令,该指令会产生一个访管中断,从而让系统暂停当前进程执行,转入核心态调用处理程序。

接下来进入实际操作
一、下载虚拟机
常用虚拟机软件:Vimware workstation pro或VitualBox
创建虚拟机之前先去下载对应系统的iso文件
虚拟机配置:64位Ubuntu 16.04,磁盘空间100G(建议大于80G,有条件的可以分在固态盘C盘,速度比较快),内存8G,2核
磁盘空间太小会因空间不足而导致编译内核失败。内存太小会影响编译速度,一般编译时间在1.5h-3h。


注:以下操作均在虚拟机内进行

二、网上下载内核
下载内核:点我QAQwww.kernel.org

笔者下载的是最新的4.16.2,点击黄色框框即可下载


三、添加系统调用
切换到root用户,将下载的内核文件复制到/home或者其他空闲目录,在该目录下打开终端,分两步解压缩:

(1)sudo xz -d linux-4.16.2.tar.xz
(2)sudo tar -xvf linux-4.16.2.tar

解压完成后会生成一个linux-4.16.2的文件,进入该文件夹,开始添加系统调用。
添加系统调用需三步:

(1)查看系统调用表(./arch/x86/entry/syscalls/syscall_64.tbl)

每个系统调用在表中占一项,格式为:
<系统调用号> <64/x32/common> <系统调用名> <服务例程入口>
系统调用号非常关键,一旦分配就不能就任何更改。每个系统调用需要一个服务例程完成其具体功能。

选择一个未使用的系统调用号进行分配
如图:

(2)声明系统调用服务例程
进入目录linux-4.16.2/include/linux/syscalls.h中,在文件末尾添加内容
如图:

asmlinkage是一个必须的限定词,用于通知编译器仅从内核中提取该函数的参数,而不是从寄存器中,因为在执行服务例程之前系统已经将通过寄存器传递过来的参数压入内核堆栈了。

(3)实现系统调用服务例程
这里就要编写系统调用实现代码了,进入目录linux-4.16.2/kernel/sys.c,
在该文件中添加以下代码:

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;
}

如图:

以上用到的函数和结构体可以在linux源码中查阅。
另外一开始很困惑为什么SYSCALL_DEFINE类型的函数参数声明中类型和参数名要用逗号分开,直到查到了这篇文章:
Linux系统调用之SYSCALL_DEFINE


四、开始内核编译
在linux-4.16.2目录下打开终端

step 1.安装编译可能需要的库(血泪教训:没有这些库编译会出更多错)

sudo apt-get install libncurses5-dev libssl-dev sudo apt-get install build-essential openssl sudo apt-get install zlibc minizip sudo apt-get install libidn11-dev libidn11

step 2.库安装完成后执行以下命令

sudo make mrproper //清除以前编译的残留文件sudo make clean sudo make menuconfig //配置内核

在该过程中可能会出现一些依赖不存在的问题
只需按照图中的错误提示,sudo apt-get install <文件名> 就可以解决了
例如:

提示说“bison:not found”
解决方法:sudo apt-get install bison

然后会弹出以下窗口:
如图:

不用管它(保留默认值不做修改),save一下然后exit退出即可

step 3.编译内核
sudo make
tips:若虚拟机是多核,可执行sudo make -j N 加快编译速度,其中N是核的数量
该步骤耗时较长,笔者用了2小时(等哭了有木有啊!)

step 4.编译模块
sudo make modules
只用了10分钟。。。网上都说编译内核快,编译模块慢(总觉得在骗我Q_Q)

step 5.安装内核
(1)安装模块:sudo make modules_install
(2)安装内核:sudo make install

step 6.配置grub引导
(顺便提一下引导作用:计算机启动时,引导程序在对计算机系统进行初始化后,把操作系统的核心部分程序装入住存储器)
sudo update-grub2

step 7.重启系统
reboot
重启后应该能够在grub中在新老内核中切换
如图:

进入Ubuntu高级选项

若不能切换,解决方案:
桌面打开终端->sudo update-grub->sudo gedit /etc/default/grub

在该行之前加一个“#”注释掉该行后重启。


五、测试系统调用
新建一个文本文档,文件名为Test.c

在该文档所在目录打开终端,执行以下三步
(1)gcc Test.c
(2)./a.out //gcc默认文件名
(3)dmesg //显示内核信息

a.out用户态程序输出:

dmesg内核程序输出:

比对发现测试成功!

操作系统添加系统调用+内核编译相关推荐

  1. Linux内核2.6.34.14添加系统调用及编译方法(CentOS-6.4-x86_64)

    <?xml version="1.0" encoding="UTF-8"?> //我添加系统调用步骤,仅供参考,尤其是系统调用的实现部分,建议大家自 ...

  2. 操作系统 CentOS8 Linux内核编译一遍通过教程

    操作系统课要求编译内核. 已经把所有坑踩了一遍,完全按照以下内容做能一遍成功. 实验环境: Centos 8 + VMWare Workstation 15 Pro + Linux Kernel 5. ...

  3. 西电软工操作系统实验:编译Ubuntu18.04新内核并添加系统调用(含代码以及详细分析)

    西电软工操作系统实验一:编译Linux内核 目录 (一)前言 (二)实验内容 (三)实验环境 (四)实验过程 4.1安装虚拟机 4.2虚拟机换源 4.3 添加系统调用内核 4.4 下载编译所需的软件依 ...

  4. Linux内核学习8——添加系统调用

    基于linux 5.0内核添加一个系统调用,但是单纯添加一个系统调用会显得有些单调,所以这里把系统调用,工作队列,修改内核,内核编译,内核模块的编写,插入等结合起来. 要添加的是一个系统调用日志收集系 ...

  5. 操作系统实验(linux内核编译,添加系统调用,windows进程创建,脚本程序编写)

    <操作系统原理>实验报告 一.实验目的 (1)理解操作系统生成的概念和过程; (2)理解操作系统两类用户界面(操作界面,系统调用)概念; 二.实验内容 (1)在Unbantu或Fedora ...

  6. 杭电操作系统实验一----Linux内核编译及添加系统调用(完整实验报告)

    一 题目介绍 Linux是开源操作系统.在系统中根据需要添加新的系统调用是修改内核的一种常用手段,通过本次实验,我们可以理解Linux系统处理系统调用的流程以及增加系统调用的方法.Linux系统提供了 ...

  7. 杭电操作系统实验一 --- Linux内核编译及添加系统调用(arm架构华为云)

    实验要求  掌握Linux 内核的编译与安装 掌握Linux 系统调用基本概念 设计和添加linux系统调用 (1)修改或返回指定进程的优先级(nice值和prio值)(详见教材P328)提示:可能参 ...

  8. 【HUST】网安|操作系统实验|实验一 内核编译、系统调用、编写批处理脚本

    文章目录 目的 任务 前言 一.linux内核编译 非常靠谱的两篇参考文章: 补注: 总结 二.添加新的系统调用 特别靠谱的参考文章: 补注: 1. 我修改的文件: 2. 图中需要敲入的全部代码: 3 ...

  9. 【Linux】Linux添加系统调用以及内核编译过程

    在想要替换原有系统内核或者需要在原来的系统中添加一些系统调用的时候就会涉及到Linux内核的编译.但是内核编译虽然步骤简单,但是需要注意的东西还是太多了.首先一点就是由于Linux的开源性导致的版本问 ...

  10. Linux 系统调用(二)——使用内核模块添加系统调用(无需编译内核)

    本文将介绍Linux使用内核模块添加系统调用的方法(无需编译内核),思路就是修改映射在内存中的系统调用表,把一个空闲的系统调用表项指向自己写的模块中的函数,如果是已使用的表项,甚至可以实现系统调用劫持 ...

最新文章

  1. 人脸对齐--Face Alignment at 3000 FPS via Regressing Local Binary Features
  2. vue-auto-focus: 控制自动聚焦行为的 vue 指令
  3. 作业06-接口、内部类
  4. [HDOJ1301]Jungle Roads
  5. 如何使用Openssl 制作CA证书
  6. 将CAGradientLayer当做mask使用
  7. JQuery合并表格单元格
  8. 新浪微博api接口java_新浪微博API(java版)
  9. 计算机双面打印设置,双面打印怎么设置?双面打印设置方法步骤
  10. 音乐倒数计数器(求解答,lcd相关知识点)
  11. PHP实现输入地址,获取当前位置的经纬度,$lng和$lat即为经纬度的返回值
  12. 光场相机微透镜阵列排布方式以及其填充率比较
  13. 条形码怎么看?一文带你认识!
  14. 常用通讯电平转换电路整理
  15. 【测试方法】黑盒测试、灰盒测试、白盒测试这些你确定都会了吗?
  16. system call——系统调用
  17. 2017lol服务器维修,LOL2017年8月15日更新维护到几点 8.15更新内容
  18. HTTP post 上传
  19. 【名单回顾】中国计算机学会NOI Online能力测试入门组获得前25%证书名单(北京地区小学组)
  20. Unity与Android交互(双端通信)

热门文章

  1. Openfile安装和使用
  2. 六月份大学毕业,却感觉自己什么都不会。很迷茫,怎么办?
  3. Java实现的中间库
  4. 编译原理 -- 词法分析程序设计
  5. 用IAR调试芯唐Cortex-M0系列芯片指南
  6. Mysql 不包含某个字符
  7. matlab求广义逆及线性方程组的解
  8. 微处理器 微型计算机 单片机之间有何区别,微处理器,微计算机,微处理机,CPU,单片机,它们之间有何区别...
  9. Mybatis使用关联查询由于表名字段重复导致的问题
  10. spss系列——一元线性回归的分析与预测实例