QEMU Direct Linux Kernel Boot
Here, I will employ QEMU to emulate a minimal Linux x86_64 platform with a minimal root filesystem from scratch, as well as debugging with GDB
:
- Build Linux x86_64 kernel
- Build Linux x86_64 rootfs(root filesystem)
- Run QEMU
- Debug with
GDB
Why do I use QEMU to boot Linux kernel directly with skipping BIOS/UEFI boot procedures?
Use QEMU to launch a Linux kernel directly without having to make a fully bootable disk image. This is very useful for:
- Linux kernel testing
- root filesystem testing
- arm system emulation
Prerequisites
On Ubuntu,
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison
On macOS, you need create a Case Sensitive filesystem and use GNU GCC instead of Clang
the following ways:
hdiutil create -size 20g -type SPARSE -fs "Case-sensitive HFS+" -volname brosx brosx.sparseimage
hdiutil attach brosx.sparseimage
hdiutil detach /Volumes/brosx -force
brew install gpatch gcc flock attr libtool libart
ln -s /opt/homebrew/bin/gcc-13 /opt/homebrew/bin/gcc
n -s /opt/homebrew/bin/gcc-13 /opt/homebrew/bin/cc
ln -s /opt/homebrew/bin/g++-13 /opt/homebrew/bin/g++
ln -s /opt/homebrew/bin/g++-13 /opt/homebrew/bin/c++
rm /opt/homebrew/bin/gcc /opt/homebrew/bin/cc /opt/homebrew/bin/g++ /opt/homebrew/bin/c++
Build Linux kernel
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.55.tar.xz
tar xvf linux-6.1.55.tar.xz
cd linux-6.1.55
# Use the default `x86_64` configuration file form `/x86/configs/x86_64_defconfig`
make ARCH=x86_64 x86_64_defconfig
# Tweak some options for GDB and initramfs
make menuconfig
make -j8
Generate kernel file ./arch/x86/boot/bzImage
.
To extract vmlinux
from bzImage
,
./scripts/extract-vmlinux ./arch/x86_64/boot/bzImage >./arch/x86_64/boot/vmlinux
Build root filesystem
git clone https://github.com/buildroot/buildroot.git
cd buildroot
make menuconfig
Choose x86_64
as Target Architecture and ext4
root file system.
make -j8
Generate root filesystem disk ./output/images/rootfs.ext4
.
Run QEMU
Copy bzImage
and rootfs.ext4
to any host machine with QEMU available.
rsync -l ./linux-6.1.55/arch/x86/boot/bzImage destination_directory/
rsync -l ./buildroot/output/images/rootfs.ext4 destination_directory/
kernel="$PWD/linux_qemu/x86_64/bzImage"
vmlinuz="$PWD/linux_qemu/x86_64/vmlinux"
initrd="$PWD/linux_qemu/x86_64/rootfs.ext4"
img="$PWD/linux_qemu/x86_64/rootfs.ext4"
qemu-system-x86_64 \
-nographic \
-m 4G \
-kernel $kernel \
-append "earlyprintk loglevel=8 root=/dev/zero console=ttyS0"
qemu-system-x86_64 \
-nographic \
-m 4G \
-kernel $kernel \
-hda $img \
-append "earlyprintk loglevel=8 root=/dev/sda rootfstype=ext4 console=ttyS0" \
-netdev user,id=mynet,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=mynet
Default password: root
Debug Linux kernel
qemu-system-x86_64 \
-s -S \
-nographic \
-m 4G \
-kernel $kernel \
-append "earlyprintk loglevel=8 root=/dev/zero console=ttyS0 nokaslr"
Options in details,
-s
: allows porttcp::1234
for remote debug-S
: stop CPU until continue from GDB what is connected to tcp1234
port-append
nokaslr
: turn off KASLR
Or with root filesystem,
qemu-system-x86_64 \
-nographic \
-m 4G \
-s -S \
-kernel $kernel \
-hda $img \
-append "earlyprintk loglevel=8 root=/dev/sda rootfstype=ext4 console=ttyS0 nokaslr" \
-netdev user,id=mynet,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=mynet
Enter gdb
,
$ gdb ./vmlinux
In gdb
shell,
(gdb) target remote 10.6.64.243:1234
Remote debugging using 10.6.64.243:1234
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x000000000000fff0 in ?? ()
(gdb) continue
Continuing.
Resources
GitHub - dhruvvyas90/qemu-rpi-kernel: Qemu kernel for emulating Rpi on QEMU https://medicineyeh.wordpress.com/2016/03/29/buildup-your-arm-image-for-qemu/
Prepare the environment for developing Linux kernel with qemu. | by DaeSeok Youn | Medium