Zircon の QEMU ブート(aarch64)
本記事では、aarch64 用 Zircon カーネルを QEMU 上で起動させるときの動作を紹介します。
Zircon 起動の流れ
-
qemu-boot-shimQEMU 上で physboot を起動するためのブートローダ[1]
-
physboot圧縮された Zircon カーネルイメージを展開するブートローダ[2]
-
zirconZircon カーネルイメージ
本記事では、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.12QEMU で使用する 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_offsetqemu/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 1233125376x0が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