OS实验一

实验内容:
1.     在Linux/OpenEuler/OpenKylin系统中,增加一个系统调用/或内核模块,鼓励程序逻辑的多样化

2.     撰写一个应用测试程序调用该系统调用/测试该内核模块

3.     使用trace/ptrace/strace,或类似的系统跟踪工具来对该测试程序进行跟踪调试

4.     附加:在指定的国产OS上,安装一个KVM,或Xen,再装一个guestOS,体会一下,或学习使用容器。

任务4交由队友完成

在Linux系统中增加一个系统调用

参考资料:
《操作系统概念》原书第9版
给 Linux 内核添加自己定义的系统调用 - 知乎
操作系统作业:给linux系统增加一个系统调用_为linux内核增加系统调用systest( )-CSDN博客

系统调用是操作系统提供给应用程序的接口,是由操作系统开发者定义在内核之中。所以我们可以自己编译内核并且注册自己的系统调用

添加系统调用需要在内核源码中操作,所以需要先下载一份内核源码,然后注册好系统调用之后把自己修改好的内核加载到系统中。


PS:由于我的虚拟机性能非常拉跨,平时对Linux的使用主要是wsl而非VMVare,所以这次使用也遇到并解决了一些使用过程中的问题
VMVare联网问题
VMware使用时无法连接网络的问题 - sunny-JJ - 博客园

鼠标消失解决方法
QA:ubuntu22.04.4桌面版虚拟机鼠标丢失的解决方法_虚拟机鼠标不见了怎么办-CSDN博客

在VMVare中使用主机VPN
VMware Ubuntu虚拟 机 使用主机VPN 配置(简单、可行)-CSDN博客


第1步 下载一份内核源码

切换到root用户
查看内核版本

可见,
我采用的系统是Ubuntu22.04.1
内核版本是6.5.0-14-generic
体系结构为x86_64


安装vim(编辑器)

1
sudo apt-get install vim

查看当前的内核版本

1
uname -r


下载Linux内核

移动文件

1
sudo mv linux-6.5.tar.xz /usr/src/

解压缩

1
tar -xvf linux-6.5.tar.xz

解压缩完成

好了,已经成功一半哩()


第2步 注册系统调用号

在Linux中,每个系统调用都被赋予了一个系统调用号。这样,通过这个独一无二的号就可以关联系统调用!
内核记录了所有已注册过的系统调用号,存储在sys_call_table
所以,我们首先要注册一个系统调用号:在系统调用表中填入对应的信息

x86_64体系结构中,这个表在arch/x86/entry/syscalls/syscall_64.tbl中定义

系统调用表的每一项的组成:

1
2
3
<number> <abi> <name> <entry point>

系统调用号 ABI 系统调用名字 系统调用在内核的接口函数

注:要用sudo才有修改权限

syscall_64.tbl中添加如下:

OK了,现在下一步


第3步 声明系统调用函数原型

1
2
cd /usr/src/linux-6.5/arch/x86/include/asm/
sudo vim syscalls.h

添加:

1
asmlinkage long sys_hello_system(void);


第4步 添加系统调用函数的定义

1
2
cd /usr/src/linux-6.5/kernel
sudo vim sys.c

在末尾加入函数声明:(不要有中文字符)

1
2
3
4
SYSCALL_DEFINE0(hello_system){
    printk("Hello,system! Hello world!");
    return 1;
}


第5步 编译并安装此内核

在此之前,需要先安装一些工具:

1
2
sudo apt-get install build-essential libncurses5-dev
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison dwarves

前往linux-6-5目录:

1
cd /usr/src/linux-6.5

清理配置文件、编译残留

1
sudo make mrproper

配置内核

1
sudo make clean
1
sudo make menuconfig




要做的事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 禁用模块签名验证
sudo sed -i 's/CONFIG_MODULE_SIG=y/CONFIG_MODULE_SIG=n/' .config

# 清空证书路径
sudo sed -i 's/CONFIG_SYSTEM_TRUSTED_KEYS=.*/CONFIG_SYSTEM_TRUSTED_KEYS=""/' .config

# 禁用吊销列表功能
sudo sed -i 's/CONFIG_SYSTEM_REVOCATION_KEYS=.*/CONFIG_SYSTEM_REVOCATION_KEYS=""/' .config

# 可选:禁用模块签名吊销检查
sudo sed -i 's/CONFIG_MODULE_SIG_ALL=y/CONFIG_MODULE_SIG_ALL=n/' .config

# 重新编译
sudo make clean

编译内核

1
2
sudo make ARCH=x86_64 bzImage -j4
sudo make ARCH=x86_64 modules -j4

安装内核模块

1
sudo make ARCH=x86_64 modules_install

安装内核

1
sudo make ARCH=x86_64 install

重启系统

1
sudo reboot

重启后换核

验证新内核


UUID问题

查看根分区的UUID

1
sudo blkid
1
2
/dev/sda3: UUID="ae8373b2-5980-4cca-a4f3-bb7630f25b9a" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="c33c455f-21b4-4fff-a7c2-2cff5b5e4e1c"

mount命令确认挂载情况

1
mount | grep " on / "

拿到正确的根分区UUID

检查并修改/etc/fstab

1
sudo vim /etc/fstab

列出所有已安装的内核映像及其版本号

1
dpkg --list | grep linux-image

列出所有已安装的内核版本

1
ls /boot/vmlinuz*
1
sudo update-initramfs -c -k 6.5.0NewKernel
1
2
3
sudo update-grub

sudo reboot

编写测试程序调用系统调用

找一个目录编写测试程序:

testSyscall.c

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

int main(void)
{
long res = 0;
res = syscall(548);
printf("The syscall returned %ld\n", res);
if(res == 1)
{
printf("A successful system call!\n");
}
return 0;
}

运行结果:


对测试程序跟踪调试

1
strace testSyscall
1
strace -e hello_system testSyscall

[!tip] 心得体会:
本次OS实验的编程并不复杂,困难的地方在于对于初次接触系统内核的我们来说,整个下载、编写、配置、编译、安装的过程非常繁琐,其中配置、编译、安装过程有着许多细节,很容易有报错,需要的是能耐着性子把它们一一解决,通过对操作系统内核源码的手动编写和编译安装,我对操作系统的内核和系统调用的认识从陌生变得熟悉,更加深刻得了解了操作系统的工作原理。


OS实验一
http://example.com/2025/03/01/OS实验一/
作者
yvyvSunlight
发布于
2025年3月1日
许可协议