🎉

自分なりにQEMUで最小構成のLinux環境を構築する

に公開

自分なりにQEMUで最小構成のLinux環境を構築する

QEMU + ARM64用の最小Linuxカーネルをビルドする
LinuxをQEMUで動かす(Armv8-A中心) を参考にQEMUで最小構成のLinux環境を作ってみる。

まずは、defconfigを使って、Linuxカーネルをコンパイルしてみた。 qemu-busybox-min.configは参考にしたサイトに書いてあるのをそのまま利用した(qemu-busybox-min.config

ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make defconfig >& log_defconfig00.txt
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make qemu-busybox-min.config >& log_defconfig_qemu-busybox-min-config00.txt
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) >& log_make_kernel01.txt &

arch/arm64/configs/qemu-busybox-min.config

CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_PL061=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_CMDLINE="console=ttyAMA0 nokaslr rdinit=/sbin/init"

allnoconfigというのを使う場合は、以下のようにする。 allnoconfigは全てのカーネルのコンパイルオプションを NOに設定する。
実用的なオプションは全て外されてしまうが、後で、必要なコンパイルオプションだけを足していくイメージ。
最後のカーネルのコンパイルは、 defconfigを使った時に比べて、相当早く終わる。

ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make allnoconfig >& log_allnoconfig00.txt
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make qemu-busybox-min.config >& log_qemu-busybox-min-config00.txt
ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j$(nproc) >& log_make_kernel00.txt &

カーネルをコンパイルしたら、qemuを起動する。

qemu-system-aarch64 -machine virt,virtualization=on,gic-version=2 \
		    -net none \
		    -cpu cortex-a53 \
		    -m 1G \
		    -kernel arch/arm64/boot/Image \
		    -nographic

実行は、initコマンドとかがないのでエラーができるが、カーネルのブートするところまでは確認できた。

ちなみに、QEMUコマンドラインを終了するには、Ctrl-A x を押す。
emacsのshellの中からだと、Ctrl-Q Ctrl-A x の順番に押した。

Busyboxのコンパイル

BusyBoxでinit ramdisk構築を参考にしながら、Busyboxのコンパイルを行った。

シェルの設定

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
  • busyboxのgit clone
  • make menuconfig
  • Build static binary (no shared libs)をオンにする
  • ネットワークのコンフィグを全てoff にしておいた (使わない可能性が高いから)
make install
cd _install
find . | cpio -H newc -ov -F ../initramfs.cpio
cd ../
gzip initramfs.cpio

今度は、さっきのQEMUのコマンドに、initの部分を追加して起動した。

qemu-system-aarch64 -machine virt,virtualization=on,gic-version=2 \
		    -net none \
		    -cpu cortex-a53 \
		    -m 1G \
		    -kernel arch/arm64/boot/Image \
		    -initrd ../busybox/initramfs.cpio.gz \
		    -nographic

参考にしたサイトと同様に、以下のようなエラーが発生した。

can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory
can't open /dev/tty2: No such file or directory
can't open /dev/tty3: No such file or directory
can't open /dev/tty4: No such file or directory

参考にしたサイトと同じように、以下のように特殊なディレクトリを作成して回避できた。

cd busybox
cd _install 
mkdir proc sys dev run etc dev/pts etc/init.d
sudo mknod -m 666 dev/null c 1 3
sudo mknod -m 600 dev/console c 5 1

vi etc/init.d/rcS

#!/bin/sh

mount -v --bind /dev /dev
mount -v --bind /dev/pts /dev/pts
mount -vt proc proc /proc
mount -vt sysfs sysfs /sys
mount -vt tmpfs tmpfs /run
/sbin/mdev -s

chmod +x rcS

U-Bootを使ったブート

参考にしたサイトの通り、以下のような手順で行った。

git clone https://source.denx.de/u-boot/u-boot.git
git checkout v2025.10

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

make qemu_arm64_defconfig
make -j

コンパイル中に以下のようなエラーが発生したので、足りないパッケージをインストールした。

tools/mkeficapsule.c:20:10: fatal error: gnutls/gnutls.h: そのようなファイルやディレクトリはありません
   20 | #include <gnutls/gnutls.h>
      |          ^~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.host:114: tools/mkeficapsule.o] エラー 1
make[1]: *** 未完了のジョブを待っています....
make: *** [Makefile:2124: tools] エラー 2
sudo apt install libgnutls28-dev

再度、実行をした。

make qemu_arm64_defconfig
make -j

コンパイルが完了後、以下のコマンドでu-bootが使用するディスクイメージを作成する。
mkimageの uRamdiskというのは、RAM Disk用のイメージのファイル名。

cd ../
./u-boot/tools/mkimage -A arm64 -O linux -T ramdisk -d ./busybox/initramfs.cpio.gz uRamdisk
Image Name:   
Created:      Wed Dec 31 16:19:38 2025
Image Type:   AArch64 Linux RAMDisk Image (gzip compressed)
Data Size:    1051129 Bytes = 1026.49 KiB = 1.00 MiB
Load Address: 00000000
Entry Point:  00000000

uRamdiskは以下のような感じで作られる

ls
-rw-rw-r--  1 aaaaa aaaaa 1051193 Dec 31 16:19 uRamdisk

参考にしたサイトの通り、 ramdiskというディレクトリを作って、カーネルイメージとRAMDISKをおいた。

mkdir ramdisk
cp linux-6.12.63/arch/arm64/boot/Image ramdisk/.
cp uRamdisk ramdisk/.

QEMUを起動するコマンドは、以下の通り。ramdiskというディレクトを指定している。

qemu-system-aarch64 \
    -bios u-boot/u-boot.bin \
    -machine virt \
    -cpu cortex-a72 \
    -m 1G \
    -nographic \
    -drive file=fat:rw:"./ramdisk",format=raw,if=none,media=disk,id=drive0 \
    -device virtio-blk,drive=drive0

U-Bootが起動したら以下のコマンドを実行した (これも参考にしたサイトの通りに実行した)。
すると、Busyboxのシェルが起動するようになった。

load virtio 0 $kernel_addr_r Image
load virtio 0 $ramdisk_addr_r uRamdisk
booti $kernel_addr_r $ramdisk_addr_r $fdt_addr

さらにコンパクトなLinuxカーネルを作ってみる

defconfigだと、コンパイル時間がそれなりにかかったので、allnoconfigをベースに必要なconfigのみを設定してスリムにしてみる。
Linux を(わりと)シンプルな構成でビルドして Qemu で起動するを参考にした。

[*] 64-bit kernel

-> General setup
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
-> General setup
  -> Configure standard kernel features
[*] Enable support for printk

-> Executable file formats / Emulations
[*] Kernel support for ELF binaries

-> Device Drivers
  -> Character devices
[*] Enable TTY

-> Device Drivers
  -> Character devices
    -> Serial drivers
[*] 8250/16550 and compatible serial support
[*]   Console on 8250/16550 and compatible serial port

実際のところ、以下のようなコンフィグファイル(qemu-busybox-min2.config)を作成して、組み込んだ。
足したのは、最後の2行のみ。

CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y

CONFIG_GPIOLIB=y
CONFIG_GPIO_PL061=y

CONFIG_KEYBOARD_GPIO=y

CONFIG_CMDLINE="console=ttyAMA0 nokaslr rdinit=/sbin/init"
#
CONFIG_BLK_DEV_INITRD=y
CONFIG_BINFMT_ELF=y

Discussion