source: asp3_tinet_ecnl_arm/trunk/asp3_dcre/arch/arm_gcc/common/core_support.S@ 374

Last change on this file since 374 was 374, checked in by coas-nagasima, 5 years ago

mbed関連を更新
シリアルドライバをmbedのHALを使うよう変更
ファイルディスクリプタの処理を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/plain;charset=UTF-8
File size: 39.9 KB
Line 
1/*
2 * TOPPERS/ASP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
5 *
6 * Copyright (C) 2000-2004 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 * Copyright (C) 2006-2018 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
10 *
11 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
12 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16 * スコード中に含まれていること.
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20 * の無保証規定を掲載すること.
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23 * と.
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27 * 報告すること.
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32 * 免責すること.
33 *
34 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 * の責任を負わない.
39 *
40 * $Id$
41 */
42
43/*
44 * カーネルのコア依存部のアセンブリ言語部(ARM用)
45 */
46
47#define TOPPERS_MACRO_ONLY
48#define TOPPERS_ASM_MACRO
49#define UINT_C(val) (val) /* uint_t型の定数を作るマクロ */
50#define ULONG_C(val) (val) /* ulong_t型の定数を作るマクロ */
51#define CAST(type, val) (val) /* 型キャストを行うマクロ */
52#include "kernel_impl.h"
53#include "offset.h"
54#include "core_asm.inc"
55
56/*
57 * 使用する命令セットの定義
58 */
59#ifdef USE_ARM_FPU
60 .fpu vfpv3
61#endif /* USE_ARM_FPU */
62
63/*
64 * 例外ベクタ
65 */
66 ASECTION(.vector)
67 AALIGN(5)
68 AGLOBAL(vector_table)
69ALABEL(vector_table)
70 ldr pc, reset_vector /* リセット */
71 ldr pc, undef_vector /* 未定義命令 */
72 ldr pc, svc_vector /* ソフトウェア割込み */
73 ldr pc, pabort_vector /* プリフェッチアボート */
74 ldr pc, dabort_vector /* データアボート */
75 ldr pc, reset_vector /* 未使用 */
76 ldr pc, irq_vector /* IRQ */
77 ldr pc, fiq_vector /* FIQ */
78
79/*
80 * 例外ベクタの命令から参照されるジャンプ先アドレス
81 */
82 AGLOBAL(vector_ref_table)
83ALABEL(vector_ref_table)
84ALABEL(reset_vector)
85 ALONG Reset_Handler
86ALABEL(undef_vector)
87 ALONG undef_handler
88ALABEL(svc_vector)
89 ALONG svc_handler
90ALABEL(pabort_vector)
91 ALONG pabort_handler
92ALABEL(dabort_vector)
93 ALONG dabort_handler
94ALABEL(irq_vector)
95 ALONG irq_handler
96ALABEL(fiq_vector)
97 ALONG fiq_handler
98
99/*
100 * タスクディスパッチャ
101 */
102 ATEXT
103 AALIGN(2)
104 AGLOBAL(dispatch)
105ALABEL(dispatch)
106 /*
107 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
108 * マスク全解除状態・ディスパッチ許可状態で呼び出される.
109 */
110 push {r12,lr} /* 戻り番地(lr)を保存 */
111 /* r12はアラインメントのため */
112#ifdef TOPPERS_SUPPORT_OVRHDR
113 bl ovrtimer_stop
114#endif /* TOPPERS_SUPPORT_OVRHDR */
115 push {r4-r11} /* 非スクラッチレジスタの保存 */
116 ldr r0, =p_runtsk /* p_runtsk → r0 */
117 ldr r0, [r0]
118#ifdef USE_ARM_FPU
119 ldr r2, [r0,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
120 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
121 tst r1, #TA_FPU
122 beq 1f
123 vpush {d8-d15} /* 非スクラッチFPUレジスタの保存 */
1241:
125#endif /* USE_ARM_FPU */
126 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
127 adr r1, dispatch_r
128 str r1, [r0,#TCB_pc] /* 実行再開番地を保存 */
129 b dispatcher /* r0にはp_runtskが格納されている */
130
131ALABEL(dispatch_r)
132 /*
133 * 【この時点のレジスタ状態】
134 * r4:p_runtsk(タスク切換え後)
135 */
136#ifdef USE_ARM_FPU
137 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
138 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
139 tst r1, #TA_FPU
140 vmrs r0, fpexc
141 biceq r0, r0, #FPEXC_ENABLE
142 orrne r0, r0, #FPEXC_ENABLE
143 vmsr fpexc, r0 /* FPEXCを設定 */
144 beq 1f
145 vpop {d8-d15} /* 非スクラッチFPUレジスタの復帰 */
1461:
147#endif /* USE_ARM_FPU */
148 pop {r4-r11} /* 非スクラッチレジスタの復帰 */
149#ifdef TOPPERS_SUPPORT_OVRHDR
150 bl ovrtimer_start
151#endif /* TOPPERS_SUPPORT_OVRHDR */
152 pop {r12,lr} /* 戻り番地を復帰 */
153 bx lr
154
155/*
156 * ディスパッチャの動作開始
157 */
158 AGLOBAL(start_dispatch)
159ALABEL(start_dispatch)
160 /*
161 * このルーチンは,カーネル起動時に,非タスクコンテキストで,NMIを
162 * 除くすべての割込みを禁止した状態(全割込みロック状態と同等)で
163 * 呼び出される.
164 *
165 * dispatcher_0へ分岐する前に,タスクコンテキスト・CPUロック状態・
166 * 割込み優先度マスク全解除状態にし,使用するスタックを,IDが1のタ
167 * スクのスタック領域に切り換えなければならない.
168 */
169
170 /*
171 * 各種のデバイス(特に割込みコントローラ)の設定が完了するのを待つ.
172 */
173 asm_data_sync_barrier r0
174
175 /*
176 * タスクコンテキストに切り換える.
177 */
178 ldr r2, =excpt_nest_count /* 例外ネストカウントを0に */
179 mov r0, #0
180 str r0, [r2]
181
182 /*
183 * IDが1のタスクのスタック領域に切り換える.
184 */
185 ldr r0, =tcb_table /* tcb_table[0] → r0 */
186 ldr r2, [r0,#TCB_p_tinib] /* tcb_table[0].p_tinib → r2 */
187 ldr r0, [r2,#TINIB_stk]
188 ldr r1, [r2,#TINIB_stksz]
189 add sp, r0, r1
190
191 /*
192 * CPUロック状態にして,ディスパッチャ本体へ分岐する.
193 */
194 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
195 b dispatcher_0
196
197/*
198 * 現在のコンテキストを捨ててディスパッチ
199 */
200 AGLOBAL(exit_and_dispatch)
201ALABEL(exit_and_dispatch)
202 /*
203 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
204 * マスク全解除状態・ディスパッチ許可状態で呼び出される.
205 */
206#ifdef LOG_DSP_ENTER
207 ldr r0, =p_runtsk /* p_runtsk → r0 */
208 ldr r0, [r0]
209#endif /* LOG_DSP_ENTER */
210 /* ディスパッチャ本体(dispatcher)へ */
211
212/*
213 * ディスパッチャ本体
214 */
215ALABEL(dispatcher)
216#ifdef LOG_DSP_ENTER
217 /*
218 * 【この時点のレジスタ状態】
219 * r0:p_runtsk(タスク切換え前)
220 */
221 bl log_dsp_enter
222#endif /* LOG_DSP_ENTER */
223
224ALABEL(dispatcher_0)
225 /*
226 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
227 * マスク全解除状態・ディスパッチ許可状態で呼び出される.実行再開番
228 * 地へもこの状態のまま分岐する.
229 */
230 ldr r0, =p_schedtsk /* p_schedtsk → r4 → p_runtsk */
231 ldr r4, [r0]
232 ldr r1, =p_runtsk
233 str r4, [r1]
234 tst r4, r4 /* p_runtskがNULLならdispatcher_1へ */
235 beq dispatcher_1
236 ldr sp, [r4,#TCB_sp] /* タスクスタックを復帰 */
237#ifdef LOG_DSP_LEAVE
238 mov r0, r4 /* p_runtskをパラメータに渡す */
239 bl log_dsp_leave
240#endif /* LOG_DSP_LEAVE */
241 ldr r0, [r4,#TCB_pc] /* 実行再開番地を復帰 */
242 bx r0 /* p_runtskをr4に入れた状態で分岐する */
243
244 /*
245 * アイドル処理
246 *
247 * 割込みをすべて許可し,CPUロック解除状態にして割込みを待つ.
248 *
249 * ターゲットによっては,省電力モード等に移行するため,標準の方法
250 * と異なる手順が必要な場合がある.そのようなターゲットでは,ター
251 * ゲット依存部でTOPPERS_CUSTOM_IDLEを定義し,アセンブラマクロとし
252 * て,toppers_asm_custom_idleを用意すればよい.
253 */
254ALABEL(dispatcher_1)
255#ifdef TOPPERS_CUSTOM_IDLE
256 toppers_asm_custom_idle
257#else /* TOPPERS_CUSTOM_IDLE */
258 msr cpsr_c, #CPSR_SVC_MODE /* 割込みを許可(スーパバイザモード)*/
259#endif /* TOPPERS_CUSTOM_IDLE */
260 b dispatcher_1 /* 割込み待ち */
261
262/*
263 * カーネルの終了処理の呼出し
264 *
265 * 割込みロック状態にし,使用するスタックを非タスクコンテキスト用のスタッ
266 * ク領域に切り替え,exit_kernelを呼び出す.
267 */
268 AGLOBAL(call_exit_kernel)
269ALABEL(call_exit_kernel)
270 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_INTLOCK)
271 ldr r0, =istkpt /* 非タスクコンテキスト用のスタックに */
272 ldr sp, [r0]
273 ldr r0, =excpt_nest_count /* 例外ネストカウントを1に */
274 mov r1, #1
275 str r1, [r0]
276 b exit_kernel
277
278/*
279 * タスクの実行開始時処理
280 */
281 ATEXT
282 AALIGN(2)
283 AGLOBAL(start_r)
284 /*
285 * 【この時点のレジスタ状態】
286 * r4:p_runtsk(タスク切換え後)
287 */
288ALABEL(start_r)
289#ifdef TOPPERS_SUPPORT_OVRHDR
290 bl ovrtimer_start
291#endif /* TOPPERS_SUPPORT_OVRHDR */
292 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
293 /* CPUロック解除状態に */
294 ldr lr, =ext_tsk /* タスク本体からの戻り番地を設定 */
295 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
296#ifdef USE_ARM_FPU
297 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
298 tst r1, #TA_FPU
299 vmrs r0, fpexc
300 biceq r0, r0, #FPEXC_ENABLE
301 orrne r0, r0, #FPEXC_ENABLE
302 vmsr fpexc, r0 /* FPEXCを設定 */
303#endif /* USE_ARM_FPU */
304 ldr r0, [r2,#TINIB_exinf] /* exinfをパラメータに */
305 ldr r1, [r2,#TINIB_task] /* タスク起動番地にジャンプ */
306 bx r1
307
308/*
309 * 割込みハンドラの出入口処理
310 */
311#ifndef OMIT_IRQ_HANDLER
312 ATEXT
313 AALIGN(2)
314 AGLOBAL(irq_handler)
315ALABEL(irq_handler)
316 /*
317 * ここには,IRQモードで分岐してくる.
318 */
319#if __TARGET_ARCH_ARM < 6
320 /*
321 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
322 */
323 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_IRQ_BIT)
324 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
325
326 /*
327 * IRQモードに戻して,戻り番地(lr−4)と戻り先のcpsr(spsr)を取
328 * 得する.
329 */
330 msr cpsr_c, #(CPSR_IRQ_MODE AOR CPSR_IRQ_BIT)
331 sub r2, lr, #4
332 mrs r1, spsr
333
334 /*
335 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
336 */
337 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_IRQ_BIT)
338 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
339 push {r1} /* 戻り先のcpsrをスタックに保存 */
340#else /* __TARGET_ARCH_ARM < 6 */
341 /*
342 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
343 * クに保存する.
344 */
345 sub lr, lr, #4 /* 戻り番地の算出 */
346 srsfd #CPSR_SVC_MODE!
347
348 /*
349 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
350 */
351 cps #CPSR_SVC_MODE
352 push {r0-r5,r12,lr}
353#endif /* __TARGET_ARCH_ARM < 6 */
354
355 /*
356 * スタックポインタの調整
357 */
358 and r1, sp, #4
359 sub sp, sp, r1
360 push {r0,r1} /* スタックポインタの調整値を保存 */
361 /* r0はスペース確保のため */
362 /*
363 * 例外ネストカウントをインクリメントする.割込みが非タスクコンテキ
364 * ストで発生した場合には,irq_handler_1へ分岐する.
365 */
366 ldr r2, =excpt_nest_count
367 ldr r3, [r2]
368 add r3, r3, #1
369 str r3, [r2]
370 teq r3, #1 /* 割込みが非タスクコンテキストで発生 */
371 bne irq_handler_1 /* ならirq_handler_1に分岐 */
372
373#ifdef TOPPERS_SUPPORT_OVRHDR
374 /*
375 * オーバランタイマを停止する.
376 */
377 bl ovrtimer_stop
378#endif /* TOPPERS_SUPPORT_OVRHDR */
379
380#ifdef USE_ARM_FPU
381 /*
382 * FPUをディスエーブルする.
383 */
384 vmrs r0, fpexc
385 str r0, [sp] /* FPEXCを保存(r0の場所)*/
386 bic r0, r0, #FPEXC_ENABLE
387 vmsr fpexc, r0 /* FPEXCを設定 */
388#endif /* USE_ARM_FPU */
389
390 /*
391 * 非タスクコンテキスト用のスタックに切り換える.
392 */
393 mov r3, sp /* この時点のスタックポインタをr3に */
394 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
395 ldr sp, [r2]
396 push {r0,r3} /* 切換え前のスタックポインタを保存 */
397 /* r0はスペース確保のため */
398ALABEL(irq_handler_1)
399 /*
400 * 割込みコントローラを操作し,割込み番号を取得する.
401 *
402 * irc_begin_intは,スタックトップ(r0の場所)に,irc_end_intで用
403 * いる情報を保存する.
404 */
405 bl irc_begin_int
406#if TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6
407 cmp r4, #TNUM_INHNO /* TNUM_INHNOの値によってはエラーになる */
408#else /* TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6 */
409 movw r3, #TNUM_INHNO
410 cmp r4, r3
411#endif /* TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6 */
412 bhs irq_handler_2 /* スプリアス割込みなら */
413 /* irq_handler_2に分岐 */
414 /*
415 * CPUロック解除状態にする.
416 */
417#if __TARGET_ARCH_ARM < 6
418 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
419#else /* __TARGET_ARCH_ARM < 6 */
420#ifndef TOPPERS_SAFEG_SECURE
421 cpsie if
422#else /* TOPPERS_SAFEG_SECURE */
423 cpsie f
424#endif /* TOPPERS_SAFEG_SECURE */
425#endif /* __TARGET_ARCH_ARM < 6 */
426
427#ifdef LOG_INH_ENTER
428 /*
429 * ログ出力の呼出し
430 */
431 mov r0, r4 /* 割込み番号をパラメータに渡す */
432 bl log_inh_enter
433#endif /* LOG_INH_ENTER */
434
435 /*
436 * 割込みハンドラの呼出し
437 */
438 ldr r2, =inh_table /* 割込みハンドラテーブルの読込み */
439 ldr r1, [r2,r4,lsl #2] /* 割込みハンドラの番地 → r1 */
440 mov lr, pc /* 割込みハンドラの呼出し */
441 bx r1
442
443#ifdef LOG_INH_LEAVE
444 /*
445 * ログ出力の呼出し
446 */
447 mov r0, r4 /* 割込み番号をパラメータに渡す */
448 bl log_inh_leave
449#endif /* LOG_INH_LEAVE */
450
451 /*
452 * カーネル管理の割込みを禁止する.
453 */
454#if __TARGET_ARCH_ARM < 6
455 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
456#else /* __TARGET_ARCH_ARM < 6 */
457#ifndef TOPPERS_SAFEG_SECURE
458 cpsid i
459#else /* TOPPERS_SAFEG_SECURE */
460 cpsid if
461#endif /* TOPPERS_SAFEG_SECURE */
462#endif /* __TARGET_ARCH_ARM < 6 */
463
464 /*
465 * 割込みコントローラを操作する.
466 */
467ALABEL(irq_handler_2)
468 bl irc_end_int
469
470 /*
471 * 例外ネストカウントをデクリメントする.
472 */
473 ldr r2, =excpt_nest_count
474 ldr r3, [r2]
475 subs r3, r3, #1
476 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
477 bne irq_handler_5 /* irq_handler_5に分岐 */
478
479 /*
480 * タスク用のスタックに戻す.
481 */
482 pop {r0,r3}
483 mov sp, r3
484
485#ifdef USE_ARM_FPU
486 /*
487 * FPUを元に戻す.
488 */
489 ldr r0, [sp] /* FPEXCを復帰 */
490 vmsr fpexc, r0
491#endif /* USE_ARM_FPU */
492
493 /*
494 * p_runtskがNULLか判定する.
495 */
496 ldr r0, =p_runtsk /* p_runtsk → r0 */
497 ldr r0, [r0]
498 tst r0, r0 /* p_runtskがNULLでなければ */
499 bne irq_handler_3 /* irq_handler_3に分岐 */
500
501 /*
502 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
503 */
504 pop {r0,r1} /* スタックポインタの調整を元に戻す */
505 add sp, sp, r1
506 add sp, sp, #40 /* スクラッチレジスタ等を捨てる */
507 b dispatcher_0
508
509 /*
510 * ディスパッチが必要か判定する.
511 */
512ALABEL(irq_handler_3)
513 /*
514 * 【この時点のレジスタ状態】
515 * r0:p_runtsk
516 */
517 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
518 ldr r1, [r1]
519 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
520 beq irq_handler_4 /* irq_handler_4へ */
521
522 /*
523 * コンテキストを保存する.
524 */
525 push {r6-r11} /* 残りのレジスタの保存 */
526#ifdef USE_ARM_FPU
527 ldr r2, [r0,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
528 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
529 tst r1, #TA_FPU
530 beq 1f /* TA_FPU属性でない場合は分岐 */
531#ifdef USE_ARM_FPU_D32
532 vpush {d16-d31}
533#endif /* USE_ARM_FPU_D32 */
534 vpush {d0-d15} /* 全FPUレジスタの保存 */
535 vmrs r1, fpscr
536 push {r1,r2} /* FPSCRの保存 */
5371: /* r2はアラインメントのため */
538#endif /* USE_ARM_FPU */
539 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
540 adr r1, ret_int_r /* 実行再開番地を保存 */
541 str r1, [r0,#TCB_pc]
542 b dispatcher /* r0にはp_runtskが格納されている */
543
544ALABEL(ret_int_r)
545 /*
546 * コンテキストを復帰する.
547 *
548 * 【この時点のレジスタ状態】
549 * r4:p_runtsk(タスク切換え後)
550 */
551#ifdef USE_ARM_FPU
552 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
553 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
554 tst r1, #TA_FPU
555 vmrs r0, fpexc
556 biceq r0, r0, #FPEXC_ENABLE
557 orrne r0, r0, #FPEXC_ENABLE
558 vmsr fpexc, r0 /* FPEXCを設定 */
559 beq 1f /* TA_FPU属性でない場合は分岐 */
560 pop {r1,r2} /* FPSCRの復帰 */
561 vmsr fpscr, r1
562 vpop {d0-d15} /* 全FPUレジスタの復帰 */
563#ifdef USE_ARM_FPU_D32
564 vpop {d16-d31}
565#endif /* USE_ARM_FPU_D32 */
5661:
567#endif /* USE_ARM_FPU */
568 pop {r6-r11} /* 残りのレジスタの復帰 */
569
570ALABEL(irq_handler_4)
571#ifdef TOPPERS_SUPPORT_OVRHDR
572 /*
573 * オーバランタイマを動作開始する.
574 */
575 bl ovrtimer_start
576#endif /* TOPPERS_SUPPORT_OVRHDR */
577
578 /*
579 * 割込み処理からのリターン
580 *
581 * 割込み処理からのリターンにより,CPUロック解除状態に遷移するよ
582 * うにする必要があるが,ARMはCPSRのビットによってCPUロック状態を
583 * 表しているため,CPSRを元に戻してリターンすればよい.
584 */
585ALABEL(irq_handler_5)
586 pop {r0,r1} /* スタックポインタの調整を元に戻す */
587 add sp, sp, r1
588
589#if __TARGET_ARCH_ARM < 6
590 pop {r0} /* 戻り先のcpsrをspsrに設定 */
591 msr spsr_cxsf, r0
592 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
593 /* ^付きなので,spsr → cpsr */
594#else /* __TARGET_ARCH_ARM < 6 */
595 pop {r0-r5,r12,lr} /* スクラッチレジスタ+αの復帰 */
596 rfefd sp!
597#endif /* __TARGET_ARCH_ARM < 6 */
598#endif /* OMIT_IRQ_HANDLER */
599
600/*
601 * CPU例外ハンドラ出入口処理
602 */
603ALABEL(start_exc_entry)
604
605/*
606 * 未定義命令
607 */
608#ifndef OMIT_UNDEF_HANDLER
609 ATEXT
610 AALIGN(2)
611 AGLOBAL(undef_handler)
612ALABEL(undef_handler)
613 /*
614 * ここには,未定義モードで分岐してくる.
615 */
616#if __TARGET_ARCH_ARM < 6
617 /*
618 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
619 * ラッチレジスタ+αを保存する.
620 */
621 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
622 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
623
624 /*
625 * 未定義モードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を取
626 * 得する.
627 */
628 msr cpsr_c, #(CPSR_UND_MODE AOR CPSR_FIQ_IRQ_BIT)
629 mov r2, lr
630 mrs r1, spsr
631
632 /*
633 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
634 */
635 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
636 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
637 push {r1} /* 戻り先のcpsrをスタックに保存 */
638#else /* __TARGET_ARCH_ARM < 6 */
639 /*
640 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
641 * クに保存する.
642 */
643 srsfd #CPSR_SVC_MODE!
644
645 /*
646 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
647 */
648 cps #CPSR_SVC_MODE
649 push {r0-r5,r12,lr}
650#endif /* __TARGET_ARCH_ARM < 6 */
651 mov r4, #EXCNO_UNDEF
652 b exc_handler_1
653#endif /* OMIT_UNDEF_HANDLER */
654
655/*
656 * スーパバイザコール
657 */
658#ifndef OMIT_SVC_HANDLER
659 ATEXT
660 AALIGN(2)
661 AGLOBAL(svc_handler)
662ALABEL(svc_handler)
663 /*
664 * ここには,スーパバイザモードで分岐してくる.
665 */
666#if __TARGET_ARCH_ARM < 6
667 /*
668 * IビットとFビットをセットし,戻り番地(lr),スクラッチレジスタ
669 * +α,戻り先のcpsr(spsr)を保存する(lrは二重に保存される).
670 */
671 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
672 push {lr}
673 push {r0-r5,r12,lr}
674 mrs r1, spsr
675 push {r1}
676#else /* __TARGET_ARCH_ARM < 6 */
677 /*
678 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
679 * クに保存する.
680 */
681 srsfd #CPSR_SVC_MODE!
682
683 /*
684 * スーパバイザモードで,スクラッチレジスタ+αを保存する.
685 */
686 push {r0-r5,r12,lr}
687#endif /* __TARGET_ARCH_ARM < 6 */
688 mov r4, #EXCNO_SVC
689 b exc_handler_1
690#endif /* OMIT_SVC_HANDLER */
691
692/*
693 * プリフェッチアボート
694 */
695#ifndef OMIT_PABORT_HANDLER
696 ATEXT
697 AALIGN(2)
698 AGLOBAL(pabort_handler)
699ALABEL(pabort_handler)
700 /*
701 * ここには,アボートモードで分岐してくる.
702 */
703#if __TARGET_ARCH_ARM < 6
704 /*
705 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
706 * ラッチレジスタ+αを保存する.
707 */
708 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
709 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
710
711 /*
712 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
713 * 取得する.
714 */
715 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
716 mov r2, lr
717 mrs r1, spsr
718
719 /*
720 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
721 */
722 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
723 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
724 push {r1} /* 戻り先のcpsrをスタックに保存 */
725#else /* __TARGET_ARCH_ARM < 6 */
726 /*
727 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
728 * クに保存する.
729 */
730 srsfd #CPSR_SVC_MODE!
731
732 /*
733 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
734 */
735 cps #CPSR_SVC_MODE
736 push {r0-r5,r12,lr}
737#endif /* __TARGET_ARCH_ARM < 6 */
738 mov r4, #EXCNO_PABORT
739 b exc_handler_1
740#endif /* OMIT_PABORT_HANDLER */
741
742/*
743 * データアボート
744 */
745#ifndef OMIT_DABORT_HANDLER
746 ATEXT
747 AALIGN(2)
748 AGLOBAL(dabort_handler)
749ALABEL(dabort_handler)
750 /*
751 * ここには,アボートモードで分岐してくる.
752 *
753 * データアボートが,CPU例外の入口(start_exc_entryとend_exc_entry
754 * の間)で発生した場合には,fatal_dabort_handlerに分岐する.アボー
755 * トモードのspを汎用レジスタの代わりに使用する.
756 */
757 ldr sp, =start_exc_entry+8
758 cmp lr, sp
759 bcc dabort_handler_1
760 ldr sp, =end_exc_entry+8
761 cmp lr, sp
762 bcc fatal_dabort_handler
763
764ALABEL(dabort_handler_1)
765#if __TARGET_ARCH_ARM < 6
766 /*
767 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
768 * ラッチレジスタ+αを保存する.
769 */
770 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
771 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
772
773 /*
774 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
775 * 取得する.
776 */
777 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
778 mov r2, lr
779 mrs r1, spsr
780
781 /*
782 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
783 */
784 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
785 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
786 push {r1} /* 戻り先のcpsrをスタックに保存 */
787#else /* __TARGET_ARCH_ARM < 6 */
788 /*
789 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
790 * クに保存する.
791 */
792 srsfd #CPSR_SVC_MODE!
793
794 /*
795 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
796 */
797 cps #CPSR_SVC_MODE
798 push {r0-r5,r12,lr}
799#endif /* __TARGET_ARCH_ARM < 6 */
800 mov r4, #EXCNO_DABORT
801 b exc_handler_1
802#endif /* OMIT_DABORT_HANDLER */
803
804/*
805 * CPU例外の入口で発生したデータアボート
806 */
807ALABEL(fatal_dabort_handler)
808#if __TARGET_ARCH_ARM < 6
809 /*
810 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
811 * クポインタを初期化し,スクラッチレジスタ+αを保存する.
812 */
813 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
814 ldr sp, =istkpt
815 ldr sp, [sp]
816 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
817
818 /*
819 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
820 * 取得する.
821 */
822 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
823 mov r2, lr
824 mrs r1, spsr
825
826 /*
827 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
828 */
829 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
830 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
831 push {r1} /* 戻り先のcpsrをスタックに保存 */
832#else /* __TARGET_ARCH_ARM < 6 */
833 /*
834 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
835 * クポインタを初期化する.
836 */
837 cpsid if, #CPSR_SVC_MODE
838 ldr sp, =istkpt
839 ldr sp, [sp]
840
841 /*
842 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
843 * スーパバイザモードのスタックに保存する.
844 */
845 cps #CPSR_ABT_MODE
846 srsfd #CPSR_SVC_MODE!
847
848 /*
849 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
850 */
851 cps #CPSR_SVC_MODE
852 push {r0-r5,r12,lr}
853#endif /* __TARGET_ARCH_ARM < 6 */
854
855 /*
856 * 例外ネストカウントの最上位ビットを1にする.
857 */
858 ldr r2, =excpt_nest_count
859 ldr r3, [r2]
860 orr r3, r3, #0x80000000
861 str r3, [r2]
862
863 mov r4, #EXCNO_DABORT
864 b exc_handler_1
865
866/*
867 * FIQ
868 */
869#ifndef OMIT_FIQ_HANDLER
870 ATEXT
871 AALIGN(2)
872 AGLOBAL(fiq_handler)
873ALABEL(fiq_handler)
874 /*
875 * ここには,FIQモードで分岐してくる.
876 */
877#if __TARGET_ARCH_ARM < 6
878 /*
879 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
880 * ラッチレジスタ+αを保存する.
881 */
882 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
883 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
884
885 /*
886 * FIQモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を取得
887 * する.
888 */
889 msr cpsr_c, #(CPSR_FIQ_MODE AOR CPSR_FIQ_IRQ_BIT)
890 mov r2, lr
891 mrs r1, spsr
892
893 /*
894 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
895 */
896 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
897 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
898 push {r1} /* 戻り先のcpsrをスタックに保存 */
899#else /* __TARGET_ARCH_ARM < 6 */
900 /*
901 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
902 * クに保存する.
903 */
904 srsfd #CPSR_SVC_MODE!
905
906 /*
907 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
908 */
909 cps #CPSR_SVC_MODE
910 push {r0-r5,r12,lr}
911#endif /* __TARGET_ARCH_ARM < 6 */
912 mov r4, #EXCNO_FIQ
913 b exc_handler_1
914#endif /* OMIT_FIQ_HANDLER */
915
916ALABEL(end_exc_entry)
917
918/*
919 * CPU例外ハンドラ出入口処理の共通部分
920 */
921ALABEL(exc_handler_1)
922 /*
923 * 【この時点のレジスタ状態】
924 * r4:CPU例外ハンドラ番号
925 *
926 * CPU例外が発生した状況の判断に用いるために,CPU例外発生前の割
927 * 込み優先度マスクと例外ネストカウントをスタックに保存する.
928 */
929 bl irc_get_intpri
930 push {r0} /* 割込み優先度マスクを保存 */
931 ldr r2, =excpt_nest_count
932 ldr r3, [r2]
933 push {r3} /* 例外ネストカウントを保存 */
934 mov r5, sp /* CPU例外の情報を記憶している領域の */
935 /* 先頭番地をr5に保存 */
936 /*
937 * スタックポインタの調整
938 */
939 and r1, sp, #4
940 sub sp, sp, r1
941 push {r0,r1} /* スタックポインタの調整値を保存 */
942 /* r0はスペース確保のため */
943 /*
944 * カーネル管理外のCPU例外か判定する
945 *
946 * カーネル管理外のCPU例外は,カーネル実行中,全割込みロック状態,
947 * CPUロック状態,カーネル管理外の割込みハンドラ実行中に発生した
948 * CPU例外である.ARMコアの場合は,戻り先のCPSRのIビットかFビット
949 * のいずれかがセットされているなら,これ該当する.
950 */
951 ldr r1, [r5,#T_EXCINF_cpsr] /* 例外フレームからcpsrを取得 */
952 ands r1, r1, #CPSR_FIQ_IRQ_BIT
953 bne nk_exc_handler_1 /* カーネル管理外のCPU例外の処理へ */
954
955 /*
956 * 【この時点のレジスタ状態】
957 * r2:excpt_nest_countの番地
958 * r3:excpt_nest_countの値
959 * r4:CPU例外ハンドラ番号
960 * r5:CPU例外の情報を記憶している領域の先頭番地
961 */
962
963 /*
964 * 例外ネストカウントをインクリメントする.
965 */
966 add r3, r3, #1
967 str r3, [r2]
968 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
969 bne exc_handler_2 /* ならexc_handler_2に分岐 */
970
971#ifdef TOPPERS_SUPPORT_OVRHDR
972 /*
973 * オーバランタイマを停止する.
974 */
975 bl ovrtimer_stop
976#endif /* TOPPERS_SUPPORT_OVRHDR */
977
978#ifdef USE_ARM_FPU
979 /*
980 * FPUをディスエーブルする.
981 */
982 vmrs r0, fpexc
983 str r0, [sp] /* FPEXCを保存(r0の場所)*/
984 bic r0, r0, #FPEXC_ENABLE
985 vmsr fpexc, r0 /* FPEXCを設定 */
986#endif /* USE_ARM_FPU */
987
988 /*
989 * 非タスクコンテキスト用のスタックに切り換える.
990 */
991 mov r3, sp /* この時点のスタックポインタをr3に */
992 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
993 ldr sp, [r2]
994 push {r0,r3} /* 切換え前のスタックポインタを保存 */
995 /* r0はスペース確保のため */
996ALABEL(exc_handler_2)
997 /*
998 * 【この時点のレジスタ状態】
999 * r4:CPU例外ハンドラ番号
1000 * r5:CPU例外の情報を記憶している領域の先頭番地
1001 */
1002
1003 /*
1004 * (必要なら)割込みコントローラを操作する.
1005 *
1006 * irc_begin_excは,スタックトップ(r0の場所)に,irc_end_excで用
1007 * いる情報を保存する.
1008 */
1009 bl irc_begin_exc
1010
1011 /*
1012 * CPUロック解除状態にする.
1013 *
1014 * カーネル管理外のCPU例外ハンドラは別ルーチンで呼び出すため,単純
1015 * に割込みを許可するだけでよい.
1016 */
1017#if __TARGET_ARCH_ARM < 6
1018 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
1019#else /* __TARGET_ARCH_ARM < 6 */
1020#ifndef TOPPERS_SAFEG_SECURE
1021 cpsie if
1022#else /* TOPPERS_SAFEG_SECURE */
1023 cpsie f
1024#endif /* TOPPERS_SAFEG_SECURE */
1025#endif /* __TARGET_ARCH_ARM < 6 */
1026
1027 /*
1028 * ログ出力の呼出し
1029 */
1030#ifdef LOG_EXC_ENTER
1031 mov r0, r4 /* CPU例外番号をパラメータに渡す */
1032 bl log_exc_enter
1033#endif /* LOG_EXC_ENTER */
1034
1035 /*
1036 * CPU例外ハンドラの呼出し
1037 */
1038 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1039 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1040 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1041 /* 先頭番地を第1パラメータに渡す */
1042 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1043 mov lr, pc /* CPU例外ハンドラの呼出し */
1044 bx r3
1045
1046 /*
1047 * ログ出力の呼出し
1048 */
1049#ifdef LOG_EXC_LEAVE
1050 mov r0, r4 /* CPU例外番号をパラメータに渡す */
1051 bl log_exc_leave
1052#endif /* LOG_EXC_LEAVE */
1053
1054 /*
1055 * カーネル管理の割込みを禁止する.
1056 */
1057#if __TARGET_ARCH_ARM < 6
1058 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
1059#else /* __TARGET_ARCH_ARM < 6 */
1060#ifndef TOPPERS_SAFEG_SECURE
1061 cpsid i
1062#else /* TOPPERS_SAFEG_SECURE */
1063 cpsid if
1064#endif /* TOPPERS_SAFEG_SECURE */
1065#endif /* __TARGET_ARCH_ARM < 6 */
1066
1067 /*
1068 * 割込みコントローラを操作して,割込み優先度マスクを,CPU例外発
1069 * 生時の値に設定する.
1070 */
1071 bl irc_end_exc
1072
1073 /*
1074 * 例外ネストカウントをデクリメントする.
1075 */
1076 ldr r2, =excpt_nest_count
1077 ldr r3, [r2]
1078 subs r3, r3, #1
1079 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1080 bne exc_handler_5 /* exc_handler_5に分岐 */
1081
1082 /*
1083 * タスク用のスタックに戻す.
1084 */
1085 pop {r0,r3}
1086 mov sp, r3
1087
1088#ifdef USE_ARM_FPU
1089 /*
1090 * FPUを元に戻す.
1091 */
1092 ldr r0, [sp] /* FPEXCを復帰 */
1093 vmsr fpexc, r0
1094#endif /* USE_ARM_FPU */
1095
1096 /*
1097 * p_runtskがNULLか判定する.
1098 */
1099 ldr r0, =p_runtsk /* p_runtsk → r0 */
1100 ldr r0, [r0]
1101 tst r0, r0 /* p_runtskがNULLでなければ */
1102 bne exc_handler_3 /* exc_handler_3に分岐 */
1103
1104 /*
1105 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
1106 */
1107 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1108 add sp, sp, r1
1109 add sp, sp, #48 /* スクラッチレジスタとCPU例外が発生した */
1110 b dispatcher_0 /* 状況を判断するための追加情報を捨てる */
1111
1112 /*
1113 * ディスパッチが必要か判定する.
1114 */
1115ALABEL(exc_handler_3)
1116 /*
1117 * 【この時点のレジスタ状態】
1118 * r0:p_runtsk
1119 */
1120 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
1121 ldr r1, [r1]
1122 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
1123 beq exc_handler_4 /* exc_handler_4へ */
1124
1125 /*
1126 * コンテキストを保存する.
1127 */
1128 push {r6-r11} /* 残りのレジスタの保存 */
1129#ifdef USE_ARM_FPU
1130 ldr r2, [r0,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
1131 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
1132 tst r1, #TA_FPU
1133 beq 1f /* TA_FPU属性でない場合は分岐 */
1134#ifdef USE_ARM_FPU_D32
1135 vpush {d16-d31}
1136#endif /* USE_ARM_FPU_D32 */
1137 vpush {d0-d15} /* 全FPUレジスタの保存 */
1138 vmrs r1, fpscr
1139 push {r1,r2} /* FPSCRの保存 */
11401: /* r2はアラインメントのため */
1141#endif /* USE_ARM_FPU */
1142 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
1143 adr r1, ret_exc_r /* 実行再開番地を保存 */
1144 str r1, [r0,#TCB_pc]
1145 b dispatcher /* r0にはp_runtskが格納されている */
1146
1147ALABEL(ret_exc_r)
1148 /*
1149 * コンテキストを復帰する.
1150 *
1151 * 【この時点のレジスタ状態】
1152 * r4:p_runtsk(タスク切換え後)
1153 */
1154#ifdef USE_ARM_FPU
1155 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
1156 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
1157 tst r1, #TA_FPU
1158 vmrs r0, fpexc
1159 biceq r0, r0, #FPEXC_ENABLE
1160 orrne r0, r0, #FPEXC_ENABLE
1161 vmsr fpexc, r0 /* FPEXCを設定 */
1162 beq 1f /* TA_FPU属性でない場合は分岐 */
1163 pop {r1,r2} /* FPSCRの復帰 */
1164 vmsr fpscr, r1
1165 vpop {d0-d15} /* 全FPUレジスタの復帰 */
1166#ifdef USE_ARM_FPU_D32
1167 vpop {d16-d31}
1168#endif /* USE_ARM_FPU_D32 */
11691:
1170#endif /* USE_ARM_FPU */
1171 pop {r6-r11} /* 残りのレジスタの復帰 */
1172
1173ALABEL(exc_handler_4)
1174#ifdef TOPPERS_SUPPORT_OVRHDR
1175 /*
1176 * オーバランタイマを動作開始する.
1177 */
1178 bl ovrtimer_start
1179#endif /* TOPPERS_SUPPORT_OVRHDR */
1180
1181 /*
1182 * CPU例外処理からのリターン
1183 *
1184 * CPU例外処理からのリターンにより,CPUロック解除状態に遷移するよ
1185 * うにする必要があるが,ARMはCPSRのビットによってCPUロック状態を
1186 * 表しているため,CPSRを元に戻してリターンすればよい.
1187 */
1188ALABEL(exc_handler_5)
1189 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1190 add sp, sp, r1
1191 add sp, sp, #8 /* スタック上の情報を捨てる */
1192
1193#if __TARGET_ARCH_ARM < 6
1194 pop {r0} /* 戻り先のcpsrをspsrに設定 */
1195 msr spsr_cxsf, r0
1196 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
1197 /* ^付きなので,spsr → cpsr */
1198#else /* __TARGET_ARCH_ARM < 6 */
1199 pop {r0-r5,r12,lr} /* スクラッチレジスタ+αの復帰 */
1200 rfefd sp!
1201#endif /* __TARGET_ARCH_ARM < 6 */
1202
1203/*
1204 * カーネル管理外のCPU例外の出入口処理
1205 */
1206ALABEL(nk_exc_handler_1)
1207 /*
1208 * 【この時点のレジスタ状態】
1209 * r1:CPU例外発生前のCPSRのFビットとIビットの値
1210 * r2:excpt_nest_countの番地
1211 * r3:excpt_nest_countの値
1212 * r4:CPU例外ハンドラ番号
1213 * r5:CPU例外の情報を記憶している領域の先頭番地
1214 */
1215
1216 /*
1217 * 例外ネストカウントをインクリメントする.
1218 */
1219 add r3, r3, #1
1220 str r3, [r2]
1221 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
1222 bne nk_exc_handler_2 /* ならnk_exc_handler_2に分岐 */
1223
1224#ifdef USE_ARM_FPU
1225 /*
1226 * FPUをディスエーブルする.
1227 */
1228 vmrs r0, fpexc
1229 str r0, [sp] /* FPEXCを保存(r0の場所)*/
1230 bic r0, r0, #FPEXC_ENABLE
1231 vmsr fpexc, r0 /* FPEXCを設定 */
1232#endif /* USE_ARM_FPU */
1233
1234 /*
1235 * 非タスクコンテキスト用のスタックに切り換える.
1236 */
1237 mov r3, sp /* この時点のスタックポインタをr3に */
1238 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
1239 ldr sp, [r2]
1240 push {r0,r3} /* 切換え前のスタックポインタを保存 */
1241 /* r0はアラインメントのため */
1242ALABEL(nk_exc_handler_2)
1243 /*
1244 * システム状態(コンテキストは除く)を,CPU例外発生時の状態へ
1245 */
1246 orr r1, r1, #CPSR_SVC_MODE
1247 msr cpsr_c, r1
1248
1249 /*
1250 * CPU例外ハンドラの呼出し
1251 */
1252 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1253 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1254 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1255 /* 先頭番地を第1パラメータに渡す */
1256 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1257 mov lr, pc /* CPU例外ハンドラの呼出し */
1258 bx r3
1259
1260 /*
1261 * 例外ネストカウントをデクリメントする.
1262 */
1263 ldr r2, =excpt_nest_count
1264 ldr r3, [r2]
1265 subs r3, r3, #1
1266 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1267 bne exc_handler_5 /* exc_handler_5に分岐 */
1268
1269 /*
1270 * タスク用のスタックに戻す.
1271 */
1272 pop {r0,r3}
1273 mov sp, r3
1274
1275#ifdef USE_ARM_FPU
1276 /*
1277 * FPUを元に戻す.
1278 */
1279 ldr r0, [sp] /* FPEXCを復帰 */
1280 vmsr fpexc, r0
1281#endif /* USE_ARM_FPU */
1282 b exc_handler_5
1283
1284/*
1285 * ステータスレジスタの操作関数
1286 *
1287 * Thumbモードではmrs/msr命令が使用できないため,関数として実現して,
1288 * ARMモードに移行して実行する.
1289 */
1290#ifdef __thumb__
1291
1292 ATEXT
1293 AALIGN(2)
1294 AWEAK(_kernel_current_cpsr)
1295ALABEL(_kernel_current_cpsr)
1296 mrs r0, cpsr_cxsf
1297 bx lr
1298
1299 AALIGN(2)
1300 AWEAK(_kernel_set_cpsr)
1301ALABEL(_kernel_set_cpsr)
1302 msr cpsr_cxsf, r0
1303 bx lr
1304
1305#endif /* __thumb__ */
1306
1307/*
1308 * 微少時間待ち
1309 *
1310 * キャッシュラインのどの場所にあるかのよって実行時間が変わるため,大
1311 * きめの単位でアラインしている.
1312 */
1313 ATEXT
1314 AALIGN(8)
1315 AGLOBAL(sil_dly_nse)
1316ALABEL(sil_dly_nse)
1317 mov r1, #0
1318 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1319 asm_inst_sync_barrier r3
1320 subs r0, r0, #SIL_DLY_TIM1
1321 bxls lr
1322ALABEL(sil_dly_nse1)
1323 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1324 asm_inst_sync_barrier r3
1325 subs r0, r0, #SIL_DLY_TIM2
1326 bhi sil_dly_nse1
1327 bx lr
Note: See TracBrowser for help on using the repository browser.