实验介绍
上篇文章已经介绍了Linux内核的编译与安装,我们已经掌握了Linux系统内核的编译和启用。接下来,我们将学习掌握如何添加Linux的系统调用,学习掌握测试Linux系统调用。
什么是系统调用(system call)
由操作系统提供的供所有系统调用的程序接口集合;用户程序通常只在用户态下运行,当用户程序想要调用只能在内核态运行的子程序时,所以操作系统需要提供访问这些内核态运行的程序的接口,这些接口的集合就叫做系统调用。简要的说,系统调用是内核向用户进程提供服务的唯一方法。应用程序有时会需要一些危险的、权限很高的指令,如果把这些权限放心地交给用户程序是很危险的(比如一个进程可能修改另一个进程的内存区,导致其不能运行),但是又不能完全不给这些权限。于是有了系统调用,危险的指令被包装成系统调用,用户程序只能调用而无权自己运行那些危险的指令。另外,计算机硬件的资源是有限的,为了更好的管理这些资源,所有的资源都由操作系统控制,进程只能向操作系统请求这些资源。操作系统是这些资源的唯一入口,这个入口就是系统调用。
实验准备
华为云服务器,OpenEuler操作系统,Xshell远程登录软件(可选)
在做此实验时需要多次编译内核,如果使用VMware本地虚拟机来进行实验,8个线程编译内核耗时过多,所以使用华为云服务器,购买32线程的云服务器编译内核1分钟就搞定,这样会节省很多时间,而且不用担心编译内核时出现bug导致本地虚拟机死机。


本次实验全程在华为云服务器下进行
掌握Linux内核的编译与安装请参考https://blog.csdn.net/weixin_/article/details/?spm=1001.2014.3001.5501
开始实验
1.2——掌握Linux系统调用基本概念
添加一个新的系统调用,通过内核打印调试语句printk打印自己的学号
1.将系统调用的函数加入到syscalls数组中
输入
cd kernel-kernel-4.19/include/uapi/asm-generic/ /*进入操作目录*/ vim unistd.h /*编辑该文件*/
在该文件中输入
#define __NR_hyb 294 __SYSCALL(__NR_hyb, sys_hyb)

如上图所示(注意坑点1:在编辑该文件时,找到文件最后一行为294,在其上加入系统调用函数,然后将最后的294改为295。后续实验添加调用函数后将295改为296以此类推。)
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
2.在头文件中声明系统调用函数
输入
cd kernel-kernel-4.19/include/linux/ /*进入头文件目录*/ vim syscalls.h /*编辑该文件*/
在该文件中输入
asmlinkage long sys_hyb(void);

如上图所示(注意坑点2: 在编辑该文件时,不要将声明的函数加在 if 语句中,即将该声明放在#endif下面)
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
3.添加函数体
输入
cd kernel-kernel-4.19/kernel/ /*进入目录*/ vim sys.c /*在该文件中添加需要的函数体*/

在文件中添加如上图所示的内容(这里的坑点与坑点2相同)
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
4.编译、安装内核
输入
make -j 32 /*32为线程数,虚拟机为多少这里就写多少*/ make modules_install make install reboot
此操作时间取决于线程数量,越多耗时越短(注意坑点3:类似的操作都需要在kernel-kernel-4.19目录下进行)
5.编写测试代码
参考课本
输入
vim hyb.c /*新建一个名为hyb.c的C语言文件*/

输入如上图所示的内容
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
6.编译生成hyb_0文件
输入
gcc hyb.c -o hyb_0

如图所示,生成了一个名为hyb_0的文件
输入
./hyb_0 /*查看编译运行结果*/

如图所示即为1.2实验结果
1.3——设计和添加系统调用
经过1.2的步骤,对于1.3来说,大致的过程与1.2不尽相同(三步走:写调用函数——编译安装内核——编写测试代码)
题目一(必做):修改或返回指定进程的优先级(nice值和prio值)
提示:可能参考的内核函数:set_user_nice()
1.将系统调用的函数加入到syscalls数组中
输入
cd kernel-kernel-4.19/include/uapi/asm-generic/ /*进入操作目录*/ vim unistd.h /*编辑该文件*/
在该文件中输入
#define __NR_hybsetnice 295 __SYSCALL(__NR_hybsetnice, sys_hybsetnice)

如图所示,同理,根据上文介绍将末尾的数字295改为296
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
2.在头文件中声明系统调用函数
输入
cd kernel-kernel-4.19/include/linux/ /*进入头文件目录*/ vim syscalls.h /*编辑该文件*/
在该文件中输入

(这里的坑点与坑点2相同)
3.添加函数体
输入
cd kernel-kernel-4.19/kernel/ /*进入目录*/ vim sys.c /*在该文件中添加需要的函数体*/

在该文件中添加函数体,注意格式正确(坑点与坑点2相同)
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
4.编译、安装内核
输入
make -j 32 /*32为线程数,虚拟机为多少这里就写多少*/ make modules_install make install reboot
5.编写测试代码
输入
vim hyb_1.c /*生成一个C语言文件并且编辑*/
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
6.编译生成hyb_1文件
输入
gcc hyb_1.c -o hyb_1

我们可以看到已经生成了hyb_1编译后的文件

如图所示即为运行后的实验结果
题目一小结:
在实验中,需要用到 Linux top命令行操作,什么是top?
top 命令可以动态地持续监听进程地运行状态,与此同时,该命令还提供了一个交互界面,用户可以根据需要,人性化地定制自己的输出,进而更清楚地了进程的运行状态。

在上图中看到有PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND值,这里着重注意PR值和NI值。(PR值——优先级;NI值——nice值,有+有-,负值表示高优先级,正值表示低优先级)也就是题目中的nice prio值。
那么,什么是nice值和prio值?
通俗来说,nice值越低,证明这个进程越不nice(这个进程很霸道)抢占CPU的能力就越强,所以,值越低,进程的优先级越高。prio值即为priority值,为top命令中看到的PR值,优先级。
选做题目二
(牢记三步走战术)
1.将系统调用的函数加入到syscalls数组中
输入
cd kernel-kernel-4.19/include/uapi/asm-generic/ /*进入操作目录*/ vim unistd.h /*编辑该文件*/

同理,将下方的数字296改为297。
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
2.在头文件中声明系统调用函数
cd kernel-kernel-4.19/include/linux/ /*进入头文件目录*/ vim syscalls.h /*编辑该文件*/
在文件中输入

(这里的坑点与坑点2相同)
3.添加函数体
输入
cd kernel-kernel-4.19/kernel/ /*进入目录*/ vim sys.c /*在该文件中添加需要的函数体*/

在该文件中添加函数体,注意格式正确(坑点与坑点2相同)
Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
4.编译、安装内核
输入
make -j 32 /*32为线程数,虚拟机为多少这里就写多少*/ make modules_install make install reboot
5.编写测试代码
输入
vim hyb_2.c

Esc退出编辑模式,:wq保存并退出,cd /root返回桌面
6.编译生成hyb_2文件
输入
gcc hyb_2.c -o hyb_2

我们可以看到生成了名为hyb_2的文件,运行
在输入PID时,可以参考前面提到过的top命令,输入一个存在的PID,以防报错。

我们可以看到已经返回了6个想要的数据,而且ret=0为正确(ret=-1为错误)。
题目二小结:
题目要求输出6个需要的返回值,在参考资料后,我们发现这个内核函数中还有许许多多其他的返回参数,要学会举一反三。
至此,实验1.3已全部完成,与上一篇博客一起,就是操作系统实验课的实验一。
写在最后:
本次实验是一个很耗时的实验,但是理解掌握了实验的“三步走”方法(声明——加入——编写),这个实验也会迎刃而解。查阅了非常多的资料,网络上的博客也是良莠不齐,晦涩难懂,需要多多参透课本的内容。内核编译需要非常强大的CPU,购买32核64G内存的服务器可以在make modules_install时节省大量的时间(用完记得关!!!)
历经了很多次把内核编译崩溃的情况后,一定要冷静,仔细观察书写的代码有没有漏洞。有时候,往往那简单的一个” “、; 错误就会导致内核的编译失败(浪费了那么多时间还失败了真的很抓狂)。这就告诉我们,书写代码一定要规范仔细不可马虎。这个实验说难很难,说简单也很简单,不光只是1.3的两道题目,更要掌握其运行本质,这样才能在添加系统调用中如鱼得水。
文章写作时间仓促,如有错误请指正,如有问题请在评论区中提问。
加油!
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212309.html原文链接:https://javaforall.net
