原标题:Linux操作系统原理实验 - 实验报告
补档时间:2020-02-12 19:04:35
因为原稿时间久远,相关的图片素材可能已经遗失。
实验一: 安装Arch Linux并配置图形界面
一、实验描述
在虚拟机上安装可以日常使用的Arch Linux,并为之配置图形界面。
二、实验设计
安装前准备:
启动Hyper-V虚拟机、下载Arch引导镜像、创建虚拟机并且从镜像启动安装Arch Linux:
检测网络、分区并挂载、更改镜像源、使用pacman
安装Arch、配置Arch、解挂载并重启安装图形界面:
登录Arch、安装图形界面软件包安装常用软件包:
安装yaourt、安装WMwarm-tools
三、实验原理
pacman
包管理器和Ubuntu不一样,Arch Linux使用的包管理程序是
pacman
。使用pacman安装一个新的包的命令是:和Ubuntu的1
pacman -S <包名>
apt
一样,pacman也需要更新它的信息。更新pacman的软件包的数据库可以使用以下命令的任意一条:除此之外,pacman还有以下的常用命令:1
2
3pacman -Syy
pacman -Syu
pacman -Sy1
2
3
4
5
6
7
8
9
10
11# 移除软件包
pacman -R <包名>
# 移除软件包以及依赖项
pacman -Rs <包名>
# 查看可用的包R
pacman -Sl | grep <关键词>
# 列出已安装的包
pacman -Q <包名>UEFI模式
对于一台使用了“快速创建”的虚拟机或者物理机,我们首先需要知道它引导启动的模式。在archiso的终端执行命令
efivar -l
,如果输出正确的列出了UEFI变量,则是UEFI模式启动。如果通过UEFI模式,那么需要将分区挂载到/boot/EFI目录,而不是BIOS模式下挂载到/boot目录。
窗口环境的软件包
在配置图形界面过程中安装的众多软件包中,不同的软件包有不同的作用:
- xorg server: 众多窗口环境的软件包的基础
- sddm: 提供了图形化的用户登录界面
- xfce4: 常用的Linux桌面环境
- plasma: 基于KDE的更加美观的桌面环境
安装以上所有的软件包之后,在用户的登陆页面将出现选项框,可以选择进入不同的桌面环境。
四、实验步骤
安装前准备
因为Windows 10 1903 对旧版的VMware Workstation存在兼容性问题,为了方便,所以本次实验采用基于Windows10自带的Hyper-V的虚拟机。Hyper-V功能默认是关闭的。在控制面板中选择“程序或功能->添加/删除Windows功能”中选择启动Hyper-V,随后系统将会下载相关的数据并且重新启动,Hyper-V功能将启用。
进入官网或者镜像站下载Arch Linux的镜像,这里给出浙江大学镜像站的下载地址,进入后选择archlinux-2019.10.01-x86_64.iso
下载即可。将下载的镜像文件作为新建的Hyper-V虚拟机中虚拟光驱引入,完成虚拟机创建。
搜索栏中输入“Hyper-V管理器”,可以打开它。在右侧状态栏中选择新建,手动配置新虚拟机的信息。这次实验我使用的是第一代(基于BIOS)的虚拟机,你也可以使用第二代(基于UEFI)虚拟机,但是具体操作将会与本实验报告描述内容存在出入。使用刚才下载的光盘镜像文件作为虚拟光驱,创建虚拟机并启动。
安装Arch Linux
启动刚刚新建的虚拟机,虚拟机将会自动加载的光驱并且进入引导界面。选择Boot Arch Linux(x86_64)选项启动,进入archiso的tyy控制台界面。此时已经可以使用一些常用的Linux命令操作了,安装过程本身也是使用Linux命令完成的。在控制台中输入ping baidu.com
,可以检测网络状态——如果ping通,则网络连接正常。否则,可能需要退出虚拟机检查Hyper-V的虚拟网卡/交换器的设置,这可以参考Microsoft Docs。
使用cfdisk
命令打开cfdisk为虚拟机进行分区。在这次实验中,我将硬盘划分为四个区域,并将它们分别挂载为不同的目录:
分区名 | 大小 | 文件系统 | 挂载目录 |
---|---|---|---|
/dev/sda1 | 32GB | ext4 | /mnt |
/dev/sda2 | 1G | vfat | /mnt/boot |
/dev/sda3 | 4G | .. | SWAP分区 |
/dev/sda4 | 余下所有空间 | ext4 | /mnt/home |
在cfdisk中,上下方向键对存储块进行选择,左右键对命令选择,回车键开始操作。完成分区操作之后要执行[Write]命令保存分区信息后方可退出。可以使用lsblk
命令展示分区的状态。完成分区之后,需要对分区进行挂载。挂载的命令如下:
1 | mkfs.ext4 /dev/sda1 |
genfstab -U /mnt >> /mnt/etc/fstab
生成文件系统信息。这一步是必要的,因为生成的文件系统信息会被用来在后面的步骤生成启动引导文件。Arch的安装是使用pacman
安装的,他需要接收一些必要的数据才可以安装。而国内直接连接Arch官网的速度是非常的不理想的,所以需要更换镜像站,使用国内的镜像站下载必要的文件。首先,可以在控制台中输入vi /etc/pacman.d/mirrorlist
以使用vim打开pacman的镜像文件,然后在文件开头加入你喜欢的镜像站,比如:
1 | Server = http://mirrors.163.com/archlinux/$repo/os/$arch |
pacman -Syy
更新镜像源,就完成了镜像源的替换。在终端执行pacstrap -i /mnt base base-devel linux linux-firmware
命令,使用缺省的默认设置(一路回车)就可以安装Arch了。特别注意的是,因为新版的Arch基本包已经不再包含Linux内核了,所以安装过程中一定要安装linux和linux-firmware两个包。否则之后创建引导的时候会因为找不到系统而安装失败。
此时,Arch Linux已经安装到了虚拟机的硬盘中,为了配置刚安装的Arch Linux,我们需要从光盘的终端中切换到安装好的系统的终端中去。实现这件事的命令是arch-chroot /mnt /bin/bash
。archiso-tyy执行这个命令之后的行首会发生变化,很容易观察到。在新的系统的终端中,我们可以: + 配置语言区域
使用vi etc/locale.gen
打开文件,删除en_US.UTF-8
前的#号,保存之后在终端运行locale-gen
.
配置时区
1
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
安装grub并生成引导文件
1
2
3pacman -S grub
grub-install --force /dev/sda
grub-mkconfig -o /boot/grub/grub.cfg安装dhcpcd并配置网络
对于有线网络,因为Base包里已经不包括联网所需的程序,所以需要下载dhcp客户端之后才能启动服务。1
2pacman -S dhcpcd
systemctl enable dhcpcd.service设置主机名
1
echo shiohalinux > /etc/hostname
将主机名增加到
/etc/hosts
使用vim打开这个文件,将主机名添加到这个文件的后面,大概就像这样1
2
3127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
127.0.1.1 shirohalinux.localdomain shirohalinux设置root的密码
终端中输入passwd
命令后输入两次要创建的密码就可以了。创建登录用户并给予它sudo权限
终端中输入useradd -m -G wheel -s /bin/bash shiroha
就可以创建名为shiroha的用户。这里的命令最重要的是-G:它指定了用户要加入的附加组列表;现在我们将用户加到wheel组中,之后可以在接下来的操作中给予这个组执行sudo命令的权限,可以方便使用。(当然,你也可以在新用户中使用)使用su - root
切换到root用户执行sudo命令passwd shiroha
命令可以为新用户shiroha创建密码。可以通过修改/etc/sudoers
文件为普通用户提权,但是一般使用命令visudo
修改。使用该命令打开sudoers之后,删除wheel组前的#就可以了。特别说明:在使用visudo
之前,请确保系统中已经安装了vim。
完成了对新系统的配置之后,就可以退出光驱启动而直接从硬盘启动Arch Linux了。先在当前的终端中执行exit
退回tyy终端,再使用umount -R /mnt
解挂载光驱,并执行reboot
命令重启。特别说明:因为Hyper-V的解挂载并不能弹出虚拟光驱,所以不需要执行解挂载的过程,使用shutdown
关机之后再虚拟机管理页面弹出光驱,再手动启动虚拟机就可以了。
安装图形界面
如果安装Arch Linux成功完成,那么可通过控制台登录到Arch。首先可以使用root登录到Arch,输入用户名root和正确的密码即可。
图形界面是Arch Linux中额外的软件包提供的功能。所以安装图形界面就是安装和这个图形界面相关的软件包就可以了。与这个相关的软件包主要包括xorg
,sddm
,xfce4
,plasma
,ifconfig
.当然,这一步骤还会包括安装一些使用软件。
安装脚本:
所有的软件包都是使用1
2
3
4
5
6
7
8pacman -S xorg
pacman -S xterm
pacman -S xorg-xinit
pacman -S sddm
pacman -S xfce4
pacman -S xfce4-goodies
pacman -S plasma
pacman -S kde-applicationspacman
命令安装,特别要注意的是plasma安装前必须要确保xorg已经安装到虚拟机中;此外,因为plasma桌面环境是基于KDE桌面环境的,所以需要安装kde环境常用的软件包。配置脚本:
这步主要是配置sddm:首先生成ssdm的配置文件,随后将ssdm服务增加开机启动项。ssdm主要提供了用户登录界面。1
2sddm --example-config > /etc/sddm.conf
systemctl enable sddm.service
ssdm的登陆只能使用普通用户登录。这意味着如果你在之前的步骤没有增加一个普通用户,那么你需要使用useradd
命令为电脑增加一个用户,并使用passwd
为其设置密码。
安装常用软件包
需要安装的一些常用软件包,主要是ifconfig
,ssh
,zsh
,git
以及wget
.安装这些所有的软件包的脚本如下:
1 | pacman -S net-tools dnsutils inetutils iproute2 |
/etc/pacman.conf
文件末尾处增加镜像源:1 | [archlinuxcn] |
1 | pacman -Sy |
比如安装Chrome可以使用命令
yaourt google-chrome
。如果使用的虚拟机是VMWare而不是Hyper-V,可以为Arch安装vmware提供的VMwarm-tools。安装过程如下:
1 | # 通过虚拟机软件挂载VMwarm-tools |
五、实验结果
安装Linux:重新启动后,虚拟机画面上出现了grub的加载界面,其中的首选项是+Arch Linux。选择该项启动后,进入了Arch Linux的登陆终端而不是archiso的tyy终端,输入设置的用户以及对应的密码可以进入终端,安装完成。
安装图形界面:此步完成后,启动虚拟机,待看到了服务启动的终端输出之后,将会看到sddm提供的用户登陆界面。输入正确的用户密码后会看到plasma桌面环境的加载画面,随后进入plasma桌面环境。
实验二: 编译并安装Linux内核
一、实验描述
在实验一中安装的Arch Linux虚拟机中编译一个从Arch官方网站上下载的内核,并且将这个内核安装到虚拟机中。
二、实验设计
下载、编译、安装
进入官网下载内核、编译内核、安装内核模块、将编译的模块复制到/boot目录制作初始化内存盘
制作初始化内存盘、复制System.map更新引导程序
更新grub配置、重启验证结果
三、实验原理
编译内核的
menuconfig
编译内核需要一个配置文件,而获得这个配置文件有很多种方法。其中一种方法是通过
make menuconfig
命令进入一个图形化的配置页面进行对内核的自定义配置,然后生成对应的.config文件。接下来简要的介绍一下键入这个命令后系统的执行的流程:首先,这个过程涉及到了以下的文件:
Linux内核根目录下的
/scripts
文件夹
arch/$ARCH/Kconfig
文件、各层目录下的Kconfig
文件
Linux内核根目录下的makefile
文件、各层目录下的makefile
文件
Linux内核根目录下的的.config
文件、arm/$ARCH/.config
文件
Linux内核根目录下的include/generated/autoconf.h
文件首先系统读取
arch/$ARCH/Kconfig
文件,使用/scripts下的绘制图形相关的文件生成图形化的config界面。环境变量$ARCH
是定义在根目录的makefile文件中的。arch/$ARCH/configs
目录下存储了默认的配置。内核会默认读取根目录下的.config
文件作为默认配置。但是为了和内核完全匹配,往往需要对这个文件进行修改。在图形化的配置界面调整了不同的选项之后,最后保存退出时Linux内核会把新的选项新到.config中。此时将.config重命名为其它文件保存起来(当执行
make distclean
时系统会把.config文件删除)就可以在需要的时候还原这个配置了。make
命令当
make
命令被执行时,它会扫描当前目录下makefile文件找到目标以及其依赖。如果这些依赖自身也是目标,继续为这些依赖扫描Makefile文件并且建立其依赖关系,然后编译它们。一旦主依赖编译之后,然后就编译主目标。如果之后某个源文件发生了修改,再次执行make
命令,它将只编译与该源文件相关的目标文件。make
指令的命令参量: >-f:指定“makefile”文件; >-i:忽略命令执行返回的出错信息; >-s:沉默模式,在执行之前不输出相应的命令行信息; >-r:禁止使用build-in规则; >-n:非执行模式,输出所有执行命令,但并不执行; >-t:更新目标文件; >-q:make操作将根据目标文件是否已经更新返回"0"或非"0"的状态信息; >-p:输出所有宏定义和目标文件描述; >-d:Debug模式,输出有关文件和检测时间的详细信息。 >-C dir:在读取makefile 之前改变到指定的目录dir; >-I dir:当包含其他makefile文件时,利用该选项指定搜索目录; >-h:help文挡,显示所有的make选项; >-w:在处理makefile之前和之后,都显示工作目录。 >-j:指定编译的线程数,线程数越大理论越快。make install
是编译后的安装过程,它从makefile中读取信息,并且将软件包安装到指定位置。可以使用configure
生成makefile文件。往往需要sudo
权限来向系统写入数据。有的软件包在安装之前可能需要先运行make check
或make test
来进行一些测试。make clean
命令在编译前会清除之前编译的可执行文件及配置文件。而make distclean
命令则会在编译前删除所有之前的编译生成的文件。使用这两项命令会使得编译过程延长,但是在编译内核的时候可以保证生成的内核树的绝对清洁。
四、实验步骤
安装前准备
在开始之前,我们需要先查看一下虚拟机上的Arch Linux的当前的内核信息。查看内核信息可以通过screenfetch
命令。这个软件包不是Arch Linux的基本包中包含的内容,所以再使用之前需要先安装:
1 | pacman -S screenfetch |
screenfetch
命令查看内核信息了。截图保存以与应用新自定义内核后形成对比。首先,可以访问官网选择想要安装的内核版本进行下载。但是由于国内访问官网速度较慢,也可以通过国内的开源镜像站下载,比如清华大学镜像站。选择需要下载的镜像之后使用wget
命令下载。Arch的基本包是没有wget的,所以如果之前没有安装wget则需要通过pacman
安装。这里我选择了Linux 5.3版本的内核,执行的命令如下:
1 | wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/linux-5.3.tar.xz |
下载完成后,使用xz
命令和tar
命令解压下载的内核包。解压后使用cd
命令进入解压得到的目录下。
编译内核
进入目录后就可以开始编译了,编译使用的命令是make
。它有很多的模式可以选择,比如make menuconfig
命令会进入由Kconfig和scripts构建的图形化的配置页面,完成配置后会生成一个.config文件。这里我使用的是缺省配置:
1 | zcat /proc/config.gz > .config |
复制内核配置文件之后,还需要通过修改得到的config文件的CONFIG_LOCALVERSION
的值来修改内核版本,以避免将要编译的内核文件覆盖当前内核文件。
得到了.config文件之后就可以开始编译了。编译的命令是make -j<线程数>
。可以根据虚拟机的配置修改这里线程数的值。因为内核的编译需要一段较长的时间,合理的线程数可以增加编译的速度。我使用的是make -j2
。
安装内核并验证
完成了内核的编译之后就可以开始安装内核了。安装内核主要包括这些步骤:安装内核模块->复制内核文件->制作initramfs镜像->复制System.map->生成新的启动引导。执行的命令脚本如下:
安装内核模块:
这条命令会将编译好的模块安装到主目录/lib/modules下。这样,会使得这些模块独立于虚拟机原有内核的模块。1
sudo make modules_install
复制内核文件:
将内核编译完成生成的bzImage(较大的压缩的内核映像,使用gzip压缩)文件复制到1
2
3
4
5# 对于32位(i686)内核:
sudo cp -v arch/x86/boot/bzImage /boot/vmlinuz-linux53
# 对于64位(x86_64)内核:
sudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-linux53/boot
目录下。制作initramfs(初始内存盘)镜像:
复制并且修改mkinitcpio(一个创建initramfs的脚本)preset就可以通过官方内核一样的方式生成自定义内核的initramfs镜像。复制之后需要使用vim修改这个文件。打开linux53.preset文件之后,修改部分字段使得它与新的自定义内核所匹配。需要修改的字段如下:1
2sudo cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux53.preset
sudo vi /etc/mkinitcpio.d/linux53.preset修改并保存之后执行1
2
3
4
5# /etc/mkinitcpio.d/linux53.preset
ALL_kver="/boot/vmlinuz-linux53"
default_image="/boot/initramfs-linux53.img"
fallback_image="/boot/initramfs-linux53-fallback.img"sudo mkinitcpio -p linux53
就可以使用官方内核生成的方式生成自定义内核的initramfs镜像。复制System.map 如果虚拟机的/boot挂载到的分区的文件系统是
ext4
格式。就需要将解压目录下的System.map文件复制到/boot中,并且创建/boot/System.map,将新建的System.map软链接到复制到其中的System.map中。需要执行的命令如下:但是由于本次使用的虚拟机的boot分区挂载的分区是1
2
3sudo touch /boot/System.map
sudo cp System.map /boot/System.map-MyKernel
sudo ln -sf /boot/System.map-Mykernel /boot/System.mapvfat
文件系统的,无需也不必创建软链接。更新grub引导的配置信息 使用命令
grub-mkconfig -o /boot/grub/grub.cfg
可以生成grub默认的配置信息。它会自动地将刚添加的内核增加到启动配置中。在Ubuntu这种系统中,这个命令被包装成了update-grub
或其他形式。
随后使用reboot
命令重新启动虚拟机,使用screenfetch
命令查看当前的系统信息,就可以看到系统的内核发生了变化。这样内核的编译和安装就完成了。
五、实验结果
实验前和试验后,对Arch Linux虚拟机使用screenfetch
命令获得的内核信息不相同,内核信息变成了安装的内核的版本信息,说明用户的自定义内核已经成功的编译并且安装。
实验三: 为Linux内核增加系统调用
一、实验描述
在实验一的Arch Linux虚拟机的基础上,在Linux内核中增加一个系统调用,并对这个修改生成patch。将这个patch应用到一个Linux内核中,编译并安装这个自定义内核,验证对内核增加的系统调用是否已经成功的应用到操作系统。
二、实验设计
修改内核源码
向内核中增加一个函数、将函数注册为系统调用生成补丁并重新编译内核
使用diff
生成补丁、安装patch补丁、编译并安装内核测试补丁是否成功patch
编写调用自定义系统调用的源文件、执行源文件观察结果
三、实验原理
patch
Patch有两种常用意思: > Patch文件: > > 也就是补丁文件。在Linux社区中,如果某人对某一个版本的Linux源码做出了一定的修改以解决某些问题,并且希望把它分享出去,他就可以为代码生成一个patch文件供社区使用。往往,patch文件的目的是用于修正已知错误或者作为一种调试手段调试代码。一般来说,patch文件可以使用diff
指令比较原有代码和修改过的代码生成。 > > Patch指令 > > 是Linux中的一个指令。可以用于将patch文件的修改应用到一个代码中。并且在此基础上可以提供一些实用的功能:比如消除父目录,检测对象代码是否已经安装过此补丁等。关于patch命令的详细使用方法可以使用man
命令或者求助Google。本次实验需要生成一个自定义的系统调用的patch文件,并且将这个patch文件应用到内核中。生成patch文件可以使用
diff
指令:指令中,kernel/是修改前的内核源码所在的文件夹,kernel_new/目录是修改过的内核源代码所在的文件夹。这条指令将会比较两个内核的源码的差别并且根据对比结果生成"new.patch"文件。1
diff -Naur kernel/ kernel_new/ > new.patch
如果要将这个patch文件应用到一个未修改的内核,可以使用
patch
命令将patch文件中记录的改动应用到内核源码中:首先将patch文件放在将要打补丁的源码目录下,再使用1
2
3cp -v new.patch kernel/
cd kernel
patch -p1 < new.patchpatch
命令就可以了。由于patch文件中记录了基于原代码所在目录的名字(所在目录的绝对地址),可能和当前打补丁的源码所在目录不匹配。比如当向Linux-5.3.x打Linux-5.3的补丁,就需要使用使用-p1参数忽视文件名目录的第一个分量。官方网站也提供了Patch包下载。这些Patch包是用于大版本内的小版本更新的。使用时,只需要将对应的Patch文件patch到对应版本的内核源码文件中,编译安装patch后的内核即可。
系统调用
增加最简单的系统调用主要分为增加新函数->增加新声明->将新调用增加到系统调用注册表三个步骤。增加新的系统调用函数:比如可以向内核缓存区打印一条消息。可以使用
printk
函数实现这个功能。打印到内核缓存区的消息不会直接输出到控制台中,需要使用dmesg -c
命令清除所有缓冲区日志并且查看内核缓存区信息。printk
函数打印的信息将会这里显示。增加系统调用的声明:不同的Linux发行版所需要增加声明的头文件地址不同。大体是在内核文件夹下的include/目录下的unistd.h和syscalls.h文件中。对于Arch Linux,需要修改的头文件的目录是
include/uapi/asm-generic/unistd.h
和include/linux/syscalls.h
。可以在这个文件的对应位置增加在系统源文件(一般是sys.c)中增加的系统调用函数的声明。注册新系统调用:不同的Linux发行版OS的系统调用表所在的位置不同,对于Arch Linux而言,系统调用注册表的位置在
arch/x86/entry/syscalls
目录下。它包含了32位系统和64位系统的注册表,分别是syscall_32.tbl
和syscall_64.tbl
。内核编程相关
dmesg 命令: > >dmesg
命令在设备故障诊断中有重要的用途。它可以用于检测硬件连接或断开的信息,可以查看内核缓存区的信息,可以使用Linux管道规定它的输出范围获得需要的数据:比如搜索和特定硬件相关的消息等。关于这个命令的使用可以参考man
或者Google。以下只介绍基本的一些使用方法。 > >+ 列出所有检测到的硬件: > > 比如要显示所有被内核检测到的硬盘设备,可以使用grep
参量搜索sda
关键词。最后执行的命令是:dmesg | grep sda
。此外,grep
命令参量可以附加-i
选项表示忽略搜索字符串的大小写。 > >+ 输出指定行数的日志: > > 可以通过跟随head
或者tail
命令参量来控制显示的日志范围。比如需要显示前20行日志,可以使用命令dmesg | head -20
。 > >+ 清空dmesg缓冲区日志 > > 可以使用命令dmesg -c
来清空dmesg的日志。该命令会清空dmesg环形缓冲区中的日志。但是依然可以查看存储在‘/var/log/dmesg’文件中的日志。此时连接任何的设备都会产生dmesg日志输出。asmlinkage修饰符: > >
asmlinkage
的定义: > > 位于/usr/include/asm/linkage.h
中,定义内容如下: >>1
>
__attribute__
是关键字,是gcc的C语言扩展,regparm(0)
表示不从寄存器传递参数。如果是__attribute__((regparm(3)))
,那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数。 > >这主要涉及了函数传参的方式是否通过寄存器。asmlinkage
表示这些函数通过堆栈而不是通过寄存器传递参数。gcc编译器在汇编过程中调用C语言函数时传递参数有两种方法:一种是通过堆栈,另一种是通过寄存器。缺省时采用寄存器。 > >一般来说,内核中的函数都是通过asmlinkage
限定使用堆栈传递参数的。我们向内核源文件中增加的系统调用函数也需要使用asmlinkage
修饰。
四、实验步骤
准备工作
将从官网上下载的一个Linux内核源码解压,并将解压得到的文件夹复制一份。一份作为原版源码,对另一份进行修改。这里我使用实验二中使用的Linux内核作为基础。
增加系统调用
进入待修改的内核源码根目录,之后所有的相对路径都建立在内核源代码根目录的基础上。使用vim打开将要增加系统调用的实现的源文件kernel/sys.c
。这里我们要增加的是最简单的系统调用,即在内核缓冲区打印消息,所以在它的末尾增加如下函数:
1 | asmlinkage void sys_shirohashow(void) |
sys_shirohashow
的实现。增加完实现之后,我们还需要为这个函数增加声明。增加声明主要需要修改两个文件。首先使用vim打开include/uapi/asm-generic/unistd.h
,在这个文件的末尾处增加宏:
1 |
|
find syscall_64.tbl
寻找这个文件并使用vi
或者nano
查看确认系统调用编号的使用情况),然后使用没有被占用的系统调用编号。增加宏之后,还需要再使用命令vi include/linux/syscalls.h
打开syscalls头文件,将函数的声明asmlinkage void sys_shirohashow(void);
增加到该头文件中/* kernel/sys.c */
的部分中。
注册系统调用
完成了系统调用的声明和实现后,还需要将系统调用注册到注册表中,才可以使得它可以被正确的系统调用编号调用。系统调用注册表文件储存在arch/x86/entry/syscalls
目录下。32位系统是syscall_32.tbl
,64位系统是syscall_64.tbl
。可以根据需要修改对应的注册表。这里以修改64位注册表为例,将在syscall_64.tbl
的第435号系统调用后增加以下内容:
1 | 765 common shirohashow sys_shirohashow |
生成补丁并patch
完成上述步骤中所有的操作后,就可以生成patch补丁了。可以通过diff
命令对比原内核代码和修改后的内核代码得到补丁文件,执行命令:
1 | diff -Naur ../../linux-5.3/kernel/ kernel/ > new.patch |
可以将生成的patch文件应用到原内核源码中,也可以直接编译修改过的内核源码。(本质上,对原内核源码运行patch
命令打得到的补丁文件变为修改过后的版本)打补丁的命令是:
1 | cp -v new.patch ../../linux-5.3/kernel/new.patch |
make clean && make mrproper
命令,但是这样的编译速度较慢,耗时较多。编译完成之后,可以采用实验二中的步骤(安装内核模块->复制内核文件->制作initramfs镜像->生成新的启动引导)来安装新的内核。安装完成后,重启虚拟机,打过自定义补丁的内核就安装完成了。
验证系统调用
我们对内核的修改是增加了一条系统调用。这个系统调用会在内核缓存目录中打印一条消息。所以验证该系统调用是否被正确应用,只需要编写一个程序调用该系统调用,并观察该系统调用是否正确执行即可。
首先,使用以下命令新建一个C程序源文件并使用vim打开它:
1 | touch myTest.c |
1 |
|
1 | gcc -o myTest myTest.c |
printk
函数是向内核缓冲区打印信息而不是控制台。需要使用dmesg -c
命令输出内核缓冲区的信息,可以检查printk
的输出结果。五、实验结果
在安装了patch过的内核的Arch Linux虚拟机中执行调用新系统调用的C程序,并且使用dmesg -c
命令查看内核缓存区,发现了系统调用使用printk
函数打印的字符串。这说明增加的系统调用成功注册,并且随着编译后的内核成功安装到了虚拟机中。
2020-3-8 更新: 原本的截图可以去这里下载。
附录
疑问和未解决问题
虚拟机分辨率问题
采用了Microsoft Docs中提到的,在grub配置文件中修改分辨率的方法。只对虚拟机运行时的tyy终端界面有效,而无法改变图形环境的分辨率。
虚拟机没有显卡
使用screenfetch
命令查看系统信息的时候发现虚拟机没有显卡。初步判定这是导致无法改变桌面环境的分辨率以及执行OpenGL程序的原因。
patch后内核编译缓慢
使用patch对已经预编译的内核进行打补丁操作之后,使用make
编译时,make将所有的文件重新编译。而这种情况下,make
应当只重新编译被patch修改过的极少部分文件。
参考链接
ArchLinux 安装/配置/美化 - 米V米
arch里没有update-grub这个命令吗 - 百度知道
Hyper-V虚拟机安装Linux后修改Linux的屏幕分辨率 - CSDN
Linux环境下root用户与普通用户切换 - CSDN
Windows 10 hyper-v安装manjaro 18.0.4+Xfce4 后调整分辨率 - CSDN
美轮美奂的Arch, 详解Arch虚拟机安装 - 简书
Arch Linux 安装指南(ArchISO 2014.10) - Ubuntu论坛
defconfig、.config、kconfig与makefile和make menuconfig流程 - CSDN
make oldconfig和make defconfig有何区别 - 百度知道
Linux 内核编译 - CSDN
zimage和bzimage有什么区别 - 博客园
asmlinkage的用法 - CSDN
dmesg七种用法 - 博客园
关于asmlinkage - 博客园
汇编语言的主程序与子程序之间的参数传递方式 - CSDN
Archlinux官方Wiki - mkinitcpio(简体中文)
Dian团队 - 网安组@李勉学长
Installation guide (简体中文) - Arch Wiki