ARM GIC(General Interrupt Controller)仕様書の勉強

#概要
ARM GICの日本語ドキュメントが
https://www.aps-web.jp/academy/ca/224/
くらいしかなかったので、GICの仕様書
GIC (General Interrupt Controller) Architecture Version 1.0
http://download.xskernel.org/docs/processors/arm/IHI0048A_gic_architecture_spec_v1_0.pdf
を訳しながら勉強してみた。

※
日本語にすると不自然な単語は英語のまま書いています
興味のあるところから訳しています
<font color="Red">赤文字：重要だと思った部分</font>
<font color="Green">緑文字：個人的なコメント</font>

SW視点だとGICのステートマシンは理解しておく必要があると思った

#1. イントロダクション
#1.3用語
###1.3.1 割り込み状態
次の状態がGICとプロセッサ間でのインターフェースとして適用される

- Inactive
    - activeでもpendingでもない状態
- Pending
    - GICへの割り込みがハードウェアでアサートされたと認識されている状態。もしくは、ソフトウェアが生成して、ターゲットプロセッサから使用されるのを待っている状態
- Active
    - GICへの割り込みがプロセッサによってacknowledgeされ、処理されているが完了していない状態
- Active and Pending
    - プロセッサが処理中で、同じソースからの割り込みがGICで保持している状態
   

###1.3.2 割り込みタイプ

- ペリフェラル割り込み
    - Private Peripheral Interrupt(PPI)
        - 1つのプロセッサに固有のペリフェラル割り込み
    - Shared peripheral Interrupt(SPI)
        - ディストリビュータがプロセッサの組み合わせにルーティングできるペリフェラル割り込み
    - 各ペリフェラル割り込みは以下のどれかとなる
        - エッジトリガー
            - 割り込み信号の立ち上がりでアサートされ、信号の状態にかかわらず、定義された仕様でコンディションがクリアされるまでアサートを維持する
        - レベルセンシティブ
            - 割り込み信号がHighのときはいつでもアサートされ、Lowのときはいつでもディアサートされる
- Software-generated Interrupt(SGI)
    - SWがGICの特定のレジスタに書き込むことによって発生する割り込み。プロセッサ間の通信に使われる
    - SW割り込みはエッジトリガ特性となる。ソフトウェアの割り込みトリガは、ペリフェラルのエッジトランジションと同等である

###1.3.3 割り込みハンドリングのモデル
マルチプロセッサでは以下の２つのモデルがある

- 1-N model
    - １つのプロセッサが割り込みをハンドルする。システムとしてどのプロセッサが割り込みをハンドルするか決める実装をする必要がある
- N-N model
    - すべてのプロセッサが独立して割り込みをハンドルする。プロセッサが割り込みをacknowledgeすると、pending状態はそのプロセッサに対してクリアされる。他のプロセッサに対してはpending状態を維持する

###1.3.4 疑似割り込み (Spurious Interrupts)
###1.3.6 バンク
- 割り込みバンク
    - マルチプロセッサでは、PPI, SGIでは、GICは同じ割り込みIDを持つ割り込みを持つことができる。このような割り込みをbanked interruptと呼び、割り込みIDと関連したCPUインターフェースの組み合わせで認識される。
- レジスタバンク
    - レジスタバンクは同じアドレスのレジスタに対する複数コピーの実装である。以下を発生させる
        - マルチプロセッサでは、いくつかのレジスタはバンク割り込みに対応する
        - セキュリティ拡張を使うGICでは、いくつかのレジスタでsecure, non-secureのコピーを使う

#Chapter2 GICパーティショニング (GIC Partitioning)
##2.1 GICパーティショニングについて
GICアーキテクチャは、論理的に１つのディストリビュータブロックと１つ以上のCPUインターフェースブロックに分割される。Figure2-1参照
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/7e8ccfe4-04e1-8373-fa69-1a1c843076da.png)

- ディストリビュータ
    - 割り込み優先度の実施とCPUインターフェースへの分配をする
- CPUインターフェース
    - 各CPUインターフェースは、優先度のマスクとプリエンプションの管理を行う

各ブロックは、GICプログラマーモデルのパーツとなり、そのプログラマーモデルはおおまかには各CPUインターフェースの実装と同じである。このモデルは１つかマルチプロセッシングのGIC実装をサポートする。

***Note***
- GICのディストリビュータ、CPUインターフェスへの分割は抽象化されたアーキテクチャである。実際にはどのブロックが別々に、または統合されて実装されているかにより、実装依存となる。
- マルチプロセッサでのセキュリティ拡張が実装されたGICでは、CPUインターフェスは以下を受け取れるように実装できる
    - Secure, Non-secureのアクセス
    - Secureアクセスのみ
    - Non-secureアクセスのみ

GICは最大8(番号0-7)までのCPUインターフェスを実装できる。

##2.2 ディストリビュータ(The Distributor)
ディストリビュータはすべての割り込みソースを集中させ、各割り込みの優先度を決定する。また各CPUインターフェースのために、最も高い優先度の割り込みをディスパッチする。
ディストリビュータはプログラミングインターフェースとして以下を提供する

- CPUインターフェースへの転送をグローバルに有効化する
- 各割り込みへのenable, disable
- 各割り込みへの優先度設定
- 各割り込みへのターゲットプロセッサの設定
- ペリフェラルインターフェースに対するレベルセンシティブ、エッジトリガーの設定
- GICがセキュア環境を実装していた場合、各割り込みのSecure, Nonk-secureの設定
- SGIを1つまたは複数のターゲットプロセッサへの送信

加えて

- 各割り込み状態の視覚化
    - <font color="Green">※レジスタから割り込みの状態を見れるということだと思う</font>
- ペリフェラル割り込みのpending状態をセット、クリアする仕組み

###2.2.1 割り込みID(Interrupt IDs)
ソースからの割り込みは、IDを使って認識される。各CPUインターフェースは1020の割り込みを認識できる。SPI, PPIのバンクを考慮すると、ディストリビュータは1244までサポートしている
GICは割り込みID0-1019を以下のようにアサインする

- 割り込み番号ID32-ID1019はSPIに使われる
- 割り込み番号ID0-ID31はCPUインターフェースへのプライベート割り込み、ディストリビュータへのバンクとして使用される
    - バンクされた割り込みは、ディストリビュータが同じIDで複数の割り込みを持つことができる。バンクされた割り込みはIDとCPUインターフェース番号で一位に認識される
        - ID0-ID15はSGI
        - ID16-ID31はPPI
    - マルチプロセッサシステムでは
        - PPIは固有のCPUインターフェスにシグナルされ、そのインターフェスにとってプライベートとなる。CPUインターフェスへの優先度付けでは、ディストリビューターはPPIのみを考慮にいれる。
        - 各CPUは `ICDSGIR` に書き込むことでSGIを発行できる。各SGIは複数のプロセッサをターゲットにできる。ディストリビューター、ターゲットプロセッサでは、SGIは割り込みID0-15とプロセッサソースID(CPUID0-CPUID7)の組み合わせで認識される。SGIをバンクするとは、GICがリソースの競合なしに複数のソフトウェア割り込みを同時にハンドルできることを意味する。ディストリビュータはCPUインターフェースに接続されていないプロセッサから `ICDSGIR` に書き込まれても無視する。どのようにディストリビュータが `ICDSGIR` に書き込んだプロセッサソースIDを決めているかは実装依存である
    - 1つのプロセッサシステムでは、shared, private割り込みの違いはない。プロセッサIDが常に0となるからだ。
- ID1020-ID1023は特殊用途に予約されている

ソフトウェアは各割り込み番号に対して優先度を設定することができる。

##2.3 CPUインターフェース(CPU Interfaces)
各CPUインターフェースブロックは、各CPUがGICを操作するインターフェスを提供する。各CPUインターフェスは以下のプログラミングインターフェスを提供する。

- CPUインターフェースからの割り込み要求シグナルをenableする
- 割り込みをacknowledgeする
- 割り込み処理完了を示す
- プロセッサに対して割り込みマスクする
- プロセッサに対するプリエンプションポリシーを定義する
- pending状態の割り込みから優先度の最も高い割り込みを決定する

enable時には、CPUインターフェースは接続されているプロセッサへの最も優先度の高いpending状態の割り込みを選択して、プロセッサへの割り込み要求へシグナルするための十分な優先度を持っているかどうか決定する。どの割り込み要求をプロセッサにシグナルするのかを決めるために、CPUインターフェースは、プロセッサに設定された割り込み優先度マスクとプリエンプションを管区人する。いつでも接続されたプロセッサはCPUインターフェースレジスタから、最も優先度の高いactiveな割り込みの優先度をリードすることができる。
プロセッサへのシグナル方法は実装依存となっている。

***Note***
ARMプロセッサの実装では、割り込み要求をシグナルするトラディショナルな方法は、nIRQ, nFIQのアサートである

<font color="Red">プロセッサは、CPUインターフェースのacknowledgeレジスタを読むことで、割り込みリクエストをacknowledgeできる。</font>CPUインターフェースは以下のうち１つをリターンする

- もし割り込みがプロセッサに割り込み例外を発生させるのに十分な優先度を持っていた場合、pending状態の割り込みのうち最も高いID。これはacknowledgeに対する通常のレスポンスである
- 例外として疑似割り込みを示すIDを返すことがある

<font color="Red">プロセッサがCPUインターフェースで、割り込みをacknowledgeすると、ディストリビュータは割り込み状態をpendingからactive or active pending状態へ遷移させる。</font>。このときCPUインターフェースは、activeな割り込みをプリエンプトさせるために、もう１つの割り込みにシグナルを送ることができる。プロセッサに対して、シグナルするのに十分な優先度をもったpending割り込みがない場合は、インターフェースは割り込み要求をdeassertする.

割り込みハンドラが処理を終了すると、割り込みが終了したことを示すためにCPUインターフェースに書き込む。このとき、ディストリビュータは、割り込みを以下のどれかの状態に変更する

- activeからinactive
- active and pendignからpending

#Chapter3 割り込みハンドリングと優先度(Interrupt Handling and prioritization)
##3.1 割り込みハンドリングと優先度について
このサブセクションでは、GICによってサポートされる割り込み情報について詳しく説明する。また接続されたプロセッサがどのように、割り込みIDの範囲を決定すべきかを説明する

- マルチプロセッサでの異なる割り込みタイプのハンドリング
- サポートされている割り込みの認識

割り込みハンドリングについては以下を説明する

- どのようにGICが割り込みを認識するか
- そのようにソフトウェアが割り込みを認識、コントロールできるようにGICをプログラムするか
- GICが維持する各CPUインターフェースに対する各割り込みの状態遷移
- どのようにexceptionモデルがGICと相互作用するか

優先度については以下を説明する

- 割り込み優先度の設定、制御
- pending状態割り込みの実行順序
- いつ割り込みがプロセッサに対して見えるかの決定
    - 割り込み優先度マスク
    - 割り込みグルーピング
    - active割り込みのプリエンプション

GICアーキテクチャはユニプロセッサ、マルチプロセッサをサポートする。どちらでもGICはARM Security拡張を実装できる。GICは以下をSecurity Extensionで実装する

- GICレジスタへのSecureまたはNon-secureアクセスを実装したプロセッサの認識
- 以下のサポート
    - SecureまたはNon-secure割り込みの設定
    - SecureまたはNon-secure割り込みのハンドリング
- マルチプロセッサシステムでは、いくつかのCPUインタフェースだけにSecurity拡張を実装する

###3.1.1 マルチプロセッサシステムでの異なる割り込みタイプのハンドリング

###3.1.2 サポートされた割り込みの認識
GICアーキテクチャは異なる割り込みには異なるIDを定義する。しかし、連続したIDのブロックに実装する必要はない

***Note***
ARMは実装する割り込みは最も低いIDを使ってグルーピングすることを強く推奨する。なぜなら、実装や確認するレジスタの数を減らすことができるからだ。

正しく割り込みをハンドリングするためには、ソフトウェアはどのIDがGICによってサポートされているかを知る必要がある。`Interrupt Set Enable Registers (ICDISERn)` 参照。もしプロセッサがSecurity Extensionを実装する場合、セキュリティソフトウェアはどの割り込みをNon-secureなソフトウェアに見せるかを決める必要がある。Non-secureなソフトウェアはどの割り込みが見えるかを、検索プロセスで知る必要がある。
`ICDISER0`はSet-enables bitsを提供する

- SGI ID15-0はbit[15:0]
- PPI ID31-16はbit[31:16]

のこりの`ICDISER1`から始まるICDISERsは、ID32から始まるSPIへのSet-enable bitsを提供する。
もし割り込みが

- サポートされていない場合、Set-enable bitはRAZ/WIとなる。[^RAZ/WI]
- 恒久的にenableの場合、Set-enable bitはRAO/WIとなる。[^RAO/WI]

ソフトウェアはどの割り込みがサポートされているかを以下の方法で確認できる

- `ICDICTR(Interrupt Controller Type Register)`を読む。ITLinesNumberは`ICDISER`の実装されている数を確認できる。そのためSPIがサポートされている最大の番号となる
- `ICDDCR.Enable bit(Distributor Control Register)`にゼロを書くと、CPUインターフェースへの割り込み転送をdisableできる
    - Note:`ICDDCR.Enable`が0のとき、GICはペリフェラル信号の状態を無視する。これはエッジトリガー割り込みを無視することになる
- ICDISER0から始まる、各`ICDISER`に対して、
    - 0xFFFFFFFFを`ICDISER`にライト
    - ICDISERをリードすると、1となっているビットは、サポートされている割り込みIDに対応する

ソフトウェアは`ICDICER(Clera-Enable Register)`で、どの割り込みが恒久的に有効かを調べることができる。ICDICER0から始まる各レジスタに対して

- 0xFFFFFFFFをICDICERに書くと、disable可能なすべての割り込みがdisableされる
- ICDICERをリードして、1になっているビットは恒久的にenableな割り込みに対応する
- ICDICERに1を書くと、再度enableすべき割り込みとなる

GICは同じ数のICDISER, ICDICERを実装している。
ソフトウェアがdiscovery（ICDDCR.Enable bitを1にライト）を完了すると、CPUインターフェスへの割り込み転送を有効化する
GICがSecurity拡張を実装していた場合、ソフトウェアは以下へのSecureアクセスを使用できる

...

###3.2 通常の割り込みハンドリング
<font color="Red">ディストリビュータは、各CPUに対する各割り込みに対してステートマシーンを維持する。割り込みハンドリングステートマシーンは以下の状態がある。</font>

- incative
- pending
- active
- active and pending

<font color="Red">GICが割り込み要求を認識したときには、状態はpendingになる。pending割り込みに対する再生成は、割り込みの状態に影響しない</font>
GICは以下に沿って割り込みを操作する。

***1. GICはどの割り込みがenableなのか見つける。enableでない割り込みはこれ以降のGIC動作には影響しない***
***2. 各enableな割り込みに対して、ディストリビュータはターゲットプロセッサを決める***
***3. 各プロセッサに対して、ディストリビュータは最も優先度の高いpendingされている割り込みを決める。そして、その割り込みをCPUインターフェスに転送する***
***4. CPUインターフェスは割り込みの優先度と、今のプロセッサの割り込み優先度を比較する。決定は、優先度マスクレジスタ、今のプリエンプション設定、プロセッサの最も高いactiveな割り込みによって行われる。もし割り込みが十分な優先度を持っていた場合、GICはプロセッサに対して割り込み例外をシグナルする。***
---***Note***---
このドキュメントを通して割り込みは、以下の場合「十分な優先度」を持っていると説明される。もし、その優先度、優先度マスクレジスタとの比較、プリエンプション設定、プロセッサ上で最も高い優先度のactiveな割り込みの場合、CPUインターフェスはプロセッサに割り込み要求シグナルを発行しなければならない。
***5. プロセッサが割り込み例外を取得した場合、割り込みをacknowledgeするために、CPUインターフェースの`ICCIAR(Interrupt Acknowledge Register)`をリードする。このリードは割り込みはプロセッサが正しい割り込みハンドラを使うために、割り込みIDをリターンする。このリードを認識するとGICは割り込み状態を以下に遷移させる***
- 割り込みがactiveになったときに、割り込みがpendig状態を維持するのである、または再度割り込みが生成されたのであれば、pendigからavtive and pendingに遷移する
- 上記以外の場合は、pendigからactiveと遷移する

---***Note***---
- プロセッサによってacknowledgeされたとき、level-sensitive割り込みは維持される。なぜなら、そのプロセッサで動作している割り込みサービスルーチン(ISR)がシグナルをアサートしているペリフェラルにアクセスするまで　GICへの割り込みシグナルはアサートされているから。
- マルチプロセッサシステムではGICは以下をハンドルする
    - N-N modelのSGIでは、1つのプロセッサからのacknowledgeはCPUインターフェースの状態に影響しない
    - 1-Nのペリフェラル割り込みのでは、１つのプロセッサからのacknowledgeが他のターゲットとなっているプロセッサ含めてpending状態から抜ける

***6. プロセッサが割り込み処理を完了すると、`ICCEOIR (End of Interrupt Register)`にライトすることで完了を通知できる***
GICはacknowledgeとは逆の順序で、プロセッサから完了通知を受ける必要がある。そのため最後のacknowledgeの割り込みは、最初に完了する必要がある。
プロセッサがICCEOIRに書き込むと、GICは対応するCPUインターフェースの割り込みの状態を以下のどれかに変更する

- activeからinactive
- active and pendingからpending

プロセッサにシグナルするCPUインターフェースで十分な優先度の割り込みがない場合、インタフェースはプロセッサに対する割り込み例外リクエストをdeassertする。
CPUインタフェースはactive and pendingの割り込みをプロセッサに送ることはない。<font color="Red">pedingで十分な優先度を持った割り込みだけが送られる。</font>

- SPIにとっては、activeやactive and pendingの割り込みはシグナルされることはない
- SGIにとっては、activeやactive and pendingの割り込みはシグナルされることはない。ただし、他のインターフェースへの割り込み状態は考慮されない
- PPIはインタフェースにとってprivateなので、active and pendingの割り込みはシグナルされない

###3.2.1 GICの割り込みコントロール
以下のGIC上の割り込みコントロールについて説明する

- 割り込みenable
- pending状態のsetting, clearing
- active or pending状態の割り込みを見つける
- SGIの生成

####割り込みenable
ペリフェラル割り込みに対して、プロセッサは

- 適切なICDISER bitにライトすることでenableできる
- 適切なICDICER bitにライトすることでdisableできる

SGIは恒久的なenableか、enable/disable可能かは実装依存。
ICDISER, ICDICERへのライトは、ディストリビュータがCPUインターフェースに送るかどうかをコントロールする。ICDICERでdisableした割り込みは、割り込みが状態遷移をするのを妨げない。

####割り込みpending状態のsettingとclearing
ペリフェラル割り込みに対して、プロセッサは

- `ICDISPR(Interrupt Set-Pending Register)`にライトすることでsetできる
- `ICDICPR(Interrupt Clear-Pending Register)`にライトすることでclearできる

level-sensitive割り込み対しては

- <font color="Red">プロセッサが対応するICDICPRにライトしたときにハードウェアがシグナルをアサートしている場合、そのライトは割り込みのpending状態にはなにも影響をあたえない</font>
- プロセッサがICDISPRに1をライトすると、対応する割り込みはハードウェアのシグナル状態にかかわらずpending状態となる。シグナルがassert, deassertされるにかかわらず、pending状態を維持する

SGIに対しては、GICはICDISPR, ICDISCRへのライトは無視する。プロセッサはソフトウェア生成の割り込みの状態を変えることはできない

####active or pending状態の割り込みを見つける
プロセッサは以下を見つけることができる

- 対応するICDISPRまたはICDIPRビットから、割り込みのpending状態がわかる
- ICDABRビットから、割り込みのactive状態がわかる

対応するレジスタビットが１の場合、割り込みはpendig or active状態にある。両方１の場合はactive and pending状態にある。

####SGIの生成

###3.2.2 1-Nモデルの意味

###3.2.3 割り込みハンドリングステートマシーン
ディストリビュータは各CPUのサポートしている各割り込みに対してステートマシーンを維持する。Figure3-1は状態遷移図を示す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/60ebd766-994f-0b10-ac69-01c1d67439b6.png)
***---Note---***
SGIはICDSGIRにライトしてのみ生成される。ペリフェラル割り込みは、ペリフェラルが割り込み要求を出すか、ICDISPRにライトすることで生成される
***----------***
ディストリビュータとCPUインターフェースがenableのとき、状態遷移は以下に従う

***A1, A2への遷移でpending状態を追加***

- SGI
    - ICDSGIRへのライト
    - GICがセキュリティ拡張を実装して、ICDSGIRへのライトはセキュアの場合、この遷移は　ICDSGIR.SATTビットの値に対応した適切なCPUインターフェースに対する、SGIへのセキュリティ設定がされている場合のみ発生する
- SPI or PPIの場合、以下のどれかの場合に発生する
    - ペリフェラルが割り込みシグナルをアサートした場合
    - ソフトウェアがICDISPRにライトした場合

***B1またはB2への遷移でpendig状態を外れる***

- SGIには適用されない
    - pending SGIはactive状態へ遷移する、もしくはpending状態を外すにはリセットしなければいけない
    - active and pending SGIははpending状態へ遷移する、もしくはpending状態を外すにはリセットしなければいけない
- SPI, PPI
    - level-sensitve割り込みがインプットシグナルがassertされてからpendig状態になって、deassertされたとき
    - edge-triggered割り込み信号のassertion、またはICDISPRへのライト、の後に対応するICDICPRへのライトすることのみによって、割り込みはpending状態になる。

***Cへの遷移***
割り込み優先度が十分で、シグナルがプロセッサに送られ、ソフトウェアがICDICPRをライトする

***Dへの遷移***
SGIでは、SGIがenableされ、プロセッサが前のSGIのacknowledgeするためにICCIARを読むと同時に、ディストリビュータがCPUインターフェースに転送するときに発生する。遷移が発生するかどうかは、関連するICCIARをリードするタイミングに依存する
SPI, PPIでは

- 以下全てが適用されたときに発生する
    - 割り込みがenable
    - ソフトウェアがICCIARを呼んで、Active状態へ遷移させる
    - level-sensitive割り込みでは、割り込みがアサートを維持している。これが通常のjケースである。なぜならペリフェラルはプロセッサが割り込みサービスを完了するまではdeassertしないからである
- edge-triggered割り込みの場合、遷移が発生するかどうかは、再度assertする割り込みのICCIAR(Ack)のリードタイミングに依存する。ICCIARのリードでCの遷移が発生して、A2の遷移が発生しうる場合がある。※otherwiseの訳し方がわからん

***E1 or E2への遷移でactiveを取り除く場合***
ソフトウェアがICCEOIRをライトした場合

 





#Glossary
[^RAO/WI]: RAZ/WI Read-As-One, Write Ignored.
[^RAZ/WI]: RAZ/WI Read-As-Zero, Write Ignored.