Timeline
Timeline
2025-12-31
init
2025-01-14
add buildroot
This article introduces the method of using Qemu to emulate a Raspberry Pi 4b Linux module development environment, detailing the selection and configuration of cross-compilers, the compilation of the kernel and root file system, and discussing the configuration options and precautions when customizing the system based on Buildroot and Yocto build systems.
Environment
Host OS
Using Arch Linux with WSL2

Using Ubuntu is also possible, refer to:
compiler
ARM has currently released a total of 8 architectures: ARMv1, ARMv2, ARMv3, ARMv4, ARMv5, ARMv6, ARMv7, ARMv8.
For processors supporting the ARMv8 instruction set, you can use-march=armv8-aparameters to compile code, the ARM GNU compiler can be downloaded via the link below
For example, the aarch64-linux-gnu-gcc version downloaded via pacman on Arch Linux is 15.1.0, and its files are in a flat layout. It is not suitable for the buildroot compilation toolchain.

It is recommended to use the compiler from the official ARM website, which is portable and ready to use after decompression.
This article uses the 11.2 version of the cross-compiler
You can add it to the environment variables
1 | # ~/.bashrc or ~/.bash_profile |
Using version 11.2.1 of aarch64-none-linux-gnu-gcc

Compile the kernel
1 | sudo pacman -Syu bc |
Output:
arch/arm64/boot/Imagearch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dtb
Compile the root file system
busybox
Reference:
Note that this blog uses the aarch64-linux-gnu-gcc compiler downloaded via pacman on Arch Linux. It is best to keep the compiler consistent with the one used to compile the kernel, so here we choose aarch64-none-linux-gnu-gcc
When copying dynamic library files, copy those from the compiler directory:
1 | cp ~/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/aarch64-none-linux-gnu/libc/lib/ld-linux-aarch64.so.1 ./lib/ |
After compilation, enter the Linux kernel code and install the driver:
1 | # Install driver, copy to root filesystem |
buildroot
The default toolchain of Archlinux and the cross toolchain provided by AUR cannot be copied and used, because Buildroot copies the toolchain to the working directory for execution during the build process, therefore we need tochoose a Portable toolchain。
1 | wget https://buildroot.org/downloads/buildroot-2025.11.tar.gz |
The configuration is as follows
1 | Target Options ---> |
Do not enable the options in the kernel here (they are disabled by default), because we want to compile the kernel ourselves; do not enable the bootloader options either, because using qemu to boot does not require a bootloader.
External toolchain kernel headers series (4.20.x) here refers to the kernel version corresponding to the toolchain, which can be viewed in the
gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/aarch64-none-linux-gnu/libc/usr/include/linux/version.hdirectory, here it should be 4.20.x
Compile:
1 | sudo pacman -Syu unzip cpio rsync |
Enter the linux kernel directory, install the driver
1 | # Install driver, copy to root filesystem |
yocto
1 | mkdir -p ~/repository/linux/yocto |
Yocto does not automatically recognize any external toolchain!
There must be a dedicated layer to provide support for this toolchain (viatcmode-*.incandtoolchain-*.conffile).
Common support layers:meta-arm→ Supports ARM official GNU Toolchain
Yocto Project / OpenEmbedded build system available in distribution configuration
poky-masterPoky is the reference distribution of the Yocto Project.
-masterindicates the use of the latest development main branch code, which is the unreleased, under-development version。
oe-nodistro-masterOpenEmbedded (OE) is the underlying build framework of the Yocto Project.
nodistroIndicates “no distribution” mode —Not bound to any specific distribution policy, only providing the most basic build capabilities.-masterAlso indicates using development mainline。
oe-nodistro-whinlatterBased on OpenEmbedded of
nodistroconfiguration;Use Yocto 5.3 version codename “whinlatter” stable branch;
Is a long-term support version;
nodistroIndicates “no distribution” mode.
poky-whinlatterPoky distribution of 5.3 “whinlatter” stable version;
Includes complete default configurations (such as using systemd, optional RPM/deb package formats, default toolchain, etc.);
Is a long-term support version;
Is the reference platform officially tested and certified by the Yocto Project.
“whinlatter” is the codename for Yocto Project 5.3(Yocto versions have been named after birds since 4.0, 5.3 = Whinchat + Lark → “Whinlatter”).
BitBake build configuration (layers / templates)
pokyThis is Standard Poky build configuration。
All packages (recipes) will be built completely from source (unless you already have a local cache).
Secure, reliable, and predictable behavior.
poky-with-sstate- Enabled Remote shared state (sstate) cache。
- During the build, it will attempt to fetch from Yocto official or specified sstate mirror servers Download pre-compiled intermediate artifacts (such as compiled libraries, kernel modules, etc.), therebysignificantly speeding up the build process。
- but there are strict prerequisites:
- your local network must be very stable and have sufficient bandwidth;
- must be able to access external sstate servers (usually requires internet);
- if the network is interrupted or the mirror does not match, it may lead to build failure or inconsistency;
- “Use with caution” is exactly a reminder of this.
sstate is Yocto’s caching mechanism: it saves the output of tasks (such as
do_compileresults), which can be directly reused next time the same content is built, without redoing it.
Target Machine
machine/qemux86-64PC simulating the x86_64 architecture, using QEMU virtual machine。
based on standard PC hardware models (such as Intel/AMD 64-bit CPUs, common peripherals).
machine/qemuarm64Simulating the ARM64 (AArch64) architecture virtual devices (such as systems based on Cortex-A57).
Also runs via QEMU, without the need for a real ARM board.
machine/qemuriscv64- Simulating the RISC-V 64-bit architecture virtual machine.
machine/genericarm64Generic ARM64 real hardware reference configuration (not an emulator).
Not tied to specific boards (such as Raspberry Pi, BeagleBone), but provides a “generic” ARM64 BSP.
Need to flash the generated image toReal ARM64 development boardrunning on.
May lack specific board-level drivers (such as GPU, WiFi), requiring manual adaptation.
machine/genericx86-64Generic x86_64 real hardware reference configuration (e.g., regular PC, Intel NUC, industrial computer).
The generated image can be directly written to a USB drive and booted on a real x86_64 computer.
Distribution configuration variants
distro/poky- Standard Poky distribution configuration. Includes a complete Linux system: glibc, systemd, package manager (RPM or IPK), common tools (bash, coreutils, networking, etc).
- Uses systemd as the init system by default.
- Suitable for general development, learning, and most embedded application scenarios.
- The image is large (a few hundred MB), but fully functional.
distro/poky-altcfgAlternative Poky configuration
Usually used to test different combinations of underlying components, for example:
- Use musl libc Alternative to glibc;
- Use busybox + sysvinit Alternative to systemd;
- Smaller default image or different security policies.
Specific behavior depends on the Yocto version,Less documentation, stability is not as good as standard Poky。
Mainly used for Yocto internal testing or advanced customization scenarios。
distro/poky-tiny- Minimalist Poky, designed specifically for resource-constrained devices.
- Features:
- Use musl libc(smaller, faster);
- Use busybox + sysvinit(no systemd);
- Removed a large number of non-essential packages;
- The final root filesystem can be as small as 10–20 MB。
- Limited functionality: may lack network tools, simplified shell features, no package management.
- Suitable for: microcontroller-level applications, minimal environments after bootloader, safety-critical systems.
1 | # Enter the build environment |
Kernel module
Kernel module example code
1 |
|
external module
Here, the busybox root filesystem is taken as an example
Makefile
1 | DRIVER_NAME := hello_world |
The script that packages the root filesystemdeploy.shAs follows:
1 |
|
Encountered a problem where there is no print when compiling with aarch64-linux-gnu-gcc on WSL2 archlinux (aarch64-none-linux-gnu-gcc also doesn’t work), haven’t found a solution yet, described the specific problem in detail on stackoverflow:
However, this problem does not occur when using WSL2 Ubuntu20.04.
built-in module
Indrivers/char(Taking character driver as an example) Create a folder named helloworld, then put the driver source code into it, and then create a Kconfig file
1 | config HELLO_WORLD |
Modify drivers
1 | emacs ../Kconfig |
Create a Makefile in the driver source code
1 | obj-$(CONFIG_helloworld) += helloworld.o |
Then add to the upper-level Makefile:
1 | emacs ../Makefile |
Then compile the kernel
qemu run
qemu version
1 | $ sudo pacman -Syu qemu-system-aarch64 |
busybox root filesystem
Here we compile busybox into initramfs.cpio.gz as the value of the initrd parameter.
Run
1 | qemu-system-aarch64 \ |
look up bycommand + a, then press x to exit qemu
buildroot root filesystem
In buildroot, we use an SD card to mount the filesystem
1 | $ qemu-system-aarch64 \ |
look up bycommand + a, then press x to exit qemu
yocto root filesystem
Use initramfs.cpio.gz or use an SD card to mount the filesystem
1 | $ qemu-system-aarch64 \ |

