目次: Linux
OpenSBIのブート部分を調べます。OpenSBIはいくつか動作モードがあるのですが、payloadを持ったタイプを調べます。対象のファイル名はbuild/platform/generic/firmware/fw_payload.binもしくは.elfです。
今回はOpenSBIを見る前にQEMUの動作、デバイスツリーの扱いについて調べます。実行環境はQEMU RV64 virt machine(qemu-system-riscv64 -machine virt)です。なぜ突然QEMUの話をするかというと、OpenSBIはQEMUからデバイスツリーを受け取るからです。OpenSBIを調べる前にQEMUがわかっていた方が理解しやすいです。
QEMUは-dtbオプションにてデバイスツリーファイルを明示的に指定できます。もし-dtbオプションを省略するとHW構成に従ってデバイスツリーを自動生成します。便利ですね。明示的に指定した場合、自動生成した場合いずれであってもQEMUのメモリの何処かにデバイスツリーのデータを展開します。
OpenSBIを起動するときはレジスタa0にhartid、レジスタa1にデバイスツリーのアドレスを渡す決まりがあります。
####opensbi/docs/firmware/fw.md#### OpenSBI Platform Firmwares ========================== OpenSBI provides firmware builds for specific platforms. Different types of firmwares are supported to deal with the differences between different platforms early boot stage. All firmwares will execute the same initialization procedure of the platform hardware according to the platform specific code as well as OpenSBI generic library code. The supported firmwares type will differ in how the arguments passed by the platform early boot stage are handled, as well as how the boot stage following the firmware will be handled and executed. The previous booting stage will pass information via the following registers of RISC-V CPU: * hartid via *a0* register * device tree blob address in memory via *a1* register. The address must be aligned to 8 bytes. (適当訳) OpenSBIは特定のプラットフォーム用のファームウェアビルドを提供します。初期ブートローダーでの 異なるプラットフォーム間の違いに対処するため、いろいろな種類のファームウェアがサポートされています。 全てのファームウェアはプラットフォーム固有のコードとOpenSBIの汎用ライブラリのコードに従って、 プラットフォームHWの同じ初期化処理を実行します(訳注: 何を言いたいかよくわからん……)。 サポートされているファームウェアの種類は、プラットフォームの初期ブートローダーから渡された引数が どのように処理されるかと、ファームウェアに続く起動段階がどのように処理され実行されるかによって異なります。 直前のブートローダーは、次のRISC-V CPUレジスタ経由で情報を渡します: * レジスタa0経由でhartid * レジスタa1経由でメモリ上のデバイスツリーブロブ(訳注: *.dtbのこと)のアドレス、アドレスは8バイトアラインが必要
QEMUの場合はブートROMコード(qemu-system-riscv64 -machine virtの場合はアドレス0x1000付近)がレジスタa1にアドレスを設定します。コードの逆アセンブルはこんな感じです。
0x1000: auipc t0,0x0 //t0 <- 0x1000 0x1004: addi a2,t0,40 //a2 <- 0x1028 0x1008: csrr a0,mhartid //a0 <- hartid 0x100c: ld a1,32(t0) //a1 <- 0x87e00000(アドレス0x1020の値) 0x1010: ld t0,24(t0) //t0 <- 0x80000000(アドレス0x1018の値) 0x1014: jr t0 //0x80000000にジャンプ(OpenSBIの先頭) 0x1000: 0x00000297 0x02828613 0xf1402573 0x0202b583 0x1010: 0x0182b283 0x00028067 0x80000000 0x00000000 0x1020: 0x87e00000 0x00000000 0x4942534f 0x00000000 0x1030: 0x00000002 0x00000000 0x80000000 0x00000000
QEMUはリセットすると必ずブートROMコードから実行開始しますから、常にレジスタa1に0x87e00000(-m 128MBの場合、メモリ量に依存してアドレスが変わる)を設定してからOpenSBIにジャンプすることがわかります。アドレス0x87e00000付近の内容をダンプすると、
0x87e00000: 0xedfe0dd0 0x201c0000 0x38000000 0x341a0000 0x87e00010: 0x28000000 0x11000000 0x10000000 0x00000000 0x87e00020: 0xec010000 0xfc190000 0x00000000 0x00000000 0x87e00030: 0x00000000 0x00000000 0x01000000 0x00000000 0x87e00040: 0x03000000 0x04000000 0x1d000000 0x02000000 0x87e00050: 0x03000000 0x04000000 0x11000000 0x02000000 0x87e00060: 0x03000000 0x0d000000 0x06000000 0x63736972 0x87e00070: 0x69762d76 0x6f697472 0x6d657100 0x03000000
なるほど、このデータはデバイスツリーですね……と思える人は相当デバイスツリー通です。私はわかりませんので、データが何者か調べるため先頭にある謎の値0xedfe0dd0に注目します。
デバイスツリーのドキュメント(5. Flattened Devicetree (DTB) Format)を見るとヘッダは下記のようになっています。先頭のmagicメンバーはマジックナンバーであり、ビッグエンディアンの0xd00dfeedでなければならないと記述されています。
struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
メモリ上にあった謎の値0xedfe0dd0をビッグエンディアンで解釈すると0xd00dfeedとなり、struct fdt_headerのマジックナンバーと一致しました。このデータはきっとデバイスツリーでしょう。
まとめるとQEMU(qemu-system-riscv64 -machine virt)のブートROMコードは、
このような動作をします。
QEMUが自動生成したデバイスツリーをファイルにダンプする方法をメモしておきます。簡単に言えばQEMU Monitorでdumpdtb (file名)コマンドを実行すればダンプできます。
QEMU Monitorを使うにはいくつか手があります。グラフィック環境が使えるなら-nographicと-monオプションを外し、ウインドウから入力するのが一番早いでしょう。
# グラフィック環境が使えるとき ./qemu-system-riscv64 \ -machine virt \ -bios none \ -chardev stdio,id=con,mux=on \ -serial chardev:con \ -smp 4
こんなウインドウが表示されるはずです。
グラフィック環境がない場合はシリアル出力を一時的に無効化して、-monを標準入出力に振り向けると使えるようです。
# グラフィック環境が使えないとき ./qemu-system-riscv64 \ -machine virt \ -bios none \ -nographic \ -chardev stdio,id=con,mux=on \ -chardev null,id=none,mux=on \ -serial chardev:none \ -mon chardev=con,mode=readline \ -smp 4 QEMU 9.0.2 monitor - type 'help' for more information (qemu) dumpdtb virt.dtb info: dtb dumped to virt.dtb (qemu)
もっとスマートなやり方がありそうですけど……使えればよしとしましょう。
QEMUは起動時にデバイスツリーを自動生成もしくはファイルからロードしてくれることがわかりました。次回はOpenSBIでデバイスツリーをどう扱っているか調べたいと思います。
< | 2024 | > | ||||
<< | < | 07 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | - | - | - |
合計:
本日: