Slide 1

Slide 1 text

BareMetalで遊ぶ Raspberry Pi 5 PCIe編 Toshifumi NISHINAGA (CV: ついなちゃん) @tnishinaga 2024-08-10 KernelVM Tokyo 17 https://speakerdeck.com/tnishinaga/kernelvm-tokyo17 1

Slide 2

Slide 2 text

背景 • 以下よりPCIeコントローラーのドライバを書かないと HelloWorldできないと思っていた • Pi 5はIOのほぼすべてをRP1が担当する • SoCとRP1はPCIe経由で接続されている • PCIeドライバを書いてHelloWorldをすることにした 2

Slide 3

Slide 3 text

おことわり • PCI/PCIeについて誤り・不正確な部分が(確実に)あります。 見つけたらコメント等で教えて下さい :pray: • 個人では1次資料にアクセスできないため、2次資料と各種ソースコ ードを読んで調査を行っています 4

Slide 4

Slide 4 text

謝辞 • レビューありがとうございます! • homelithさん • recurakiさん 5

Slide 5

Slide 5 text

PCI/PCIeデバイス制御の導入 6

Slide 6

Slide 6 text

PCI/PCIeとは? • PCとデバイスをつなぐ規格のひとつ • 近いもの: USBとか • Raspberry Pi 5ではSoCとRP1チップ の接続に使われている • PCIと発展型のPCIeがある • PCIe仕様はPCIの仕様がベース • 基本PCIe側で説明(しているつもり) 7 Pi 5のSoC BCM2712 RP1 SoCとRP1をつなぐ PCIe配線(x4)

Slide 7

Slide 7 text

SoC PCIeの論理接続構成 • PCIeはツリー型のネットワーク構成 • 根っこはRoot Complex(RC) • デバイス(EndPoint/EP)は各バスの下に 接続 • Bridge(※)を介すと別のバスを作れる • 各デバイスの識別は以下で行う • 接続しているバス番号(Bus) • バス内のデバイス番号(Device) • Linux等ではdevice • FreeBSDではslot 8 Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex ※PCIeでは正確ではありませんが、説明のためbridgeと呼びます

Slide 8

Slide 8 text

Pi5とRP1の例 • Root Complex • BroadcomのPCIeコントローラー • bcrmstb-pcie • BCM2712には3つ搭載 • PCIe0: 未使用? • PCIe1: Pi5の外部コネクタ • PCIe2: RP1 • PCIe bridge • RC内にあるbridge • Bus0とBus1をつなぐ • RP1 • BUS1のSlot1, Func0に存在 • 他のデバイスは繋がれていないのでBusとSlot は固定 9 BCM2712 Bridge Bus1 RP1 Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Cortex-A72 bcrmstb-pcie Host/PCI Bridge Root Complex

Slide 9

Slide 9 text

PCI/PCIeデバイスの制御概要 • 基本はデバイスのメモリを プロセッサのメモリに割り 当てて制御する仕組み • まずはこの状態を目指して 各種デバイス等を設定する • DMAを使った高速アクセス は未到達 10 processor memory space device memory space map

Slide 10

Slide 10 text

PCI/PCIeのメモリ空間 • メモリ空間 • 一般的なメモリ空間 • 設定済みならCPUからアクセス可能 • IOメモリ空間 • (多分)今は使われていない • Configuration空間 • デバイスやブリッジを設定するためのメモリ空間 • アクセス方法はデバイス固有 11

Slide 11

Slide 11 text

メモリ空間 • デバイスの持つメモリ空間 • ペリフェラルのMMIOやSRAM が存在 • CPUメモリにマップしてアク セスする • map設定はPCI configuration spaceのBARで行う(後述) 12 processor memory space device memory space map

Slide 12

Slide 12 text

PCI/PCIeコンフィギュレーション空間 • PCI/PCIeデバイスごとに存在す る設定領域 • 書き換え方法はコントローラー 依存 • Pi 5はSoCのPCIeコントローラー経 由でやる • 各領域のサイズは以下 • PCI: 0x00 – 0x40 • PCIe: 0x040 - 0xFFF(MAX) 13 PCI Configuration Space Extended Configuration Space 0x0000 0x0040 0x1000 参考: Figure 3-2: PCI Compatible Configuration Register Space, PCI Express Technology 3.0, Mindshare

Slide 13

Slide 13 text

PCIeデバイスを制御するまでの概要 1. PCIeコントローラーの初期化 1. クロック設定やRC/EP選択等 2. RCのPCIe bridgeを設定 1. BARやBUS番号等を設定 3. デバイス(EP)を設定 1. BAR等を設定 4. 完了 1. 以降はプロセッサのメモリ経由でデバイスを制御 14 デバイス固有 PCIe共通

Slide 14

Slide 14 text

Broadcom PCIeコントローラ ーの設定 15

Slide 15

Slide 15 text

PCIeコントローラーの初 期化 • 主にPCIeのHost/PCI Bridge 部を設定する • 右図赤枠部 • PCIeコントローラーごとに 手順が異なる(はず) 16 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 16

Slide 16 text

brcmstb-pcieコントローラー • BroadcomのPCIeコントローラー • settop boxで使われているらしい • > Bcrmstb is a new Broadcom STB PCI Express controller driver used by some settop boxes. • > https://www.phoronix.com/news/Intel-Gateway-SoC-PCIe-5.6 • Raspberry Pi 4から採用 • Pi 4とPi 5はレジスタ配置が微妙に違う • 仕様は非公開 • 多分NDAが必要 • 今回は各種既存ソースコードを読んで仕様や使い方を把握 • ハード固有の処理の詳細はわからないのでなぞるだけ • ↑多分こういう処理じゃないかとかわかる方教えて下さい 17

Slide 17

Slide 17 text

参考にしたコード • FreeBSDのドライバ • https://github.com/freebsd/freebsd- src/blob/ad9cc86bf60cee2b35e804b348840a096f66561d/sys/arm/broadcom/bcm2835/bcm2838_pci.c • 基本はこのドライバで動作を学習 • レジスタ名が役割に応じてリネームされていてわかりやすい • OSの知識なしの場合でも処理が比較的追いやすかった • Pi4向け実装のみ。Pi5向け実装はまだない • raspberrypi/linuxのドライバ • https://github.com/raspberrypi/linux/blob/rpi-6.6.y/drivers/pci/controller/pcie-brcmstb.c • Pi 5向けの実装のオリジナルはここ • pciの一般的な設定方法もわかりやすい • EDK2のドライバ • https://github.com/worproject/edk2- platforms/blob/8e1779b538bcc1e6dc68d7df625394f933651d7a/Silicon/Broadcom/Bcm27xx/Library/Bcm271 2PciHostBridgeLib/Bcm2712PciHostBridge.c • Pi5向け実装あり。linuxより読みやすい(多分linuxのドライバベース) • linuxよりコードがフラット • dts使わないので変数の中身がわかりやすい 18

Slide 18

Slide 18 text

メモリレイアウト • 0x0000-0x1000 • Bus0とBus1をつなぐP2P BridgeのPCI/PCIe config space • Bus0, Slot0, Func0のアクセスはここを読み書 きする • https://github.com/freebsd/freebsd- src/blob/ad9cc86bf60cee2b35e804b348840a096f66561d/ sys/arm/broadcom/bcm2835/bcm2838_pci.c#L276-L281 • 0x1000-0x5000 • RC設定用のレジスタたち • 0x8000-0x9004 • PCI/PCIe config space読み書き用レジスタ • ECAMと似ているが微妙に違う • 使い方 • addressでconfig spaceのbus, slot, funcを指定 • config dataに指定したspaceが割り当てられる • dataでconfig spaceにアクセス 19 +0x0000 +0x1000 +0x2000 +0x4000 +0x5000 +0x8000 +0x9000 +0xFFFF RC PCI/PCIe configuration space mdio等のconfig config data 主にbar関係 config address 謎

Slide 19

Slide 19 text

PCIeコントローラー初期化の手順 • リセット • PERSTのアサート • phyのリセット • 各種クロックの再設定 • AXIエラーの抑制 • Pi5から追加 • DMAの設定 • 各種タイムアウトの設定 • 各種BARの無効化 • メモリwindowの設定 • Root Port classの設定 • P2P bridgeにする • 割り込みの無効化 • リンクスピードの設定 • BARのエンディアン設定 • ASPMの設定 • リセットの解除 • 今回は未実施 • DMAの設定 • MSI割り込みの設定 20

Slide 20

Slide 20 text

メモリwindow設定 • (PCIeコントローラーが扱う) CPUメモリ空間とPCIメモリ空間全体 の割当可能範囲を設定する • OutboundとInbound設定がある • Outboud: CPU -> PCI • Inbound: CPU <- PCI 21 processor memory space device memory space outbound inbound

Slide 21

Slide 21 text

Outbound設定 • 一部CPUメモリ空間へのアクセスを PCIメモリ空間へのアクセスに変換す る設定 • 以下を指定して設定 • CPUメモリのbase address • PCI側のbase address • マップするサイズ • 各baseよりlimitアドレスを計算 22 processor memory space device memory space outbound 0x1f_0..0 0x1ff...c Base Limit 0x0..0 Base

Slide 22

Slide 22 text

Outbound設定例(Pi5 PCIe2) • 割当情報 • CPU base: 0x1f_0000_0000 • PCI base: 0x0000_0000 • size: 0xffff_fffc • 32bit空間全部 • CPUメモリ0x1f_0..0へのアクセ スはPCIデバイスの32bitメモリ空 間全体へのアクセスになる 23 processor memory space device memory space 0x1f_0..0 0x1ff...c Base Limit 0x0..0 Base 0xF..F

Slide 23

Slide 23 text

Outbound設定方法 • outbound_cpu_window_limit設定 • base 16bit, limit 16bitの合計32bitで1セット x 4 • Base/Limit CPUメモリアドレス >> 20(=/1MiB) をセットする • outbound_cpu_window(0x4080~0x40a0)設 定 • base用32bit, limit用32bitの合計64bitで1セット x 4 • Base/Limit CPUメモリアドレスの上位32bitを書 き込む • outbound_bus_window(0x400c~0x402c)設 定 • PCI側のbaseアドレス(64bit)を書き込む • PCI側はLimitアドレス設定が(多分)不要 24 outbound cpu window register(32bit) 0x1F_0...0 0x1_F000 >> 20 Base window_limit register(32bit) 0x0000_001F >> 32

Slide 24

Slide 24 text

Inbound設定 • PCIeデバイスからCPUメモリを読み書 きするバスマスターアクセスを行うた めの設定 • DMAでデバイスからCPUメモリを読み書 きするために必要 • ↑NVMeなど高速非同期通信を行うデバイスで はこれをうまく使うのが重要(homelithさん より) • Pi5では64GiBフルアクセスできるよう 設定する • アクセス制限はIOMMUでやる 25 processor memory space device memory space inbound

Slide 25

Slide 25 text

ブリッジの設定 26

Slide 26

Slide 26 text

ブリッジの設定 • ブリッジを設定してRP1の 参加するBus1を作る • 右図赤枠部 • 以降はPCI/PCIeデバイスの 一般的な設定の話 27 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 27

Slide 27 text

ブリッジ設定でやること • PCI config space • command部を設定 • バス番号を設定 • メモリリミットの設定 • PCIe config space • ペイロードサイズの設定 28

Slide 28

Slide 28 text

PCI config headerの詳細 • PCIコンフィギュレーション空間 にあるヘッダ • 前半24-byteは共通ヘッダ部 • 後半の構成はHeader Type事に違う • PCIeの文脈では以下の2種がある • Type0: PCIデバイス(EP) • Type1: PCI-to-PCI Bridge • Typeの判別は共通部のTypeフィ ールドで行う 29 共通部 Type固有部 0x0000 0x0018 0x0040 参考: Figure 3-2: PCI Compatible Configuration Register Space, PCI Express Technology 3.0, Mindshare Type 0x000C 0x0E 0x0C 0x0D 0x0F

Slide 29

Slide 29 text

PCI Header Type1 • PCI to PCI Bridge用のヘッダ • BUS番号の設定やメモリリミ ットの設定ができる • 以降Type1 headerを設定して いく 30 https://wiki.osdev.org/PCI より引用

Slide 30

Slide 30 text

command部の設定 • 以下をHighにする • BusMaster • PCIアクセスを生成するのに必要 • Memory Space • メモリ空間へのアクセスに必要 31 https://wiki.osdev.org/PCI より引用

Slide 31

Slide 31 text

バス番号の設定 • Primary Bus Number(0x18) • Bridgeより上にいるBus番号 • 0を設定 • Secondary Bus Number(0x19) • Bridgeの下に生やすBus番号 • 1に設定 • Subordinate Bus Number(0x1a) • 下流にあるBus番号の最大値 • 1に設定 32 https://wiki.osdev.org/PCI より引用 Bridge Bus1 EndPoint /Device Bus0 Bus:0, Slot:0

Slide 32

Slide 32 text

メモリリミットの設定 • bridgeの下流で利用できるメモリアドレス範囲に制限をかける • 以下のフィールドを設定する • Memory Base(0x20, 16bit) • Memory Limit(0x22, 16bit) • Prefechable Memory Base(0x24, 16bit) • Prefechable Memory Limit(0x26, 16bit) • Prefechable Base Upper 32bit(0x28, 32bit) • Prefechable Limit Upper 32bit(0x2c, 32bit) 33 参考: https://wiki.osdev.org/PCI

Slide 33

Slide 33 text

Prefetchable/Non-Prefetchable Memory • Prefetchable Memory • 読んでも副作用のないメモリ • 事前読み込み(prefetch)可能 • Non-Prefetchable Memory • 読み込みに副作用のあるメモリ • 例: MMIOでフラグレジスタのを読み込むとフラグがリセットされる • 事前読み込み不可 34

Slide 34

Slide 34 text

例: Pi5のメモリプリフェッチ可否領域 • RP1の接続されているメモリ(0x1f_0...0) はNon-Prefetchable • 最初はlimitが0x1f_f...bだけど、後で0x1f_005f_ffffになる • RP1のメモリ空間に合わせて縮小している? (※) • →0x1f_0...0をbase、0x1f_005f_ffffをlimitとしてリミット設定すれば良い • 64bit memory map(0x1c_0...0)はPrefetchable • 使ってない領域なのでskip 35 ↑linuxの起動ログ ※メモリサイズおよびprefetch可否はデバイスのBAR[3]からわかる 参考: https://osdev.jp/wiki/PCI-Memo

Slide 35

Slide 35 text

Non-Prefetchableメモリ設定 • base/limit(オフセット)アドレスの上位12bitを Memory Base/Limitレジスタ(各16bit)の上位 12bitに書き込む(左詰め) • アドレス(32bit)の下位20bitは固定 • Baseは0x0_0000 • Limitは0xF_FFFF • 参考元 • https://www.macnica.co.jp/business/semiconductor/ articles/microchip/140354/ • https://www.macnica.co.jp/business/semiconductor/ articles/microchip/140362/ • Prefetchableな方法はPCI_Express_Technology_3.0, Figure 4.8: Example Prefetchable Memory Base/Limit Register Values,pp.138, MindShareを参照 36 limit 0x005F_FFFF base 0x0000_0000 CPU memory(offset) limit 0x0050 base 0x0000 PCI Type 1 Memory Limit/Base ↑0x1F_0..0 ~ 0x1F_005F_FFFF を通す場合の設定例 >> 20 << 4 >> 20 << 4

Slide 36

Slide 36 text

Extended Configuration Spaceの詳細 • PCIeで追加されたConfiguration Space • PCI configuration Spaceの後ろに ある • 具体的なオフセットはPCIヘッダの 「Capabilities Pointer」に記載 • 対応する速度等の確認や設定を行 う 37 PCI Configuration Space Extended Configuration Space 0x0000 0x0040 0x1000 参考: Figure 3-2: PCI Compatible Configuration Register Space, PCI Express Technology 3.0, Mindshare

Slide 37

Slide 37 text

Extended Configuration Spaceの探索 • Extended Configuration Spaceには複 数のstructureが存在する • どのstructureかはCapability IDで特定 • 今回制御するのはPCI Express Capability Structure(0x01) • Next Cap Pointerを辿って探索 • 0が入っていたら探索終了 • その他の場合、目的のCapIDが見つかる まで探索 38 参考: http://nahitafu.cocolog-nifty.com/nahitafu/2007/02/pci_express_2b63.html PCI Configuration Space Extended Configuration Space CapPtr structure CapPtr structure 0

Slide 38

Slide 38 text

PCI Express Capability Structure • PCIeに関するstatusや設定 が入っている構造体 • PCIeのGenや速度設定がで きる 39 https://www.intel.com/content/www/us/en /docs/programmable/683488/16-0/pci- express-capability-structure.html Figure 31.より引用

Slide 39

Slide 39 text

PCI Express Capability Structure の設定 • Genとリンクスピードの設定 • brcmstb-pciドライバ内で設定 • ペイロードサイズの設定 40 https://www.intel.com/content/www/us/en /docs/programmable/683488/16-0/pci- express-capability-structure.html Figure 31.より引用。 赤枠内は今回設定する部分

Slide 40

Slide 40 text

Genとリンクスピード設定 • Gen設定 • Link Control 2[0:3] で設定 • RP1はGen2設定 • リンクスピード設定 • Link Capabilities[0:3] で設定 • RP1は5.0GT/s 設定 • RO だけどなぜか設定できる(※) 41 https://www.intel.com/content/www/us/en /docs/programmable/683488/16-0/pci- express-capability-structure.html Table 55,60より引用 ※ linuxではdtsでgenを設定すると強制的にそのGenでの設定を試みる ↑これはnvme接続時(PCIe1)にPCIe1をGen3に設定する話とは多分無関係

Slide 41

Slide 41 text

Bridgeのペイロードサイズ設定 • ペイロードサイズ • PCIeでやり取りするデータのパケットサイズ • 参考: https://faq-avaldata.dga.jp/faq_detail.html?id=150 • 最大サイズはDevice Capabilities Registerから取得 • Linuxでは MPS(Max Payload Size) • BridgeのMPSは、自身と下流のデバイスのMPSの最小値を設定 42

Slide 42

Slide 42 text

bridgeのMPS設定例 • 例: Pi 5 linux起動時のdmesg • bridgeのMPSは512だけど、RP1のMPS が256なので256(/512)を設定 • ログを出しているコード • https://github.com/raspberrypi/linux/blob/7 69634f344626ed73bcda14c91b567067974d7 b2/drivers/pci/probe.c#L2070 43 Bridge Bus1 RP1 MPS 512 設定値 256 MPS 256 設定値 256

Slide 43

Slide 43 text

デバイス(EP)設定 45

Slide 44

Slide 44 text

デバイス(EP)設定 • RP1のデバイスを設定 • 主にBARを使ってCPUとデバイス のメモリマップを設定する 46 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 45

Slide 45 text

デバイスの設定 • command部の設定 • bridgeと同じなのでskip • BARの設定 • payload sizeの指定 • これもbridgeと同じなのでskip 47

Slide 46

Slide 46 text

PCI Header Type0 • PCI device(EP)用のヘッダ • Type1(bridge)と比べるとBAR が多い 48 https://wiki.osdev.org/PCI より引用

Slide 47

Slide 47 text

BaseAddressRegister(BAR) • PCIデバイスのメモリをCPUにマップ するためのレジスタ • BARにはCPU側のメモリアドレスの オフセットを設定 • ベースはRCが決める • PCIデバイスのどのメモリ(とアドレ ス)にどのBARが対応してるかはデ バイス次第(?) • マニュアル参照 • 32bitアドレスは1つ、64bitは2つで設 定 • 詳細はosdev-jpのwiki参照 • https://osdev.jp/wiki/PCI-Memo 49 processor memory space device memory space BAR2 0x4000_0000 0x1f_40..0 RC BAR 0x1f_0...0

Slide 48

Slide 48 text

例: RP1のBAR設定 • RP1はBAR1にペリフェラル、BAR2にShared SRAMが割当 • > The AP accesses Peripherals and Shared SRAM over PCIe as offsets from the assigned base addresses in BAR1 and BAR2 respectively. • 2.3.1. PCIe and 40-bit to peripheral address mapping, Raspberry Pi RP1 Peripherals, https://datasheets.raspberrypi.com/rp1/rp1-peripherals.pdf より 引用 • LinuxではBAR1をoffset 0, BAR2をoffset 0x0040_0000に設定 • RCでbaseを0x1f_0000_0000 に設定しているため 50

Slide 49

Slide 49 text

コードとデモ https://github.com/tnishinaga/pi5_hack/tree/develop/baremetal/XX_pcie 51

Slide 50

Slide 50 text

PCIe関係の初期化と設定 52 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 51

Slide 51 text

UARTとGPIOの設定 53 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 52

Slide 52 text

Hello World 54 SoC Bridge Bus1 EndPoint /Device Bus:1, Slot:1 Bus0 Bus:0, Slot:0 Processor PCI/PCIe controller Host/PCI Bridge Root Complex

Slide 53

Slide 53 text

動作デモ動画 55

Slide 54

Slide 54 text

まとめ • PCIデバイスはデバイスのメモリをCPUメモリにマップして制 御する • Pi 5でPCIeデバイスとおしゃべりするには以下を設定する • PCIeコントローラー • Root Complex • PCIe bridge • PCIe device 56

Slide 55

Slide 55 text

オチ • 実はfirmwareの設定をすればPCIeドライ バ自作は不要だった • 初期化済みのPCIe&RP1のセットをKernelに わたすオプションがある • https://tnishinaga.hatenablog.com/entry/2024/ 06/04/012033 • SoC内のUARTペリフェラルもearly printに 使える • Debug端子からシリアル出力できる • https://forums.raspberrypi.com/viewtopic.php? p=2159255&hilit=pciex4_reset%3D0#p2159255 57 Pi 5のDebug端子

Slide 56

Slide 56 text

参考資料 • PCI Express Technology 3.0, Mindshare • 一番参考になった本 • PCIeに関する情報が網羅的に書かれている • PCI/PCIeデバイス設定方法に関する記述は少なめ • https://www.mindshare.com/Books/Titles/PCI_Express_Technology_3.0 • Stratix V Avalon-ST Interface with SR-IOV PCIe Solutions: User Guide • PCIe capabilities structureの詳細が書かれている • https://www.intel.com/content/www/us/en/docs/programmable/683488/16-0/pci-express-capability-structure.html • osdev • configuration spaceの詳細を理解するのに有用 • https://wiki.osdev.org/PCI • https://wiki.osdev.org/PCI_Express • マクニカの特集やFAQ • 特定レジスタの詳細を知るのに有用 • https://www.macnica.co.jp/business/semiconductor/support/faqs/intel/92193/ • osdev-jp • BARの詳細がわかる • https://osdev.jp/wiki/PCI-Memo 58