BareMetalで遊ぶ Raspberry Pi 4 - GIC v2編-/BareMetal Raspberry Pi 4 - GICv2 -

BareMetalで遊ぶ Raspberry Pi 4 - GIC v2編-/BareMetal Raspberry Pi 4 - GICv2 -

KernelVM 関西 10回目の発表資料(省略なし)版です。
BereMetal Raspberry Pi 4のGICv2を使って割り込みを処理する方法をご紹介します。

Bdd3fb3269e67bbc512f2530c409a926?s=128

Toshifumi NISHINAGA

February 08, 2020
Tweet

Transcript

  1. 7.

    過去の実績 • 初代Raspberry Pi(BCM2835) ◦ ARMv6での自作コード起動、 GPIO、UART、SPI、I2C、割り込みまでBareMetal開発をした ◦ やり方をまとめて本を出した ▪

    https://tatsu-zine.com/books/raspi-bm • Raspberry Pi 2(BCM2836) ◦ 割愛 • Raspberry Pi 3(BCM2837) ◦ ARMv8 64bitモードで起動、GPIO、UART、割り込みまでBareMetal開発をした ↑ Pi4でも動かしたい ◦ やり方をまとめてセキュリティ・キャンプ 2019の教材として配布 7
  2. 15.

    Raspberry Pi 2登場 • マルチコアになった • BCM2835-armctrl-icはマルチコア対応していない • Q. どうしたか?

    • A. もう一つ割り込みコントローラを追加した ◦ https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf 15
  3. 16.

    BCM2836/BCM2837の割り込み • bcm2835-armctrl-ic (arm_control) で割り込みをフィルタ • bcm2836-arm-l1-intc (IRQ routing) でルーティング

    16 図は「BCM2836 ARM-local peripherals, 3.2 Interrupt routing, pp.4」より引用 https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/Q A7_rev3.4.pdf
  4. 18.
  5. 20.

    • ARM® Generic Interrupt Controller Architecture version 2.0 Architecture Specification

    ◦ https://static.docs.arm.com/ihi0069/c/IHI0069C_gic_architecture_specification.pdf ◦ GICv2全体の仕様が書いてある。基本これだけで良い。 • CoreLink GIC-400 Generic Interrupt Controller Technical Reference Manual ◦ http://infocenter.arm.com/help/topic/com.arm.doc.ddi0471a/DDI0471A_gic400_r0p0_trm.pdf ◦ Pi 4に乗ってるGICの実装。実装依存の機能を扱いたい場合に読む。 マニュアルの場所 20
  6. 21.

    その他情報源 21 • TOPPERSプロジェクト 設計メモ GIC(ARM Generic Interrupt Controller)に関す るメモ

    ◦ https://dev.toppers.jp/trac_user/contrib/export/306/asp3_wo_tecs/trunk/arch/arm_gcc/doc/gic_ memo.txt ◦ GICv2の説明が日本語で箇条書きで書かれている。わかりやすい。 • GIC(汎用割り込みコントローラ)|Cortex-A編 - APS ◦ https://www.aps-web.jp/academy/ca/08/ ◦ 多分GICv1の説明。レジスタ名などが異なるが大まかな部分は同じ。
  7. 22.

    用語説明 22 • 割り込みタイプ ◦ SGI ◦ PPI ◦ SPI

    • Interrupt ID • GICの機能ブロック ◦ Distributor ◦ CPU Interface ◦ Virtual CPU Interface ▪ Virtual interface control ▪ Virtual CPU interface
  8. 23.

    割り込みタイプ • Software Generated Interrupt(SGI) ◦ ソフトウェア割り込み ◦ GICD_SGIRレジスタに書き込むと発生させられる ◦

    interprocessor communication(IPC)に使う • Private Peripheral Interrupt(PPI) ◦ 特定プロセッサ用のペリフェラル割り込み • Shared Peripheral Interrupt(SPI) ◦ プロセッサを指定しないペリフェラル割り込み ◦ どのプロセッサに割り込みを送るかは要設定 23
  9. 24.

    割り込みID • 割り込み要因に割り当てられたID • IDの割当は実装依存 • IDの範囲は0 - 1023 •

    割り込みタイプによって番号の割当範囲が決まってる ◦ SGI : 0 - 15 ◦ PPI : 16 - 31 ◦ SPI : 32 - 1019 ◦ 特殊用途: 1020 - 1023 24
  10. 25.

    GICの機能ブロック • Distributor ◦ 割り込み優先度や割り込みのルーティングを設定する • CPU Interface ◦ 各プロセッサに届いた割り込みを処理するためのブロック

    ◦ プロセッサ毎にあるらしい(試せてない) • Virtual CPU Interface ◦ 仮想マシンで使うらしい ◦ 今回は扱わないので省略 25 Distributor CPU Interfaces Peripherals Processors GIC
  11. 31.

    GICv2レジスタのベースアドレス調査 • ベースアドレスは0xff841000 ◦ rangesで0x40000000が0xff800000に変換 • 各レジスタのアドレス ◦ GICD: 0xff841000

    ◦ GICC: 0xff842000 ◦ GICH: 0xff844000 ◦ GICV: 0xff846000 31 https://github.com/raspberrypi/linux/blob/rpi-4.19.y/ arch/arm/boot/dts/bcm2838.dtsi より引用
  12. 32.

    UARTの割り込みID調査 • 割り込みIDは153 ◦ dtsに書かれているのは SPIの中で何番目かの値 ◦ GICではその前にSGIとPPIがいるので32を加算した 値がGICの割り込みIDになる ◦

    詳しくはマニュアル参照 https://github.com/raspberrypi/linux/blob/rpi-4.19.y/Documentation /devicetree/bindings/interrupt-controller/arm,gic.txt 32 https://github.com/raspberrypi/linux/blob/rpi-4.19.y/ arch/arm/boot/dts/bcm2838.dtsi より引用
  13. 33.

    armstubで行なっている初期設定確認 • Raspberry Pi はEL3でarmstubを実行し、EL2に降りてカーネルを起動する ◦ https://github.com/raspberrypi/tools/blob/master/armstubs/armstub8.S • armstubで以下のGIC設定を行ってから起動する ◦

    GICD_CTLRでGroup1とGroup0の割り込みを有効化 ◦ GICC_CTLRでGroup関係なくIRQをGICで制御するよう設定 ◦ GICC_PMRで割り込み優先度マスクを 0xff(全レベル)に設定 ◦ GICD_IGROUPRで全割り込みIDをGroup1に設定 33
  14. 34.

    Pi4での割り込み初期設定コード 1. ペリフェラルの割り込み設定 a. UART入力割り込みを有効化 2. 割り込みコントローラ設定 a. 後述 3.

    プロセッサの割り込み設定 a. ベクタテーブル設定 b. 割り込みのルーティング設定( EL1以外では必要) c. IRQ割り込みの有効化(DAIFレジスタ) 34
  15. 35.

    Pi4での割り込み初期設定コード 1. ペリフェラルの割り込み設定 a. UART入力割り込みを有効化 2. 割り込みコントローラ設定 a. 後述 3.

    プロセッサの割り込み設定 a. ベクタテーブル設定 b. 割り込みのルーティング設定( EL1以外では必要) c. IRQ割り込みの有効化(DAIFレジスタ) 35
  16. 36.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 36
  17. 37.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 37
  18. 39.

    GICv2の初期設定(non-secure, Pi 4の場合) 39 • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定

    • GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定
  19. 41.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 41
  20. 42.

    GICD_PRIORITYRで割り込み優先度を設定 • 割り込みの優先度(0 - 255)を設定するレジスタたち • 1つのIDあたり8bitで設定 • 優先度は0が最高、255が最低 •

    例:割り込みIDがmの割り込み優先度を最高にする ◦ GICD_PRIORITYR[ m / 4 ] &= ~(0xff << ((m mod 4) * 8)) ◦ (GICD_PRIORITYRの型はuint32_t) 42 31 0 Priority Priority Priority Priority 8|7 16|15 24|23
  21. 43.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 43
  22. 44.

    • 割り込みルーティング先プロセッサ(複数可らしい)を指定するレジスタ • 2の冪数で指定する • 例:割り込みIDがmの割り込みをプロセッサxに送る ◦ GICD_ITARGETSR[ m /

    4 ] |= (1 << x) << ((m mod 4) * 8) ◦ (GICD_ITARGETSRの型はuint32_t, レジスタ内はクリアされてるものとする ) GICD_ITARGETSRで送り先プロセッサ設定 44 31 0 CPU targets CPU targets CPU targets CPU targets 8|7 16|15 24|23
  23. 45.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 45
  24. 47.

    GICv2の初期設定(non-secure, Pi 4の場合) • GICD_TYPERで割り込みIDの最大値を調べる • GICD_ISENABLERで割り込みを有効するIDを設定 • GICD_PRIORITYRで割り込み優先度を設定 •

    GICD_ITARGETSRで送り先プロセッサ設定 • GICD_CTLRでDistributorを有効化 • GICC_CTLRで割り込みを許可するグループを設定 47
  25. 59.