はじめに
こんにちは、tnishinagaです。
今回はRP1のJTAGデバッグ方法を見つけたので、ご紹介します。
注意
本記事ではRP1が想定していない操作を行うため、本内容の実施によりRP1含めRaspberry Pi 5が故障する可能性があります。
十分ご注意の上、実施される際は自己責任のもとでお願いします。
要約
- RP1のJTAGは基板裏面のJ19やテストパッドから出ている
- RP1のCortex-M3コアのJTAG TAPは隠しコマンドを送ると出てくる
overview in english
- RP1 JTAG port exporsed from J19 or test pads on the back of the Pi5 board
- Nahitafu’s reverse engineering result
- Sending hidden command makes the JTAG TAPs of the each Cortex-M3 core of RP1 visiable
RP1とリバースエンジニアリング
RP1はRaspberry Pi 5に搭載されているサウスブリッジ的なチップです。
Pi 5のIOのほぼすべてをこのRP1が担っているため、RP1を自由に制御できればPi5を自由に制御できると言えるのではと勝手に思っています。
このRP1のペリフェラルマニュアルは公開されていますが、中で動いているコードや一部仕様については非公開となっています。
そのため自由に扱うにはリバースエンジニアリングが必要であり、私を含め国内外で数人が取り組んでいるようです。
リバースエンジニアリングでは、人間がコンピューターの状態をなんとかして知る手段の確保が重要です。
その中でもとくにJTAGデバッガーが利用可能になると、プロセッサの制御を自由に行えて大変嬉しいです。
どこかに使えるJTAG端子は生えていないでしょうか?
RP1のJTAGを探す旅
RP1のペリフェラルマニュアルを読んでみると、6ページのFigure2にARM DEBUGと書かれた部分があり、少なくともプロセッサコアからJTAG端子が出ているとわかります。
画像はRP1のペリフェラルマニュアル, pp.6, Figure2より引用
また、特殊電子回路株式会社のなひたふさんの解析結果より、Pi 5のUSB端子の下にあるフレキシブルケーブル用のパターンからRP1のJTAG端子が出ていることが確認されています。
実際に自分も0.5mmピッチのフレキシブルケーブルと端子を購入してJTAGデバッガーとつなげて様子を見てみたところ、Raspberry Pi Trading LtdのTAPが見つかりました。
~/p/t/r/pi5_jtag ❯❯❯ openocd -f interface/ftdi/olimex-arm-usb-tiny-h.cfg -c 'transport select jtag'
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
jtag
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Warn : An adapter speed is not selected in the init scripts. OpenOCD will try to run the adapter at the low speed (100 kHz)
Warn : To remove this warnings and achieve reasonable communication speed with the target, set "adapter speed" or "jtag_rclk" in the init scripts.
Warn : libusb_detach_kernel_driver() failed with LIBUSB_ERROR_ACCESS, trying to continue anyway
Info : clock speed 100 kHz
Warn : There are no enabled taps. AUTO PROBING MIGHT NOT WORK!!
Info : JTAG tap: auto0.tap tap/device found: 0x20001927 (mfg: 0x493 (Raspberry Pi Trading Ltd), part: 0x0001, ver: 0x2)
Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -irlen 5 -expected-id 0x20001927"
Warn : gdb services need one or more targets defined
これがRP1のCortex-M3コアのTAPと考えてDAPの接続等を試行しましたが、うまくいきませんでした。
Arm Debug Interfaceでは命令ビット長は4または8bitと決められていますが、OpenOCDがAutoProbeで見つけた命令ビット長は5bitなので、合っていません。
よって、Cortex-M3以外の何らかのTAPが見えていると考えられます。
※Arm Debug Interfaceの仕様やデバッグの詳細については手前味噌ですがこちらの資料をご覧ください。
- JTAGでarmプロセッサをデバッグする話
隠しコマンド、発見
TAPID 0x20001927へのDAP接続試行を何度か試していたところ、たまに違うTAPIDが見つかる事がありました。
# 当時のログを再現
Info : JTAG tap: auto0.tap tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4)
Info : JTAG tap: auto1.tap tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4)
Warn : AUTO auto0.tap - use "jtag newtap auto0 tap -irlen 4 -expected-id 0x4ba00477"
Warn : AUTO auto1.tap - use "jtag newtap auto1 tap -irlen 4 -expected-id 0x4ba00477"
最初はTAPのStateがおかしくなったのかなと思っていたのですが、よく見るとTAP IDのManufacturer ID Code部がArm Ltdとなっています。
もしやと思って出てきたTAPに対しDAPの接続を試したところ、Cortex-M3のDebug Unitが見えました。
そしてさらに調査を行ったところ、以下の操作を行うことでRP1のCortex-M3のTAPが見えるようになることを見つけました。
- IRに0x1dをセットする
- DRに0を128bit送る
どうやら隠しコマンドを見つけてしまったようです。
もしかすると他にも似たような隠しコマンドがあるかもしれません。
RP1にJTAG接続する方法
ここでやり方をまとめましょう。
ハードウェアの準備
Raspberry Pi 5のUSB下にあるフレキケーブル端子のパターン、またはテストポイントからJTAGに使う以下の線を引き出してください。
(端子とテストポイントの対応はなひたふさんのブログ記事を参考)
- TDI : TP53
- TDO : TP54
- TCK : TP55
- TMS : TP56
- GND : GPIO端子等
- 3.3V: GPIO端子等
引き出したらJTAGデバッガーと接続します。
私の使用したARM-USB-TINY-Hというデバッガーと接続するための回路図を共有しますので、ARM JTAG 20のピン配置を確認しつつ接続を行ってください。
ARM JTAG 20のピン配置はなひたふさんの解説がわかりやすくてオススメです。
- ARMのJTAGピン配置
私はつなぎ間違えが怖いので基板を作りました。
隠しコマンドの発行
JTAGデバッガーをつなぎ、OpenOCDを入れたマシンに以下のスクリプトを保存し、実行します。
これで次回のOpenOCD実行時からCortex-M3のTAPが見えるようになります。
# SPDX-License-Identifier: GPL-2.0-or-later
# Toshifumi Nishinaga<tnishinaga.dev@gmail.com>
# rp1_init.cfg
transport select jtag
adapter speed 1
jtag newtap cpu0 cpu -expected-id 0x20001927 -irlen 5
init
pathmove IRSHIFT
irscan cpu0.cpu 0x1d
pathmove DRSHIFT
drscan cpu0.cpu 8 0
openocd -f interface/ftdi/olimex-arm-usb-tiny-h.cfg -f rp1_init.cfg
Cortex-M3コアへの接続
先ほどと同様に、以下のファイルを作ってからopenocdを実行してください。
# rp1.cfg
# This file is based on target/bcm2711.cfg
# SPDX-License-Identifier: GPL-2.0-or-later
# Toshifumi Nishinaga<tnishinaga.dev@gmail.com>
transport select jtag
adapter speed 100
jtag newtap cpu0 cpu -expected-id 0x4ba00477 -irlen 4
jtag newtap cpu1 cpu -expected-id 0x4ba00477 -irlen 4
dap create cpu0.dap -chain-position cpu0.cpu
dap create cpu1.dap -chain-position cpu1.cpu
# cpu0
target create cpu0.ap mem_ap -dap cpu0.dap -ap-num 0
target create cpu0 cortex_m -dap cpu0.dap -ap-num 0 -dbgbase 0xe000e000
# cpu1
target create cpu1.ap mem_ap -dap cpu1.dap -ap-num 0
target create cpu1 cortex_m -dap cpu1.dap -ap-num 0 -dbgbase 0xe000e000
openocd -f interface/ftdi/olimex-arm-usb-tiny-h.cfg -f rp1.cfg
以下のようなログが出たら成功です。
~/p/t/r/pi5_jtag ❯❯❯ openocd -f interface/ftdi/olimex-arm-usb-tiny-h.cfg -f rp1.cfg
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
3758153728
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Warn : libusb_detach_kernel_driver() failed with LIBUSB_ERROR_ACCESS, trying to continue anyway
Info : clock speed 100 kHz
Info : JTAG tap: cpu0.cpu tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4)
Info : JTAG tap: cpu1.cpu tap/device found: 0x4ba00477 (mfg: 0x23b (ARM Ltd), part: 0xba00, ver: 0x4)
Info : [cpu0] Cortex-M3 r2p1 processor detected
Info : [cpu0] target has 6 breakpoints, 4 watchpoints
Info : [cpu1] Cortex-M3 r2p1 processor detected
Info : [cpu1] target has 6 breakpoints, 4 watchpoints
Info : gdb port disabled
Info : starting gdb server for cpu0 on 3333
Info : Listening on port 3333 for gdb connections
Info : gdb port disabled
Info : starting gdb server for cpu1 on 3334
Info : Listening on port 3334 for gdb connections
あとはgdbでTCP 3333や3334番につなぐとRP1を自由に操作できます。
(gdb) tar remote :3334
(gdb) i r
r0 0x676e6f6c 1735290732
r1 0x77207265 1998615141
r2 0x696b726f 1768649327
r3 0x1 1
r4 0x34 52
r5 0x100029b0 268446128
r6 0x34 52
r7 0x20003990 536885648
r8 0x200057d0 536893392
r9 0x10002010 268443664
r10 0x200057d8 536893400
r11 0x200057d4 536893396
r12 0x0 0
sp 0x10002980 0x10002980
lr 0x100002dd 268436189
pc 0x100003ae 0x100003ae
xPSR 0x81000000 -2130706432
msp 0x10002980 0x10002980
psp 0x0 0x0
primask 0x0 0
basepri 0x0 0
faultmask 0x0 0
control 0x0 0
試しにRP1のcore1に接続してレジスタを眺めたところ、PCがProc Local ISRAMの領域を指している様子が伺えました。
以上です。
Happy Hacking!