source: EcnlProtoTool/trunk/asp3_dcre/arch/arm_gcc/common/core_support.S@ 429

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

ASP3, TINET, mbed を更新

  • 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-2019 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 AWEAK(svc_handler)
662 AGLOBAL(svc_handler)
663ALABEL(svc_handler)
664 /*
665 * ここには,スーパバイザモードで分岐してくる.
666 */
667#if __TARGET_ARCH_ARM < 6
668 /*
669 * IビットとFビットをセットし,戻り番地(lr),スクラッチレジスタ
670 * +α,戻り先のcpsr(spsr)を保存する(lrは二重に保存される).
671 */
672 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
673 push {lr}
674 push {r0-r5,r12,lr}
675 mrs r1, spsr
676 push {r1}
677#else /* __TARGET_ARCH_ARM < 6 */
678 /*
679 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
680 * クに保存する.
681 */
682 srsfd #CPSR_SVC_MODE!
683
684 /*
685 * スーパバイザモードで,スクラッチレジスタ+αを保存する.
686 */
687 push {r0-r5,r12,lr}
688#endif /* __TARGET_ARCH_ARM < 6 */
689 mov r4, #EXCNO_SVC
690 b exc_handler_1
691#endif /* OMIT_SVC_HANDLER */
692
693/*
694 * プリフェッチアボート
695 */
696#ifndef OMIT_PABORT_HANDLER
697 ATEXT
698 AALIGN(2)
699 AGLOBAL(pabort_handler)
700ALABEL(pabort_handler)
701 /*
702 * ここには,アボートモードで分岐してくる.
703 */
704#if __TARGET_ARCH_ARM < 6
705 /*
706 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
707 * ラッチレジスタ+αを保存する.
708 */
709 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
710 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
711
712 /*
713 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
714 * 取得する.
715 */
716 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
717 mov r2, lr
718 mrs r1, spsr
719
720 /*
721 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
722 */
723 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
724 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
725 push {r1} /* 戻り先のcpsrをスタックに保存 */
726#else /* __TARGET_ARCH_ARM < 6 */
727 /*
728 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
729 * クに保存する.
730 */
731 srsfd #CPSR_SVC_MODE!
732
733 /*
734 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
735 */
736 cps #CPSR_SVC_MODE
737 push {r0-r5,r12,lr}
738#endif /* __TARGET_ARCH_ARM < 6 */
739 mov r4, #EXCNO_PABORT
740 b exc_handler_1
741#endif /* OMIT_PABORT_HANDLER */
742
743/*
744 * データアボート
745 */
746#ifndef OMIT_DABORT_HANDLER
747 ATEXT
748 AALIGN(2)
749 AGLOBAL(dabort_handler)
750ALABEL(dabort_handler)
751 /*
752 * ここには,アボートモードで分岐してくる.
753 *
754 * データアボートが,CPU例外の入口(start_exc_entryとend_exc_entry
755 * の間)で発生した場合には,fatal_dabort_handlerに分岐する.アボー
756 * トモードのspを汎用レジスタの代わりに使用する(r13と記述している).
757 */
758 adr r13, start_exc_entry+8
759 cmp lr, r13
760 bcc dabort_handler_1
761 adr r13, end_exc_entry+8
762 cmp lr, r13
763 bcc fatal_dabort_handler
764
765ALABEL(dabort_handler_1)
766#if __TARGET_ARCH_ARM < 6
767 /*
768 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
769 * ラッチレジスタ+αを保存する.
770 */
771 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
772 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
773
774 /*
775 * アボートモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を
776 * 取得する.
777 */
778 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
779 mov r2, lr
780 mrs r1, spsr
781
782 /*
783 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
784 */
785 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
786 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
787 push {r1} /* 戻り先のcpsrをスタックに保存 */
788#else /* __TARGET_ARCH_ARM < 6 */
789 /*
790 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
791 * クに保存する.
792 */
793 srsfd #CPSR_SVC_MODE!
794
795 /*
796 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
797 */
798 cps #CPSR_SVC_MODE
799 push {r0-r5,r12,lr}
800#endif /* __TARGET_ARCH_ARM < 6 */
801 mov r4, #EXCNO_DABORT
802 b exc_handler_1
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 * 例外ネストカウントをインクリメントする.
857 */
858 ldr r2, =excpt_nest_count
859 ldr r3, [r2]
860 add r3, r3, #1
861 str r3, [r2]
862
863 mov r4, #EXCNO_FATAL
864 b exc_handler_1
865#endif /* OMIT_DABORT_HANDLER */
866
867/*
868 * FIQ
869 */
870#ifndef OMIT_FIQ_HANDLER
871 ATEXT
872 AALIGN(2)
873 AGLOBAL(fiq_handler)
874ALABEL(fiq_handler)
875 /*
876 * ここには,FIQモードで分岐してくる.
877 */
878#if __TARGET_ARCH_ARM < 6
879 /*
880 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
881 * ラッチレジスタ+αを保存する.
882 */
883 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
884 push {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
885
886 /*
887 * FIQモードに戻して,戻り番地(lr)と戻り先のcpsr(spsr)を取得
888 * する.
889 */
890 msr cpsr_c, #(CPSR_FIQ_MODE AOR CPSR_FIQ_IRQ_BIT)
891 mov r2, lr
892 mrs r1, spsr
893
894 /*
895 * スーパバイザモードに切り換え,戻り番地と戻り先のcpsrを保存する.
896 */
897 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
898 str r2, [sp,#0x20] /* 戻り番地をスタックに保存(pcの場所)*/
899 push {r1} /* 戻り先のcpsrをスタックに保存 */
900#else /* __TARGET_ARCH_ARM < 6 */
901 /*
902 * 戻り番地(lr)と戻り先のcpsr(spsr)をスーパバイザモードのスタッ
903 * クに保存する.
904 */
905 srsfd #CPSR_SVC_MODE!
906
907 /*
908 * スーパバイザモードに切り換え,スクラッチレジスタ+αを保存する.
909 */
910 cps #CPSR_SVC_MODE
911 push {r0-r5,r12,lr}
912#endif /* __TARGET_ARCH_ARM < 6 */
913 mov r4, #EXCNO_FIQ
914 b exc_handler_1
915#endif /* OMIT_FIQ_HANDLER */
916
917ALABEL(end_exc_entry)
918
919/*
920 * CPU例外ハンドラ出入口処理の共通部分
921 */
922ALABEL(exc_handler_1)
923 /*
924 * 【この時点のレジスタ状態】
925 * r4:CPU例外ハンドラ番号
926 *
927 * CPU例外が発生した状況の判断に用いるために,CPU例外発生前の割
928 * 込み優先度マスクと例外ネストカウントをスタックに保存する.
929 */
930 bl irc_get_intpri
931 push {r0} /* 割込み優先度マスクを保存 */
932 ldr r2, =excpt_nest_count
933 ldr r3, [r2]
934 push {r3} /* 例外ネストカウントを保存 */
935 mov r5, sp /* CPU例外の情報を記憶している領域の */
936 /* 先頭番地をr5に保存 */
937 /*
938 * スタックポインタの調整
939 */
940 and r1, sp, #4
941 sub sp, sp, r1
942 push {r0,r1} /* スタックポインタの調整値を保存 */
943 /* r0はスペース確保のため */
944 /*
945 * カーネル管理外のCPU例外か判定する
946 *
947 * カーネル管理外のCPU例外は,カーネル実行中,全割込みロック状態,
948 * CPUロック状態,カーネル管理外の割込みハンドラ実行中に発生した
949 * CPU例外である.ARMコアの場合は,戻り先のCPSRのIビットかFビット
950 * のいずれかがセットされているなら,これ該当する.
951 */
952 ldr r1, [r5,#T_EXCINF_cpsr] /* 例外フレームからcpsrを取得 */
953 ands r1, r1, #CPSR_FIQ_IRQ_BIT
954 bne nk_exc_handler_1 /* カーネル管理外のCPU例外の処理へ */
955
956 /*
957 * 【この時点のレジスタ状態】
958 * r2:excpt_nest_countの番地
959 * r3:excpt_nest_countの値
960 * r4:CPU例外ハンドラ番号
961 * r5:CPU例外の情報を記憶している領域の先頭番地
962 */
963
964 /*
965 * 例外ネストカウントをインクリメントする.
966 */
967 add r3, r3, #1
968 str r3, [r2]
969 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
970 bne exc_handler_2 /* ならexc_handler_2に分岐 */
971
972#ifdef TOPPERS_SUPPORT_OVRHDR
973 /*
974 * オーバランタイマを停止する.
975 */
976 bl ovrtimer_stop
977#endif /* TOPPERS_SUPPORT_OVRHDR */
978
979#ifdef USE_ARM_FPU
980 /*
981 * FPUをディスエーブルする.
982 */
983 vmrs r0, fpexc
984 str r0, [sp] /* FPEXCを保存(r0の場所)*/
985 bic r0, r0, #FPEXC_ENABLE
986 vmsr fpexc, r0 /* FPEXCを設定 */
987#endif /* USE_ARM_FPU */
988
989 /*
990 * 非タスクコンテキスト用のスタックに切り換える.
991 */
992 mov r3, sp /* この時点のスタックポインタをr3に */
993 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
994 ldr sp, [r2]
995 push {r0,r3} /* 切換え前のスタックポインタを保存 */
996 /* r0はスペース確保のため */
997ALABEL(exc_handler_2)
998 /*
999 * 【この時点のレジスタ状態】
1000 * r4:CPU例外ハンドラ番号
1001 * r5:CPU例外の情報を記憶している領域の先頭番地
1002 */
1003
1004 /*
1005 * (必要なら)割込みコントローラを操作する.
1006 *
1007 * irc_begin_excは,スタックトップ(r0の場所)に,irc_end_excで用
1008 * いる情報を保存する.
1009 */
1010 bl irc_begin_exc
1011
1012 /*
1013 * CPUロック解除状態にする.
1014 *
1015 * カーネル管理外のCPU例外ハンドラは別ルーチンで呼び出すため,単純
1016 * に割込みを許可するだけでよい.
1017 */
1018#if __TARGET_ARCH_ARM < 6
1019 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
1020#else /* __TARGET_ARCH_ARM < 6 */
1021#ifndef TOPPERS_SAFEG_SECURE
1022 cpsie if
1023#else /* TOPPERS_SAFEG_SECURE */
1024 cpsie f
1025#endif /* TOPPERS_SAFEG_SECURE */
1026#endif /* __TARGET_ARCH_ARM < 6 */
1027
1028 /*
1029 * ログ出力の呼出し
1030 */
1031#ifdef LOG_EXC_ENTER
1032 mov r0, r4 /* CPU例外番号をパラメータに渡す */
1033 bl log_exc_enter
1034#endif /* LOG_EXC_ENTER */
1035
1036 /*
1037 * CPU例外ハンドラの呼出し
1038 */
1039 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1040 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1041 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1042 /* 先頭番地を第1パラメータに渡す */
1043 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1044 mov lr, pc /* CPU例外ハンドラの呼出し */
1045 bx r3
1046
1047 /*
1048 * ログ出力の呼出し
1049 */
1050#ifdef LOG_EXC_LEAVE
1051 mov r0, r4 /* CPU例外番号をパラメータに渡す */
1052 bl log_exc_leave
1053#endif /* LOG_EXC_LEAVE */
1054
1055 /*
1056 * カーネル管理の割込みを禁止する.
1057 */
1058#if __TARGET_ARCH_ARM < 6
1059 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
1060#else /* __TARGET_ARCH_ARM < 6 */
1061#ifndef TOPPERS_SAFEG_SECURE
1062 cpsid i
1063#else /* TOPPERS_SAFEG_SECURE */
1064 cpsid if
1065#endif /* TOPPERS_SAFEG_SECURE */
1066#endif /* __TARGET_ARCH_ARM < 6 */
1067
1068 /*
1069 * 割込みコントローラを操作して,割込み優先度マスクを,CPU例外発
1070 * 生時の値に設定する.
1071 */
1072 bl irc_end_exc
1073
1074 /*
1075 * 例外ネストカウントをデクリメントする.
1076 */
1077 ldr r2, =excpt_nest_count
1078 ldr r3, [r2]
1079 subs r3, r3, #1
1080 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1081 bne exc_handler_5 /* exc_handler_5に分岐 */
1082
1083 /*
1084 * タスク用のスタックに戻す.
1085 */
1086 pop {r0,r3}
1087 mov sp, r3
1088
1089#ifdef USE_ARM_FPU
1090 /*
1091 * FPUを元に戻す.
1092 */
1093 ldr r0, [sp] /* FPEXCを復帰 */
1094 vmsr fpexc, r0
1095#endif /* USE_ARM_FPU */
1096
1097 /*
1098 * p_runtskがNULLか判定する.
1099 */
1100 ldr r0, =p_runtsk /* p_runtsk → r0 */
1101 ldr r0, [r0]
1102 tst r0, r0 /* p_runtskがNULLでなければ */
1103 bne exc_handler_3 /* exc_handler_3に分岐 */
1104
1105 /*
1106 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
1107 */
1108 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1109 add sp, sp, r1
1110 add sp, sp, #48 /* スクラッチレジスタとCPU例外が発生した */
1111 b dispatcher_0 /* 状況を判断するための追加情報を捨てる */
1112
1113 /*
1114 * ディスパッチが必要か判定する.
1115 */
1116ALABEL(exc_handler_3)
1117 /*
1118 * 【この時点のレジスタ状態】
1119 * r0:p_runtsk
1120 */
1121 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
1122 ldr r1, [r1]
1123 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
1124 beq exc_handler_4 /* exc_handler_4へ */
1125
1126 /*
1127 * コンテキストを保存する.
1128 */
1129 push {r6-r11} /* 残りのレジスタの保存 */
1130#ifdef USE_ARM_FPU
1131 ldr r2, [r0,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
1132 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
1133 tst r1, #TA_FPU
1134 beq 1f /* TA_FPU属性でない場合は分岐 */
1135#ifdef USE_ARM_FPU_D32
1136 vpush {d16-d31}
1137#endif /* USE_ARM_FPU_D32 */
1138 vpush {d0-d15} /* 全FPUレジスタの保存 */
1139 vmrs r1, fpscr
1140 push {r1,r2} /* FPSCRの保存 */
11411: /* r2はアラインメントのため */
1142#endif /* USE_ARM_FPU */
1143 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
1144 adr r1, ret_exc_r /* 実行再開番地を保存 */
1145 str r1, [r0,#TCB_pc]
1146 b dispatcher /* r0にはp_runtskが格納されている */
1147
1148ALABEL(ret_exc_r)
1149 /*
1150 * コンテキストを復帰する.
1151 *
1152 * 【この時点のレジスタ状態】
1153 * r4:p_runtsk(タスク切換え後)
1154 */
1155#ifdef USE_ARM_FPU
1156 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
1157 ldr r1, [r2,#TINIB_tskatr] /* p_runtsk->p_tinib->tskatr → r1 */
1158 tst r1, #TA_FPU
1159 vmrs r0, fpexc
1160 biceq r0, r0, #FPEXC_ENABLE
1161 orrne r0, r0, #FPEXC_ENABLE
1162 vmsr fpexc, r0 /* FPEXCを設定 */
1163 beq 1f /* TA_FPU属性でない場合は分岐 */
1164 pop {r1,r2} /* FPSCRの復帰 */
1165 vmsr fpscr, r1
1166 vpop {d0-d15} /* 全FPUレジスタの復帰 */
1167#ifdef USE_ARM_FPU_D32
1168 vpop {d16-d31}
1169#endif /* USE_ARM_FPU_D32 */
11701:
1171#endif /* USE_ARM_FPU */
1172 pop {r6-r11} /* 残りのレジスタの復帰 */
1173
1174ALABEL(exc_handler_4)
1175#ifdef TOPPERS_SUPPORT_OVRHDR
1176 /*
1177 * オーバランタイマを動作開始する.
1178 */
1179 bl ovrtimer_start
1180#endif /* TOPPERS_SUPPORT_OVRHDR */
1181
1182 /*
1183 * CPU例外処理からのリターン
1184 *
1185 * CPU例外処理からのリターンにより,CPUロック解除状態に遷移するよ
1186 * うにする必要があるが,ARMはCPSRのビットによってCPUロック状態を
1187 * 表しているため,CPSRを元に戻してリターンすればよい.
1188 */
1189ALABEL(exc_handler_5)
1190 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1191 add sp, sp, r1
1192 add sp, sp, #8 /* スタック上の情報を捨てる */
1193
1194#if __TARGET_ARCH_ARM < 6
1195 pop {r0} /* 戻り先のcpsrをspsrに設定 */
1196 msr spsr_cxsf, r0
1197 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
1198 /* ^付きなので,spsr → cpsr */
1199#else /* __TARGET_ARCH_ARM < 6 */
1200 pop {r0-r5,r12,lr} /* スクラッチレジスタ+αの復帰 */
1201 rfefd sp!
1202#endif /* __TARGET_ARCH_ARM < 6 */
1203
1204/*
1205 * カーネル管理外のCPU例外の出入口処理
1206 */
1207ALABEL(nk_exc_handler_1)
1208 /*
1209 * 【この時点のレジスタ状態】
1210 * r1:CPU例外発生前のCPSRのFビットとIビットの値
1211 * r2:excpt_nest_countの番地
1212 * r3:excpt_nest_countの値
1213 * r4:CPU例外ハンドラ番号
1214 * r5:CPU例外の情報を記憶している領域の先頭番地
1215 */
1216
1217 /*
1218 * 例外ネストカウントをインクリメントする.
1219 */
1220 add r3, r3, #1
1221 str r3, [r2]
1222 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
1223 bne nk_exc_handler_2 /* ならnk_exc_handler_2に分岐 */
1224
1225#ifdef USE_ARM_FPU
1226 /*
1227 * FPUをディスエーブルする.
1228 */
1229 vmrs r0, fpexc
1230 str r0, [sp] /* FPEXCを保存(r0の場所)*/
1231 bic r0, r0, #FPEXC_ENABLE
1232 vmsr fpexc, r0 /* FPEXCを設定 */
1233#endif /* USE_ARM_FPU */
1234
1235 /*
1236 * 非タスクコンテキスト用のスタックに切り換える.
1237 */
1238 mov r3, sp /* この時点のスタックポインタをr3に */
1239 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
1240 ldr sp, [r2]
1241 push {r0,r3} /* 切換え前のスタックポインタを保存 */
1242 /* r0はアラインメントのため */
1243ALABEL(nk_exc_handler_2)
1244 /*
1245 * システム状態(コンテキストは除く)を,CPU例外発生時の状態へ
1246 */
1247 orr r1, r1, #CPSR_SVC_MODE
1248 msr cpsr_c, r1
1249
1250 /*
1251 * CPU例外ハンドラの呼出し
1252 */
1253 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1254 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1255 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1256 /* 先頭番地を第1パラメータに渡す */
1257 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1258 mov lr, pc /* CPU例外ハンドラの呼出し */
1259 bx r3
1260
1261 /*
1262 * 例外ネストカウントをデクリメントする.
1263 */
1264 ldr r2, =excpt_nest_count
1265 ldr r3, [r2]
1266 subs r3, r3, #1
1267 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1268 bne exc_handler_5 /* exc_handler_5に分岐 */
1269
1270 /*
1271 * タスク用のスタックに戻す.
1272 */
1273 pop {r0,r3}
1274 mov sp, r3
1275
1276#ifdef USE_ARM_FPU
1277 /*
1278 * FPUを元に戻す.
1279 */
1280 ldr r0, [sp] /* FPEXCを復帰 */
1281 vmsr fpexc, r0
1282#endif /* USE_ARM_FPU */
1283 b exc_handler_5
1284
1285/*
1286 * ステータスレジスタの操作関数
1287 *
1288 * Thumbモードではmrs/msr命令が使用できないため,関数として実現して,
1289 * ARMモードに移行して実行する.
1290 */
1291#ifdef __thumb__
1292
1293 ATEXT
1294 AALIGN(2)
1295 AWEAK(_kernel_current_cpsr)
1296ALABEL(_kernel_current_cpsr)
1297 mrs r0, cpsr_cxsf
1298 bx lr
1299
1300 AALIGN(2)
1301 AWEAK(_kernel_set_cpsr)
1302ALABEL(_kernel_set_cpsr)
1303 msr cpsr_cxsf, r0
1304 bx lr
1305
1306#endif /* __thumb__ */
1307
1308/*
1309 * 微少時間待ち
1310 *
1311 * キャッシュラインのどの場所にあるかのよって実行時間が変わるため,大
1312 * きめの単位でアラインしている.
1313 */
1314 ATEXT
1315 AALIGN(8)
1316 AGLOBAL(sil_dly_nse)
1317ALABEL(sil_dly_nse)
1318 mov r1, #0
1319 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1320 asm_inst_sync_barrier r3
1321 subs r0, r0, #SIL_DLY_TIM1
1322 bxls lr
1323ALABEL(sil_dly_nse1)
1324 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1325 asm_inst_sync_barrier r3
1326 subs r0, r0, #SIL_DLY_TIM2
1327 bhi sil_dly_nse1
1328 bx lr
Note: See TracBrowser for help on using the repository browser.