VideoCore4で動くrpi-open-firmwareを試す


ベアメタルRaspberry PiのMicroPythonのほうへ、「VideoCore4で動かすことは考えてみた?」というコメントを頂きました。

VC4 baremetal? · Issue #23 · boochow/micropython-raspberrypi

VideoCore4(以下VC4)はRaspberry PiのGPUとして使われているシステムの名称です。
VC4を使う、というと、Idein, IncがVC4をGPGPUとして使って、画像認識モデルを高速に動作させたデモが最近では有名です。
私もそのうち試してみたいなあと思っていたところでした。

が、今回頂いたコメントはGPUをGPGPUとして使うというのとは違います。
GPGPUでは、QPU(Quad Processer)という並列演算プロセッサを使って計算を行うのがポイントですが、今回の話ではQPUはメインではなく、VPUというVC4を制御しているCPU上でMicroPythonを動かすのはどうか、というお話でした。

Raspberry Piの起動シーケンスは

(1)GPUがまず起動し、
(2)bootcode.binとstart.elfを読み込んで実行し、
(3)それらがハードウェアを初期化してARM用のカーネルを読み込みARMコアを起動する

という順で動作します。
この処理は実際にはVPUが行っているわけですが、そのVPUが最初に実行するコードであるbootcode.binをMicroPythonに置き換えてしまうのは興味ないか?ということです。

通常私達が「Raspberry PiのGPU」と呼んでいるものは、VC4というシステムで、そのシステムはVPUとQPUから成り、ThreadXというOSで動作しています。

このVPUというプロセッサの素性はかなり解析されていて、gccも移植されています。

VideoCore IV Programmers Manual · hermanhermitage/videocoreiv Wiki

また、VPU上で動作するrpi-open-firmwareというソフトウェアが開発されており、これを使ってLinuxカーネルの起動もできるそうです。

christinaa/rpi-open-firmware: Open source VPU side bootloader for Raspberry Pi.

国内では、GPUでLチカを動作させてみたという記事がありました。

Raspberry Pi ZeroでLチカする – Qiita

今回は、rpi-open-firmwareを実際にビルドして動かしてみました。

まずは、以下のVC4用toolchainをビルドします。

itszor/vc4-toolchain: A port of the GNU toolchain to the Raspberry Pi's VideoCore4 processor.

ビルドの仕方はドキュメントにありますが、Debianの場合についてのみ書かれています。
私の環境はUbuntu 16.04なので若干異なり、gccもv6ではなくv5.4ですが、一応ビルドできました。
なお、ビルドにあたってはディスクスペースが5.6GBほど必要になります。時間も結構かかります。


check.shを動かすとクロスコンパイラのテストができます。これもかなり時間がかかります。
私の環境では以下のような結果になりました。

		=== gcc Summary ===

# of expected passes		64423
# of unexpected failures	2164
# of unexpected successes	6
# of expected failures		98
# of unsupported tests		1556

		=== g++ Summary ===

# of expected passes		79706
# of unexpected failures	1978
# of expected failures		261
# of unresolved testcases	3
# of unsupported tests		4109

failしているものが結構ありますが、rpi-open-firmwareをコンパイルする限りにおいては問題ありませんでした。

source ./env.sh

でtoolchainにpathを張ることができます。

pathを張ったらrpi-open-firmwareのビルドですが、これはgit cloneし、gcc-teststubをcheckoutしてmakeするだけです。
なお、先にarm_chainloader/をmakeしておく必要がありました。

バイナリはbuild/bootcode.binにできています。サイズは77,776バイトでした。
これをSDカードにコピーして、Raspberry Piに挿すと実行されます。

シリアルポートはmini UARTなので、結線は普通にベアメタルプログラミングをする場合と同じで、8番ピンがTX(シリアルインタフェースモジュールのRXに接続)、10番ピンがRX(シリアルインタフェースモジュールのTXに接続)です。

コマンドは、まだ動作未確認ですが、rpi-open-firmware/romstage.cを見ると

? : 「OK」を表示
L : XMODEMで実行ファイルをダウンロード
G : ダウンロードしたコードを実行
T : 300秒後にリセット
R : リセット

となっています。ダウンロードするアドレスは0x20000からとなっています。

このコマンドはvc4-toolchainに付属のvc4-toolchain/rpirun.cと組み合わせて使う想定のようです。

bootcode.binの出力を自分のメモ用に貼っておきます。

=========================================================
::
:: kFW for bcm2708, Copyright 2016, Kristina Brooks.
::
:: BUILDATE  : Feb 10 2019 12:33:25
:: BUILDSTYLE: OPENSOURCE
::
=========================================================
CPUID    = 0x4000104
LoadAddr = 0x80000200
TB_BOOT_OPT = 0x0
[SDRAM:sdram_init]: (0) SD_CS = 0x794200
[SDRAM:switch_to_cprman_clock]: switching sdram to cprman clock (src=1, div=1), waiting for busy (4011) ...
[SDRAM:switch_to_cprman_clock]: busy set, switch complete!
[SDRAM:reset_phy]: reset_phy: resetting SDRAM PHY ...
[SDRAM:reset_phy]: reset_phy: resetting DPHY CTRL ...
[SDRAM:reset_phy_dll]: resetting aphy and dphy dlls ...
[SDRAM:reset_phy_dll]: waiting for dphy master dll to lock ...
[SDRAM:reset_phy_dll]: dphy master dll locked!
[SDRAM:sdram_init]: waiting for SDUP (210242) ...
[SDRAM:sdram_init]: SDRAM controller has arrived! (218E42)
[SDRAM:calibrate_pvt_early]: DPHY_CSR_DQ_PAD_DRV_SLEW_CTRL = 0x333
[SDRAM:calibrate_pvt_early]: waiting for address PVT calibration ...
[SDRAM:calibrate_pvt_early]: waiting for data PVT calibration ...
[SDRAM:calibrate_pvt_early]: waiting for SDRAM calibration command ...
[SDRAM:sdram_init]: SDRAM Type: Elpida 512MB LPDDR2 (BC=0x18)
[SDRAM:sdram_init]: *** USING LOW tREFI (~7.8us) FOR 512MB, YOUR RAM MAY LEAK!!!!
[SDRAM:reset_with_timing]: waiting for SDRAM controller to go down (218E4A) ...
[SDRAM:reset_with_timing]: SDRAM controller down!
[SDRAM:reset_with_timing]: SDRAM clock disabled!
[SDRAM:reset_with_timing]: waiting for master ddr pll to lock ...
[SDRAM:reset_with_timing]: master ddr pll locked!
[SDRAM:reset_with_timing]: SDRAM Addressing Mode: Bank=2 Row=2 Col=2 SB=0xDA
[SDRAM:reset_phy_dll]: resetting aphy and dphy dlls ...
[SDRAM:reset_phy_dll]: waiting for dphy master dll to lock ...
[SDRAM:reset_phy_dll]: dphy master dll locked!
[SDRAM:reset_with_timing]: waiting for address dll to lock ...
[SDRAM:reset_with_timing]: address dll locked!
[SDRAM:selftest]: Starting self test ...
[SDRAM:selftest_at]: Testing region at 0xC0000000 ...
[SDRAM:selftest_at]: Testing region at 0xCFF00000 ...
[SDRAM:selftest_at]: Testing region at 0xDFF00000 ...
[SDRAM:selftest]: Self test successful!
SDRAM initialization completed successfully!
Attempting relocation...
Middle state from uncached SDRAM: continue from 0xc0021454
Successfully relocated boot code! (Continuing from 0x14ae)
>>> Test harness starting

コメント