2020年9月22日火曜日

Ubuntu 20.04 で Raspberry Pi 3B のUSBブートを有効にする

以前買った Raspberry Pi 3B で時々遊んでいる。
最初はRaspbianを入れていたが、途中でLubuntuにしていたが、最近では、Ubuntu20.04を使っている。PCでもUbuntuなので、統一しておいたほうが便利だからだ(とはいえ、PCはbionic、RaspberryPiはfocal)。

以前、PCでUSB Bootable Ubuntuを、普通に使っていたことがある。8GBのUSBメモリだったが、毎日使っていると1ヶ月ぐらいでUSBメモリでエラーが出るようになっていた。
リムーバブルメディアの寿命は、基本的にそんなものだ。MicroSDだったとしても、大して変わらない。
しかしながら、SSDは多少事情が異なる。
SSDは頻繁に読み書きする事を前提で設計されているので、寿命が長い。
最近のUSB接続のSSDの容量が、512MBではなく480MBなど少なめの中途半端な容量になっているのは、おそらく代替え領域などを多めに確保しているためだろう(未確認。詳細不明)。
RaspberryPiもUSBポートがあるので、USB接続のSSDが使える。
本格的に使うなら1ヶ月で壊れるものは使いにくい。SSDの方がMicroSDよりもいい。
以前、どこかでRaspberryPi3BでもUSBブートできるという記事を読んでいたので、それをやってみようと思った。

もう一度調べ直すと、おおよそ
  • OTP(One Time Programable)領域の特定のビットをセットする。
  • セットするには、/boot/config.txtの末尾に、"program_usb_boot_mode=1"を書き込んでリブートする。
  • 確認には、vcgencmdコマンドを使う。
ということだ。難しそうな所はない。
過去に調べた時、そのような操作をしたような気もするが、不可逆的なので躊躇していたようにも思う。Raspbianを使っていた頃のことなので、もうだいぶ時間が経っている。記憶があやふやだ。

確認しようとして、Ubuntu20.04で、vcgencmdを起動しようとしたら、動かない。
focal(Ubuntu20.04)には、vcgencmdが入っていないのだ。
ネットで調べると、PPAを設定して入れる方法が見つかったが、focalでは動かない。focal用のものが用意されていないようだ。
OTPの物理アドレスが解ればアクセスできるかと思ってそれを調べたが、この記事の中ぐらいに、以下のような書き込みを見つけた。
That's impossible to do because of the closed source GPU code. 
There's no user API to access any OTP memory.
自分なりに訳すと、
それを行うのは不可能だ。なぜならクローズドソースのGPUコードだからだ。
あらゆるOTPメモリをアクセスするユーザAPIは無い。
直接アクセス可能な物理メモリ空間にあるのではなく、GPU経由でアクセスするメモリに存在しているようだ。これでは読めない。

やはり、なんとしてもvcgencmdを動かさないといけない。
色々調べると、githubでuserlandのソースが管理されている事がわかった。
以下のようにして、gitリポジトリをクローンする。
git clone https://github.com/raspberrypi/userland.git
サブディレクトリ userland/ ができている。
スクリプトのbuildmeを読むと、uname -mの戻り値によっては、セルフビルドするようになっている。ただし、cmakeをインストールする必要がある。
ビルドツール類をまだ入れていないなら、それらもまとめてinstallしてしまおう。
以下のようにする。
sudo apt install cmake build-essential
後はビルドするだけだ。

git cloneでできたサブディレクトリuserland/へ移動して、buildmeを実行する。
cd userland
./buildme
なんだかんだ色々表示されてビルドが終わる。終了後、/opt/vc/以下に様々な生成物がinstallされている。
もちろん念願のvcgencmdも/opt/vc/bin/の下にある。

ビルドはできたが、このままでは、ライブラリパスも実行パスも通っていない。
まずは、ライブラリパスを通す。
ファイル /etc/ld.so.conf.d/00-vmcs.conf を以下の内容で作成する。
/opt/vc/lib
この状態で、"sudo ldconfig"を実行し、ライブラリパスをキャッシュする。
sudo ldconfig
これで、ライブラリパスの設定はおわり。

つづいて、実行パスも通すのだが、vcgencmdはsudo経由で実行しなければならないため、/etc/sudoersファイル内の、Default secure="..."に、"/opt/vc/bin/"を追加する。
また、このファイルは、直接編集できない。"sudo -e /etc/sudoers" で編集する。
結果的にその行はウチでは以下のようになった。
Defaults	secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/opt/vc/bin"
これで、vcgencmdが実行できるはずだ。 以下のようにして、vcgencmdを実行してみたら、
$ sudo vcgencmd otp_dump | grep '^17:'
17:1020000a
うーん。これではUSBブートできない。3020000aでないといけない。
不可逆な変更なので、躊躇していたようだ。
それにしても、たった1bit確認するだけで、細かく色々、どんだけ手間がかかるんだ。

USBブートがセットされてないことが解ったので、セットしよう。
セットするには、/boot/config.txtの末尾に、"program_usb_boot_mode=1"を書き込んでリブートするらしいのだが、Focalでは/boot/config.txtが存在しない。
Raspbianのイメージをダウンロードして調べてみると、MicroSDの第一パーティション(FATフォーマット)のconfig.txtだ。
Focalでそれは/boot/firmware/config.txt だ。
そのため、以下のようにして書き込む。
echo program_usb_boot_mode=1 | sudo tee -a /boot/firmware/config.txt
これで、再起動してOTP領域を確認すると、
$ sudo vcgencmd otp_dump | grep '^17:'
17:3020000a
よしよし。やっとUSBブートのセットができた。

これで全てではない。
ダウンロードしてきたイメージをUSBでブートできるようになったのだが、実際に使うにはもう少し手間がかかる。
1ビット確認して、1ビット書き換えただけで、妙に長くなってしまったので、とりあえず今回はここまで。

つづく。

0 件のコメント:

コメントを投稿