原文:https://zhuanlan.zhihu.com/p/594235031 目录 收起 0 背景 1 宿主机与qemu虚拟机互传文件 2 编写ko demo,做内核测试 推荐阅读
0 背景
当搭建好qemu调试arm64 linux内核的环境(详见同事的文章VSCode+GDB+Qemu调试ARM64 linux内核)后,还有个需求亟待解决,就是宿主机与虚拟机之间互传文件。因为会想写简单的demo,测试代码行为。比如写简单驱动,在宿主机交叉编译,到虚拟机insmod执行。 本文记录该需求实现过程,以及踩过的坑。
linux内核tag :v5.4-rc8
宿主机: WSL Ubuntu20.04
1 宿主机与qemu虚拟机互传文件
搜索了一波发现基本有3类方法:
(1)通过网络。这要求qemu虚拟机配置了网卡。
(2)通过9p VirtFS协议。qemu虚拟机内核需要打开以下配置项
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_9P_FS=y
(3)挂载伪设备。通过回环设备loop device实现。
因为方案(3)最方便,因此首先尝试的是该方案,参考该文章在qemu环境下,实现宿主机和虚拟机之间的数据传输。但由于WSL不支持loop设备挂载,参考该文章wsl下mount -o loop是出现的权限问题,因此放弃。
接下来尝试方案(2),最终该方案走通。
1> 保证qemu虚拟机内核打开了以下配置项:
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_9P_FS=y
2> 如果qemu arm64环境搭建参考的是VSCode+GDB+Qemu调试ARM64 linux内核,需要去掉根文件系统 /etc/fstab中的9p挂载,即 kmod_mount /mnt 9p trans=virtio 0 0 , 记得修改完根文件系统的内容后,需要重新编译根文件系统。
3> qemu启动命令行中增加以下内容 -fsdev local,security_model=passthrough,id=fsdev0,path=/home/haonan/workspace/kernel_study/linux_old1/kmodules -device virtio-9p-device,id=fs0,fsdev=fsdev0,mount_tag=hostshare 其中有几点需要解释:path=后的路径名即为待与虚拟机共享的文件路径,请自行指定;-device后不使用virtio-9p-pci,而是virtio-9p-device,这里感谢文章qemu模拟器错误9pnet_virtio: no channels available for device 我的完整qemu启动命令如下:
qemu-system-aarch64 -m 512M -smp 4 -cpu cortex-a57 -machine virt -kernel arch/arm64/boot/Image -append "rdinit=/linuxrc nokaslr console=ttyAMA0 loglevel=8" -nographic -s -fsdev local,security_model=passthrough,id=fsdev0,path=/home/haonan/workspace/kernel_study/linux_old1/kmodules -device virtio-9p-device,id=fs0,fsdev=fsdev0,mount_tag=hostshare
4>进入虚拟机后,执行以下命令:
mkdir /mnt/host_files
mount -t 9p -o trans=virtio,version=9p2000.L hostshare /mnt/host_files
此时虚拟机中的/mnt/host_files路径中的内容,即与主机的/home/haonan/workspace/kernel_study/linux_old1/kmodules内容一致了。
2 编写ko demo,做内核测试
这部分内容可能写出来的价值不大,不过还是有两个坑值得分享。源文件和makefile文件如下:
//test.c文件
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/io.h> //含有iomap函数iounmap函数
#include <asm/uaccess.h> //含有copy_from_user函数
#include <linux/device.h> //含有类相关的处理函数
int init_hello_module(void)
{
printk("***************Start***************\n");
printk("Hello World Init! \n");
return 0;
}
void exit_hello_module(void)
{
printk("***************End***************\n");
printk("Hello World Exit! \n");
}
module_init(init_hello_module);
module_exit(exit_hello_module);
MODULE_LICENSE("Dual BSD/GPL");//一般放到最后
#Makefile文件
CROSS_COMPILE:= aarch64-linux-gnu-
ARCH:= arm64
CC:= $(CROSS_COMPILE)gcc
LD:= $(CROSS_COMPILE)ld
obj-m := test.o
KERNELDIR = /home/haonan/workspace/kernel_study/linux_old1
PWD := $(shell pwd)
modules:
$(MAKE) ARCH=$(ARCH) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) ARCH=$(ARCH) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -f *.o
rm -f *.symvers
rm -f *.order
rm -f *.ko
rm -f *.mod.c
makefile文件要做点说明,KERNELDIR宏需要根据本地的实际情况,指定到qemu执行的内核源码的路径;()行中一定要加入(MAKE)行中一定要加入ARCH=(MAKE)行中一定要加入ARCH=(ARCH),否则非交叉编译,会遇到奇怪的问题。
make modules编译成功后,将ko文件放到共享文件夹内,在虚拟机内执行:
insmod test.ko
会看到这样的报错:
因为该ko不是和内核一起编译出来的,因此过不了kernel的magic number检查。为了本地调试的方便,可调整内核文件如下:
重新编译内核后,insmod成功结果如下:
推荐阅读
1.qemu 支持 host 和 guest 中共享目录
2.qemu模拟器错误9pnet_virtio: no channels available for device
3.qemu-kvm虚拟机与宿主机之间简单文件传输方法