- 准备编译linux内核
获取内核源码:wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.1.80.tar.xz
bash
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j32
- 确认编译产出
2.1 最常见的内核镜像文件(具体名称取决于架构和配置)
arch/arm64/boot/Image # 对于ARM64
arch/x86/boot/bzImage # 对于x86_64
arch/arm/boot/zImage # 对于ARM
/vmlinux # 未压缩带符号表的镜像,gdb调试用
- 准备根文件系统
3.1 下载编译busybox
bash
$ wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
$ tar -xf busybox-1.36.1.tar.bz2
$ cd busybox-1.36.1
$ make menuconfig
Settings --->
[*] Build static binary (no shared libs)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j32
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- CONFIG_PREFIX=../rootfs/arm64/ install # 会生成_install目录
3.2 制作根文件系统
静态链接的不需要复制so文件
3.2.1 /etc/profile
- 用户登录shell时自动执行的脚本,用于设置环境变量
bash
# 设置主机名HOSTNAME、用户名USER和家目录HOME
export HOSTNAME=virt-machine
export USER=root
export HOME=/home
# 设置命令提示符的格式,例如 [root@virt-machine ~]#
export PS1="[$USER@$HOSTNAME \W]\# "
# 设置shell查找命令的路径
PATH=/bin:/sbin:/usr/bin:/usr/sbin
# 设置动态链接器查找共享库的路径
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH
3.2.2 /etc/fstab
- 定义系统启动时需要自动挂载的文件系统
bash
#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
# 将QEMU启动参数中定义的 9p网络文件系统(共享文件)挂载到虚拟机的 /mnt目录
kmod_mount /mnt 9p trans=virtio 0 0
3.2.3 /etc/inittab
- init进程(系统第一个进程)的配置文件,定义了系统的运行级别和启动流程
bash
#系统初始化时执行/etc/init.d/rcS脚本
::sysinit:/etc/init.d/rcS
#这两行都用于启动shell
# respawn表示如果shell进程退出,会自动重新启动
::respawn:-/bin/sh
# askfirst则会先打印"Please press Enter to activate this console"并等待回车
::askfirst:-/bin/sh
#在串口控制台(console=ttyAMA0)下,通常使用respawn;在图形界面或终端下,使用askfirst。这里可能配置了两个,系统会选择其中一个
3.2.4 /etc/init.d/rcS
bash
# 创建虚拟文件系统挂载点 /sys /tmp /proc /mnt
mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
# 挂载所有在 /etc/fstab文件中定义的文件系统
/bin/mount -a
# pseudo-terminal slave 虚拟终端从设备文件系统的挂载点。它为每个打开的终端(如 SSH 连接、xterm 窗口)提供一个对应的设备文件(如 /dev/pts/0)
mkdir -p /dev/pts
# 将 devpts 文件系统挂载到 /dev/pts目录
mount -t devpts devpts /dev/pts
# 设置内核的热插拔事件处理程序为 /sbin/mdev
# 这是 BusyBox 的 mdev 机制的核心配置。当内核检测到设备事件(如USB设备插入、移除)时,会调用这个路径指定的程序来处理。mdev会根据这些事件,自动在 /dev目录下创建设备节点文件,实现设备的动态管理
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
- 制作虚拟硬盘
bash
$ $mkdir virtdisk
$ $cd ./virtdisk/
$ $ls
$ $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 ../rootfs/arm64/ ./rootfs -a
$ sudo chown -R root:root rootfs
$ sudo cp -af rootfs/* tmpfs/
$ sudo umount tmpfs
$ chmod 777 rootfs_ext4.img
- 启动qemu仿真
bash
# 共享目录
mkdir share
SAHRE_DIR=./share
KERNEL_IMAGE=../linux-6.1.80/arch/arm64/boot/Image
# 启动qemu虚拟机
qemu-system-aarch64 \
-machine virt -cpu cortex-a57 \
-m 1024 \
-smp 4 \
-kernel $KERNEL_IMAGE\
--append "noinitrd root=/dev/vda rw console=ttyAMA0 loglevel=8" \
-nographic \
-drive if=none,file=../virtdisk/rootfs_ext4.img,id=hd0 \
-device virtio-blk-device,drive=hd0 \
--fsdev local,id=kmod_dev,path=$SAHRE_DIR,security_model=none \
-device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
# -s: 在1234端口启动GDB服务器; -S: 启动时暂停CPU
- 启动gbd调试
bash
# 启动GDB并加载符号
gdb path/to/vmlinux # vmlinux是带调试信息的未压缩内核
# # 连接到QEMU (默认端口1234)
# (gdb) target remote localhost:1234