赞
踩
目录
QEMU(QuickEmulator)是一套开源的虚拟机软件,可以模拟多个如x86、arm等处理器架构,用于虚拟化、仿真和调试,非常适合没有开发板而又想研究Linux内核结构和工作模式的人使用,对于嵌入式+Linux的学习十分有帮助
本文也是参考了下方多篇博客,记录下自己在使用QEMU搭建环境时成功的步骤,便于后续的学习和实践
- sudo apt-get install gcc-aarch64-linux-gnu
- sudo apt-get install libncurses5-dev build-essential git bison flex libssl-dev
安装成功后可以查看版本
- user@ubuntu18:/$ aarch64-linux-gnu-gcc -v
- Using built-in specs.
- COLLECT_GCC=aarch64-linux-gnu-gcc
- COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/7/lto-wrapper
- Target: aarch64-linux-gnu
- Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 7.5.0-3ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include
- Thread model: posix
- gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04)
这里我采用的是从源码安装,也可以从ubuntu仓库安装
- wget https://download.qemu.org/qemu-4.2.1.tar.xz
- tar xvJf qemu-4.2.1.tar.xz
- cd qemu-4.2.1
- ./configure
- make -j 8
- sudo make install
安装成功后可以查看版本
- user@ubuntu18:/$ qemu-system-aarch64 --version
- QEMU emulator version 4.2.1
- Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
完成最小的根文件系统,并且可以运行动态编译的应用程序
下载网址:Index of /downloads
tar jxvf busybox-1.36.1.tar.bz2
- cd busybox-1.36.1
- export ARCH=arm64
- export CROSS_COMPILE=aarch64-linux-gnu-
- 1、make menuconfig
- Settings --->
- [*] Build static binary (no shared libs)
- 2、make
- 3、make install
编译完成后,会生成_install目录
- cd _install/
- mkdir dev etc lib sys proc tmp var home root mnt
(1)etc目录更新
a.创建 profile 文件,添加下面内容
- #!/bin/sh
- export HOSTNAME=user
- export USER=root
- export HOME=/home
- export PS1="[$USER@$HOSTNAME \W]\# "
- PATH=/bin:/sbin:/usr/bin:/usr/sbin
- LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
- export PATH LD_LIBRARY_PATH
b.创建 inittab 文件,添加下面内容
- ::sysinit:/etc/init.d/rcS
- ::respawn:-/bin/sh
- ::askfirst:-/bin/sh
- ::ctrlaltdel:/bin/umount -a -r
c. 创建 fstab 文件,添加下面内容,指定挂载的文件系统
- #device mount-point type options dump fsck order
- proc /proc proc defaults 0 0
- tmpfs /tmp tmpfs defaults 0 0
- sysfs /sys sysfs defaults 0 0
- tmpfs /dev tmpfs defaults 0 0
- debugfs /sys/kernel/debug debugfs defaults 0 0
- kmod_mount /mnt 9p trans=virtio 0 0
d.创建init.d目录
- mkdir init.d
- cd init.d
创建 rcS文件,添加下面内容
- mkdir -p /sys
- mkdir -p /tmp
- mkdir -p /proc
- mkdir -p /mnt
- /bin/mount -a
- mkdir -p /dev/pts
- mount -t devpts devpts /dev/pts
- echo /sbin/mdev > /proc/sys/kernel/hotplug
- mdev -s
添加权限
chmod 777 rcS
e.利用tree命令查看etc下目录结构如下所示
- tree
- .
- ├── fstab
- ├── init.d
- │ └── rcS
- ├── inittab
- └── profile
-
- 1 directory, 4 files
(2)dev目录下必要文件
- cd dev
- sudo mknod console c 5 1
(3)lib下必要文件
为了支持动态编译的应用程序的执行,根文件系统需要支持动态库,所以我们添加arm64相关的动态库文件到lib下
- cd lib
- cp /usr/aarch64-linux-gnu/lib/*.so* -a .
下载Linux内核源码,https://www.kernel.org
我这边是linux-6.1.83的,直接点击tarball就能下载
tar xvf linux-6.1.83.tar.xz
- export ARCH=arm64
- export CROSS_COMPILE=aarch64-linux-gnu-
- cd linux-6.1.83
- cp ../../busybox-1.36.1/_install _install_arm64 -a
修改defconfig
- 添加hotplug支持:
- +CONFIG_UEVENT_HELPER=y
- +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
- 添加initramfs的支持:
- +CONFIG_INITRAMFS_SOURCE="_install_arm64"
make defconfig 生成.config
或者不修改defconfig,直接make defconfig,然后make menuconfig 会基于现在的.config以图形化方式去配置,按照下面添加即可
- a.添加hotplug支持
- Device Drivers
- -> Generic Driver Options
- -> Support for uevent helper
- (/sbin/hotplug) path to uevent helper
- b.添加initramfs支持
- General setup --->
- [*]Initial RAM filesystem and RAM disk(initramfs/initrd)
- support(_install_arm64) Initramfs souce file(s)
- c.Virtual address space配置
- Kernel Features --->
- Page size(4KB) --->
- Virtual address space size(48-bit)--->
make all -j8
在内核源码目录下创建目录
mkdir kmodules
在内核源码目录下执行下面的命令
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
- --- machine virt:使用virt机器类型。
- --- cpu cortex-a57:使用Cortex-A57 CPU模型。
- --- -m 1024:设置虚拟机内存大小为1024MB。
- --- -smp 4:设置虚拟机使用4个CPU核心。
- --- -kernel arch/arm64/boot/Image`:指定Linux内核镜像的路径。
- --- --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"`:指定内核启动参数,其中`rdinit`指定init程序的路径,`root`指定根文件系统的设备,`rw`表示以读写模式挂载根文件系统,`console`指定控制台设备,`loglevel`指定内核日志级别。
- --- -nographic`:禁用图形界面,使用纯文本控制台。
- --- --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none`:创建一个本地文件系统设备,其中`id`指定设备ID,`path`指定设备挂载的本地路径,`security_model`指定安全模型。
- --- -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount`:将本地文件系统设备挂载到虚拟机中,其中`fsdev`指定设备ID,`mount_tag`指定设备挂载的标签。
a.如果出现下面的错误,大概率是qemu版本的问题,换个新版本进行测试
qemu-system-aarch64: rom check and register reset failed
b.出现下面报错,加上Config即可
mount: mounting debugfs on /sys/kernel/debug failed: No such file or directory
启动成功后会打印如下内容,点击Enter进入控制台
- [ 0.926519] EXT4-fs (vda): recovery complete
- [ 0.949860] EXT4-fs (vda): mounted filesystem with ordered data mode. Quota mode: none.
- [ 0.951653] VFS: Mounted root (ext4 filesystem) on device 254:0.
- [ 0.961548] devtmpfs: mounted
- [ 1.019640] Freeing unused kernel memory: 12416K
- [ 1.020514] Run /sbin/init as init process
- [ 1.020595] with arguments:
- [ 1.020660] /sbin/init
- [ 1.020721] with environment:
- [ 1.020784] HOME=/
- [ 1.020870] TERM=linux
- Please press Enter to activate this console.
- [root@user ]# ls
- bin etc lib mnt root sys usr
- dev home linuxrc proc sbin tmp var
在内核源码的kmodules目录中echo一个文件
…linux/kmodules$ echo "hello world!" > hello.txt
可以在QEMU的mnt目录下看到
- [root@user mnt]# ls
- hello.txt
- [root@user mnt]# cat hello.txt
- hello world!
(1)应用测试
- 1、编写程序
- #include <stdio.h>
-
- int main(int argc, char **argv)
- {
- printf("Hello World!\n");
- return 0;
- }
-
- 2、编译
- aarch64-linux-gnu-gcc test.c -o run
-
- 3、利用共享目录传递到QEMU中
- cp ./run ../../../kmodules/
在QEMU中可以正常运行,说明应用程序可以使用动态链接库
- [root@user mnt]# ls
- hello.txt run
- [root@user mnt]# ./run
- Hello World!
(2)内核module测试
编写Makefile
- export ARCH=arm64
- export CROSS_COMPILE=aarch64-linux-gnu-
-
- KERNEL_DIR ?= //此处填写你内核源码的目录
- obj-m := module_test.o
-
- modules:
- $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
-
- clean:
- $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
-
- install:
- cp *.ko $(KERNEL_DIR)/kmodules
a.编写一个简单的module
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
-
- static int __init test_init(void)
- {
- printk("test_init\n");
- return 0;
- }
-
- static void __exit test_exit(void)
- {
- printk("test_exit\n");
- }
-
-
- module_init(test_init);
- module_exit(test_exit);
- MODULE_LICENSE("GPL");

b.编译module,拷贝到共享目录
- make modules
- make install
c.在QEUM执行module的插入与卸载,可以看到成功执行并打印log
- [root@user mnt]# ls
- hello.txt module_test.ko run
- [root@user mnt]# insmod module_test.ko
- [ 570.643309] module_test: loading out-of-tree module taints kernel.
- [ 570.649633] test_init
- [root@user mnt]# lsmod
- module_test 16384 0 - Live 0xffff800000ff0000 (O)
- [root@user mnt]# rmmod module_test.ko
- [ 582.596130] test_exit
initramfs的方式将我们的根文件系统的目录直接打包到内核源码,成为了内核的一部分,当然这个时候可以操作文件,但是系统重启就会丢失,你可以试试新建一些文件后关闭再进入QEMU,会发现文件不见了,因为所有的文件改动都是在内存中
所以下面使用模拟磁盘的方式来挂载根文件系统,永久保存数据
(1)制作磁盘文件
- dd if=/dev/zero of=rootfs_ext4.img bs=1M count=8192
- mkfs.ext4 rootfs_ext4.img
- mkdir -p tmpfs
- mount -t ext4 rootfs_ext4.img tmpfs/ -o loop
- cp -af _install_arm64/* tmpfs/
- umount tmpfs
- rm -rf tmpfs
- chmod 777 rootfs_ext4.img
(2)执行QEMU从磁盘启动
qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "noinitrd root=/dev/vda rw console=ttyAMA0 loglevel=8" -nographic -drive if=none,file=rootfs_ext4.img,id=hd0 -device virtio-blk-device,drive=hd0 --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
可以看到800多M可以被我们使用,重新进入QEMU也能看到之前在根目录下创建的文件
- [root@sofine ]# df -h
- Filesystem Size Used Available Use% Mounted on
- /dev/root 973.4M 11.5M 894.7M 1% /
- devtmpfs 465.0M 0 465.0M 0% /dev
- tmpfs 487.1M 0 487.1M 0% /tmp
- kmod_mount 1.8T 349.5G 1.4T 20% /mnt
【参考博客】
[1] 掌握QEMU虚拟化技术:搭建ARM64+Linux调试环境实战指南 - 知乎
[3] https://www.cnblogs.com/lvzh/p/14907592.html
[4] (2023)从零开始用qemu搭建虚拟arm环境_qemu虚拟机-CSDN博客
[6] 使用QEMU(x86)模拟运行ARM64架构并进行内核调试_qemu86-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。