はじめに
はじめまして。 tnishinagaです。
この度ご縁があって、こちらのブログに寄稿させていただく事になりました。
よろしくお願いいたします。
要約
- Raspberry Pi 5のハードウェアデバッグはJTAGからSWDを使う方法に変わりました
- Raspberry Pi Debug ProbeとOpenOCDを使えばハードウェアデバッグできます
BareMetalで遊びたい! Raspberry Pi 5
この度Raspberry Pi 5が日本で発表されました。
ここで私を含めシステムプログラマが気になるのは「Raspberry Pi 5で自作OS開発などのベアメタル開発ができるのか」ではないでしょうか。
早速入手したRaspberry Pi5を用いてハードウェアデバッグ方法について調べてみたので、今回はその方法を共有します。
おことわり
とくに言及がない限り、本内容はすべて「オープンな情報」および「リバースエンジニアリングで得た情報」を用いて調査して書かれています。
Raspberry Pi財団等の公式見解ではないため、誤りがあったり、今後の仕様変更で記載した方法を利用できなくなることがあります。
あらかじめご了承ください。
ハードウェアデバッグの方法
Raspberry Pi 5からのハードウェアデバッグは、Raspberry Pi 4までと比べて以下の点が変わっていました。
- デバッグインターフェイスがJTAGからSWDに変わった
- デバッグ用端子が出ている場所が40pin GPIOからUART/デバッグ用コネクタに変わった
- UARTとハードウェアデバッグ機能は排他
- Raspberry Pi Debug Probeがあれば簡単に接続可能
- デバッグ・CTIのアドレスが変わった
- OpenOCDの設定ファイルに変更が必要
デバッグの仕組みがSWDに変わったので、Raspberry Pi 4まで利用していたJTAGデバッガーは使えなくなりました。
一方、Raspberry Pi Debug Probeは一般的なデバッガーの中では比較的安価ですし、接続もケーブル1本でよくなりました。
そのため、全体的なデバッグの敷居は低くなった印象です。
必要なもの
今回Raspberry Pi 5のデバッグには以下の製品を利用しました。
SWD接続できるデバッガーであれば何でもよいのですが、接続に使うJSTコネクタを用意するのがちょっとだけ大変なので上記Probeの利用をオススメします。
セットアップ
デバッグまでの事前準備として、以下を行います。
config.txt
の修正- Raspberry PiとDebug Probeの接続
- OpenOCDのインストールと設定ファイルの作成
Raspberry Pi側の準備
Raspberry Pi ImagerなどでRaspberry Pi OS(64bit)をmicroSDカードに書き込んでください。
その後、第1パーティション(Raspberry Pi OS上からは /boot/firmware/
以下)の config.txt
の末尾に以下の行を追記してください。
enable_jtag_gpio=1
この設定を入れることでRaspberry Pi 5のUART端子の機能が起動時にSWDへ変わり、デバッガーをつなげるようになります。
接続
以下の画像を参考に、Raspberry Pi 5のUART端子(HDMI端子の間)とDebug ProbeのSWD端子(右側のDと書かれたほう)をコネクタで繋いでください。
OpenOCDのインストール
Debug Probe制御のためOpenOCDを利用します。
以下を参考にご自身のPCにOpenOCDをインストールしてください。
https://openocd.org/pages/getting-openocd.html
本記事ではOpenOCD 0.12.0を用いて動作を確認しています。
もしうまく動かない場合は、こちらのバージョンを使って動作を確認してください。
設定ファイルの作成
OpenOCDを使ってデバッグを行う際は、デバッグターゲットの設定ファイルが必要です。
ROM infoから得られる情報を用いてRaspberry Pi 5に搭載されているBCM2712用の設定ファイルを作ったので、以下を適当な場所に保存してください。
(OpenOCDに含まれる target/bcm2711.cfg
をベースに作成したので、このファイルのライセンスは元ファイルと同じくGPL2.0で提供します)
# bcm2712.cfg
# SPDX-License-Identifier: GPL-2.0-or-later
# OpenOCD target config file
# This file is based on target/bcm2711.cfg
# I have checked that it works with Open On-Chip Debugger 0.12.0
# using the Raspberry Pi Debug-Probe interface
transport select swd
adapter speed 1000
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME bcm2712
}
if { [info exists CHIPCORES] } {
set _cores $CHIPCORES
} else {
set _cores 4
}
if { [info exists USE_SMP] } {
set _USE_SMP $USE_SMP
} else {
set _USE_SMP 0
}
if { [info exists DAP_TAPID] } {
set _DAP_TAPID $DAP_TAPID
} else {
set _DAP_TAPID 0x2ba00477
}
# swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID
swd newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
# MEM-AP for direct access
target create $_CHIPNAME.ap mem_ap -dap $_CHIPNAME.dap -ap-num 0
# these addresses are obtained from the ROM table via 'dap info 0' command
set _DBGBASE {0x80010000 0x80110000 0x80210000 0x80310000}
set _CTIBASE {0x80020000 0x80120000 0x80220000 0x80320000}
set _smp_command "target smp"
for { set _core 0 } { $_core < $_cores } { incr _core } {
set _CTINAME $_CHIPNAME.cti$_core
set _TARGETNAME $_CHIPNAME.cpu$_core
cti create $_CTINAME -dap $_CHIPNAME.dap -ap-num 0 -baseaddr [lindex $_CTIBASE $_core]
target create $_TARGETNAME aarch64 -dap $_CHIPNAME.dap -ap-num 0 -dbgbase [lindex $_DBGBASE $_core] -cti $_CTINAME
set _smp_command "$_smp_command $_TARGETNAME"
}
if {$_USE_SMP} {
eval $_smp_command
}
# default target is cpu0
targets $_CHIPNAME.cpu0
以上で準備は完了です。
ハードウェアデバッグ
ここからは実際にOpenOCDを立ち上げてデバッグを行ってみます。
OpenOCDの起動
さきほど取得したファイル等を用いてOpenOCDを起動し、Raspberry Pi 5に接続します。
Raspberry Pi 5の電源を入れて数秒待った後(※)、以下のコマンドをPC上で実行してください。
(※: 最初しばらくはブートローダーのログ出力のために使われるので、SWD機能に変わるのを待つ必要があります)
openocd -f interface/cmsis-dap.cfg -f bcm2712.cfg
うまく接続ができれば、以下のようなログが出てきます。
~/p/t/r/pi5_jtag ❯❯❯ openocd -f interface/cmsis-dap.cfg -f bcm2712.cfg
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=SERIAL_NUMBER
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 1000 kHz
Info : SWD DPIDR 0x2ba01477
Info : bcm2712.cpu0: hardware has 6 breakpoints, 4 watchpoints
Info : bcm2712.cpu1: hardware has 6 breakpoints, 4 watchpoints
Info : bcm2712.cpu2: hardware has 6 breakpoints, 4 watchpoints
Info : bcm2712.cpu3: hardware has 6 breakpoints, 4 watchpoints
Info : gdb port disabled
Info : starting gdb server for bcm2712.cpu0 on 3333
Info : Listening on port 3333 for gdb connections
Info : starting gdb server for bcm2712.cpu1 on 3334
Info : Listening on port 3334 for gdb connections
Info : starting gdb server for bcm2712.cpu2 on 3335
Info : Listening on port 3335 for gdb connections
Info : starting gdb server for bcm2712.cpu3 on 3336
Info : Listening on port 3336 for gdb connections
GDBの接続
OpenOCDが正常に立ち上がった場合、OpenOCDがtelnetとGDBのサーバーを起動します。
このサーバーに各種デバッガーで接続すると、デバッグを行えます。
例としてGDBの接続方法をご紹介します。
aarch64向けのgdb(aarch64-elf-gdb
やgdb-multiarch
)を起動した後、以下のコマンドを実行してOpenOCDのGDBサーバー接続してください。
target remote :3333
あとは自由にデバッグを行えます。
たとえば Ctrl + C
を実行してコアをhaltしたあと、i r
でレジスタの中身が見られます。
(gdb) i r
x0 0xffffb001f2910000 18446656121143885824
x1 0xffff8001ffac3a70 18446603344805640816
x2 0xffffd0000d4d84c0 18446691297374602432
x3 0xffffd0000d18c008 18446691297371144200
x4 0x1 1
x5 0xffffd0000d4d1000 18446691297374572544
x6 0x1db3292f5 7972492021
x7 0x0 0
x8 0xffffd0000d4c3c98 18446691297374518424
x9 0xffffd0000c0df61c 18446691297353659932
x10 0x1a90 6800
x11 0x1ef 495
x12 0x2 2
x13 0x0 0
x14 0x1 1
x15 0x0 0
x16 0xffffd0000cc076a0 18446691297365358240
x17 0x0 0
x18 0x0 0
x19 0x0 0
x20 0xffffd0000d4d0998 18446691297374570904
x21 0xffffd0000d4d0878 18446691297374570616
x22 0xffffd0000d1b4e38 18446691297371311672
x23 0xffffd0000cf72108 18446691297368940808
x24 0x0 0
x25 0x0 0
x26 0xffffd0000d4d84c0 18446691297374602432
x27 0x0 0
x28 0x12789fc 19368444
x29 0xffffd0000d4c3d40 18446691297374518592
x30 0xffffd0000cc03464 18446691297365341284
sp 0xffffd0000d4c3d40 0xffffd0000d4c3d40
pc 0xffffd0000cc0344c 0xffffd0000cc0344c
おわり
以上でハードウェアデバッグ方法のご紹介を終わります。
この内容がみなさまのお役に立てれば幸いです。
参考資料
- Raspberry Pi 5 JTAG configuration
- https://forums.raspberrypi.com/viewtopic.php?t=362067
- (この記事を書いたあとに投稿を見つけたので、答え合わせとして参考にさせていただきました)
- https://forums.raspberrypi.com/viewtopic.php?t=362067