Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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を使って割り込みを処理する方法をご紹介します。

Toshifumi NISHINAGA

February 08, 2020
Tweet

More Decks by Toshifumi NISHINAGA

Other Decks in Programming

Transcript

  1. BareMetalで遊ぶ Raspberry Pi 4
    - GIC v2編-
    2020/02/08
    KernelVM Kansai@10
    @tnishinaga
    1

    View full-size slide

  2. 今日のコード
    https://github.com/tnishinaga/baremetal_pi4_irq_sample
    2

    View full-size slide

  3. 動機と目的
    3

    View full-size slide

  4. 2019/11/26 Raspberry Pi 4 日本販売開始
    4

    View full-size slide

  5. Q. Pi 4でなにがしたい?
    5

    View full-size slide

  6. A. Pi 4でBareMetal開発したい!!
    6

    View full-size slide

  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

    View full-size slide

  8. ● Pi 4で追加された割り込みコントローラGICv2への対応が必要
    ● 参考
    ○ dtsの目diff結果
    https://docs.google.com/spreadsheets/d/1e51SxsiOClDed5u0zteMjrxNY6Pgj7kWrGNz7XM0o
    ek/edit?usp=sharing
    ○ BCM2711について @eggman
    https://qiita.com/eggman/items/402d8ba20fa021cc4531
    Pi 4でも既存のコードを動かすには
    8

    View full-size slide

  9. 発表の目標
    9
    読んだ人がBareMetal Raspberry Pi 4
    でGICv2使った割り込みをできるようにする

    View full-size slide

  10. 割り込みコントローラ
    10

    View full-size slide

  11. 割り込みコントローラとは
    ● 大体以下の機能をもつもの
    ○ ペリフェラル等からの割り込みをフィルタ
    ○ 適切なプロセッサに割り込みをルーティング
    11
    Interrupt
    Controller
    Processor
    Peripheral
    N 1 N
    1

    View full-size slide

  12. Raspberry Piの割り込みコントローラ
    ● BCM2835(初代), BCM2836-BCM2837(Pi2-Pi3), BCM2711(Pi4)で異なる
    12

    View full-size slide

  13. BCM2835の割り込みアーキテクチャ
    ● コントローラはbcm2835-armctrl-icのみ
    13
    bcm2835-a
    rmct-ic
    Processor
    Peripheral
    N 1 1
    1

    View full-size slide

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

    View full-size slide

  15. Raspberry Pi 2登場
    ● マルチコアになった
    ● BCM2835-armctrl-icはマルチコア対応していない
    ● Q. どうしたか?
    ● A. もう一つ割り込みコントローラを追加した
    ○ https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
    15

    View full-size slide

  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

    View full-size slide

  17. BCM2711の割り込み
    ● GICv2だけになったはず
    ○ 割り込みの親はすべて GICv2のはず
    ○ 一応bcm2836-arm-l1-intcも搭載
    (armstubでプリスケーラの設定などに使ってる)
    ● GICv2でフィルタとルーティング
    17
    GICv2 Processor
    Peripheral
    N 1 N
    1

    View full-size slide

  18. Generic Interrupt Controller version 2(GICv2)とは
    ● arm社の作った割り込みコントローラ
    ● 仮想化支援機能あり
    ● セキュリティ機能あり
    ○ 一部レジスタアクセス制限など
    19

    View full-size slide

  19. ● 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

    View full-size slide

  20. その他情報源
    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の説明。レジスタ名などが異なるが大まかな部分は同じ。

    View full-size slide

  21. 用語説明
    22
    ● 割り込みタイプ
    ○ SGI
    ○ PPI
    ○ SPI
    ● Interrupt ID
    ● GICの機能ブロック
    ○ Distributor
    ○ CPU Interface
    ○ Virtual CPU Interface
    ■ Virtual interface control
    ■ Virtual CPU interface

    View full-size slide

  22. 割り込みタイプ
    ● Software Generated Interrupt(SGI)
    ○ ソフトウェア割り込み
    ○ GICD_SGIRレジスタに書き込むと発生させられる
    ○ interprocessor communication(IPC)に使う
    ● Private Peripheral Interrupt(PPI)
    ○ 特定プロセッサ用のペリフェラル割り込み
    ● Shared Peripheral Interrupt(SPI)
    ○ プロセッサを指定しないペリフェラル割り込み
    ○ どのプロセッサに割り込みを送るかは要設定
    23

    View full-size slide

  23. 割り込みID
    ● 割り込み要因に割り当てられたID
    ● IDの割当は実装依存
    ● IDの範囲は0 - 1023
    ● 割り込みタイプによって番号の割当範囲が決まってる
    ○ SGI : 0 - 15
    ○ PPI : 16 - 31
    ○ SPI : 32 - 1019
    ○ 特殊用途: 1020 - 1023
    24

    View full-size slide

  24. GICの機能ブロック
    ● Distributor
    ○ 割り込み優先度や割り込みのルーティングを設定する
    ● CPU Interface
    ○ 各プロセッサに届いた割り込みを処理するためのブロック
    ○ プロセッサ毎にあるらしい(試せてない)
    ● Virtual CPU Interface
    ○ 仮想マシンで使うらしい
    ○ 今回は扱わないので省略
    25
    Distributor
    CPU Interfaces
    Peripherals
    Processors
    GIC

    View full-size slide

  25. GICv2のレジスタ
    ● 機能ブロックごとにレジスタのブロックが分かれている
    ● レジスタ名にはブロック名前が入る
    ○ Distributor(GICD_*)
    ○ CPU Interface(GICC_*)
    ○ Hypervisor(GICH_*)
    ○ Virtual CPU Interface(GICV_*)
    26

    View full-size slide

  26. セキュアアクセスとノンセキュアアクセス
    ● 一部レジスタへのアクセスを制限できる
    ● Pi 4のカーネルはEL2で動くのでノンセキュアアクセスしかできない
    ○ Raspberry Piはkernel起動前にEL3(secure)からEL2(non-secure)に移行するため
    ● 今回はノンセキュア時の設定のみ紹介
    27

    View full-size slide

  27. GICv2の初期設定
    (Raspberry Pi 4の場合)
    28

    View full-size slide

  28. ● GICv2を理解するために
    UART入力割り込みを受けて、
    入力を出力におうむ返しするプログラムを作る
    目標
    29

    View full-size slide

  29. やること
    ● GICv2レジスタのベースアドレス調査
    ● UARTの割り込みIDの調査
    ● armstubで行っている初期設定確認
    ● GIC初期化コード記述
    ● 割り込み処理コード記述
    30

    View full-size slide

  30. 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 より引用

    View full-size slide

  31. 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 より引用

    View full-size slide

  32. 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

    View full-size slide

  33. Pi4での割り込み初期設定コード
    1. ペリフェラルの割り込み設定
    a. UART入力割り込みを有効化
    2. 割り込みコントローラ設定
    a. 後述
    3. プロセッサの割り込み設定
    a. ベクタテーブル設定
    b. 割り込みのルーティング設定( EL1以外では必要)
    c. IRQ割り込みの有効化(DAIFレジスタ)
    34

    View full-size slide

  34. Pi4での割り込み初期設定コード
    1. ペリフェラルの割り込み設定
    a. UART入力割り込みを有効化
    2. 割り込みコントローラ設定
    a. 後述
    3. プロセッサの割り込み設定
    a. ベクタテーブル設定
    b. 割り込みのルーティング設定( EL1以外では必要)
    c. IRQ割り込みの有効化(DAIFレジスタ)
    35

    View full-size slide

  35. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    36

    View full-size slide

  36. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    37

    View full-size slide

  37. GICD_TYPERで割り込みIDの最大値を調べる
    ● 全割り込みを初期設定するためにはIDの総数は必須
    ● 割り込みIDの数は実装依存
    ● GICD_TYPERレジスタの下位5bit(= ITLinesNumber)を以下の式で計算
    ● 割り込みIDの数 = (2 ^ ITLinesNumber) - 1
    38
    ITLinesN
    umber
    LSPI
    Reserved
    16|15 11 9 8
    10 7 5 4 0
    Reserved
    SecurityExtn
    CPU Number

    View full-size slide

  38. GICv2の初期設定(non-secure, Pi 4の場合)
    39
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定

    View full-size slide

  39. GICD_ISENABLERで割り込みを有効するIDを設定
    ● 割り込みを有効に設定するレジスタたち
    ● 対応するビットを1にすると有効化
    ● 例:割り込みIDがmの割り込みを有効化
    ○ GICD_ISENABLER [ m / 32 ] |= 1 << m mod 32
    ○ (GICD_ISENABLERの型はuint32_t)
    40
    Set-enable bits
    31 0

    View full-size slide

  40. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    41

    View full-size slide

  41. 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

    View full-size slide

  42. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    43

    View full-size slide

  43. ● 割り込みルーティング先プロセッサ(複数可らしい)を指定するレジスタ
    ● 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

    View full-size slide

  44. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    45

    View full-size slide

  45. GICD_CTLRでDistributorを有効化
    ● 有効化するとCPU Interfaceに割り込みが送られるようになる
    ● non-secure時は最下位ビットを1にするとDistributorが有効化
    46

    View full-size slide

  46. GICv2の初期設定(non-secure, Pi 4の場合)
    ● GICD_TYPERで割り込みIDの最大値を調べる
    ● GICD_ISENABLERで割り込みを有効するIDを設定
    ● GICD_PRIORITYRで割り込み優先度を設定
    ● GICD_ITARGETSRで送り先プロセッサ設定
    ● GICD_CTLRでDistributorを有効化
    ● GICC_CTLRで割り込みを許可するグループを設定
    47

    View full-size slide

  47. GICC_CTLRで割り込みを許可するグループを設定
    ● 一部レジスタアクセス時の挙動やIRQ, FIQのバイパス設定、特定グループの割り
    込み有効化ができるレジスタ
    ● Pi4の場合は最下位ビットのEnableGrp1を1にすると割り込みがプロセッサに送ら
    れる
    48

    View full-size slide

  48. コントローラ設定コード
    ● GICDを停止
    ● 割り込みID数を確認
    ● UART割り込みを有効化
    ● 優先度を最高(0)に設定
    ● 宛先プロセッサを0に設定
    ● GICCを有効化
    ● GICDを有効化
    49

    View full-size slide

  49. Pi4での割り込み処理(発生から復帰まで)
    50
    レジスタ保存
    レジスタ復旧
    割り込みベクタ
    IRQ
    GIC:割り込みID確認
    割り込み処理
    割り込みハンドラ
    GIC:割り込み終了
    eret

    View full-size slide

  50. Pi4での割り込み処理(発生から復帰まで)
    51
    レジスタ保存
    レジスタ復旧
    割り込みベクタ
    IRQ
    GIC:割り込みID確認
    割り込み処理
    割り込みハンドラ
    GIC:割り込み終了
    eret

    View full-size slide

  51. ● GICC_IARで最優先割り込みIDを取得
    ● 割り込みを処理
    ● GICC_IARの値をGICC_EOIRに書いて割り込みを完了
    GICv2の割り込み処理手順(non-secure)
    52

    View full-size slide

  52. ● GICC_IARで最優先割り込みIDを取得
    ● 割り込みを処理
    ● GICC_IARの値をGICC_EOIRに書いて割り込みを完了
    GICv2の割り込み処理手順(non-secure)
    53

    View full-size slide

  53. GICC_IARで最優先割り込みIDを取得
    ● 現在入っている最も優先度の高い割り込みIDが得られるレジスタ
    ● このレジスタを読んで適切な割り込み処理を呼び出す
    54
    Interrupt ID
    CPU
    ID
    Reserved
    13|12 0
    10|9

    View full-size slide

  54. ● GICC_IARで最優先割り込みIDを取得
    ● 割り込みを処理
    ○ 割愛
    ● GICC_IARの値をGICC_EOIRに書いて割り込みを完了
    GICv2の割り込み処理手順(non-secure)
    55

    View full-size slide

  55. ● GICC_IARで最優先割り込みIDを取得
    ● 割り込みを処理
    ● GICC_IARの値をGICC_EOIRに書いて割り込みを完了
    GICv2の割り込み処理手順(non-secure)
    56

    View full-size slide

  56. GICC_EOIRで最優先割り込みIDを取得
    ● 割り込みIDを書き込むと、その割り込み処理を完了できる
    ● GICC_IARで読んだ内容をそのまま書き込めば良い
    57
    Interrupt ID
    CPU
    ID
    Reserved
    13|12 0
    10|9

    View full-size slide

  57. 割り込み処理
    ● GICC_IARで割り込みID取得
    ● UART割り込みか確認
    ● UART受信&送信
    ● UART割り込みフラグクリア
    ● GICC_EOIRで割り込み完了
    58

    View full-size slide

  58. まとめ
    ● Pi 4から割り込みコントローラがGICv2(GIC-400)になった
    ● Pi 4上でGICv2の割り込み制御を行う方法を解説した
    ○ Pi4ではnon-secureモードの設定を行えば良い
    ○ (dtsに書かれたSPIのID + 32)がGICでのInterrupt IDになる
    61

    View full-size slide