QEMU搭建ARM64+Linux环境
QEMU()是一套开源的虚拟机软件,可以模拟多个如x86、arm等处理器架构,用于虚拟化、仿真和调试,非常适合没有开发板而又想研究Linux内核结构和工作模式的人使用,对于嵌入式+Linux的学习十分有帮助本文也是参考了下方多篇博客,记录下自己在使用QEMU搭建环境时成功的步骤,便于后续的学习和实践。
目录
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)
二、安装QEMU
这里我采用的是从源码安装,也可以从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
三、制作根文件系统
完成最小的根文件系统,并且可以运行动态编译的应用程序
1、从busybox下载最新版本源码
下载网址:Index of /downloads
tar jxvf busybox-1.36.1.tar.bz2
2、制定编译工具链
cd busybox-1.36.1
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
3、编译
1、make menuconfig
Settings --->
[*] Build static binary (no shared libs)
2、make
3、make install
4、创建需要的目录
编译完成后,会生成_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 .
四、编译内核源码
1、下载源码
下载Linux内核源码,https://www.kernel.org
我这边是linux-6.1.83的,直接点击tarball就能下载
tar xvf linux-6.1.83.tar.xz
2、指定编译工具
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
3、将根文件系统放到源码根目录
cd linux-6.1.83
cp ../../busybox-1.36.1/_install _install_arm64 -a
4、配置生成 .config
修改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)--->
5、编译
make all -j8
五、启动QEMU
1、创建共享文件目录
在内核源码目录下创建目录
mkdir kmodules
2、运行 QEMU 模拟器
在内核源码目录下执行下面的命令
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
3、利用共享目录传递文件
在内核源码的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!
4、利用共享目录传递应用程序并在QEMU中执行
(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
5、从磁盘启动QEMU
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博客
更多推荐
所有评论(0)