Zircon の QEMU ブート(aarch64)
本記事では、aarch64 用 Zircon カーネルを QEMU 上で起動させるときの動作を紹介します。
Zircon 起動の流れ
-
qemu-boot-shim
QEMU 上で physboot を起動するためのブートローダ[1]
-
physboot
圧縮された Zircon カーネルイメージを展開するブートローダ[2]
-
zircon
Zircon カーネルイメージ
本記事では、QEMU
の部分を紹介します。
イメージファイル
Zircon の起動には 2 つのイメージファイルが必要です。
-
qemu-boot-shim.bin
-
qemu-boot-shim
ブートローダの実体
-
-
fuchsia-ssh.zbi
-
physboot
と圧縮Zirconカーネルイメージ
などを含むイメージファイル - ZBI データ構造についてはこちらの記事を参照
-
QEMU
Fuchsia 開発環境では、 fx qemu
コマンドを使って QEMU 上で Zircon カーネルおよび Fuchsia OS を起動します。
fx qemu
コマンドは最終的に次のコマンドを実行します。
qemu-system-aarch64 -kernel qemu-boot-shim.bin -initrd fuchsia-ssh.zbi \
-m 8192 -machine virt-2.12(以下略)
-
-kernel qemu-boot-shim.bin
qemu-boot-shim.bin
をメモリへロードし、エントリポイントへジャンプする -
-initrd fuchsia-ssh.zbi
fuchsia-ssh.zbi
を RAM ディスクとしてメモリへロードする -
-m 8192
メモリ 8GiB -
-machine virt-2.12
QEMU で使用する aarch64 ボードに virt を指定する
qemu コマンドの詳細は付録を参照。
virt のメモリマップ
Address | Size | Description |
---|---|---|
0x00000000 | 0x40000000 (1GiB) | device I/O |
0x40000000 | 0x200000000 (8GiB) | RAM |
RAM
はアドレス 0x40000000
から開始します。
イメージファイルのロードアドレス
QEMU は qemu-boot-shim.bin
と fuchsia-ssh.zbi
をメモリにロードします。
Load Address | Size | Description |
---|---|---|
0x40080000 | 65,536 | qemu-boot-shim.bin |
0x48000000 | 24,676,320 | fucnshia-ssh.zbi |
ロードアドレス決定の詳細は付録を参照。
Device Tree Blob の作成
virt
ボードの場合、DTB(Device Tree Blob)は QEMU が生成します。
DTB の内容
qemu-boot-shim
で使用する情報だけ掲載します。
-
CPU 情報
例cpu@0 { reg = < 0x00 >; enable-method = "psci"; compatible = "arm,cortex-a57"; device_type = "cpu"; }; cpu@1 {...}; cpu@2 {...}; cpu@3 {...};
- CPU 数 4
-
メモリ情報
例memory@40000000 { reg = < 0x00 0x40000000 0x02 0x00 >; device_type = "memory"; };
- 開始アドレス 0x00000000_40000000
- サイズ 0x00000002_00000000(8 GiB)
-
割り込みコントローラ情報
例intc@8000000 { (省略) compatible = "arm,gic-v3";
- gic(Generic Interrupt Controller)のバージョン 3
-
initrd(fuchsia-ssh.zbi)情報
例chosen { linux,initrd-end = < 0x497887e0 >; linux,initrd-start = < 0x48000000 >;
- fuchsia-ssh.zbi のロードアドレス 0x00000000_48000000
-
起動オプション
例chosen { (省略) bootargs = "TERM=xterm-256color kernel.entropy-mixin=7f9f544b87325f191bc692748707fc14d77b0055f3dbb6f8c1408bfb96db210f kernel.halt-on-panic=true ";
-
Zircon の起動オプション
TERM=xterm-256color kernel.entropy-mixin=7f9f544b87325f191bc692748707fc14d77b0055f3dbb6f8c1408bfb96db210f kernel.halt-on-panic=true
-
DTB 内容の確認方法は付録を参照。
DTB のアドレス
Load Address | Size | Description |
---|---|---|
0x40080000 | 65,536 | qemu-boot-shim.bin |
0x48000000 | 24,676,320 | fucnshia-ssh.zbi |
0x49800000 | 1,048,576 | Device Tree Blob |
DTB は 0x49800000
に配置します。
これは、fuchsia-ssh.zbi
の後方、2 MiB 境界のアドレスとなります。
また、このアドレスを x0
レジスタ経由で qemu-boot-shim
に渡します。
アドレス決定の詳細は付録を参照。
qemu-boot-shim へジャンプ
qemu-boot-shim.bin
、fuchsia-ssh.zbi
、DTB のロード後、qemu-boot-shim
のエントリポイント(0x40080000)へジャンプします。
qemu-boot-shim
へ渡す情報は次のとおりです。
Register | Value | Description |
---|---|---|
x0 | 0x49800000 | Device Tree Blob |
x4 | 0x40080000 | Entry Address |
- DTB 中に、
fuchsia-ssh.zbi
のロードアドレスが含まれています。
引数レジスタおよびジャンプの詳細は付録を参照。
ジャンプ前の状態
qemu-boot-shim
で関係のある CPU ステータスのみ掲載します。
Function | Status |
---|---|
Exception Level | EL2 |
IRQ | Mask |
FIQ | Mask |
I-Cache | Disable |
D-Cache | Disable |
MMU | Disable |
gdb にて 0x40080000
でブレークさせ、info registers
コマンドで PSTATE_EL2
、SCTLR_EL2
レジスタを確認しました。
-
PSTATE_EL2
レジスタ =0x4000_07c9
-
SCTLR_EL2
レジスタ =0x0
レジスタの詳細は付録を参照。
付録
QEMU コマンド詳細
fuchsia/prebuilt/third_party/qemu/linux-x64/bin/qemu-system-aarch64 \
-kernel fuchsia/out/default/qemu-boot-shim.bin \
-initrd fuchsia/out/default/tmp.yym/fuchsia-ssh.zbi \
-m 8192 -nographic -nic none -smp 4 -machine virtualization=true \
-cpu max -machine virt-2.12,gic-version=max \
-append 'TERM=xterm-256color kernel.entropy-mixin=7f9f544b87325f191bc692748707fc14d77b0055f3dbb6f8c1408bfb96db210f kernel.halt-on-panic=true '
-
fuchsia/prebuilt/third_party/qemu/linux-x64/bin/qemu-system-aarch64
fuchsia リポジトリに含まれている qemu コマンドを使用する -
-kernel fuchsia/out/default/qemu-boot-shim.bin
QEMU が起動するバイナリイメージファイル -
-initrd fuchsia/out/default/tmp.yym/fuchsia-ssh.zbi
RAM ディスクイメージファイル -
-m 8192
メモリ 8GiB -
-nographic
グラフィカル出力を無効 -
-nic none
ネットワークデバイスなし -
-smp 4
4 CPU -
-machine virtualization=true
QEMU で動作させる CPU の仮想化サポートを有効。
EL2(例外レベル 2)で動作する
— ‘virt’ generic virtual platform (virt) -
-cpu max
すべての CPU feature を有効 -
-machine virt-2.12,gic-version=max
QEMU が提供するボードをvirt-2.12
に指定。
Generic Interrupt Controller のバージョンをベストなものにする
— ‘virt’ generic virtual platform (virt) -
-append 'TERM=xterm-256color (省略)
起動するバイナリに DTB 経由で提供するコマンドラインオプション
qemu-boot-shim.bin のロードアドレス
*entry = mem_base + kernel_load_offset;
-
*entry
qemu-boot-shim.bin
のロードアドレスおよびエントリポイント -
mem_base
RAM の開始アドレス。今回は0x40000000
-
kernel_load_offset
qemu/hw/arm/boot.c#define KERNEL64_LOAD_ADDR 0x00080000
qemu-boot-shim.bin
のロードアドレスおよびエントリポイントは、0x40080000 となります。
fuchsia-ssh.zbi のロードアドレス
info->initrd_start = info->loader_start +
MIN(info->ram_size / 2, 128 * MiB);
-
info->initrd_start
fucnshia-ssh.zbi
のロードアドレス -
info->loader_start
RAM の開始アドレス。今回は0x40000000
-
info->ram_size
RAM のサイズ。今回は8 GiB
RAM サイズが 256MiB 以上の場合、fuchsia-ssh.zbi
は loader_start + 128MiB
(0x48000000)にロードされます。
ただし、-kernel
で指定したイメージがこの領域にある場合は、別の領域を使用します。
Device Tree Blob のアドレス
info->dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size,
align);
/* Round number down to multiple */
#define QEMU_ALIGN_DOWN(n, m) ((n) / (m) * (m))
/* Round number up to multiple. Safe when m is not a power of 2 (see
* ROUND_UP for a faster version when a power of 2 is guaranteed) */
#define QEMU_ALIGN_UP(n, m) QEMU_ALIGN_DOWN((n) + (m) - 1, (m))
-
info->dtb_start
DTB(Device Tree Blob)のアドレス -
info->initrd_start
0x48000000
-
initrd_size
0x17887e0
(23.5MiB)$ ls -l fuchsia/out/default/tmp.HA0/fuchsia-ssh.zbi -rw-r--r-- 1 junkawa junkawa 24676320 Oct 3 11:23 fuchsia/out/default/tmp.HA0/fuchsia-ssh.zbi
-
align
2MiB
(0x200000) -
アドレス
0x49800000
x0
レジスタ経由でqemu-boot-shim
に渡す(gdb) break *0x40080000 (gdb) target extended-remote :1234 Remote debugging using :1234 0x0000000040000000 in ?? () Thread 1 hit Breakpoint 1, 0x0000000040080000 in ?? () (gdb) info registers x0 0x49800000 1233125376
x0
が0x49800000
であることが確認できます
qemu-boot-shim のファイル形式
$ file fuchsia/out/default/qemu-boot-shim.bin
fuchsia/out/default/qemu-boot-shim.bin: MS-DOS executable, MZ for MS-DOS
.section .text.boot0,"ax"
FUNCTION(_start)
// magic instruction that gives us UEFI "MZ" signature
add x13, x18, #0x16
b header_end
.quad 0 // image offset from start of ram (unused)
.quad 0 // image size (unused)
.quad 0
.quad 0
.quad 0
.quad 0
// arm64 magic number
.byte 'A'
.byte 'R'
.byte 'M'
.byte 0x64
.align 3
header_end:
// x0 typically points to device tree at entry
- QEMU から
_start
にジャンプしたとき、add 命令後、b 命令でheader_end
にジャンプする
$hexdump -C -v -n 64 qemu-boot-shim.bin
00000000 4d 5a 00 91 0f 00 00 14 00 00 00 00 00 00 00 00 |MZ..............|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000030 00 00 00 00 00 00 00 00 41 52 4d 64 1f 20 03 d5 |........ARMd. ..|
00000040
Offset | Field | Value | Description |
---|---|---|---|
0x00 | Executable code | 4d,ta,00.91 | "MZ" |
0x04 | Executable code | 0f,00,00,14 | branch |
0x08 | Image load offset | 0 | unused |
0x10 | Effective Image size | 0 | unused |
0x18 | kernel flags | 0 | |
0x20 | reserved | 0 | |
0x28 | reserved | 0 | |
0x30 | reserved | 0 | |
0x38 | Magic number | 41,52,4d,64 | "ARM",0x64 |
— 4. Call the kernel image - Booting AArch64 Linux
- 圧縮 Linux カーネルのヘッダーフォーマットを利用
- 先頭に "MZ" シグネチャを利用
これは UEFI アプリケーションのシグネチャ
QEMU でのファイル形式確認
QEMU は、-kernel
で指定したファイルの形式を確認して処理を行います。
-
arm_load_elf()
ヘッダー先頭が0x7f
かどうかでELF
形式かどうかを確認 -
load_uimage_as()
ヘッダー先頭が0x27051956
かどうかでU-Boot
形式かどうか確認 -
load_image_gzipped_buffer()
ヘッダー先頭が0x1f、0x8b
かどうかでgzip
形式かどうかを確認
以上のどれも当てはまらない、今回の qemu-boot-shim.bin
ような場合、RAW イメージとして処理します。
このとき、ファイル先頭から 56 バイト目の arm64 magic number
を確認します。
qemu-boot-shim.bin
は前述のアセンブラ boot-shim.S
で見たようにこれに該当します。
ここで、ヘッダーから image offset
、image size
を取得しようと試みます。
しかし、どちらも 0 なのでこれらの値は使用されません。
以上より、MZ
による PE フォーマットも、ARM
+0x64 による arm64 magic header
も QEMU では意味のある扱いは行いません。
(調査した範囲において)
QEMU virt DTB
virt
ボードで使用する DTB を確認する方法を紹介します。
$ qemu-system-aarch64 \
-kernel fuchsia/out/default/qemu-boot-shim.bin \
-initrd fuchsia/out/default/tmp.yym/fuchsia-ssh.zbi \
-m 8192 -nographic -nic none -smp 4 -machine virtualization=true \
-cpu max -machine virt-2.12,gic-version=max \
-append 'TERM=xterm-256color kernel.entropy-mixin=7f9f544b87325f191bc692748707fc14d77b0055f3dbb6f8c1408bfb96db210f kernel.halt-on-panic=true ' \
-machine dumpdtb=aarch64-virt.dtb
qemu-system-aarch64: info: dtb dumped to aarch64-virt.dtb. Exiting.
$ dtc -o aarch64-virt.dts -O dts -I dtb aarch64-virt.dtb
-
-machine dumpdtb=aarch64-virt.dtb
を指定して、DTB をファイルに出力する -
dtc
コマンドで DTB バイナリファイルを DTS テキスト形式に変換する
参考:kaz399; QEMU aarch64 virt のデバイスツリー · uchan-nos/os-from-zero Wiki
ジャンプ前の CPU ステータス
PSTATE_EL2
0x4000_07c9
Bits | Name | Value | Description |
---|---|---|---|
31 | N | 0 | Negative condition flag |
30 | Z | 1 | Zero condition flag |
29 | C | 0 | Carry condition flag |
28 | V | 0 | oVerflow condition flag |
25 | TCO | 0 | Tag Check Override |
24 | DIT | 0 | Data Independent Timing |
23 | UAO | 0 | User Access Override |
22 | PAN | 0 | Privileged Access Never Bit |
21 | SS | 0 | Software step bit |
20 | IL | 0 | Illegal Execution state bit |
12 | SSBS | 0 | Speculative Store Bypass Safe |
11,10 | BTYPE | 0,1 | Branch Type |
9 | D | 1 | Debug mask bit |
8 | A | 1 | SError interrupt mask bit |
7 | I | 1 | IRQ mask bit |
6 | F | 1 | FIQ mask bit |
4 | nRW | 0 | not Register Width: 0=64, 1=32 |
3,2 | EL | 1,0 | Exception Level: EL2 |
0 | SP | 1 | Stack pointer select: 0=SP0, 1=SPx, use SP_EL2 |
— C5.2.18 SPSR_EL2, Saved Program Status Register (EL2), Arm® Architecture Reference Manual
QEMU は Linux カーネルの呼び出しルールに従って、CPU ステータスを設定しているようです。
参考:4. Call the kernel image - Booting AArch64 Linux
qemu-boot-shim 実行の詳細
QEMU は数十バイトのブートローダを介して qemu-boot-shim
を実行します。
QEMU はブートローダを RAM の先頭(0x40000000)に配置し、そこへジャンプします。
ldr x0, arg
mov x1, xzr
mov x2, xzr
mov x3, xzr
ldr x4, entry
br x4
arg:
.word 0x49800000
.word 0
entry:
.word 0x40080000
.word 0
- arg
DTB のアドレス - entry
qemu-boot-shim.bin のアドレス
Register | Value | Description |
---|---|---|
x0 | 0x49800000 | Device Tree Blob |
x1 | 0 | |
x2 | 0 | |
x3 | 0 | |
x4 | 0x40080000 | Entry Address |
ブートローダは、レジスタを上記の状態にして、qemu-boot-shim のエントリポイントへジャンプします。
Discussion