そのアクセスポートには何があるのか?
What's on That Access Port? (danielmangum.com)
要約
この記事は、Nordic SemiconductorのnRF54LM20 SoCにおけるデバッグアーキテクチャ、特に複数のコア(Cortex-M33アプリケーションコアとRISC-VコプロセッサFLPR)間のデバッグ接続に焦点を当てています。Zephyr RTOSと`west` CLIツールを使用することで、これらのコアに個別に接続し、デバッグすることが可能になります。記事では、J-Linkデバッガがどのようにして異なるコア(AHB-APやCTRL-AP)を識別し、アクセスポート(AP)のマップをスキャンしてデバッグセッションを確立するかの低レベルな仕組みについても解説しています。
全文翻訳
そのアクセスポートには何があるのか?
私の前回の投稿では、Nordic SemiconductorのnRF54LM20をデバッグする際に、ペリフェラル、特にKey Management Unit (KMU)がCPUの停止中に直接メモリに書き込む問題について書きました。あるいは、nRF54LM20にはRISC-Vコプロセッサ(VPR)であるFast Lightweight Peripheral Processor (FLPR)も搭載されているため、アプリケーションコア(Cortex-M33)のデバッグについて書いたと言うべきでしょう。NordicがVPRコアを発表した頃、私はそのアーキテクチャに関する投稿と、それとアプリケーションコア間の通信がどのように機能するかについての投稿を2つ書きました。
後者のVPRに関する投稿では、GDBとJLinkGDBServerを使用してアプリケーションコアに接続し、通信プロトコルをステップ実行しました。この戦略は、それぞれの投稿で説明されている操作には適していましたが、場合によってはVPRコアをデバッグのために接続することが望ましいかもしれません。
通常、シリコンベンダーは、より高い抽象化レベルで接続したいコアを指定しやすくするためのツールを提供したり、オープンソースプロジェクトと協力したりします。例えば、Nordic製品はZephyr RTOSエコシステムで強力なサポートを受けており、ZephyrのメタCLIであるwestは、すべてのチップでファームウェアのビルド(west build)とフラッシュ(west flash)に使用できます。westはSystem Build (Sysbuild)を使用して、複数のイメージを1回の操作でビルドおよびフラッシュすることをサポートしています。Sysbuildによって管理される各ビルドシステムはドメインと呼ばれ、--domainフラグを使用して指定されたドメインのみに対して指定された操作を実行できます。
通常、ビルドとフラッシュの際にはすべてのドメインをターゲットにしたいのですが、west debugは--domainフラグがどのように役立つかを示す良い例です。例えば、nRF54LM20のZephyr blinkyサンプルを、NordicのHigh Performance Framework (HPF)(HPFに関する将来の投稿にご期待ください)を介してGPIO制御のためにFLPRで使用する場合、アプリケーションコア用のblinkyアプリケーションとFLPRコア用のGPIOアプリケーションをビルドするために、以下のコマンドを使用します。
west build -p -b nrf54lm20dk/nrf54lm20b/cpuapp nrf/samples/zephyr/basic/blinky -- -DSB_CONFIG_HPF=y -DSB_CONFIG_HPF_GPIO=y -DSB_CONFIG_HPF_GPIO_BACKEND_ICMSG=y -DEXTRA_DTC_OVERLAY_FILE="./boards/nrf54lm20dk_nrf54lm20b_cpuapp_hpf_gpio.overlay"
結果のbuild/ディレクトリには、以下の内容を持つトップレベルのdomains.yamlファイルが表示されます。
default: blinky
build_dir: <local-path>/build
domains:
- name: blinky
build_dir: <local-application-path>/build/blinky
- name: hpf_gpio
build_dir: <local-application-path>/build/hpf_gpio
flash_order:
- blinky
- hpf_gpio
west flashコマンドを発行すると両方のイメージがデバイスにフラッシュされますが、一度に1つのコアしかデバッグできないため、フラグなしのwest debugはdefaultドメイン(blinky)をターゲットにし、アプリケーションコアに接続します。hpf_gpioを指定すると、代わりにFLPRに接続されます。
west debug --domain hpf_gpio
グラフィカルなUXを好む場合は、NordicのVSCodeツールを利用して、この同じ機能を利用できます。これは私のNordicの同僚であるSebastian Vivianiによるこの投稿で説明されています。
裏側では、Zephyrはwestがデバッグ接続をどのようにセットアップするかを知るのに役立つボードサポートファイルを含んでいます。各ドメインのbuild/<domain>/zephyr/ディレクトリを見ると、runners.yamlファイルが見つかります。例えば、前のビルドのhpf_gpioドメインには以下の内容が含まれています。
# Available runners configured by board.cmake.
runners:
- nrfutil
- jlink
# Default flash runner if --runner is not given.
flash-runner: nrfutil
# Default debug runner if --runner is not given.
debug-runner: jlink
# Common runner configuration values.
config:
board_dir: <local-application-path>/zephyr/boards/nordic/nrf54lm20dk
# Build outputs:
elf_file: zephyr.elf
hex_file: zephyr.hex
bin_file: zephyr.bin
# Host tools:
gdb: <local-zephyr-sdk-path>/zephyr-sdk-1.0.1/gnu/riscv64-zephyr-elf/bin/riscv64-zephyr-elf-gdb
openocd: <local-zephyr-sdk-path>/zephyr-sdk-1.0.1/hosttools/usr/bin/openocd
openocd_search:
- <local-zephyr-sdk-path>/zephyr-sdk-1.0.1/hosttools/opt/openocd/share/openocd/scripts
# Runner specific arguments
args:
nrfutil:
[]
jlink:
- --dt-flash=y
- --device=nRF54LM20A_RV32
- --speed=4000
ZephyrソースツリーのnRF54LM20 DKボードサポートファイルを見ると、以下のCMakeスニペットが見つかります。
boards/nordic/nrf54lm20dk/board.cmake
if(CONFIG_SOC_NRF54LM20A_CPUAPP OR CONFIG_SOC_NRF54LM20B_CPUAPP)
board_runner_args(jlink "--device=nRF54LM20A_M33" "--speed=4000")
elseif(CONFIG_SOC_NRF54LM20A_CPUFLPR OR CONFIG_SOC_NRF54LM20B_CPUFLPR)
board_runner_args(jlink "--device=nRF54LM20A_RV32" "--speed=4000")
endif()
if(CONFIG_TFM_FLASH_MERGED_BINARY)
set_property(TARGET runners_yaml_props_target PROPERTY hex_file tfm_merged.hex)
endif()
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
runners.yamlファイルの末尾にあるargs.jlinkフラグは、これらのboard_runner_args() CMakeマクロから取得され、対応するドメインのwest debugを呼び出す際にJLinkGDBServerに渡されます。J-LinkはnRF54Lシリーズのネイティブマルチコアサポートを持っているため、--deviceフラグを使用して、JLinkGDBServerにそれぞれのコアに接続する方法に関する情報を内部データベースに問い合わせるように指示できます。
デバッガがまだSoCアーキテクチャを認識していない場合、より詳細な情報を提供する必要があるかもしれません。例えば、nRF54H20のJ-Linkスクリプトを参照して、アプリケーションコアに接続してください。
実際に、nRF54LM20でFLPRコアにJLinkExe -device nRF54LM20A_RV32を使用して直接接続した場合、初期出力で以下の行が表示されます。
Found SW-DP with ID 0x6BA02477
RISC-V behind DAP detected
DPIDR: 0x6BA02477
CoreSight SoC-400 or earlier
AP[1] (AHB-AP) specified by user as debug AP.
AP map scan skipped.
AP map:
AP[0]: AHB-AP, APAddr = 0x00000000
AP[1]: AHB-AP, APAddr = 0x01000000
AP[2]: MEM-AP, APAddr = 0x02000000
Core base addr: 0x5004C400 (user configured)
私のnRF54LM20 KMUの投稿では、nRF54LM20データシートから、デバッグアーキテクチャ、特にデバッグアクセスポート(DAP)を介して利用可能な3つのアクセスポート(AP)を説明する以下の図を含めました。
[画像: access-port-0]
データシートには、各アクセスポートの機能を示す表も含まれています。
| AP ID | Type | Description |
|---|---|---|
| 0 | AHB-AP | CM33 access port |
| 1 | AHB-AP | AUX access port |
| 2 | CTRL-AP | Control access port |
JLinkExeの出力で観察されたように、アクセスポートマップのスキャンをスキップして、RISC-V FLPRコアのアクセスポートであることがわかっている2番目のAHB-AP(AP[1])に直接接続することを選択します。代わりにCortex-M33アプリケーションコアをデバッグするためにJLinkExe -device nRF54LM20A_M33を呼び出した場合、以下の出力が表示されます。
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
CoreSight SoC-400 or earlier
AP map detection skipped. Manually configured AP map found.
AP[0]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[1]: APB-AP (IDR: Not set, ADDR: 0x00000000)
AP[2]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
Iterating through AP map to find AHB-AP to use
AP[0]: Core found
AP[0]: AHB-AP ROM base: 0xE00FE000
CPUID register: 0x411FD210. Implementer code: 0x41 (ARM)
この場合、J-Linkは再びAPマップが認識されていると報告しますが、アクセスポートをすぐに選択する代わりに、Cortex-M33コアを探してマップを反復処理します。基盤となるロジックは、ほとんどのJ-Linkツールで使用されるクローズドソースのJLinkArm.dllライブラリに隠されていますが、J-Linkで認識されているデバイス上のArmコアのデフォルトの動作は、Arm Debug Interface (ADI)が提供する情報を使用してコアとその機能を検出することである可能性が高いです。
ADIは、デバッグアクセスポート(DAP)のアーキテクチャを指定します。DAPは、デバッグポート(DP)と1つ以上のアクセスポート(AP)で構成されます。
[画像: access-port-1]
デバッグポートには、JTAG(JTAG-DP)、Serial Wire(SW-DP)、Serial Wire / JTAG(SWJ-DP)など、複数のタイプがあります。同様に、アクセスポートにも複数のタイプがあり、Advanced High-performance Bus Access Port(AHB-AP)自体はMemory Access Port (MEM-AP)のタイプであり、Control Access Port(CTRL-AP)はNordicによるカスタムAP実装です。DPとAPそれぞれに、どの実装でも提供されなければならない最小限のレジスタセットがあります。以下の図は、DPとMEM-AP(したがってAHB-AP)の間の相互作用の概要を示しています。
[画像: access-port-2]
この図は、J-Linkのようなデバッグプローブが、SoCがすでに認識されていない場合でも、指定されたDAPで利用可能なアクセスポートをどのように発見するかを示唆しています。最初の関連レジスタは、DPのAP Select(SELECT)レジスタ(上記のDPレジスタで強調表示)です。これは、アクセスポート(APSEL)とアクセスポート内のレジスタバンク(APBANKSEL)を選択するために使用できます。
| APSEL | RES0 | APBANKSEL | DPBANKSEL |
|---|---|---|---|
| XXXXXXXX | XXXXXXXXXXXXXXXX | XXXX | XXXX |
| [31:24] | [23:8] | [7:4] | [3:0] |
APSELビットの値がDAP上のアクセスポートに対応しない場合、ADIは以下の動作を定義しています。
APSELというIDのAPが存在しない場合、すべてのAPトランザクションは読み取り時にゼロを返し、書き込みは無視されます。
アクセスポートの選択に成功した後、APの識別レジスタ(IDR)(上記のMEM-APレジスタで強調表示)は、すべてのAPで実装されなければならない唯一のレジスタであり、APの属性を理解するために使用できます。これは常にAPレジスタ空間の最後のレジスタであり、0xFCに位置します。
| Revision | Designer | Class | RES0 | Variant | Type |
|---|---|---|---|---|---|
| XXXX | XXXXXXXXXXX | XXXX | XXXXX | XXXX | XXXX |
| [31:28] | [27:17] | [16:13] | [12:8] | [7:4] | [3:0] |
ほとんどの場合、デバッガはDPおよびAPレジスタへの特定の読み書きを、メモリ位置の読み取りやCPUのプログラムカウンタの進めなどの、より高いレベルの抽象化の後ろに隠します。しかし、J-LinkはDP(ReadDP / WriteDP)およびAP(ReadAP / WriteAP)に直接読み書きするための低レベルコマンドをサポートしています。APマップを手動でスキャンしたい場合は、以下のコマンドシーケンスを使用できます。
DPレジスタ2(SELECT)に書き込み、APSEL値を0、APBANKSEL値を0xFに設定します。これにより、後続のAP読み取りでIDRレジスタ(0xFC)をターゲットにできるようになります。
J-Link> WriteDP 2 0x000000F0
Writing DP register 2 = 0x000000F0 (0 write repetitions needed)
APレジスタ3(バンク0xFのIDR)を読み取ります。
J-Link> ReadAP 3
Reading AP register 3 = 0x84770001 (0 read repetitions needed)
結果の値(0x84770001)をデコードすると、APに関する情報が得られます。これはすでにAHB-APであることがわかっています。
| Revision | Designer | Class | RES0 | Variant | Type |
|---|---|---|---|---|---|
| 1000 | 01000111011 | 1000 | 00000 | 0000 | 0001 |
| Revision 8 | Arm Limited | Mem-AP | RESERVED | - | AMBA AHB3 bus |
3番目のアクセスポート(2)を読み取ると、異なるIDR値が返されます。
J-Link> WriteDP 2 0x010000F0
Writing DP register 2 = 0x010000F0 (0 write repetitions needed)
J-Link> ReadAP 3
Reading AP register 3 = 0x84770001 (0 read repetitions needed)
J-Link> WriteDP 2 0x020000F0
Writing DP register 2 = 0x020000F0 (0 write repetitions needed)
J-Link> ReadAP 3
Reading AP register 3 = 0x32880000 (0 read repetitions needed)
これは、3番目のAPがNordicのCTRL-AP(0x32880000)であるため、予想通りです。レジスタのフィールドをデコードすると、nRF54LM20データシートで指定されているように、DESIGNERフィールドのNordicのJEDEC製造コードを特定できます。
| Revision | Designer | Class | RES0 | Variant | Type |
|---|---|---|---|---|---|
| 0011 | 00101000100 | 0000 | 00000 | 0000 | 0000 |
| Revision 3 | Nordic VLSI ASA | Undefined | RESERVED | - | CTRL-AP |
4番目のアクセスポート(3)を選択しようとすると、IDRレジスタの読み取りで0x00000000が返され、APマップの終わりに達した可能性が高いことを示しています。
シリコンベンダーは通常、デバッグインターフェースの低レベルの詳細の理解を不要にしますが、デバッガがSoCのさまざまなコンポーネントにどのようにアクセスおよび制御を可能にするかについての、少なくとも概略的な知識を持っていることは役立ちます。未知のチップをリバースエンジニアリングする場合、独自のデバッグツールを作成する場合、または製品のセキュリティ状態を検証しようとする場合には、直接のDPおよびAPレジスタアクセスが必要になることがあります。
ルール
- 技術用語は適切にカタカナ表記または原語のまま残し、それ以外の英単語は日本語に訳してください
- 数値と単位は原文の意味を正確に保って訳してください(例: trillion は「兆」)
- 本文は Markdown で与えられます。translatedBody も Markdown で書き、原文の構造(見出し・段落・箇条書き・番号付きリスト・引用・表・強調・取り消し線)をそのまま保ってください。段落の間には空行を入れ、全文を1つの塊にまとめないでください
- コードブロックとインラインコードは翻訳せずそのまま残してください
- リンク テキスト はテキストだけを翻訳し、URL は一字も変えずに残してください
- [画像: …][動画: …][音声: …][図: …]は原文に画像・動画・音声・図があった位置を示す印です。印の形と位置はそのまま残し、「…」の説明文だけを翻訳してください
- 原文にない見出しや装飾を追加しないでください
- タイトル先頭の「Ask HN:」「Show HN:」「Tell HN:」「Launch HN:」は翻訳せず、そのまま titleJa の先頭に残してください
- titleJa と summary は Markdown を使わないプレーンテキストで書いてください(太字、箇条書きの記号、# 見出し、テキスト のリンクなどの記法は使わない)
- 本文が取得できない場合は、タイトルから推測した簡潔な説明のみを記述し、「本文が取得できません」等の取得状況には一切言及しないでください
- 記事の順番を維持してください