Lab 6:Linux系统调用
这个实验的目的是学会配置和编译移植到ARM上的Linux内核,深入理解Linux系统调用,比较 ARM和x86系统调用的不同。
嵌入式Linux
以下为自备(可选)器材:
使用交叉编译工具或本机编译工具,通过Linux内核源码进行实验:
1. 寻找、下载Linux实验板卡所用的Linux内核源码;
本次实验从github上下载了linux-rpi-3.6.y源码。解压后文件夹大致内容如下:
2. 在内核中加入新的系统调用,具体功能没有要求,能输出调试信息即可;
首先在arch/arm/kernel中新建一个sys_mysyscall.c文件,编写系统调用函数实体,用于在后面输出内容来调试。
同时,需要在makefile文件里面加上编译出的.o文件,用于之后的编译内核。
之后需要修改中断向量表。即修改arch/arm/kernel/calls.S文件。参考以前做过的操作系统实验课程,223号调用没有被使用。于是考虑这次实验也修改223调用。修改为如下:
之后在include/uapi/asm-generic/unistd.h头文件中把之前的系统调用与宏联系在一起:
之后就可以编译了。
3. 修改内核代码配置,编译内核;
修改config文件,使用现在树莓派上的config文件即可编译。可以使用zcat命令查看/proc/config.gz的内容。
使用重定向修改了config文件。之后就可以进行编译了。
接着使用已有配制配制内核就可以了。
之后如同之前的操作系统实验上的,使用make和make module_install:
一开始选择现在PC上编译,发现编译出来还得放到树莓派上。后来嫌麻烦就直接在树莓派上编译了,虽然速度很慢。
4. 将编译好的内核装载到板卡启动;
使用新的内核之前,需要备份更新一下内核和固件,当然还需要先备份一下。
然后更新固件和内核:
之后就可以reboot重启进入新的内核了。
5. 编写C代码,用两种方法做系统调用,测试:
a. 嵌入汇编代码,用r0传参数;
b. 用syscall()函数。
使用系统调用函数syscall()的方法如下:
嵌入式汇编代码如下:
汇编函数首先保存之前的寄存器值,之后写入r0寄存器为223,之后使用bl调用syscall,最后重回现场即可。
上述两者方法都可以正确进行。运行编译结果./a.out,可以看到输出内容,使用dmesg | tail命令查看:
可以看到都正确输出了结果。
6. 编写内核模块,在模块加载和卸载时能通过内核打印函数输出提示信息;
编写内核模块,可以参考以前的操作糸统的实验:
#include <linux/init.h> |
#include <linux/kernel.h> |
#include <linux/module.h> |
MODULE_LICENSE("GPL"); |
tatic int __init reverse_init(void) |
{ |
printk(KERN_INFO "Hi!\n"); |
return 0; |
} |
static void __exit reverse_exit(void) |
{ |
printk(KERN_INFO "Bye!\n"); |
} |
module_init(reverse_init); |
module_exit(reverse_exit); |
该模块可以在装载时输出“Hi!”,在卸载时可以输出“Bye!”。由于直接在树莓派上编译出现了问题,最后选择在PC上使用交叉编译的方法,编译出.ko文件,然后拷贝到树莓派上使用insmod和lsmod测试即可。因此需要在PC上重新编写makefile:
obj-m := mykernel.o |
KERNEL_VER := 3.6.y |
KERNEL_DIR := /media/turtle/g1t15346-h4h8-4h64-4g56-45269hfbne1/lib/modules/$(KERNEL_VER)/build |
PWD := $(shell pwd) |
ARGS := ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- |
all: |
make -C $(KERNEL_DIR) SUBDIRS=$(PWD) $(ARGS) modules |
clean: |
rm *.o *.ko *.mod.c |
.PHONY:clean |
之后使用make编译出ko文件拷贝到树莓派上即可。
7. 通过insmod和lsmod等命令测试内核模块。
使用insmod和lsmod来测试模块是否安装成功:
然后可以在日志里查看安装模块时是否有输出(使用dmesg | tail命令):
可以看到使用insmod和rmmod之后正确在日志里输出了正确结果。