- 由 虚拟的现实创建于12月 26, 2024 需要 3 分钟阅读时间
前言
推荐在 Linux 系统上安装 qemu。可以登录www.qemu.org/download/ 下载最新的qemu版本。根据需要选择源码构建安装或者直接使用各个Linux发行版仓库中的版本。如无特殊需要,可以直接使用Linux发行版自带的qemu,安装简单方便。
qemu-system-aarch64 --version
下载并编译内核
(1)以下载6.7.6版本的Linux kernel代码为例,其他版本可自行修改 $ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.6.tar.xz (2)解压代码压缩包 $ tar -Jxf linux-6.7.6.tar.xz (3)安装编译工具和依赖库 $ sudo apt install gcc-aarch64-linux-gnu $ sudo apt install libncurses5-dev build-essential git bison flex libssl-dev 检查安装情况 $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/11/lto-wrapper Target: aarch64-linux-gnu Configured with: ../src/configure -v --with-pkgversion='Ubuntu 11.4.0-1ubuntu1~22.04' --with-bugurl=file:///usr/share/doc/gcc-11/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-11 --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-libphobos-checking=release --without-target-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 --with-build-config=bootstrap-lto-lean --enable-link-serialization=2 Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) (4)指定环境变量 $ export ARCH=arm64 $ export CROSS_COMPILE=aarch64-linux-gnu- (5) 配置内核:这里采用ARM公司提供的Versatile Express开发平台模拟 cd 到解压出来的内核代码根目录下 $ cp arch/arm/configs/vexpress_defconfig .config $ make menuconfig 添加hotplug的支持 Device Drivers -> Generic Driver Options -> Support for uevent helper (/sbin/hotplug) path to uevent helper 配置内核的虚拟地址空间范围 Kernel Features ---> Page size(4KB) ---> Virtual address space size(48-bit)---> 增加debug_fs的支持 Kernel hacking ---> Generic Kernel Debugging Instruments ---> [*] Debug Filesystem (6)编译内核,编译产物为arch/arm64/boot/Image。 $ make all 视自己的机器配置情况,为了提升编译速度,可以使用make all -j4 或者make all -j8
制作根文件系统 rootfs
(1)下载busybox $ wget http://busybox.net/downloads/ $ tar jxvf busybox-1.36.1.tar.bz2 (2) busybox编译配置打开静态链接选项 $ make menuconfig Settings ---> [*] Build static binary (no shared libs) (3) 编译busybox,执行成功会在代码根目录生成_install目录 cd 到busybox代码根目录 $ make && make install (4) 在rootfs里添加/etc /lib 和/dev目录 $ cd _install $ mkdir etc lib dev $ ls bin dev etc lib linuxrc sbin usr // 在etc目录下创建如下文件 $ cat profile #!/bin/sh export HOSTNAME=virt-machine 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 $ cat 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 $ cat inittab ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a -r // 指明挂载的文件系统 $ mkdir -p etc/init.d $ cat etc/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 +x rcS // 添加设备文件 $ cd dev $ sudo mknod console c 5 1 $ sudo mknod null c 1 3 // 拷贝lib库到lib目录,方便qemu虚拟机启动后,动态编译的程序可以运行 $ cd linb && cp /usr/aarch64-linux-gnu/lib/*.so* -a . $ ls ld-linux-aarch64.so.1 libatomic.so.1 libgcc_s.so.1 liblsan.so.0 libnss_compat.so.2 libresolv.so libtsan.so.0 libBrokenLocale.so libatomic.so.1.2.0 libgomp.so.1 liblsan.so.0.0.0 libnss_dns.so.2 libresolv.so.2 libtsan.so.0.0.0 libBrokenLocale.so.1 libc.so libgomp.so.1.0.0 libm.so libnss_files.so.2 librt.so.1 libubsan.so.1 libanl.so libc.so.6 libhwasan.so.0 libm.so.6 libnss_hesiod.so libstdc++.so.6 libubsan.so.1.0.0 libanl.so.1 libc_malloc_debug.so libhwasan.so.0.0.0 libmemusage.so libnss_hesiod.so.2 libstdc++.so.6.0.30 libutil.so.1 libasan.so.6 libc_malloc_debug.so.0 libitm.so.1 libnsl.so.1 libpcprofile.so libthread_db.so libasan.so.6.0.0 libdl.so.2 libitm.so.1.0.0 libnss_compat.so libpthread.so.0 libthread_db.so.1
制作虚拟硬盘
cd 到内核源码根目录下,执行下面的命令 dd if=/dev/zero of=rootfs_ext4.img bs=1M count=1024 mkfs.ext4 rootfs_ext4.img mkdir -p tmpfs sudo mount -t ext4 rootfs_ext4.img tmpfs/ -o loop sudo cp ~/busybox-1.36.1/_install/ ./rootfs -a sudo chown -R root:root rootfs sudo cp -af rootfs/* tmpfs/ sudo umount tmpfs chmod 777 rootfs_ext4.img
qemu 启动
// 创建qemu和主机的共享目录,该目录下的文件可以同时被qemu虚拟机中的Linux和主机上的Linux访问修改 mkdir kmodules // 启动qemu虚拟机 qemu-system-aarch64 -machine virt -cpu cortex-a57 \ -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
qemu-system-aarch64: 这是 QEMU 的命令行工具,用于启动模拟 ARM64 架构的虚拟机。
-machine virt: 这个选项指定要模拟的虚拟机的类型,即通用的虚拟机。
-cpu cortex-a57: 指定虚拟机使用的 CPU 模型,这里选择了 Cortex-A57。
-m 1024: 设置虚拟机的内存大小为 1GB。
-smp 4: 指定虚拟机的 CPU 核心数量为 4 个。
-kernel arch/arm64/boot/Image: 指定用作虚拟机启动镜像的内核文件。
--append "noinitrd root=/dev/vda rw console=ttyAMA0 loglevel=8": 这个参数指定了启动内核时要传递给内核的命令行参数。具体来说:
- noinitrd: 表示不使用 initramfs(即不使用 RAM 文件系统)。
- root=/dev/vda: 指定根文件系统的设备为/dev/vda。
- rw: 将根文件系统挂载为读写模式。
- console=ttyAMA0: 将控制台输出重定向到串行端口 ttyAMA0。
- loglevel=8: 设置内核日志级别为 8,以便显示更多的调试信息。
-nographic: 这个选项告诉 QEMU 不要显示图形窗口,而是将所有输出发送到控制台。
-drive if=none,file=rootfs_ext4.img,id=hd0: 这个选项定义了一个虚拟硬盘驱动器。具体来说:
- if=none: 指定不使用任何接口类型,因为后面会使用virtio-blk-device设备来连接这个虚拟硬盘。
- file=rootfs_ext4.img: 指定虚拟硬盘的镜像文件为rootfs_ext4.img。
- id=hd0: 为这个虚拟硬盘指定一个唯一的标识符。
-device virtio-blk-device,drive=hd0: 这个选项定义了一个 virtio 块设备,连接到之前定义的虚拟硬盘。drive=hd0指定连接到名为hd0的虚拟硬盘。
--fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none: 这个参数定义了一个本地文件系统设备,用于将主机上的文件系统挂载到虚拟机中。具体来说:
- local: 指定这是一个本地文件系统。
- id=kmod_dev: 为这个设备指定一个唯一的标识符。
- path=$PWD/kmodules: 指定要挂载到虚拟机中的文件系统路径。这里假设在当前工作目录下有一个名为kmodules的文件夹。
- security_model=none: 禁用安全模型,允许对文件系统进行完全的读写访问。
-device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount: 这个选项定义了一个 virtio-9p 设备,用于将之前定义的本地文件系统挂载到虚拟机中。具体来说:
- fsdev=kmod_dev: 指定要挂载的文件系统设备。
- mount_tag=kmod_mount: 指定挂载的标签名称,在虚拟机中将使用这个标签来识别挂载的文件系统。
- 无标签