2.掌握系统调用的实现过程,通过编译内核方法,增加一个新的系统调用。另编写一个应用程序,调用新增加的系统调用。实现的功能是:文件拷贝;
实验环境:
-
从阿里云开源镜像站下载镜像ubuntu-18.04.6-desktop-amd64.iso,根据虚拟机安装步骤安装好Linux-5.4.0版本的Linux系统,(注:千万不要更新至ubuntu-20.04版本,不然版本高很多函数不一样);
-
从清华大学开源软件镜像站下载linux-5.4.180.tar.xz压缩包至安装好的Linux系统里的桌面上;
-
安装好编译所依赖的软件:
sudo apt-get insatll git fakeroot build-essential ncurses-dev bc flex libelf-dev bison gcc make libcurses-dev libssl-dev
。
具体操作:
-
在桌面上打开终端,使用命令
sudo su
输入密码进入root权限,使用命令tar -zxvf linux-5.4.180.tar.xz
解压得到linux-5.4.180文件夹,然后使用命令mv linux-5.4.180 /usr/src
将其移入/usr/src文件夹中,使用命令cd /usr/src/linux-5.4.180
进入linux-5.4.180文件夹中; -
先不要添加任何功能,使用命令
make mrproper
指令清除旧目标文件和配置,然后使用指令cp /boot/config-$(uname -r) .config
拷贝当前linux系统中的内核配置文件,使用指令make localmodconfig
简化内核的配置,此时使用指令gedit .config
对.config文件进行修改(此处极大可能在后面make -j4时出现如下图所示错误,如果出错再返回这步,将CONFIG_SYSTEM_TRUSTED_KEYS="=“debian/canonical-certs.pem”“改为CONFIG_SYSTEM_TRUSTED_KEYS=”"); -
现在开始上面的指令不需要用了(就算修改了kernel/sys.c文件也只要从这里的指令开始),此时使用指令
make -j4
进行编译(我的是四核,2*2,也可以直接make,不过会很慢),第一次需要等待一个小时以上,去玩吧,编译完成使用指令make modules_install
对模块进行安装,安装完使用指令make install
进行安装,完成后重启虚拟机即可; -
重新登录后可以使用指令
uname -r
查看内核版本,会发现已经变成linux-5.4.180了,现在可以增加新的系统调用了; -
指令
sudo su
切换权限,指令cd /usr/src/linux-5.4.180
切换目录,指令gedit kernel/sys.c
添加新的服务例程(此linux版本不使用asmlinkage,转而使用SYSCALL_DEFINEn,例如老版本可能是asmlinkage int sys_mycopy(const char* s_file, const char* t_file)
,而新版本是SYSCALL_DEFINE2(mycopy, const char __user*, s_file, const char __user*, t_file)
),保存退出; -
指令
gedit include/uapi/asm-generic/unistd.h
增加新的系统调用号,例如我的是#define __NR_mycopy 436 __SYSCALL(__NR_mycopy, sys_mycopy)
保存退出; -
指令
gedit arch/x86/entry/syscalls/syscall_64.tbl
修改系统调用表,例如我的是436 64 mycopy __x64_sys_mycopy
,保存退出; -
指令
gedit include/linux/syscalls.h
声明系统调用函数(可以在打开的文件中ctrl f 搜索kernel/sys.c,然后在其下面的第一行声明,例如我的是asmlinkage long sys_mycopy(const char __user* s_file, const char __user* t_file)
),保存退出。 -
此时就可以进行第三步类似的操作了,分别
make -j4
、make modules_install
、make install
、reboot
。
3.掌握增加设备驱动程序的方法。通过模块方法,增加一个新的设备驱动程序,其功能可以简单。实现字符设备的驱动,演示简单字符键盘缓冲区或一个内核单缓冲区。
具体操作:
- 打开终端,指令
sudo su
切换权限,指令cd /dev
切换目录,指令mkdir device
在/dev下新创个device文件夹,然后指令touch device.c
生成文件device.c,然后使用指令chmod +777 device.c
将device.c文件权限修改成可直接修改(这种方法可以直接打开device.c文件进行修改保存再编译); - 然后使用指令
touch Makefile
生成Makefile文件(第一个M大写),然后指令chmod +777 Makefile
修改其权限,设置Makefile文件为ifneq ($(KERNELRELEASE),) obj-m := device.o else PWD := $(shell pwd) KDIR := /lib/modules/$(shell uname -r)/build modules: $(MAKE) -C $(KDIR) M=$(PWD) modules clean: $(MAKE) -C $(KDIR) M = $(PWD) clean endif
- 指令
make
编译,然后会发现device文件夹中多了许多文件,此时可以指令insmod device.ko
插入模块,指令lsmod
查看存在的模块,指令dmesg
配合printk进行调试,指令rmmod device
可以删除device模块,指令cat /proc/devices
可以查看字符设备的id以便设置新添加的字符设备的id。
注:实验二中发现Linux-5.4.180内sys_open、sys_close、sys_read、sys_write函数变成了ksys_open、ksys_close、ksys_read、ksys_write,而更高版本例如Linux-5.10版本只有后面三个函数而没有open类的函数,就会导致很难改,所以不要下载过高版本。