タイトルの通り、Raspberry PiでBIOSを焼いたときの体験についてまとめてみたいと思います。
要約
- 自作PCのマザーボード(MSI B450M PRO-VDH PLUS)でBIOSアップデートに失敗した
- USBメモリへBIOSイメージファイルを書き込んだ際に何らかの原因でファイルが破損したことが原因と思われる
- マザーボードにBIOSアップデートの際にイメージファイルを検証する機能が無いと思われる
- Raspberry Piとマザーボード上のFlash ROMを接続し、flashromコマンドによりBIOSイメージファイルを書き込み復旧した
- Raspberry Piのpin headerは(一部を除いて)3.3Vで入出力するのに対して、今回のマザーボードには1.8Vで動作するFlash ROMが搭載されていたため、電圧を変換する必要があった
- そこで三端子レギュレーターとレベル変換モジュールを使用したレベルシフト回路をブレッドボード上に構築し使用した
- 同様のトラブルの防止のためには、BIOSイメージファイルをUSBメモリへ書き込んだ後に必ず検証することが有効だと思われる
お断り
- 電子工作要素を含みますが、あまり詳しくない人間がやっていることなので間違いがあるかもしれません
- このような記事を読むとBIOSアップデート怖い、絶対やらないようにしようと思う方もいらっしゃると思いますが、CPUなどに起因する脆弱性への対処にはBIOSアップデートを必要とするケースがあるので、メーカーが推奨するアップデートはちゃんと適用しましょう
- 本稿でBIOSと呼んでいるものは正確にはUEFIファームウェアなどと呼んだ方が正しいかもしれませんが、一般的な呼ばれ方やマザーボードメーカーの呼び方に合わせてBIOSと呼びます
BIOSが吹っ飛んだ
事の始まりは去年末、親族が所有するPC(メーカー:私)のメンテナンス作業でした。
Windowsやインストールされているソフトウェアのセキュリティーアップデート等を確認・適用したり、ウイルススキャンをかけるといったお決まりの作業をしている中、PCの調子が悪いことに気付きました。
どのような不調かというと、
- アップデートなどで再起動する際にWindowsがシャットダウンしたまま起動しない
- 「電源を切らないでください」などのメッセージは消え、画面出力がない状態
- 電源ボタンの長押しにより強制終了してから起動すると正常にWindowsが起動する
といったものです。
もちろん、手動で電源を切る必要のあるPC(APM・ACPI非対応機?)ではないので、症状からWindowsとBIOSのどちらかの不具合かそれらの(対応バージョンなどの)不整合であると判断しました。
そのため、とりあえずBIOSアップデートでもして様子を見ようと思い、メーカーWebサイトから最新のBIOSをダウンロードしてUSBメモリに書き込み、BIOSメニューからアップデートを実行しました。
アップデートが完了しPCが再起動したところ......
完全に起動しなくなりました
チーン
具体的な症状は、
- 電源を入れるとファンがフル回転で回り、そのまま起動しない
- 正常だとCPU温度などに応じて回転数が制御される
- MSIマザーボードに搭載されているEZ Debug LEDのCPUが点灯したままになる
- BOOT/VGA/DRAM/CPUの4つのLEDがあり、異常箇所が点灯する
- CPU LEDの点灯はCPU故障の他にBIOS破損で点灯する例がネット上で見つけられる
といったものです。
(一応)故障診断と仮復旧
症状や起動しなくなったタイミングからしてほぼ確実にBIOSアップデートがきっかけ = BIOS破損が原因だと予測できますが、念の為原因の切り分けをしました。
まず、CMOSクリアを実施しました。
マザーボード上のボタン電池を外し、CMOSクリアピンをショートさせます。
残念ながら効果はありませんでした。
続いて、故障したパーツを特定するために、自宅から故障したPCと同じSocket AM4というCPUソケットが付いているマザーボードの在庫(AMDerなら2〜3枚は持ってますよね?)を探し、CPU・メモリ・GPU・SSDを移植します。
なお、電源・ケースに関しては元のマザーボードがMicroATXなのに対して交換品がMini-ITX規格なので別の在庫品を使用していますが、今回の故障とは関係ないと判断しました。
結果、新たに組んだPCは正常に起動したのでマザーボードの故障であると絞り込めました。
(また、修理中に親族に使ってもらうPCができました。AM4マジ便利)
原因調査
次に、BIOSアップデートに使用したUSBメモリを確認します。
USBメモリに書き込まれたBIOSイメージファイルと、メーカーWebサイトからダウンロードしたファイルを比較してみます。
すると...
tango@pc $ diff /mnt/usb/E7A38AMS.9E0 Downloads/7A38v9E/E7A38AMS.9E0
バイナリーファイル /mnt/usb/E7A38AMS.9E0 とDownloads/7A38v9E/E7A38AMS.9E0 は異なります
異なります
異なっていました。
バイナリエディタなどで中身を調べたところ、途中までは一致するもののUSBメモリに書き込まれたファイルには途中からPDFのヘッダのようなものが出現していたので、以前USBメモリに書き込んだファイルと混ざっているのではないかと思われます。
このことから、今回のトラブルの原因について以下のような推測ができます。
- アップデートのためにBIOSイメージファイルを書き込んだ際、USBメモリに正常に書き込めていなかった
- 使用したUSBメモリが9年ほど前に購入したものなので、劣化などにより書き込み時に一部のセルに書き込めなかった(書き換わらなかった?)ハードウェア的なトラブルの可能性が高いと推測
- 他に、書き込みが完了する前にPCから取り外した人為的ミスの可能性もある
- BIOSアップデートを実行した段階でデータが壊れた可能性もあるが、アップデータにUSBメモリへの書き込み機能が無さそうなことやファイルの壊れ方から可能性は低いと推測
- BIOSのアップデーターにイメージファイルを検証する機能が無く、壊れたファイルをそのままフラッシュROMに書き込んでしまった
- 検証機能がないことは、アップデート中の画面表示やハッシュ・署名などが埋め込まれて無さそうなイメージファイルの形式からの推測
BIOSやファームウェアのアップデートにUSBメモリを使う際は、書き込みが正常に行えたかを必ずチェックした方が良いという教訓が得られました。
言い訳みたいになりますが、普段使用している自作デスクトップPCやメーカー製ノートPCではBIOSアップデーターにファイル検証機能があることから、ファイルが破損していたらアップデートが止まるだろうという思い込み・油断がありました。
また、これらのPCでは(面倒なので)USBメモリを使わず、内蔵SSD内のEFIシステムパーティション等にBIOSイメージを書き込んで更新していたため、USBメモリを使用した更新自体久しぶりでした。
復旧計画
親族のPCは在庫していたマザーボードによりほぼそのまま使えるようになっており、今回壊れたマザーボードをメーカー修理に出したり、代わりのマザーボードを購入したりする必要はありません。
とはいっても、BIOS以外壊れて無さそうなマザーボードを捨てるのはもったいないですし、何より面白そうなので自力でBIOSを書き込み復旧させる方法を検討します。
前提知識として、BIOSはマザーボード上のフラッシュROMに書き込まれており、ROMライターなどを使用して外部から正常なイメージを書き込むことで修復することができます。
今回はROMライターとして、自宅に数個転がっていたRaspberry Pi(初代Raspberry Pi Model B)と書き込みソフトのflashromを使用します。
イメージとしては以下のようにRaspberry PiとICチップを接続して書き込みます。
※ 画像はイメージです。実際に行った接続とは異なります。
SPIについて
フラッシュROMとの接続方式について、この後重要になるので簡単に説明します。
このようなフラッシュROMは大抵の場合、SPIというシリアルバス規格で接続できます。
全二重通信のための2線に加え、クロックとチップセレクトを加えた以下の4線が基本的な信号線となります。
- SCK: シリアルクロック
- Masterが送信するクロック、Master/Slaveはこれに合わせてデータを送受信
- MOSI: Master Out Slave In
- Master→Slaveのデータ
- MISO: Master In Slave Out
- Slave→Masterのデータ
- CS(SS): Chip Select (Slave Select)
- Masterが通信したいSlaveを選択する (active-low)
マザーボードの確認・調査
フラッシュROM書き込みのためには、マザーボードで使われているROMチップがROMライター(今回はflashrom)によりサポートされている必要があります。
そのため、ネット上の情報も参考にしながらマザーボード上のチップを確認します。
大抵の場合、足が8本程度生えているICチップです。
今回故障したのはMSI B450M PRO-VDH PLUSというマザーボードです。
写真が少々埃っぽいのはお許しください。
型番を確認するために撮影した写真ですが、実はこの写真の中にBIOSが書き込まれたフラッシュROMが写っています。
メーカーロゴ・型番の右辺りにあるこのICチップがフラッシュROMです。
どうにか頑張ってチップにプリントされた文字を読むと、上2行には
MXIC MX
25U12873F
とプリントされています。
検索すると、MXIC MX25U12873Fという製品がヒットします。
データシートより以下のことがわかります。
- 容量128Mi bits (=16MiB)のSerial NOR Flash memory
- 接続方式は SPI, Dual SPI, Quad SPI, QPI
- 最大104MHz
- 動作電圧 1.8V (1.65 - 2.0V)
さて、この型番はflashromのSupported hardwareに記載されていませんが、近い型番のMX25U12835Fは記載されており、データシートを見比べると機能やコマンドは似ている様に見えます。
また、ネット上を検索すると動作した報告もあるのでflashromにより書き込めると判断しました。
JSPI1 ピンヘッダ
先程の写真をよく見ると、フラッシュROMの上にJSPI1
とプリントされたピンヘッダがあります。
ICチップの隣という位置や「SPI」の文字から分かる通り、このピンヘッダはフラッシュROMへ接続するためのものです。
JSPI1
で検索するとピンとICとの結線図が見つかりますので、その図を参考にピンヘッダを使って書き込みました。
(日本の方が解析・作成した図のようですが、海外フォーラムなどにも転載されていたりします)
問題発覚
Raspberry Piについて詳しい方はもうお気付きかもしれませんが、このフラッシュROMはRaspberry Piと直接接続することができません。
Raspberry Pi Documentationによると、ピンヘッダーの動作電圧は2本ある5VピンとGroundピンを除いて3.3Vなのです。
この電圧はMX25U12873Fが許容する上限電圧の2Vを超えているため、そのまま接続するとICチップが破損する恐れがあります。
正常に接続するためには、Raspberry PiとMX25U12873Fとの間にレベルシフターと呼ばれる回路を入れてやる必要があります。
レベルシフターは電圧(レベル)の異なる2つの回路間で信号電圧を変換する回路です。
Amazonで「1.8V SPI フラッシュ アダプタ」などのキーワードで検索すると使えそうな製品が出てきますが、1000円から2000円程度する上にマーケットプレイスで出品された海外事業者の商品しか見つかりません。
ネット上で調べてみると、実装されているICチップが本来のものと異なっていて実際には使えない場合もあるようで、購入する場合は不良品が来ることを覚悟する必要がありそうです。
色々と調べた結果、今回は電子部品を購入し、レベルシフト回路を自作してみることにしました。
お買い物
今回必要なのは、
- 定電圧レギュレーター
- Raspberry Piの電源ピン(5V or 3.3V)からMX25U12873Fが動作するのに必要な1.8Vを生成する
- レベルシフトIC(モジュール)
- Raspberry Piの3.3VとMX25U12873Fの1.8Vの信号を相互変換する
- 先述の通り、SPI接続のためにはRaspberry Pi(Master)→MX25U12873F(Slave)方向に3本、逆方向に1本の信号線が必要
- 1:1通信なので、CSは本当は省略できそう
- 上記部品を接続するための基板 (ブレッドボードかユニバーサル基板)
- Raspberry Piと基板、基板とMX25U12873Fを接続するためのジャンパー線
となります。
秋葉原の秋月電子通商へ行き、以下の部品を購入しました。
-
LVC8T245使用8ビット双方向レベル変換モジュール × 2
- 使えそうな製品で在庫がこれしかなかった
- データシートを確認したところ、非同期・半二重通信向けのIC
- direction-control (DIR) という入力があり、これのHigh/Lowにより通信方向を制御
- 単体ではSPI通信に使えなさそうだが、通信方向毎に2つモジュールを使用してやれば良いのではと判断し2個購入
-
低損失CMOS三端子レギュレーター 1.8V500mA NJU7223F18
- ブレッドボードにそのまま挿せる1.8V 定電圧レギュレーターの最大出力電流が大きい方
- 各ICのデータシートを確認したところ多分十分な出力 (あまり自信ないです)
-
ブレッドボード・ジャンパーワイヤ(オス-メス) 15cm黒 (10本入)
- 手持ちのものもあったが本数が足りなかったので追加
大きいブレッドボードも写っていますが、実際には手持ちの小型のものを使用したので今回は未使用です。
上記4点で総額890円、変換モジュールとレギュレーターに限れば560円です。
Amazonで売っている商品より安く済みました。
(手持ちのブレッドボード・ジャンパー線・Raspberry Piの値段はカウント外、他用途にも使えるし......)
電子工作
部品を買ったので組み立てていきます。
簡単な電子工作です。
まずレベル変換モジュールのピンヘッダを基板にはんだ付けします。
その後、ブレッドボード上に以下のような回路を作成します。
写真だと角度がついて見づらいので、図に起こすとこのような感じです。
モジュール基板上のプリントや回路は再現できていませんので、写真と見比べて下さい。
回路について簡単に説明すると、
- 下半分をRaspberry Piと接続し、上半分をMX25U12873Fと接続
- Raspberry Piから給電された3.3V電源を中央のレギュレーターで1.8Vに変換して上半分へ給電
- それぞれの変換モジュールは1(
VA
)ピンにRaspberry Piからの3.3V、23(VB
)ピンにレギュレーターからの1.8Vを入力 - 左側のモジュールによってRaspberry Pi→MX25U12873F方向の信号電圧変換
- 3(
DIR
)ピンがHigh - 4(
A1
)〜11(A8
)ピンに3.3Vで入力された信号を21(B1
)〜14(B8
)ピンに1.8Vで出力
- 3(
- 右側のモジュールによってMX25U12873F→Raspberry Pi方向の信号電圧変換
- 3(
DIR
)ピンがLow - 21(
B1
)〜14(B8
)ピンに1.8Vで入力された信号を4(A1
)〜11(A8
)ピンに3.3Vで出力
- 3(
- (モジュール基板内の配線を考慮すると不要な線もある、ブレッドボード上下のGND同士を接続している線など)
といったものになります。
Raspberry Piの準備
今回の作業に使うRaspberry Piには、公式のRaspberry Pi OSをインストールしたSDカードを挿入します。
Raspberry Piを起動・初期設定したら、今回使うflashromをインストールしましょう。
tango@raspberrypi:~ $ sudo apt update
tango@raspberrypi:~ $ sudo apt install flashrom
次に、今回フラッシュROMとの接続に利用するSPIインターフェースを有効化します。
raspi-config
で設定するか、/boot/config.txt
を直接エディタで編集してdtparam=spi=on
の行からコメントアウトを外します。
# Uncomment some or all of these to enable the optional hardware interfaces
#dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on
また、作業スペースの都合でRaspberry PiをHeadless(画面・キーボードは接続しない状態)で使用するために、SSHサーバーを有効化しました。
tango@raspberrypi:~ $ sudo systemctl enable ssh
最後に、BIOSイメージファイルを用意します。
今回のMSI製マザーボードの場合、BIOSアップデートファイルがフラッシュROMに書き込むイメージファイルそのものであるため、そのままRaspberry Piへ転送しておきます。
tango@pc $ scp Downloads/7A38v9E/E7A38AMS.9E0 raspberrypi:
(以前の記事でscpコマンドは-s
オプションによりSFTPプロトコルを使用していましたが、OpenSSH 9.0以降はSFTPの使用がデフォルトとなったためオプションは不要です)
BIOSフラッシュ
ここまで長くなりましたが、いよいよBIOSを書き込みます。
先程作成したレベルシフト回路を間に挟んでRaspberry Piとマザーボード上のピンヘッダを接続します。
JSPI1
ピンヘッダを上手く作図できなかったのでICと直接接続した図となっておりますが、実際はピンヘッダに接続しています。
- Raspberry Piの3.3V・GNDをブレッドボード下側の電源ライン・GNDラインに接続
- Raspberry Piの
MOSI
・SCLK
・CS0
を左側モジュールのA1
〜A3
に接続 - Raspberry Piの
MISO
を右側モジュールのA1
に接続 - MX25U12873FのVCC・GNDをブレッドボード上側の電源ライン・GNDラインに接続
- MX25U12873Fの
SI
・SCLK
・CS#
を左側モジュールのB1
〜B3
に接続 - MX25U12873Fの
SO
を右側モジュールのB1
に接続 - MX25U12873Fの今回使用しない
SIO2
・SIO3
は電源ラインに接続
また、JSPI1
の9番ピンはGNDに接続します。
このピンはフラッシュROMをCPU・マザーボード側パーツから独立させるスイッチとなっているらしく、GNDに落とさないとフラッシュROMに書き込めませんでした。
AMD Socket AM4はCPUとフラッシュROMが直結しています。
何か間違えると高価なCPUを壊す可能性があるため、不安な場合はCPUや他のパーツを外して書き込むことをおすすめします。
特に、ICテストクリップなどを使用してフラッシュROMにライターを直結させて書き込む場合はCPUを外す必要があるようです。
この段階で気づいたのですが、JSPI1
ピンヘッダーのピン間隔はブレッドボードなどで使用される2.54mm(1/10 in)よりも狭く、ジャンパーケーブルが挿せません。
...が無理やり挿しました。
隣り合ったピンに挿すのは3列までが限界なため、GNDは近くにあったSYS_FAN1
のGNDに挿しています。
接続が終わったらRaspberry Piの電源を入れ、flashromを使ってみましょう。
tango@raspberrypi:~ $ ls -l /dev/spi*
crw-rw---- 1 root spi 153, 0 Jan 25 14:30 /dev/spidev0.0
crw-rw---- 1 root spi 153, 1 Jan 25 14:30 /dev/spidev0.1
tango@raspberrypi:~ $ id
uid=1000(tango) gid=1000(tango) groups=1000(tango),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),104(input),106(render),108(netdev),997(gpio),998(i2c),999(spi)
まず /dev/spidev*
が存在するかを確認し、SPIインターフェースが有効になっているかを確認します。
Raspberry Piの場合はデフォルトでユーザーがspi
グループに入っているため、SPIインターフェースへのアクセスにはroot権限は不要です。
tango@raspberrypi:~ $ flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 -r current.bin
flashrom v1.2 on Linux 5.15.84+ (armv6l)
flashrom is free software, get the source code at https://flashrom.org
Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Macronix flash chip "MX25U12835F" (16384 kB, SPI) on linux_spi.
Block protection could not be disabled!
Reading flash... done.
tango@raspberrypi:~ $ ls -l
total 32768
-rw-r--r-- 1 tango tango 16777216 Jul 25 2022 E7A38AMS.9E0
-rw-r--r-- 1 tango tango 16777216 Jan 25 15:30 current.bin
flashromは-p
オプションで読み書きに使用するプログラマーを指定します。
今回はLinuxネイティブのSPIドライバーを使用するため、linux_spi
を指定した上で使用するデバイスファイル(先程CS0
に接続したので/dev/spidev0.0
)と速度を指定します。
今回1000(kHz)を指定したところ、読み書きを行うことができました。
(ブレッドボードとレベル変換モジュールを挟んだ接続なのであまり上げられないはずです)
続く-r
オプションはフラッシュROMのデータを読み出しファイルに保存する指示となります。
これによりICチップを正しく認識して通信できていることが確認できました。
(ここで取り出したイメージファイルは作業中の試行錯誤により誤って消してしまったため、推測していた原因の確認ができなくなりました)
問題なく読み取りできたら、書き込んでみましょう。
tango@raspberrypi:~ $ flashrom -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 -w E7A38AMS.9E0
flashrom v1.2 on Linux 5.15.84+ (armv6l)
flashrom is free software, get the source code at https://flashrom.org
Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Macronix flash chip "MX25U12835F" (16384 kB, SPI) on linux_spi.
Reading old flash chip contents... done.
Erasing and writing flash chip... Erase/write done.
Verifying flash... VERIFIED.
-w
オプションは指定したファイルをフラッシュROMへ書き込みます。
書き込みは読み込みより時間がかかります。
verifyが成功したら書き込み成功です。
verifyが失敗した場合でも、-r
で読み出してみると正しく書き込めていることがありました。
長い道のりを超え、やっとBIOSが修復できました。
BIOS、復活
マザーボードからRaspberry Piを外し、必要なパーツを再び取り付けて起動してみます。
起動しました!
(作業時に使用したCPUの都合で、画面に写っているBIOSバージョンは上記のものと異なっております)
この後、念の為BIOSメニューから本来の手順でBIOSをアップデートした後に親戚へPCを返却し、修理完了としました。
感想
- 電子工作(っぽいこと)は久しぶりだったが、楽しかったし成功して良かった
- PCチョットワカルと思っていたが、チョットのレベルが上がった気がする
- BIOSを直す方法が分かったので、今後は遠慮なく壊すことができそう
- corebootなどのOSSなBIOSを試してみるとか
- BIOS不良ジャンクを買ってみるとか
以上となります。
長い記事となってしまいましたが、誰かの役に立ったら嬉しいです。
秋葉原で買い物したときに食べた豆花、美味しかったのでこれから台湾へ行ってきます。
(空港ラウンジから投稿)
-
Fritzingにより作成 CC BY-SA 3.0 ↩ ↩2