抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

1.课程设计目的与要求

重新编译Linux内核。

增加一个Linux的系统调用。

写一个程序进行调用。

2.课程设计设备与环境

设备:Microsoft
Surface Laptop 5 (CPU:i7-1255U,内存16G)

环境:
宿主机Windows 11
虚拟机VirtualBox平台,使用CentOS7作为编译环境,使用Linux 4.20.4作为内核编译

3.实验过程

在VirtualBox官网下载VirtualBox最新版本,并在宿主机下载CentOS7:https://www.virtualbox.org/wiki/Downloads

打开VirtualBox,新建虚拟机,选择centos7,取消勾选Proceed with Installation,完成初始化。

1

随后打开设置,将Memory提升至4096MB,然后将CPU 数量加到5,方便后面编译linux。或者依据电脑能力调到合适的数量。这个数量和后面编译指令有关系,请记住。

2

随后安装系统,在安装的时候设置root账户。不需要设置普通账户。除了存储空间需要点进去后点击完成以外,其他任何设置都不需要碰。


在接下来的步骤之前,你需要先学会下面内容:

vim是命令行下的一种文本编辑器。打开一个文件后,首先进去的模式是命令模式。在该模式下无法进行编辑。

在该模式下,按下i进入编辑模式。进入编辑模式后用键盘上的上下左右挪动光标并进行编辑(不能粘贴)。按下esc返回到命令模式

命令模式下,最底部的区域是命令区,可以输入各种命令。以下是部分需要用到的指令:

按下“/”,会进入查找模式。后面输入想要查找的内容,按下回车后进行查找。按下”n”寻找下一项,“N”则为上一项。

按下i就会进入编辑模式,如上所示。

按下:可以进行文件操作。后面如果跟着w,则代表保存。若为q则代表退出。若强制进行操作则添加感叹号。可以进行组合,例如:w是保存,:wq是保存后退出。

小技巧:新建一个空文件,可以先 vi newfile后直接 :wq


安装完毕后,我们的虚拟机是连不上网的。我们需要添加DNS解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cd /etc/sysconfig/network-scripts/
ls
vi ifcfg-ens33

# -----------vim.start-------------
#在命令模式下按i进入编辑模式
#把ONBOOT的no改成yes
#然后在文件末尾加上两行:
DNS1=8.8.8.8
DNS2=4.2.2.2
#按下esc,返回到命令模式
#输入:eq保存
# -----------vim.end---------------
#重启网卡
systemctl restart network

测试一下是否能连上网:

1
ping baidu.com

ping通后就需要配置一下yum。因为centos7已经EOL,所以我们需要自己配置yum。

1
2
curl -O http://mirrors.aliyun.com/epel/7/x86_64/Packages/c/cloud-utils-growpart-0.31-4.el7.noarch.rpm
sudo rpm -ivh cloud-utils-growpart-0.31-4.el7.noarch.rpm

大写的O不要小写。小写的也不要大写

接下来为了方便我们操作,我们需要给自己安装一个桌面。

1
2
3
yum groupinstall "GNOME Desktop" "Graphical Administration Tools"
systemctl set-default graphical.target
reboot

重启后选择一个登陆账号,就可以用桌面进行操作了。

3

解压内核

首先打开自带的Firefox,前往:http://cdn.kernel.org/pub/linux/kernel/v4.x/ 找一个内核版本进行下载。我选择linux-4.20.4.tar.xz

4

下载的应该是.tar.xz,我第一次下载错了重新安装的时候没截图。

1
2
3
4
su
cp -r '/home/billma007/linux-4.20.2.tar.xz' /usr/src/kernels

tar xvJf linux-4.20.2.tar.xz -C /usr/src/kernels/

第二行中,'/home/billma007/linux-4.20.2.tar.xz'是下载下来的位置。小技巧:直接把文件拖进到命令行中,就可以直接把他的路径复制到命令行中。最后面的文件夹不需要改。

配置编译环境

搭建编译环境:

1
2
3
4
yum -y install bison flex
yum install gcc g++ gdb make devtoolset-7-gcc* centos-release-scl ncurses-devel
yum install elfutils-libelf-devel
yum install openssl-devel

然后把内核配置文件复制过来

1
2
cd /usr/src/kernels/linux-4.20.2/
sudo cp /boot/config-3.10.0-1160.el7.x86_64 ./.config

第二行的那个config文件不一定是这个。反正是长得像的就行。注意我的空格

基本工作已经做好了。现在开始第一次编译:

1
make menuconfig

选择save后exit

5

然后开始编译:

1
make j5

前面设置了几个CPU就改成多少。我前面拨了5个,这边就用5个核心编译来获取最大效率。8个cpu就是j8,1个就是j1,以此类推。

编译完毕的截图我忘记截了。反正如果你看到很整齐的输出没有单独一段一段的文字就是编译成功了。

编译完毕后确认没问题就可以开始添加一个系统调用。

添加函数调用

在linux-4.20.4文件夹中打开终端,添加一个调用函数的声明:

1
2
3
4
5
6
vim include/linux/syscalls.h
#这边按i进入编辑模式
#找到 #endif ,并在这一行之前输入 :
asmlinkage long sys_time(int num);
# esc返回
# 输入:wq保存并退出

7

随后编辑调用函数定义

1
2
su
vim kernel/sys.c

我添加的调用函数功能是:在不调用C语言中time()的情况下直接从linux系统中获取时间戳并上报到系统日志。

在末尾#endif后加上这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
SYSCALL_DEFINE1(time, int, num)
{
struct timespec64 ts;
ktime_get_real_ts64(&ts);

printk(KERN_INFO,
"Current time: %lld seconds, %ld nanoseconds (num=%d)\n",
(long long)ts.tv_sec,
ts.tv_nsec,
num);

return 0;
}

8

然后添加调用索引:

1
2
su
vim arch/x86/entry/syscalls/syscall_64.tbl

拉到整个文件最后,对照上面添加系统调用号,方便我们后期调用。最好按照顺序添加调用号。后面的数据不变。

9

保存后需要清除之前的编译配置,然后再次编译。

1
2
3
4
su
make mrproper
make menuconfig
make -j5

编译完成后需要将内核安装到系统中。

1
2
sudo make modules_install 
sudo make install

随后重启,再重启界面选择我们刚刚编译的linux 4.20.4,课程设计完毕。

10

4.验证实验

接下来我们验证是否可以调用我们刚刚编写的调用函数。

在桌面上创建文件1/test.c,并写一个需要调应这个函数的c语言程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#define __NR_time 548

int main(void)
{
int num = 5;
long ret = syscall(__NR_time, num);
if (ret < 0) {
perror("syscall failed");
return 1;
}
printf("syscall returned %ld\n", ret);
return 0;
}

随后编译:

1
2
3
su
gcc test.c -o test
./test

发现返回值为0,表示调用函数被成功运行。

随后查看日志:

1
dmesg | tail

发现时间戳被成功写入到日志中。

11

为了验证我们只在这个内核安装,我们返回到原本的那个Linux核心,发现程序没有检测到这个调用函数。这表明了我们确实只在新编译的内核中插入了这个函数。

12

评论