Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

動機と目的 3

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

過去の実績 ● 初代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

Slide 8

Slide 8 text

● 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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

割り込みコントローラ 10

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

GICv2 18

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

● 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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

デモ 59

Slide 60

Slide 60 text

まとめ 60

Slide 61

Slide 61 text

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