Step-by-Step Guide to Building and Debugging an ARM64 Linux Kernel with QEMU
This tutorial details how to set up a cross‑compilation toolchain on Ubuntu 20.04, install QEMU, build a BusyBox‑based root filesystem, compile and configure the ARM64 Linux kernel, create a simulated disk, share files between host and guest, and perform kernel debugging using GDB and Eclipse.
The environment uses an Ubuntu 20.04 host with an ARM64 QEMU emulator. Install the cross‑compilation toolchain:
sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev build-essential git bison flex libssl-devVerify the compiler version with aarch64-linux-gnu-gcc -v .
Install QEMU for ARM64:
sudo apt-get install qemu-system-armCheck the QEMU version with qemu-system-aarch64 --version . If needed, build QEMU from source:
wget https://download.qemu.org/qemu-4.1.0.tar.xz
tar xvJf qemu-4.1.0.tar.xz
cd qemu-4.1.0/
./configure
make -j 8
sudo make installBuild a BusyBox‑based root filesystem (rootfs): download BusyBox, extract, configure for static build, and install required ncurses libraries:
tar jxvf busybox-1.33.1.tar.bz2
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make menuconfig # enable "[*] Build static binary"
make -j 8 && sudo make installCreate the rootfs directory structure (etc, dev, lib) and add essential files such as profile , fstab , and inittab . Populate dev with mknod for console and null, and copy required shared libraries into lib .
Compile the Linux kernel for ARM64:
# Clone a forked Linux source tree
git clone https://github.com/luteresa/linux.git
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
cp ../busybox-1.33.1/_install/ ./_install_arm64 -a
cp arch/arm/configs/vexpress_defconfig .config
make menuconfig # enable hotplug helper and initramfs support
make all -j8
mkdir kmodulesRun the kernel with QEMU using the built image:
qemu-system-aarch64 -machine virt -cpu cortex-a57 -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_mountTo preserve data across reboots, create a simulated disk image and mount it as the root filesystem:
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 -af _install_arm64/* tmpfs/
sudo umount tmpfs
chmod 777 rootfs_ext4.imgBoot the kernel with the disk image:
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_mountHost‑guest file sharing is achieved via the 9p filesystem; files placed in the host kmodules directory appear under /mnt in the guest.
Compile and run a simple C program (hello world) from the shared directory to verify dynamic library support.
Test kernel modules by writing module_test.c , building it with the cross‑compiler, and loading it in the QEMU guest using insmod and rmmod .
Debug the kernel with GDB:
sudo apt-get install gdb-multiarch
qemu-system-aarch64 ... -S -s # wait for GDB
gdb-multiarch --tui vmlinux
(gdb) target remote localhost:1234
(gdb) b start_kernel
(gdb) cFor a visual debugging experience, set up Eclipse CDT with the OpenJDK runtime, create a Makefile project, configure the debugger to use gdbserver and gdb-multiarch , and connect to the QEMU target. This allows step‑by‑step kernel debugging with access to registers, variables, and source code.
Deepin Linux
Research areas: Windows & Linux platforms, C/C++ backend development, embedded systems and Linux kernel, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.