Zircon の QEMU 用ブートローダ(aarch64)
本記事では、aarch64 用 Zircon カーネルを QEMU 上で起動させるときの動作を紹介します。
Zircon の QEMU ブート(aarch64) の続きです。
qemu-boot-shim
主な処理
- 命令・データキャッシュと MMU を無効にする
- QEMU が用意した DTB から必要な情報を抜き出し、
fuchsia-ssh.zbi
へ追記する -
fuchsia-ssh.zbi
中のphysboot
を ZBI データの後方へコピーする -
physboot
へジャンプする
主要ソースコードの関係
主要なソースコード
-
boot-shim.S
アセンブラで CPU の状態を設定 -
boot-shim.c
メイン関数 -
zbi.c
ZBI の解析、追記 -
devicetree.c
Device Tree Blob の解析
boot-shim.S の概要
キャッシュと MMU を無効化
SCTLR_EL2
レジスタの I,C,M
ビットをクリアして、キャッシュと MMU を無効化します。
Bit | Description |
---|---|
I, bit [12] | Instruction access Cacheability control, for accesses at EL2 |
C, bit [2] | Cacheability control, for data accesses |
M, bit [0] | MMU enable for EL2 stage 1 address translation |
— D13.2.114 SCTLR_EL2, System Control Register (EL2), Arm® Architecture Reference Manual
SCTLR_EL2
レジスタ変更後、
- システムレジスタ変更の反映のために、
ISB
を実行 - キャッシュアクセスを完了するために、
DSB SY
を実行
スタックの用意
boot-shim のメモリマップ
Address | Size | Section |
---|---|---|
0x00000000 | 0x0090 | .text.boot0 |
0x00000090 | 0x16AC | .text |
0x00001740 | 0x03B9 | .rodata |
0x00001AFC | 0x0004 | .data |
0x00001B00 | 0x1010 | .bss |
スタック
Address | Symbol |
---|---|
0x00001B10 | stack |
0x00002B10 | stack_end |
.bss
セクション内の 4096 Byte がスタック領域です。
実際のアドレスは、boot-shim がロードされた 0x40080000 にオフセット 0x00002B10 を加算した、0x40082B10 となります。
SP
レジスタに 0x40082B10 をセットして、スタックとして使用可能にします。
boot_shim()を呼び出す
boot-shim.c の boot_shim() を実行します。
引数
Register | Value | Description |
---|---|---|
x0 | 0x49800000 | Device Tree Blob |
戻り値
Register | Value | Description |
---|---|---|
x0 | 0x48000000 | ZBI データ |
x1 | 0x4989436c | physboot のエントリポイント(_start ) |
戻り値は、x0、x1 レジスタに格納されています。
physboot エントリポイントへジャンプ
physboot へ渡す情報
Register | Value | Description |
---|---|---|
x0 | 0x48000000 | ZBI データ |
x1 | 0x4989436c | physboot のエントリポイント(_start ) |
CPU の状態
Function | Status |
---|---|
Exception Level | EL2 |
IRQ | Mask |
FIQ | Mask |
I-Cache | Disable |
D-Cache | Disable |
MMU | Disable |
メモリの状態
Load Address | Size | Description |
---|---|---|
0x40000000 | 40 | qemu bootloader |
0x40080000 | 65,536 | qemu-boot-shim.bin |
0x48000000 | 25,719,600 | fucnshia-ssh.zbi+α |
0x49890000 | 659,088 | physboot.zbi |
- DTB は fuchsia-ssh.zbi+α の α 部分にコピーされます
boot-shim.c の概要
device tree から initrd のアドレス取得
chosen {
linux,initrd-end = < 0x497887e0 >;
linux,initrd-start = < 0x48000000 >;
- initrd(fuchsia-ssh.zbi)のロードアドレス 0x48000000
その他の情報
initrd 以外にも、device tree から必要なものだけ device_tree_context 構造体に格納する。
typedef struct {
dt_slice_t devicetree;
node_t node;
uintptr_t initrd_start;
size_t memory_base;
size_t memory_size;
char* cmdline;
size_t cmdline_length;
uint32_t cpu_count;
int gic_version;
} device_tree_context_t;
-
devicetree
、node
device tree 解析中に使用する一時変数 -
initrd_start
initrd(fuchsia-ssh.zbi)のロードアドレス -
memory_base
、memory_size
RAM の開始アドレス、サイズ -
cmdline
、cmdline_length
コマンドラインオプション、サイズ -
cpu_count
CPU 数 -
gic_version
GIC のバージョン
ZBI から physboot を探す
Name | Size | Description |
---|---|---|
ZBI Header | 32 | ZBI の Container Header |
Boot Item Header | 32 | physboot の Header |
Boot Item Payload | physboot の Payload | |
... |
ZBI 中の最初の Boot Item がタイプ ZBI_TYPE_KERNEL_ARM64
(physboot)であることを確認します。
ZBI データにボード情報を追加
ZBI データの末尾に、ボード情報を個別の Boot Item として追記します。
ZBI に追加する情報は次のとおりです。
Boot Item Type | Data | Description |
---|---|---|
ZBI_TYPE_CPU_TOPOLOGY | cluster_id, cpu_id, ... | CPU トポロジー情報 |
ZBI_TYPE_NVRAM | base, length | ウォームブート時にデータを保持したままにするメモリ領域。クラッシュログ用 |
ZBI_TYPE_KERNEL_DRIVER (KDRV_PL011_UART) |
mmio_phys,irq | UART ドライバ設定 |
ZBI_TYPE_KERNEL_DRIVER (KDRV_ARM_GIC_V3) |
mmio_phys,gicd_offs,... | Generic Interrupt Controller ドライバ設定 |
ZBI_TYPE_KERNEL_DRIVER (KDRV_ARM_PSCI) |
- | Power State Coordination Interface ドライバ設定 |
ZBI_TYPE_KERNEL_DRIVER (KDRV_ARM_GENERIC_TIMER) |
irq_phys,irq_virt | タイマドライバ設定 |
ZBI_TYPE_PLATFORM_ID | vendor_id,product_id | ベンダ ID、プロダクト ID |
ZBI_TYPE_SERIAL_NUMBER | serial_number | シリアル番号 |
ZBI_TYPE_MEM_CONFIG (ZBI_MEM_RANGE_PERIPHERAL) |
memory_base, memory_size | 周辺機器のメモリマップド I/O 領域 |
ZBI_TYPE_MEM_CONFIG (ZBI_MEM_RANGE_RAM) |
memory_base, memory_size | RAM の領域 |
ZBI_TYPE_CMDLINE | cmdline | コマンドラインオプション |
ZBI_TYPE_DEVICETREE | DTB | Device Tree Blob |
- QEMU の
virt
ボードが提供するドライバなどを決め打ちで指定しています - DTB から取得するのは、qemu コマンドの引数で決定する情報、qemu が決定する情報でした
- 追加前サイズ 24,676,320 → 追加後サイズ 25,719,600
大部分は DTB
physboot を ZBI データの後方へコピー
fuchsia-ssh.zbi
の後方、4KiB 境界にコピーします。
+----------+-------------------+---------+--------+---------+
|ZBI Header|Boot Item(physboot)|Boot Item| ... |Boot Item|
+----------+-------------------+---------+--------+---------+
| | ^
+--------------+---------------+ |
| copy |
+---------------------------------------------------------+
-
fuchsia-ssh.zbi+α
図中の赤い部分(physboot.zbi と呼称)を、アドレス 0x49890000 へコピーします。
コピー先 ZBI Header の length を更新します。
Address | Description | |
---|---|---|
コピー元 | 0x48000000 | fucnshia-ssh.zbi+α |
コピー先 | 0x49890000 | physboot.zbi |
コピー後のメモリ
Load Address | Size | Description |
---|---|---|
0x48000000 | 25,719,600 | fucnshia-ssh.zbi+α |
0x49890000 | 659,088 | physboot.zbi |
まとめ
-
QEMU と実機の差異を吸収
- physboot 以降は、QEMU・実機ともに同じコードを実行する
- 実機では U-Boot が行う処理を qemu-boot-shim で隠蔽する
-
QEMU が用意した状態を、physboot 呼び出しに適した形に変更する
- QEMU が用意した device tree を ZBI データに移す
- QEMU が用意した device tree を ZBI データに移す
Discussion