1 | =====================================================================
|
---|
2 | ARM64プロセッサ依存部設計メモ
|
---|
3 | Last Modified: 5 Jun 2018
|
---|
4 | =====================================================================
|
---|
5 |
|
---|
6 | ○このドキュメントの位置づけ
|
---|
7 |
|
---|
8 | このドキュメントは,TOPPERS/SSPカーネルをARMv8-Aプロセッサに移植する際
|
---|
9 | の設計メモである.
|
---|
10 |
|
---|
11 |
|
---|
12 | ○ARMv8-Aの仕様まとめ
|
---|
13 |
|
---|
14 | ARMv8-Aの仕様のうち,カーネルの設計に関係する事項についてまとめる.
|
---|
15 |
|
---|
16 | ●レジスタ
|
---|
17 |
|
---|
18 | 汎用レジスタはr0〜r30 (特に64ビットレジスタはX0..X30で表現)の31種類からなる.
|
---|
19 | (参考)「Procedure Call Standard for the ARM 64-bit Architecture」
|
---|
20 |
|
---|
21 | r0...r7 Parameter/result registers(引数および返値の受け渡し用)
|
---|
22 | r8 Indirect result location register (大きなデータ構造を
|
---|
23 | 返値として返す場合など,呼び出し側が結果を取り出すために
|
---|
24 | 間接アドレッシングを多用する際,そのベースアドレスを受け渡し
|
---|
25 | するために使われる)
|
---|
26 | r9..r15 Caller-saved Temporary registers(呼び出し側で保存すべきレジスタ)
|
---|
27 | r16(IP0) The first intra-procedure-call scratch register
|
---|
28 | リンカによって veneer(注1) および PLT(Procedure Linkage Table,注2) コード
|
---|
29 | の呼び出しで使われる.それ以外の時はテンポラリレジスタとして使われることもある.
|
---|
30 | (注1)リンカによって挿入される小さなコード片で,
|
---|
31 | 分岐命令のターゲットが範囲外の場合などに使われる
|
---|
32 | (注2)共有ライブラリの呼び出しでシンボル解決を行うために使用される
|
---|
33 | 関数テーブル
|
---|
34 | r17(IP1) The second intra-procedure-call temporary register(r16と役割は同じ)
|
---|
35 | r18 The Platform Register(プラットフォームABIで使用されるレジスタ.
|
---|
36 | ABIで使われない場合はテンポラリレジスタとして使われる)
|
---|
37 | r19..r28 Callee-saved registers(呼び出された側で保存して使うレジスタ)
|
---|
38 | r29(FP) The Frame Pointer(フレームポインタ)
|
---|
39 | r30(LR) The Link Register(リンクレジスタ)
|
---|
40 |
|
---|
41 | SSPカーネルのアセンブラによる実装ではr8, r16...r18は使用していない.
|
---|
42 |
|
---|
43 |
|
---|
44 | ●コーリングコンベンション
|
---|
45 |
|
---|
46 | r0...R7 が引数および返値に使われる.
|
---|
47 | ARMにより規定されているため,コンパイラに依存せずこのルールとなる
|
---|
48 |
|
---|
49 | ●PSTATE
|
---|
50 |
|
---|
51 | AArch64ではプロセッサの状態を表すフラグの集まりをまとめてPSTATEと呼び,
|
---|
52 | それぞれのフラグへ別々にアクセスするための特別なレジスタ名が定義されている.
|
---|
53 |
|
---|
54 | PSTATEの詳細は,ARM Architecture Reference Manual
|
---|
55 | ARMv8, for ARMv8-A architecture profile の D1.7 などを参照のこと.
|
---|
56 |
|
---|
57 | ・spsel
|
---|
58 | EL1より上の例外レベルでは,spsel という特別な名称のレジスタにアクセスし,
|
---|
59 | PSTATE.SPフラグの値をセットして使用スタックの切り替えを行う.
|
---|
60 |
|
---|
61 | ・daif
|
---|
62 | daif という名称のレジスタを使用してPSTATEのD,A,I,Fビットを操作し,
|
---|
63 | 各種例外および割込みの禁止/許可を制御する
|
---|
64 |
|
---|
65 |
|
---|
66 | SSPカーネルの実装では,スタックはSP_EL1のみを使用する.
|
---|
67 | また,CPUロック状態および割込みロック状態の実装にPSTATEのIおよびFフラグを
|
---|
68 | 利用している.
|
---|
69 |
|
---|
70 |
|
---|
71 | ●割込みベクタ
|
---|
72 |
|
---|
73 | ベクタテーブルのアドレスはリセット時に,システムレジスタの一つVector Base
|
---|
74 | Address Register(VBAR, システムレジスタ)にアドレスをセットすることで,
|
---|
75 | 2048バイト境界の任意のアドレスに配置可能である.
|
---|
76 |
|
---|
77 | SSPカーネルの実装ではスタートアップルーチンで設定している.
|
---|
78 |
|
---|
79 |
|
---|
80 | ●割込み優先度
|
---|
81 |
|
---|
82 | 設定値の小さい方が高優先度となる.
|
---|
83 |
|
---|
84 | 優先度は最大8bitであり,SoC毎に実装されているビット幅が異なる.実装さ
|
---|
85 | れるビットが8bit以下の場合は,LSBから無効になる.例えば,実装されてい
|
---|
86 | るビット幅が7bitの場合は,ビット0が無効となる.
|
---|
87 |
|
---|
88 | 優先度のビットフィールドのLSBから数ビットをサブ優先度と呼ぶフィールド
|
---|
89 | に設定することが可能である.残りの上位ビットをプリエンプション優先度と
|
---|
90 | 呼ぶ.プリエンプション優先度が同じで,サブ優先度が異なる優先度のグルー
|
---|
91 | プは,お互いをプリエンプトすることができない.
|
---|
92 |
|
---|
93 | 例として,QEMU Virtボード向けSSPの実装では Cortex-A53プロセッサを
|
---|
94 | ターゲットとしており,優先度は16段階(4bit)でビット0から3が無効である.
|
---|
95 |
|
---|
96 | ●CPUモード
|
---|
97 |
|
---|
98 | プロセッサは,EL0からEL3までの例外レベルのいずれかで動作する.
|
---|
99 | またそれぞれのレベルで64ビットモード(AArch64) または32ビットモード(AArch32)を
|
---|
100 | 選択することができる.ただし,ある例外レベルが32ビットモードで動作する場合は
|
---|
101 | それより低い例外レベルでは64ビットモードを選択することができない.
|
---|
102 |
|
---|
103 | また,セキュリティ拡張機能を搭載するプロセッサではセキュアモードおよび
|
---|
104 | 非セキュアモードを選択することができる.
|
---|
105 |
|
---|
106 | SSPの実装では,64ビットモード(AArch64),非セキュア,例外レベル1(EL1) で動作する.
|
---|
107 |
|
---|
108 |
|
---|
109 | ●リセット時の状態
|
---|
110 |
|
---|
111 | リセット時はプロセッサチップがサポートする最大の例外レベルおよびそのレベルの
|
---|
112 | スタック(SP_ELx)が有効となっている.
|
---|
113 |
|
---|
114 | 例としてQEMU向けVirtボード(Cortex-A53) では,既定でEL1が最大例外レベルのため
|
---|
115 | リセット直後はSP_EL1が有効となっている.
|
---|
116 |
|
---|
117 | ●割込み/例外の受付
|
---|
118 |
|
---|
119 | 割込みを受け付けると受け付けた割込みの番号が,GICC_IARにセットされる.
|
---|
120 | 割込み番号はこのレジスタにセットされる値を使用する.
|
---|
121 |
|
---|
122 | 例外番号は,例外発生時のプロセッサ状態に応じて決定される,ベクタテーブル中の
|
---|
123 | ジャンプ先オフセット毎に異なる番号を割り振ることにしている.
|
---|
124 |
|
---|
125 | 例外発生時の状態 例外の種類 例外番号 例外ベクタ先頭からのオフセット
|
---|
126 | AArch64, EL1t(EL1, SP_EL0) Synchronous 0 0x0000
|
---|
127 | AArch64, EL1t(EL1, SP_EL0) SError 1 0x0180
|
---|
128 | AArch64, EL1h(EL1, SP_EL1) Synchronous 2 0x0200
|
---|
129 | AArch64, EL1h(EL1, SP_EL1) SError 3 0x0380
|
---|
130 | AArch64, EL0 (EL0, SP_EL0) Synchronous 4 0x0400
|
---|
131 | AArch64, EL0 (EL0, SP_EL0) SError 5 0x0580
|
---|
132 | AArch32, EL0 (EL0, SP_EL0) Synchronous 6 0x0600
|
---|
133 | AArch32, EL0 (EL0, SP_EL0) SError 7 0x0780
|
---|
134 |
|
---|
135 | 割込みを受け付けた際,受け付けた割込みに設定された優先度より低い割込みを
|
---|
136 | 禁止するため,GICC_RPRから取得した割込み要因の割込み優先度を GICC_PMRへ
|
---|
137 | セットしている.そしてハンドラ終了後に割込み発生前の割り込み優先度に戻す.
|
---|
138 |
|
---|
139 | ● スタックポインタ(SP_EL0とSP_ELx)
|
---|
140 |
|
---|
141 | スタックポインタは,例外レベル0のスタックポインタ(SP_EL0)および実行中の
|
---|
142 | 例外レベルのスタックポインタ(SP_ELx)が選択可能である.
|
---|
143 | スタックの選択はspselレジスタへ1を設定するとSP_ELxを,0を設定すると
|
---|
144 | SP_EL0 を選択する.
|
---|
145 |
|
---|
146 | SSPの実装では,EL1 で SP_EL1 のみを使用して動作する.
|
---|
147 |
|
---|
148 | ●例外レベルの遷移
|
---|
149 |
|
---|
150 | 例外レベル(EL)の遷移は割込み/例外の受付および例外リターン命令(eret)により行う.
|
---|
151 |
|
---|
152 | 割込みおよび例外を受け付けることで発生前と同じまたはより高い例外レベルへ遷移する.
|
---|
153 | 一方,同じまたはより低い例外レベルへの遷移は例外リターン命令(eret)により行う.
|
---|
154 |
|
---|
155 | 受付時の遷移先となる例外レベルの指定はシステムレジスタにより設定することで行う.
|
---|
156 | 割込み/例外リターン時の遷移先となる例外レベルは,SPSR_ELxのビット2および3で
|
---|
157 | 指定する.割込み/例外受付時,PSTATEの状態がSPSR_ELxに,リターンアドレスがELR_ELxに,
|
---|
158 | それぞれ保存されeret命令の実行によりその格納値が復帰されるため,eret実行前に
|
---|
159 | あらかじめSPSR_ELxにセットしておくことで指定した例外レベルへ遷移することが可能である.
|
---|
160 | 同じタイミングで使用スタックや64ビット/32ビットモードの指定も行うことができる.
|
---|
161 |
|
---|
162 | QEMU Virt向けSSPの実装ではEL1のみを使用するため,例外レベル間の遷移処理は行っていない.
|
---|
163 |
|
---|
164 | ●例外レベルの判定
|
---|
165 |
|
---|
166 | 現状の例外レベルを判定するには,CPSRのビット2およびビット3の値を使用する.
|
---|
167 | bit[3:2]の値が
|
---|
168 | '11'の場合:EL3
|
---|
169 | '10'の場合:EL2
|
---|
170 | '01'の場合:EL1
|
---|
171 | '00'の場合:EL0
|
---|
172 |
|
---|
173 | ●GICC_PMRレジスタ
|
---|
174 |
|
---|
175 | 設定した優先度以下(値としては以上)の優先度の割込みの受付を禁止する.
|
---|
176 | 設定可能な最大値を設定すると,全ての割込みを許可する.
|
---|
177 | 例えば優先度が16段階の場合は0xf0(=0x0f << 4)をセットするとすべての割込み許可
|
---|
178 | となる.値は例外/割込みの受付とリターンにより変化しないため,受け付けた割込み
|
---|
179 | の優先度を割込みの入口処理で設定する必要がある.
|
---|
180 |
|
---|
181 | ●例外/割込みの受付
|
---|
182 |
|
---|
183 | ・例外/割込みを受付けると,受付け時にアクティブなスタック上に以下のコ
|
---|
184 | ンテキストを保存する.
|
---|
185 |
|
---|
186 | ---------------
|
---|
187 | | GICC_PMR | <- new SP
|
---|
188 | ----------------
|
---|
189 | | 割込み/例外番号|
|
---|
190 | ----------------
|
---|
191 | | ダミー(0) |
|
---|
192 | ----------------
|
---|
193 | | 調整量(0 or 8) |
|
---|
194 | ----------------
|
---|
195 | |調整領域(必要時)| (*)アライメント調整が必要なときのみ
|
---|
196 | ----------------
|
---|
197 | | ESR_ELx |
|
---|
198 | ----------------
|
---|
199 | | ELR_ELx |
|
---|
200 | ----------------
|
---|
201 | | SPSR_ELx |
|
---|
202 | ----------------
|
---|
203 | | X30 |
|
---|
204 | ----------------
|
---|
205 | | X29 |
|
---|
206 | ----------------
|
---|
207 | | : |
|
---|
208 | | : |
|
---|
209 | ----------------
|
---|
210 | | X1 |
|
---|
211 | ----------------
|
---|
212 | | X0 |
|
---|
213 | ----------------
|
---|
214 | | | <- old SP
|
---|
215 |
|
---|
216 |
|
---|
217 | 割込み/例外発生時の主なシーケンスは次のようになる(遷移先の例外レベルをELxと表現する)
|
---|
218 |
|
---|
219 | (ハードウェアの処理)
|
---|
220 | ・PSTATEをSPSR_ELxに保存する
|
---|
221 | ・リターンアドレスをELR_ELxに保存する
|
---|
222 | ・PSTATE.{D,A,I,F}を1にセットする
|
---|
223 | ・同期例外およびSError割込みのとき,例外要因情報をESR_ELxに保存する
|
---|
224 | ・スタックポインタをSP_ELxに切り替える
|
---|
225 | ・ELxへ遷移する
|
---|
226 |
|
---|
227 | (ソフトウェアでの処理)
|
---|
228 | ・(発生時にSP_EL0を使用していた場合)スタックを割込み発生前(SP_EL0)に戻す
|
---|
229 | ・汎用レジスタ(X0-X30)をスタックに保存
|
---|
230 | ・SPSR_ELx, ESR_ELx, ELR_ELxをスタックに保存
|
---|
231 | ・スタックポインタのアライメントを調整
|
---|
232 | ・割込み番号(GICC_IARから取得),例外番号(オフセット毎に定義した値)をスタックに保存
|
---|
233 | ・割込み発生前の割込み優先度マスクをスタックに保存
|
---|
234 | ・GICC_PMRに受け付けた割込みの割込み優先度をセット
|
---|
235 | ・割込み/例外ネストカウンタのインクリメント
|
---|
236 | ・(割込みの場合)CPUロック解除
|
---|
237 | ・ベクタテーブルを読み込みハンドラを実行する
|
---|
238 |
|
---|
239 | ●例外/割込みからのリターン
|
---|
240 |
|
---|
241 | (ソフトウェアでの処理)
|
---|
242 | ・CPUロック状態へ移行
|
---|
243 | ・割込み/例外ネスとカウンタのデクリメント
|
---|
244 | ・GICC_PMRに割込み発生前の優先度マスクを戻す
|
---|
245 | ・スタックポインタのアライメント調整分を戻す
|
---|
246 | ・戻り先のコンテキストやシステム状態に応じて割込み/例外発生元へリターン
|
---|
247 | または遅延ディスパッチを実行する
|
---|
248 | ・ELR_ELxに戻り先アドレス,SPSR_ELxにプロセッサ状態がそれぞれ
|
---|
249 | セットされている状態でeret命令を実行し,割込み/例外からリターン
|
---|
250 |
|
---|
251 | ●スタックポインタのアライメント調整
|
---|
252 |
|
---|
253 | AArch64では,外部インタフェースにおいてスタックポインタは16バイト境界に
|
---|
254 | アラインさせる必要がある.しかし例外発生時にそれが満たされているとは限らないため,
|
---|
255 | 割込み/CPU例外の入口処理で,スタックポインタがアライメント条件を満たしていない場合には,
|
---|
256 | スタックポインタを調整する.また,出口処理でスタックポインタを元に戻せるように,調整量を保存する.
|
---|
257 |
|
---|
258 |
|
---|
259 | ○OSの実装
|
---|
260 |
|
---|
261 | 1.プロセッサ依存部名称: arm64
|
---|
262 |
|
---|
263 | ARMv8 では,64ビットモード(AArch64)および32ビットモード(AArch32)の両方をサポートするが
|
---|
264 | 本実装は64ビットモードのみをサポートすることを明示するためプロセッサ依存部名称を arm64 とした
|
---|
265 |
|
---|
266 | 2. 例外モードの使い分け
|
---|
267 |
|
---|
268 | 本実装ではタスクコンテキスト,非タスクコンテキストいずれも例外レベル1(EL1)で動作する.
|
---|
269 | タスクコンテキストをEL0で動作する案も考えられる.その場合は割込み/例外の出口処理において
|
---|
270 | 遅延ディスパッチの前に例外レベルの切り替えが必要となる.
|
---|
271 |
|
---|
272 | 3.ディスパッチャの実行モード
|
---|
273 |
|
---|
274 | 本実装ではすべて例外レベル1で動作するため,ディスパッチャは例外レベル1(EL1)で動作する.
|
---|
275 |
|
---|
276 |
|
---|
277 | 4.スタックの使い分け
|
---|
278 |
|
---|
279 | SSPではタスクコンテキスト,非タスクコンテキスト共に一つのスタックを共用する.
|
---|
280 | 本実装ではSP_ELxを使用している.
|
---|
281 | この他にSP_EL0を使用する実装も考えられる.その場合は割込み/例外の入口処理にて
|
---|
282 | レジスタを保存する前にSP_EL0へのスタック切り替えを行う.
|
---|
283 |
|
---|
284 | 5.コンテキストの判定
|
---|
285 |
|
---|
286 | 割込み/例外のネスト回数を保持する変数(intnest)が0ならタスクタスクコンテキスト,
|
---|
287 | 1以上なら非タスクコンテキストとする.
|
---|
288 | コンテキスト毎に例外レベルを分ける実装を取る場合はPSTATEのビット2および3で
|
---|
289 | 例外レベルを読み出すことにより判別するという方法も考えられる.
|
---|
290 | 本実装ではコンテキストによらず同じ例外レベルを使用し,プロセッサの
|
---|
291 | ステータスレジスタでは判別ができないため変数で判別する.
|
---|
292 |
|
---|
293 | 6. CPUロック
|
---|
294 |
|
---|
295 | CPUロックPSTATE.IおよびPSTATE.FによりCPUロックを実現する.
|
---|
296 |
|
---|
297 | 7. 割込みロックとCPU例外の関係
|
---|
298 |
|
---|
299 | カーネル管理外の割込みはサポートしないため,割込みロックとCPUロックがマスクする
|
---|
300 | 割込みの範囲は同じとする.ただし,フラグ自体はお互いに独立させるため,
|
---|
301 | 割込みロック状態の設定/解除の際は,ロック前にCPUロックフラグの状態を保存し,
|
---|
302 | 解除前に元の状態に戻すようにしている.
|
---|
303 |
|
---|
304 | 8. 外部優先度と内部優先度
|
---|
305 |
|
---|
306 | 外部優先度とはAPIで指定する割込み優先度(PRI型)のことであり,値が小さい
|
---|
307 | ほど優先度が高い.割込みハンドラには,-1から連続した負の値を設定可能で
|
---|
308 | ある.内部優先度は,GICC_PMRレジスタに設定する値である.
|
---|
309 | 外部優先度と内部優先度の変換は以下のマクロで表現される.
|
---|
310 |
|
---|
311 | /* 外部表現への変換 */
|
---|
312 | #define EXT_IPM(pri) \
|
---|
313 | (((PRI)((pri) >> GIC_PRI_SHIFT)) - (GIC_PRI_LEVEL - 1))
|
---|
314 |
|
---|
315 | /* 内部表現への変換 */
|
---|
316 | #define INT_IPM(ipm) \
|
---|
317 | (((uint_t)((ipm) + (GIC_PRI_LEVEL - 1))) << GIC_PRI_SHIFT)
|
---|
318 |
|
---|
319 | ここでGIC_PRI_LEVELはサポートする割込み優先度の数,GIC_PRI_SHIFTはGICC_PMRレジスタ内
|
---|
320 | の,内部優先度の値が格納される位置(ビット0からのオフセット)を表す.
|
---|
321 |
|
---|
322 |
|
---|
323 | 9. カーネル管理内の最高優先度(CPUロック状態での優先度マスク)
|
---|
324 |
|
---|
325 | カーネル管理内の割込みの最高優先度は設定可能な外部優先度の最高値と同じとする.
|
---|
326 |
|
---|
327 |
|
---|
328 | 以上.
|
---|