Vanilla ARM64 kernel on QEMU (2023)

It's been quite a while since I've tried anything and the COVID-19 pandemic lockdown has provided much needed time to try a few things outside of official work.

This blog is about how to build and run the ARM64 Linux kernel in a qemu environment with rootfs compiled with buildroot.

With buildroot it's easy to do in just 3 steps.

  • Clone the last build root.
  • Locate the appropriate configuration file and configure it.
  • Start compilation with the make command.

In short, when the following commands are used, we have a complete build of the ARM64 embedded Linux environment.

  • git-Klon git://
  • hacer qemu_aarch64_virt_defconfig;
  • create time

Once the build is complete, the Linux kernel and filesystem images can be loaded and things should start working right away. From my personal experience, buildroot is the best tool to install Linux based embedded systems without problems.

The intention of this blog is to use the latest vanilla kernel from and only use the file system created with buildroot.

Things to do summarizing the steps:

  • Create a minimal filesystem with buildroot.
  • Using the Linaro toolchain for ARM64, compile the vanilla kernel after linking it to the filesystem created with buildroot.
  • Load it with qemu and confirm that it works.
  • Run a simple C program compiled for ARM64.

Although low-cost development boards based on ARM64bit cores are available from many vendors, using qemu helps reduce the response time for application developers.

Creating a filesystem with buildroot

As mentioned above, the first step is to open the buildroot repository with the command "git-Klon git://

In the cloned repository, the list of available configuration files is in the directory called "the settings🇧🇷 The configuration file of interest is "settings/qemu_aarch64_virt_defconfig🇧🇷 When running"hacer qemu_aarch64_virt_defconfigThis will create the .config file that buildroot will use for compilation. Additional options can be selected with " for this custom batch.make setup menu” in addition to those already provided by the configuration file (a full menu of available options is displayed when this command is executed). As only a few options need to be enabled, guidemake setup menucommand, type thefile system imagessubmenu and then select "cpio the root filesystem (to use as the initial RAM filesystem)" option. Below is a screenshot:Vanilla ARM64 kernel on QEMU (1)

Save the settings and exit the menu. After exiting, check the .config file for the following options and make sure they are filled in correctly:


Serial port configuration is important here and a similar parameter needs to be updated in the kernel configuration file which is also discussed below. If changes were made to the configuration file, remember to save the configuration file and exit.

With the configuration in the buildroot configuration file, the build can now be started with the "make" command. If construction machines specifications and good internet connection are good, construction will be completed quickly. When the build is complete, the final images will be in the "Output/Images/🇧🇷 Below is the list of files that will be available.

(Video) Emulating ARM64 Raspberry Pi Image using QEMU

kasi@Vostro buildroot]$ ls output/images/ -l
15296 no total
-rw-r–r– 1 but but 7332352 1 de maio 12:41 pic
-rw-r–r– 1 but but 1908224 1 de maio 12:41 rootfs.cpio
-rw-r–r– 1 but but 62914560 1 de maio 12:41 rootfs.ext2
lrwxrwxrwx 1 because because May 11 12:41 PM rootfs.ext4 -> rootfs.ext2
-rwxr-xr-x 1 but but 508 1 de maio 12:41

rootfs.cpioThe file contains the filesystem that the Linux kernel should use. At this point, qemu can boot and run without any problems using the kernel and filesystem images created with buildroot. But instead of using the kernel provided by buildroot, it uses the vanilla kernel. The next step is to further compile the vanilla kernel with the filesystem created by buildroot.

Cross compiler setup

The toolchain provided by Linaro can be used to compile the kernel to ARM64. Below is the link to download the toolchain:

This file can be created with the command "wget-c' to the desired directory of your choice. Unzip this file so that the cross-compile environment can be set up. The following commands export the cross compiler path and configure the toolchain for cross compilation.

export PATH=<DIRECTORY WHERE THE TAR FILE IS NOT LISTED>/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
exportar CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64

If the cross compiler is not set up correctly, things may not work as expected. So, double check and make sure it's set up correctly.

Download the vanilla kernel and start compiling

At the time of writing this article, the latest stable kernel is vanilla5.6.8.Again with the wget command "wget-c kernel source code for the command can be downloaded into the desired directory. After unzipping this file, the default ARM64 configuration file is in the location "arco/arm64/configs/' no kernel source-code.

kasi@Vostro linux-5.6.8]$ ls arch/arm64/configs/ -l
24 total
-rw-rw-r–1 but but 20822 Apr 29 8:04 PM defconfig

The configuration file that already exists in the Linux kernel can be used as a base, on which changes can be made.

but @Your Linux-5.6.8]$make defconfig
Skripte HOSTCC/kconfig/conf.o
Skripte HOSTCC/kconfig/confdata.o
HOSTCC scripts/kconfig/expr.o
Guiones LEX/kconfig/lexer.lex.c
Digite YACC/kconfig/[ch]
Scripts HOSTCC/kconfig/lexer.lex.o
Skripte HOSTCC/kconfig/
Skripte HOSTCC/kconfig/preprocess.o
HOSTCC scripts/kconfig/symbol.o
Skripte HOSTCC/kconfig/util.o
*** Default configuration is based on 'defconfig'
# Configuration recorded in .config

Kernel compilation can be started with the .config file created, as the toolchain has also been configured, but before that some modifications to the .config file must be made. Look for the configuration value in the .config fileCONFIG_CMDLINE=and change like thisCONFIG_CMDLINE=”consola=ttyAMA0″.The next option to change is to add the cpio file path for the kernel to use as initramfs. modify theCONFIG_INITRAMFS_SOURCE=""Option with the location of the cpio file created with buildroot. For example,CONFIG_INITRAMFS_SOURCE=”<ROOT BUILD DIR/output/images/rootfs.cpio”.These two are the changes that need to be made to the configuration file. Example of changes made to the .config file in the kernel source code.

kasi@Vostro linux-5.6.8]$ grep CONFIG_CMDLINE .config
kasi@Vostro linux-5.6.8]$ grep CONFIG_INITRAMFS .config
CONFIG_INITRAMFS_SOURCE =”/Sourcefiles/armv8/buildroot/output/images/rootfs.cpio”

to run "make setup menu” once and save the configuration file. Kernel compilation can now be started withagainDomain. Since the defconfig configuration file provided by the kernel has many options enabled by default, it takes a long time to compile the kernel. When the kernel is built, the qemu session can be started with the newly created ARM64 image. When the build is complete (it took 90 minutes on a quad-core machine), the kernel image will be in "Bow/Arm64/Boots“.

(Video) Debugging an ARM64 linux kernel using QEMU

kasi@Vostro linux-5.6.8]$ ls arch/arm64/boot/Image -lh
-rw-rw-r– 1 pero pero 28M 1. Mai 15:10 arch/arm64/boot/Image

The image is about 28 megabytes in size because the kernel and file system are zipped together. Time to validate what has been achieved so far. For this "qemu-system-arch64You must use the command "". This command is part of the package "qemu-system-arm' and can be easily installed on any distribution (e.g. Debian/Ubuntu clonesapt-get install qemu-sistema-brazo).

Start Qemu with Vanilla

The compiled vanilla kernel can be booted into a qemu environment with the following command.

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -nographic -smp 2 -m 4096 -kernel arch/arm64/boot/Image

Most of the options are self-explanatory, but to understand them, let's go through them one by one. Both machine and machine type are populated as virtual(ual) as the environment is qemu based. The CPU parameter is the ARM CPU core emulated by qemu. The Cortex-a57 core was the largest qemu-compatible ARM64bit core ever used. No Graphics option means no fancy graphics and just do CLI. The smp parameter is used to specify how many CPU cores qemu should emulate. The more CPU cores, the longer it takes qemu to boot. A reasonable value would be two, as any processing done in qemu is done by the native hardware, which is primarily based on an Intel x86-64 machine. The m parameter specifies the amount of RAM qemu can use and the -kernel parameter is passed the location of the image.

A few lines from the bootlog

kasi@Vostro linux-5.6.8]$ qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -nographic -smp 2 -m 4096 -kernel arch/arm64/boot/Image

[0.000000] Inicialize o Linux na CPU física 0x0000000000 [0x411fd070]
[ 0.000000] Linux-Version 5.6.8 (kasi@Vostro) (gcc-Version 7.5.0 (Linaro GCC 7.5-2019.12)) #1 SMP PREEMPT Freitag, 1. Mai 13:29:30 IST
[ 0.000000] Machine model: Linux, dummy virt

Of the first three lines, the second shows the Linux kernel version and the time/date this image was created. The third line shows the machine model as virtual, which is correct. If the kernel image is successfully built, the login prompt will appear and the login should just be the username "root" login.

Welcome to buildroot
login buildroot: root

After entering bash, the full ARM64 environment is available and can be used for any purpose. Some things that can be checked are CPU information and available memory.

# gato /proc/cpuinfo
Processor: 0
BogoMIPS: 125,00
Merkmale: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU Implementer: 0x41
CPU architecture: 8
CPU-Variant: 0x1
CPU part: 0xd07
CPU check: 0

Processor: 1
BogoMIPS: 125,00
Merkmale: fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
CPU Implementer: 0x41
CPU architecture: 8
CPU-Variant: 0x1
CPU part: 0xd07
CPU check: 0

# book -m
shared cache/buffer free total used available
Memory: 3931 14 3915 1 1 3801
Exchange: 0 0 0

(Video) Emulating ARM with Virt-Manager QEMU | Linux Guide

The information above qemu corresponds to the passed parameters. To exit the qemu environment at any time, just press CTRL+A and then x.

A few more seconds saved

So far we've compiled and loaded the vanilla kernel with the filesystem containing the tools of our choice. One problem with this approach is that it takes a long time to build the kernel image because the configuration file used has many unwanted options selected and most of them are not used in the qemu environment. It also means that the image takes a long time (in seconds) to load. Buildroot also builds the kernel by building the filesystem image, but mostly not the latest one. Therefore, the configuration file available in the Buildroot kernel compilation can be used in the downloaded and compiled kernel source code. Make a backup copy of the current .config file and copy the kernel configuration file from the buildroot build.

cp <BUILD BUILD DIR>/output/build/linux-5.4.35/.config <KERNEL BUILD DIR>/.config

After copying the config file, set the two kernel optionsCONFIG_CMDLINEjCONFIG_INITRAMFS_FUENTE as done before. To domake setup menu, save and exit. Restart the kernel build withagainsend and wait

Compiling using the buildroot configuration file built in 15 minutes, while compiling using the default configuration took about 90 minutes, which is six times longer. Let's check if the new kernel works too.

kasi@Vostro linux-5.6.8]$ qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -nographic -smp 2 -m 4096 -kernel arch/arm64/boot/Image

Booting Linux on Physical CPU 0x0000000000 [0x411fd070]
Linux-Version 5.6.8 (kasi@Vostro) (gcc-Version 7.5.0 (Linaro GCC 7.5-2019.12)) #1 SMP Fr. 1. May 19: 51:35 IST 2020
Machine model: Linux, virt dummy

The second line shows when this image was built (which is different from the first build). This image actually took 15-20 seconds to load as it tried to load the eth0 interface which failed but I was still able to login. This image should load in 3-5 seconds (at most), which is a few seconds less than the previous build. Let's try to see if this can be fixed and the startup time reduced.

To remove the unwanted payload from the image's eth0 interface, do the following. Inside buildroot run build directorymake setup menuCommand and enterTarget Packages > Network ApplicationsMenu. Disable the option "scripts ifupdown“.

Vanilla ARM64 kernel on QEMU (2)

Save this configuration and exit. The next step is to make aclean” to clear out the old stuff and runagainRebuild to create a new file system image. If the buildroot build succeeds, trigger the kernel build again to ensure the kernel picks up the new image. In the new kernel build, printk is able to add timing information to the boot logs, so the time will be shown in the logs, which will be useful in the future. This change was made in the kernel .config file because this option was missing from the kernel configuration file copied from the buildroot kernel build. The newly created image can be tested again to confirm whether it works well or not.

A few lines of boot logs

[ 0.000000] Linux-Version 5.6.8 (kasi@Vostro) (gcc-Version 7.5.0 (Linaro GCC 7.5-2019.12)) #5 SMP Fr. 1. 23:03: May 17 IST 2020

<Cut here>

(Video) Building Linux Kernel for QEMU for ARM Board

[1.359785] Run /init as the startup process
Initialization of syslogd: OK
Ab klogd: OK
Running sysctl: OK
Random Seed speichern: [2.585752] random: dd: uninitialized urandom read (read 512 bytes)

Welcome to buildroot
login buildroot: root

The kernel started in 3 seconds, which is quite fast compared to the previous build. The time saved increases exponentially with the number of qemu runs

Run a simple C program in qemu

With the runtime configuration set, it's time to write a simple C program, compile it to ARM64, add it to the file system image, and run it in the qemu environment. Before starting to write the program, create a directory with the name of your choice and start programming there. The reason for creating a separate directory is to add this directory location to the buildroot configuration file and start the build. Once this is done, only the final image will contain the C program that was written and compiled.

Contents of the C program:

A directory called pgms has been created below<DIRECTORY OF CONSTRUCTION ROOT BUILDINGS>.The C program called hello.c is created and the contents are shown below.

kasi@Vostro pgms]$pwd
kasi@seus PGMs]$ cat hi.c
#include <stdio.h>
printf("Em QEMU e ARM64\n");

This program can be compiled using the cross compiler available in buildroot itself. The buildroot cross compiler is available from<BUILD BUILD DIR>/output/host/bin.

kasi@Vostro pgms]$pwd
kasi@Vostro pgms]$ ../output/host/bin/aarch64-linux-gcc -o hola hola.c
hello.c:2:1: warning: default return type is "int" [-Wimplicit-int]
kasi@Tus pgms]$ ls -l
16 no total
-rwxrwxr-x 1 because because 8672 May 2 8:04 pm hi
-rw-rw-r– 1 because because 66 May 2 11:28 olá.c
kasi@Tus pgms]$

Now that the C program has been compiled, it's time to make it part of the buildroot filesystem. To do this, an entry with the location of the C program must be updated in the buildroot .config file.BR2_ROOTFS_OVERLAYand must be updated with the location of the C program directory. For example, it is updated as follows:

BR2_ROOTFS_OVERLAY="/Source Files/armv8/buildroot/pgms"

Make one "make setup menu(Whenever the configuration file is changed, it is better to run menuconfig), save this configuration and exit. Time to start building again by clicking "again🇧🇷 The compilation only takes a few seconds as it only contains the specified files. When the buildroot compilation is complete, rebuild the kernel image to ensure that the C program source code and binaries are included in the final image. Also, compiling the kernel should only take a few seconds, as nothing has changed from the kernel's point of view and only the final image will be repackaged.

Welcome to buildroot
login buildroot: root
#ls /
bin hi lib media proc sbin usr
dev hallo.c lib64 mnt root sys var
etc. init linuxrc opt start tmp
# CD /
# ./Hello
Inside QEMU and ARM64

For any other changes made to the C program, it must first be cross-compiled, then the buildroot must be compiled, and finally the kernel must be compiled. This procedure should be used if a new file is also created.

(Video) "Large Virtual Address support (52-bit) in ARM64 kernel" - Bhupesh Sharma (LCA 2021 Online)



1. Download and compile Android kernel for ARM 64 (ranchu)
(Vito Rallo)
2. Linker scripts in the Linux Kernel, Kernel Image structure, and x86 boot sector debugging
(Ron Munitz)
3. Cross compiling for arm or aarch64 on Debian or Ubuntu
4. Raspberry Pi: Cannot Emulate Raspberry Pi using Qemu: Kernel Panic (4 Solutions!!)
(Roel Van de Paar)
5. How To Install RealVNC Server for Raspberry Pi4 64bit on a vanilla ARCH ARM64 AARCH64 installation
(Aaron South)
6. LTD20-202 Arm64 Linux Kernel Architecture update


Top Articles
Latest Posts
Article information

Author: Laurine Ryan

Last Updated: 06/06/2023

Views: 6055

Rating: 4.7 / 5 (77 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Laurine Ryan

Birthday: 1994-12-23

Address: Suite 751 871 Lissette Throughway, West Kittie, NH 41603

Phone: +2366831109631

Job: Sales Producer

Hobby: Creative writing, Motor sports, Do it yourself, Skateboarding, Coffee roasting, Calligraphy, Stand-up comedy

Introduction: My name is Laurine Ryan, I am a adorable, fair, graceful, spotless, gorgeous, homely, cooperative person who loves writing and wants to share my knowledge and understanding with you.