实验一:Linux内核编译及添加系统调用(HDU)
花了一上午的时间来写这个,良心制作,发现自己刚学的时候没有找到很详细的,就是泛泛的说了下细节地方也没有,于是自己写了这个,有点长,如果你认真的看完了,也应该是懂了。
一、前期准备工作
1.需要准备虚拟机上安装Ubuntu,笔者安装的是Ubuntu18.04,安装的教程自行百度解决,教程很多。有几点需要提一下,就是内存分配至少60G,核分配4个最好,为了在编译的时候别崩溃。
建议去熟悉一下Linux下面的文件目录结构,根目录下每个目录一般会存放什么样的文件
,然后常见命令操作也要熟悉一下。
2.下载Linux内核地址,自行选择版本,建议选择4.xx版本,因为版本高出错的概率也大。
下载好了之后,会放在自己的Ubuntu中的Downloads目录下,同时是一个压缩文件,到时候需要解压到放内核目录文件下。首先进入到该Downloads文件目录下,查看是否下载好了。
$cd ~/Downloads
$ls
linux-4.19.25.tar.xz
之后开始解压上面的那个压缩文件到存放内核的地方,就是Linux系统的/usr/src目录下,此目录用来存放内核源码的。从上图也可以了解到。
cd ~/Downloads
tar xvJf linux-4.19.25.tar.xz -C /usr/src
进入/usr/src目录查看是否有,如果有就可以开始后续工作了。
二、实验要求和内容
1. 内容要求:
(1)添加一个系统调用,实现对指定进程的nice值的修改或读取功能,并返回进程最新的nice值及优先级。建议调用原型是int mysetniec(pid_t pid, int flag, int nicevalue, void_user* prio, void_user* nice);
参数含义:
pid:进程ID
flag:若为0,则表示读取nice的值;若为1,则表示修改nice的值。
nicevalue:为指定的进程设置新的nice。
prio,nice:指向进程的优先级和nice值。
返回值:系统调用成功时返回0;失败时返回错误码EFAULT。
(2)写一个简单的应用程序测试(1)中添加的系统调用。
(3)若系统调用了Linux的内核函数,要求深入阅读相关的源码。
2. Linux系统调用的基本概念
实质是指调用内核函数,于内核态中运行,Linux中的用户通过执行一条访管指令“int $0x80”来调用系统调用,该指令会产生一个访管中断,从而让系统暂停当前的进程执行,而转去执行系统调用处理程序。通过用户态传入的系统调用号从系统调用表中找到相应的服务例程的入口并执行,完成后返回。
(1)系统调用号与系统调用表:Linux内核中设置了一张系统调用表,用于关联系统调用号及其相对应的服务例程入口地址,定义在./arch/x86/entry/syscalls/syscall_64.tbl文件中,每个系统调用占一个表项,一旦分配好就不可以有任何变更。
(2)系统调用服务例程:每个系统调用都对应一个内核服务例程来实现系统调用的功能,其命名的格式都是以"sys_开头。其代码通常放在./kernel/sys.c中,服务例程的原型声明则是放在./include/linux/syscall.h中。如sys_open,通常格式是asmlinkage long sys_open(int flag......)。其中的amslinkage是一个必需的限定词,用于通知编译器从堆栈中提取函数的参数,而不是从寄存器中。
在sys.c中编程时,格式是SYSCALL_DEFINE5(mysetnice, pid_t, pid, int, flag, int, nicevalue, void __user *, prio, void __user *, nice)
N=5代表参数的个数。
(3)系统调用参数传递:在X86中,Linux通过6个寄存器来传入参数,其中一个eax是传递系统调用号,后面的5个传递参数。
(4)系统调用参数验证
三、开始实验
1. 切换到root权限下,防止权限不够,导致出错。
$ sudo passwd root
[sudo] password for leslie:
Enter new UNIX password:
Retyp