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

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

文字コードを設定

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/plain;charset=UTF-8
File size: 34.5 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-2017 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 ASECTION(.vector)
60 AALIGN(5)
61 AGLOBAL(vector_table)
62ALABEL(vector_table)
63 ldr pc, reset_vector /* リセット */
64 ldr pc, undef_vector /* 未定義命令 */
65 ldr pc, svc_vector /* ソフトウェア割込み */
66 ldr pc, pabort_vector /* プリフェッチアボート */
67 ldr pc, dabort_vector /* データアボート */
68 ldr pc, reset_vector /* 未使用 */
69 ldr pc, irq_vector /* IRQ */
70 ldr pc, fiq_vector /* FIQ */
71
72/*
73 * 例外ベクタの命令から参照されるジャンプ先アドレス
74 */
75 AGLOBAL(vector_ref_table)
76ALABEL(vector_ref_table)
77ALABEL(reset_vector)
78 ALONG Reset_Handler
79ALABEL(undef_vector)
80 ALONG undef_handler
81ALABEL(svc_vector)
82 ALONG svc_handler
83ALABEL(pabort_vector)
84 ALONG pabort_handler
85ALABEL(dabort_vector)
86 ALONG dabort_handler
87ALABEL(irq_vector)
88 ALONG irq_handler
89ALABEL(fiq_vector)
90 ALONG fiq_handler
91
92/*
93 * タスクディスパッチャ
94 */
95 ATEXT
96 AALIGN(2)
97 AGLOBAL(dispatch)
98ALABEL(dispatch)
99 /*
100 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
101 * マスク全解除状態・ディスパッチ許可状態で呼び出される.
102 */
103 push {r12,lr} /* 戻り番地を保存,r12はダミー */
104#ifdef TOPPERS_SUPPORT_OVRHDR
105 bl ovrtimer_stop
106#endif /* TOPPERS_SUPPORT_OVRHDR */
107 stmfd sp!, {r4-r11} /* 非スクラッチレジスタの保存 */
108 ldr r0, =p_runtsk /* p_runtsk → r0 */
109 ldr r0, [r0]
110 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
111 adr r1, dispatch_r
112 str r1, [r0,#TCB_pc] /* 実行再開番地を保存 */
113 b dispatcher /* r0にはp_runtskが格納されている */
114
115ALABEL(dispatch_r)
116 ldmfd sp!, {r4-r11} /* 非スクラッチレジスタの復帰 */
117#ifdef TOPPERS_SUPPORT_OVRHDR
118 bl ovrtimer_start
119#endif /* TOPPERS_SUPPORT_OVRHDR */
120 pop {r12,lr} /* 戻り番地を復帰 */
121 bx lr
122
123/*
124 * ディスパッチャの動作開始
125 */
126 AGLOBAL(start_dispatch)
127ALABEL(start_dispatch)
128 /*
129 * このルーチンは,カーネル起動時に,非タスクコンテキストで,NMIを
130 * 除くすべての割込みを禁止した状態(全割込みロック状態と同等)で
131 * 呼び出される.
132 *
133 * dispatcher_0へ分岐する前に,タスクコンテキスト・CPUロック状態・
134 * 割込み優先度マスク全解除状態にし,使用するスタックを,IDが1のタ
135 * スクのスタック領域に切り換えなければならない.
136 */
137
138 /*
139 * タスクコンテキストに切り換える.
140 */
141 ldr r2, =excpt_nest_count /* 例外ネストカウントを0に */
142 mov r0, #0
143 str r0, [r2]
144
145 /*
146 * IDが1のタスクのスタック領域に切り換える.
147 */
148 ldr r0, =tcb_table /* tcb_table[0] → r0 */
149 ldr r2, [r0,#TCB_p_tinib] /* tcb_table[0].p_tinib → r2 */
150 ldr r0, [r2,#TINIB_stk]
151 ldr r1, [r2,#TINIB_stksz]
152 add sp, r0, r1
153
154 /*
155 * CPUロック状態にして,ディスパッチャ本体へ分岐する.
156 */
157 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
158 b dispatcher_0
159
160/*
161 * 現在のコンテキストを捨ててディスパッチ
162 */
163 AGLOBAL(exit_and_dispatch)
164ALABEL(exit_and_dispatch)
165 /*
166 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
167 * マスク全解除状態・ディスパッチ許可状態で呼び出される.
168 */
169#ifdef LOG_DSP_ENTER
170 ldr r0, =p_runtsk /* p_runtsk → r0 */
171 ldr r0, [r0]
172#endif /* LOG_DSP_ENTER */
173 /* ディスパッチャ本体(dispatcher)へ */
174
175/*
176 * ディスパッチャ本体
177 */
178ALABEL(dispatcher)
179#ifdef LOG_DSP_ENTER
180 /*
181 * 【この時点のレジスタ状態】
182 * r0:p_runtsk(タスク切換え前)
183 */
184 bl log_dsp_enter
185#endif /* LOG_DSP_ENTER */
186
187ALABEL(dispatcher_0)
188 /*
189 * このルーチンは,タスクコンテキスト・CPUロック状態・割込み優先度
190 * マスク全解除状態・ディスパッチ許可状態で呼び出される.実行再開番
191 * 地へもこの状態のまま分岐する.
192 */
193 ldr r0, =p_schedtsk /* p_schedtsk → r4 → p_runtsk */
194 ldr r4, [r0]
195 ldr r1, =p_runtsk
196 str r4, [r1]
197 tst r4, r4 /* p_runtskがNULLならdispatcher_1へ */
198 beq dispatcher_1
199 ldr sp, [r4,#TCB_sp] /* タスクスタックを復帰 */
200#ifdef LOG_DSP_LEAVE
201 mov r0, r4 /* p_runtskをパラメータに渡す */
202 bl log_dsp_leave
203#endif /* LOG_DSP_LEAVE */
204 ldr r0, [r4,#TCB_pc] /* 実行再開番地を復帰 */
205 bx r0 /* p_runtskをr4に入れた状態で分岐する */
206
207 /*
208 * アイドル処理
209 *
210 * 割込みをすべて許可し,CPUロック解除状態にして割込みを待つ.
211 *
212 * ターゲットによっては,省電力モード等に移行するため,標準の方法
213 * と異なる手順が必要な場合がある.そのようなターゲットでは,ター
214 * ゲット依存部でTOPPERS_CUSTOM_IDLEを定義し,アセンブラマクロとし
215 * て,toppers_asm_custom_idleを用意すればよい.
216 */
217ALABEL(dispatcher_1)
218#ifdef TOPPERS_CUSTOM_IDLE
219 toppers_asm_custom_idle
220#else /* TOPPERS_CUSTOM_IDLE */
221 msr cpsr_c, #CPSR_SVC_MODE /* 割込みを許可(スーパバイザモード)*/
222#endif /* TOPPERS_CUSTOM_IDLE */
223 b dispatcher_1 /* 割込み待ち */
224
225/*
226 * カーネルの終了処理の呼出し
227 *
228 * 割込みロック状態にし,使用するスタックを非タスクコンテキスト用のスタッ
229 * ク領域に切り替え,exit_kernelを呼び出す.
230 */
231 AGLOBAL(call_exit_kernel)
232ALABEL(call_exit_kernel)
233 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_INTLOCK)
234 ldr r0, =istkpt /* 非タスクコンテキストのスタックへ */
235 ldr sp, [r0]
236 b exit_kernel
237
238/*
239 * タスクの実行開始時処理
240 */
241 ATEXT
242 AALIGN(2)
243 AGLOBAL(start_r)
244 /*
245 * ディスパッチャ本体から呼び出されるため,p_runtskはr4に入っている.
246 */
247ALABEL(start_r)
248#ifdef TOPPERS_SUPPORT_OVRHDR
249 bl ovrtimer_start
250#endif /* TOPPERS_SUPPORT_OVRHDR */
251 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
252 /* CPUロック解除状態に */
253 ldr lr, =ext_tsk /* タスク本体からの戻り番地を設定 */
254 ldr r2, [r4,#TCB_p_tinib] /* p_runtsk->p_tinib → r2 */
255 ldr r0, [r2,#TINIB_exinf] /* exinfをパラメータに */
256 ldr r1, [r2,#TINIB_task] /* タスク起動番地にジャンプ */
257 bx r1
258
259/*
260 * 割込みハンドラの出入口処理
261 */
262#ifndef OMIT_IRQ_HANDLER
263 ATEXT
264 AALIGN(2)
265 AGLOBAL(irq_handler)
266ALABEL(irq_handler)
267 /*
268 * ここには,IRQモードで分岐してくる.
269 */
270#if __TARGET_ARCH_ARM < 6
271 /*
272 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
273 */
274 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_IRQ_BIT)
275 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
276
277 /*
278 * IRQモードに戻して,戻り番地とspsr(戻り先のcpsr)を取得する.
279 */
280 msr cpsr_c, #(CPSR_IRQ_MODE AOR CPSR_IRQ_BIT)
281 sub r2, lr, #4
282 mrs r1, spsr
283
284 /*
285 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
286 */
287 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_IRQ_BIT)
288 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
289 push {r1} /* spsrをスタックに保存 */
290#else /* __TARGET_ARCH_ARM < 6 */
291 /*
292 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
293 * 保存する.
294 */
295 sub lr, lr, #4 /* 戻り番地の算出 */
296 srsfd #CPSR_SVC_MODE!
297
298 /*
299 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
300 */
301 cps #CPSR_SVC_MODE
302 stmfd sp!, {r0-r5,r12,lr}
303#endif /* __TARGET_ARCH_ARM < 6 */
304
305 /*
306 * スタックポインタの調整
307 */
308 and r1, sp, #4
309 sub sp, sp, r1
310 push {r0,r1} /* r0はスペース確保のため */
311
312 /*
313 * 例外ネストカウントをインクリメントする.割込みが非タスクコンテキ
314 * ストで発生した場合には,irq_handler_1へ分岐する.
315 */
316 ldr r2, =excpt_nest_count
317 ldr r3, [r2]
318 add r3, r3, #1
319 str r3, [r2]
320 teq r3, #1 /* 割込みが非タスクコンテキストで発生 */
321 bne irq_handler_1 /* ならirq_handler_1に分岐 */
322
323#ifdef TOPPERS_SUPPORT_OVRHDR
324 /*
325 * オーバランタイマを停止する.
326 */
327 bl ovrtimer_stop
328#endif /* TOPPERS_SUPPORT_OVRHDR */
329
330 /*
331 * 非タスクコンテキスト用のスタックに切り換える.
332 */
333 mov r3, sp /* この時点のスタックポインタをr3に */
334 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
335 ldr sp, [r2]
336 push {r0,r3} /* 切換え前のスタックポインタを保存 */
337 /* r0はスペース確保のため */
338ALABEL(irq_handler_1)
339 /*
340 * 割込みコントローラを操作し,割込み番号を取得する.
341 */
342 bl irc_begin_int
343#if TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6
344 cmp r4, #TNUM_INHNO /* TNUM_INHNOの値によってはエラーになる */
345#else /* TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6 */
346 movw r3, #TNUM_INHNO
347 cmp r4, r3
348#endif /* TNUM_INHNO <= 256 || __TARGET_ARCH_ARM <= 6 */
349 bhs irq_handler_2 /* スプリアス割込みなら */
350 /* irq_handler_2に分岐 */
351 /*
352 * CPUロック解除状態にする.
353 */
354#if __TARGET_ARCH_ARM < 6
355 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
356#else /* __TARGET_ARCH_ARM < 6 */
357#ifndef TOPPERS_SAFEG_SECURE
358 cpsie if
359#else /* TOPPERS_SAFEG_SECURE */
360 cpsie f
361#endif /* TOPPERS_SAFEG_SECURE */
362#endif /* __TARGET_ARCH_ARM < 6 */
363
364#ifdef LOG_INH_ENTER
365 /*
366 * ログ出力の呼出し
367 */
368 mov r0, r4 /* 割込み番号をパラメータに渡す */
369 bl log_inh_enter
370#endif /* LOG_INH_ENTER */
371
372 /*
373 * 割込みハンドラの呼出し
374 */
375 ldr r2, =inh_table /* 割込みハンドラテーブルの読込み */
376 ldr r1, [r2,r4,lsl #2] /* 割込みハンドラの番地 → r1 */
377 mov lr, pc /* 割込みハンドラの呼出し */
378 bx r1
379
380#ifdef LOG_INH_LEAVE
381 /*
382 * ログ出力の呼出し
383 */
384 mov r0, r4 /* 割込み番号をパラメータに渡す */
385 bl log_inh_leave
386#endif /* LOG_INH_LEAVE */
387
388 /*
389 * カーネル管理の割込みを禁止する.
390 */
391#if __TARGET_ARCH_ARM < 6
392 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
393#else /* __TARGET_ARCH_ARM < 6 */
394#ifndef TOPPERS_SAFEG_SECURE
395 cpsid i
396#else /* TOPPERS_SAFEG_SECURE */
397 cpsid if
398#endif /* TOPPERS_SAFEG_SECURE */
399#endif /* __TARGET_ARCH_ARM < 6 */
400
401 /*
402 * 割込みコントローラを操作する.
403 */
404ALABEL(irq_handler_2)
405 bl irc_end_int
406
407 /*
408 * 例外ネストカウントをデクリメントする.
409 */
410 ldr r2, =excpt_nest_count
411 ldr r3, [r2]
412 subs r3, r3, #1
413 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
414 bne irq_handler_5 /* irq_handler_5に分岐 */
415
416 /*
417 * タスク用のスタックに戻す.
418 */
419 pop {r0,r3}
420 mov sp, r3
421
422 /*
423 * p_runtskがNULLか判定する.
424 */
425 ldr r0, =p_runtsk /* p_runtsk → r0 */
426 ldr r0, [r0]
427 tst r0, r0 /* p_runtskがNULLでなければ */
428 bne irq_handler_3 /* irq_handler_3に分岐 */
429
430 /*
431 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
432 */
433 pop {r0,r1} /* スタックポインタの調整を元に戻す */
434 add sp, sp, r1
435 add sp, sp, #40 /* スクラッチレジスタを捨てる */
436 b dispatcher_0
437
438 /*
439 * ディスパッチが必要か判定する.
440 */
441ALABEL(irq_handler_3)
442 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
443 ldr r1, [r1]
444 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
445 beq irq_handler_4 /* irq_handler_4へ */
446
447 /*
448 * コンテキストを保存する.
449 */
450 stmfd sp!, {r6-r11} /* 非スクラッチレジスタの保存 */
451 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
452 adr r1, ret_int_r /* 実行再開番地を保存 */
453 str r1, [r0,#TCB_pc]
454 b dispatcher /* r0にはp_runtskが格納されている */
455
456ALABEL(ret_int_r)
457 /*
458 * コンテキストを復帰する.
459 */
460 ldmfd sp!, {r6-r11} /* 非スクラッチレジスタの復帰 */
461
462ALABEL(irq_handler_4)
463#ifdef TOPPERS_SUPPORT_OVRHDR
464 /*
465 * オーバランタイマを動作開始する.
466 */
467 bl ovrtimer_start
468#endif /* TOPPERS_SUPPORT_OVRHDR */
469
470 /*
471 * 割込み/CPU例外処理からのリターン
472 *
473 * 割込み/CPU例外処理からのリターンにより,CPUロック解除状態に遷
474 * 移するようにする必要があるが,ARMはCPSRのビットによってCPUロッ
475 * ク状態を表しているため,CPSRを元に戻してリターンすればよい.
476 */
477ALABEL(irq_handler_5)
478 pop {r0,r1} /* スタックポインタの調整を元に戻す */
479 add sp, sp, r1
480
481#if __TARGET_ARCH_ARM < 6
482 ldmfd sp!, {r0} /* 戻り先のcpsrをspsrに設定 */
483 msr spsr_cxsf, r0
484 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
485 /* ^付きなので,spsr → cpsr */
486#else /* __TARGET_ARCH_ARM < 6 */
487 ldmfd sp!, {r0-r5,r12,lr}
488 rfefd sp!
489#endif /* __TARGET_ARCH_ARM < 6 */
490#endif /* OMIT_IRQ_HANDLER */
491
492/*
493 * CPU例外ハンドラ出入口処理
494 */
495ALABEL(start_exc_entry)
496
497/*
498 * 未定義命令
499 */
500#ifndef OMIT_UNDEF_HANDLER
501 ATEXT
502 AALIGN(2)
503 AGLOBAL(undef_handler)
504ALABEL(undef_handler)
505 /*
506 * ここには,未定義モードで分岐してくる.
507 */
508#if __TARGET_ARCH_ARM < 6
509 /*
510 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
511 * ラッチレジスタを保存する.
512 */
513 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
514 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
515
516 /*
517 * 未定義モードに戻して,戻り番地とspsrを取得する.
518 */
519 msr cpsr_c, #(CPSR_UND_MODE AOR CPSR_FIQ_IRQ_BIT)
520 mov r2, lr
521 mrs r1, spsr
522
523 /*
524 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
525 */
526 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
527 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
528 push {r1} /* spsrをスタックに保存 */
529#else /* __TARGET_ARCH_ARM < 6 */
530 /*
531 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
532 * 保存する.
533 */
534 srsfd #CPSR_SVC_MODE!
535
536 /*
537 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
538 */
539 cps #CPSR_SVC_MODE
540 stmfd sp!, {r0-r5,r12,lr}
541#endif /* __TARGET_ARCH_ARM < 6 */
542 mov r4, #EXCNO_UNDEF
543 b exc_handler_1
544#endif /* OMIT_UNDEF_HANDLER */
545
546/*
547 * スーパバイザコール
548 */
549#ifndef OMIT_SVC_HANDLER
550 ATEXT
551 AALIGN(2)
552 AGLOBAL(svc_handler)
553ALABEL(svc_handler)
554 /*
555 * ここには,スーパバイザモードで分岐してくる.
556 */
557#if __TARGET_ARCH_ARM < 6
558 /*
559 * IビットとFビットをセットし,スクラッチレジスタを保存する.
560 */
561 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
562 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
563
564 /*
565 * 戻り番地とspsrを取得する.
566 */
567 mov r2, lr
568 mrs r1, spsr
569
570 /*
571 * 戻り番地とspsrを保存する.
572 */
573 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
574 push {r1} /* spsrをスタックに保存 */
575#else /* __TARGET_ARCH_ARM < 6 */
576 /*
577 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
578 * 保存する.
579 */
580 srsfd #CPSR_SVC_MODE!
581
582 /*
583 * スーパバイザモードで,スクラッチレジスタを保存する.
584 */
585 cps #CPSR_SVC_MODE /* 不要と思われる */
586 stmfd sp!, {r0-r5,r12,lr}
587#endif /* __TARGET_ARCH_ARM < 6 */
588 mov r4, #EXCNO_SVC
589 b exc_handler_1
590#endif /* OMIT_SVC_HANDLER */
591
592/*
593 * プリフェッチアボート
594 */
595#ifndef OMIT_PABORT_HANDLER
596 ATEXT
597 AALIGN(2)
598 AGLOBAL(pabort_handler)
599ALABEL(pabort_handler)
600 /*
601 * ここには,アボートモードで分岐してくる.
602 */
603#if __TARGET_ARCH_ARM < 6
604 /*
605 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
606 * ラッチレジスタを保存する.
607 */
608 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
609 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
610
611 /*
612 * アボートモードに戻して,戻り番地とspsrを取得する.
613 */
614 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
615 mov r2, lr
616 mrs r1, spsr
617
618 /*
619 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
620 */
621 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
622 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
623 push {r1} /* spsrをスタックに保存 */
624#else /* __TARGET_ARCH_ARM < 6 */
625 /*
626 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
627 * 保存する.
628 */
629 srsfd #CPSR_SVC_MODE!
630
631 /*
632 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
633 */
634 cps #CPSR_SVC_MODE
635 stmfd sp!, {r0-r5,r12,lr}
636#endif /* __TARGET_ARCH_ARM < 6 */
637 mov r4, #EXCNO_PABORT
638 b exc_handler_1
639#endif /* OMIT_PABORT_HANDLER */
640
641/*
642 * データアボート
643 */
644#ifndef OMIT_DABORT_HANDLER
645 ATEXT
646 AALIGN(2)
647 AGLOBAL(dabort_handler)
648ALABEL(dabort_handler)
649 /*
650 * ここには,アボートモードで分岐してくる.
651 *
652 * データアボートが,CPU例外の入口(start_exc_entryとend_exc_entry
653 * の間)で発生した場合には,fatal_dabort_handlerに分岐する.アボー
654 * トモードのspを汎用レジスタの代わりに使用する.
655 */
656 ldr sp, =start_exc_entry+8
657 cmp lr, sp
658 bcc dabort_handler_1
659 ldr sp, =end_exc_entry+8
660 cmp lr, sp
661 bcc fatal_dabort_handler
662
663ALABEL(dabort_handler_1)
664#if __TARGET_ARCH_ARM < 6
665 /*
666 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
667 * ラッチレジスタを保存する.
668 */
669 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
670 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
671
672 /*
673 * アボートモードに戻して,戻り番地とspsrを取得する.
674 */
675 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
676 mov r2, lr
677 mrs r1, spsr
678
679 /*
680 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
681 */
682 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
683 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
684 push {r1} /* spsrをスタックに保存 */
685#else /* __TARGET_ARCH_ARM < 6 */
686 /*
687 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
688 * 保存する.
689 */
690 srsfd #CPSR_SVC_MODE!
691
692 /*
693 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
694 */
695 cps #CPSR_SVC_MODE
696 stmfd sp!, {r0-r5,r12,lr}
697#endif /* __TARGET_ARCH_ARM < 6 */
698 mov r4, #EXCNO_DABORT
699 b exc_handler_1
700#endif /* OMIT_DABORT_HANDLER */
701
702/*
703 * CPU例外の入口で発生したデータアボート
704 */
705ALABEL(fatal_dabort_handler)
706#if __TARGET_ARCH_ARM < 6
707 /*
708 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
709 * クポインタを初期化し,スクラッチレジスタを保存する.
710 */
711 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
712 ldr sp, =istkpt
713 ldr sp, [sp]
714 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
715
716 /*
717 * アボートモードに戻して,戻り番地とspsrを取得する.
718 */
719 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
720 mov r2, lr
721 mrs r1, spsr
722
723 /*
724 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
725 */
726 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
727 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
728 push {r1} /* spsrをスタックに保存 */
729#else /* __TARGET_ARCH_ARM < 6 */
730 /*
731 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
732 * クポインタを初期化する.
733 */
734 cpsid if, #CPSR_SVC_MODE
735 ldr sp, =istkpt
736 ldr sp, [sp]
737
738 /*
739 * アボートモードに戻して,戻り先(lr)とspsr(cpsr_svc)をスーパ
740 * バイザモードのスタックに保存する.
741 */
742 cps #CPSR_ABT_MODE
743 srsfd #CPSR_SVC_MODE!
744
745 /*
746 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
747 */
748 cps #CPSR_SVC_MODE
749 stmfd sp!, {r0-r5,r12,lr}
750#endif /* __TARGET_ARCH_ARM < 6 */
751
752 /*
753 * 例外ネストカウントの最上位ビットを1にする.
754 */
755 ldr r2, =excpt_nest_count
756 ldr r3, [r2]
757 orr r3, r3, #0x80000000
758 str r3, [r2]
759
760 mov r4, #EXCNO_DABORT
761 b exc_handler_1
762
763/*
764 * FIQ
765 */
766#ifndef OMIT_FIQ_HANDLER
767 ATEXT
768 AALIGN(2)
769 AGLOBAL(fiq_handler)
770ALABEL(fiq_handler)
771 /*
772 * ここには,FIQモードで分岐してくる.
773 */
774#if __TARGET_ARCH_ARM < 6
775 /*
776 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
777 * ラッチレジスタを保存する.
778 */
779 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
780 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
781
782 /*
783 * FIQモードに戻して,戻り番地とspsrを取得する.
784 */
785 msr cpsr_c, #(CPSR_FIQ_MODE AOR CPSR_FIQ_IRQ_BIT)
786 mov r2, lr
787 mrs r1, spsr
788
789 /*
790 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
791 */
792 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
793 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
794 push {r1} /* spsrをスタックに保存 */
795#else /* __TARGET_ARCH_ARM < 6 */
796 /*
797 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
798 * 保存する.
799 */
800 srsfd #CPSR_SVC_MODE!
801
802 /*
803 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
804 */
805 cps #CPSR_SVC_MODE
806 stmfd sp!, {r0-r5,r12,lr}
807#endif /* __TARGET_ARCH_ARM < 6 */
808 mov r4, #EXCNO_FIQ
809 b exc_handler_1
810#endif /* OMIT_FIQ_HANDLER */
811
812ALABEL(end_exc_entry)
813
814/*
815 * CPU例外ハンドラ出入口処理の共通部分
816 *
817 * 【この時点のレジスタ状態】
818 * r4:CPU例外ハンドラ番号
819 */
820ALABEL(exc_handler_1)
821 /*
822 * CPU例外が発生した状況の判断に用いるために,CPU例外発生前の割
823 * 込み優先度マスクと例外ネストカウントをスタックに保存する.
824 */
825 bl irc_get_intpri
826 push {r0} /* 割込み優先度マスクを保存 */
827 ldr r2, =excpt_nest_count
828 ldr r3, [r2]
829 push {r3} /* 例外ネストカウントを保存 */
830 mov r5, sp /* CPU例外の情報を記憶している領域の */
831 /* 先頭番地をr5に保存 */
832 /*
833 * スタックポインタの調整
834 */
835 and r1, sp, #4
836 sub sp, sp, r1
837 push {r0,r1} /* r0はスペース確保のため */
838
839 /*
840 * カーネル管理外のCPU例外か判定する
841 *
842 * カーネル管理外のCPU例外は,カーネル実行中,全割込みロック状態,
843 * CPUロック状態,カーネル管理外の割込みハンドラ実行中に発生した
844 * CPU例外である.ARMコアの場合は,戻り先のCPSRのIビットかFビット
845 * のいずれかがセットされているなら,これ該当する.
846 */
847 ldr r1, [r5,#T_EXCINF_cpsr] /* 例外フレームからcpsrを取得 */
848 ands r1, r1, #CPSR_FIQ_IRQ_BIT
849 bne nk_exc_handler_1 /* カーネル管理外のCPU例外の処理へ */
850
851 /*
852 * 【この時点のレジスタ状態】
853 * r2:excpt_nest_countの番地
854 * r3:excpt_nest_countの値
855 * r4:CPU例外ハンドラ番号
856 * r5:CPU例外の情報を記憶している領域の先頭番地
857 */
858
859 /*
860 * 例外ネストカウントをインクリメントする.
861 */
862 add r3, r3, #1
863 str r3, [r2]
864 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
865 bne exc_handler_2 /* ならexc_handler_2に分岐 */
866
867#ifdef TOPPERS_SUPPORT_OVRHDR
868 /*
869 * オーバランタイマを停止する.
870 */
871 bl ovrtimer_stop
872#endif /* TOPPERS_SUPPORT_OVRHDR */
873
874 /*
875 * 非タスクコンテキスト用のスタックに切り換える.
876 */
877 mov r3, sp /* この時点のスタックポインタをr3に */
878 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
879 ldr sp, [r2]
880 push {r0,r3} /* 切換え前のスタックポインタを保存 */
881 /* r0はスペース確保のため */
882ALABEL(exc_handler_2)
883 /*
884 * 【この時点のレジスタ状態】
885 * r4:CPU例外ハンドラ番号
886 * r5:CPU例外の情報を記憶している領域の先頭番地
887 */
888
889 /*
890 * (必要なら)割込みコントローラを操作する.
891 */
892 bl irc_begin_exc
893
894 /*
895 * CPUロック解除状態にする.
896 *
897 * カーネル管理外のCPU例外ハンドラは別ルーチンで呼び出すため,単純
898 * に割込みを許可するだけでよい.
899 */
900#if __TARGET_ARCH_ARM < 6
901 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
902#else /* __TARGET_ARCH_ARM < 6 */
903#ifndef TOPPERS_SAFEG_SECURE
904 cpsie if
905#else /* TOPPERS_SAFEG_SECURE */
906 cpsie f
907#endif /* TOPPERS_SAFEG_SECURE */
908#endif /* __TARGET_ARCH_ARM < 6 */
909
910 /*
911 * ログ出力の呼出し
912 */
913#ifdef LOG_EXC_ENTER
914 mov r0, r4 /* CPU例外番号をパラメータに渡す */
915 bl log_exc_enter
916#endif /* LOG_EXC_ENTER */
917
918 /*
919 * CPU例外ハンドラの呼出し
920 */
921 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
922 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
923 mov r0, r5 /* CPU例外の情報を記憶している領域の */
924 /* 先頭番地を第1パラメータに渡す */
925 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
926 mov lr, pc /* CPU例外ハンドラの呼出し */
927 bx r3
928
929 /*
930 * ログ出力の呼出し
931 */
932#ifdef LOG_EXC_LEAVE
933 mov r0, r4 /* CPU例外番号をパラメータに渡す */
934 bl log_exc_leave
935#endif /* LOG_EXC_LEAVE */
936
937 /*
938 * カーネル管理の割込みを禁止する.
939 */
940#if __TARGET_ARCH_ARM < 6
941 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
942#else /* __TARGET_ARCH_ARM < 6 */
943#ifndef TOPPERS_SAFEG_SECURE
944 cpsid i
945#else /* TOPPERS_SAFEG_SECURE */
946 cpsid if
947#endif /* TOPPERS_SAFEG_SECURE */
948#endif /* __TARGET_ARCH_ARM < 6 */
949
950 /*
951 * 割込みコントローラを操作して,割込み優先度マスクを,CPU例外発
952 * 生時の値に設定する.
953 */
954 bl irc_end_exc
955
956 /*
957 * 例外ネストカウントをデクリメントする.
958 */
959 ldr r2, =excpt_nest_count
960 ldr r3, [r2]
961 subs r3, r3, #1
962 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
963 bne exc_handler_5 /* exc_handler_5に分岐 */
964
965 /*
966 * タスク用のスタックに戻す.
967 */
968 pop {r0,r3}
969 mov sp, r3
970
971 /*
972 * p_runtskがNULLか判定する.
973 */
974 ldr r0, =p_runtsk /* p_runtsk → r0 */
975 ldr r0, [r0]
976 tst r0, r0 /* p_runtskがNULLでなければ */
977 bne exc_handler_3 /* exc_handler_3に分岐 */
978
979 /*
980 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
981 */
982 pop {r0,r1} /* スタックポインタの調整を元に戻す */
983 add sp, sp, r1
984 add sp, sp, #48 /* スクラッチレジスタとCPU例外が発生した */
985 b dispatcher_0 /* 状況を判断するための追加情報を捨てる */
986
987 /*
988 * ディスパッチが必要か判定する.
989 */
990ALABEL(exc_handler_3)
991 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
992 ldr r1, [r1]
993 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
994 beq exc_handler_4 /* exc_handler_4へ */
995
996 /*
997 * コンテキストを保存する.
998 */
999 stmfd sp!, {r6-r11} /* 非スクラッチレジスタの保存 */
1000 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
1001 adr r1, ret_exc_r /* 実行再開番地を保存 */
1002 str r1, [r0,#TCB_pc]
1003 b dispatcher /* r0にはp_runtskが格納されている */
1004
1005ALABEL(ret_exc_r)
1006 /*
1007 * コンテキストを復帰する.
1008 */
1009 ldmfd sp!, {r6-r11} /* 非スクラッチレジスタの復帰 */
1010
1011ALABEL(exc_handler_4)
1012#ifdef TOPPERS_SUPPORT_OVRHDR
1013 /*
1014 * オーバランタイマを動作開始する.
1015 */
1016 bl ovrtimer_start
1017#endif /* TOPPERS_SUPPORT_OVRHDR */
1018
1019 /*
1020 * CPU例外処理からのリターン
1021 *
1022 * CPU例外処理からのリターンにより,CPUロック解除状態に遷移するよ
1023 * うにする必要があるが,ARMはCPSRのビットによってCPUロック状態を
1024 * 表しているため,CPSRを元に戻してリターンすればよい.
1025 */
1026ALABEL(exc_handler_5)
1027 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1028 add sp, sp, r1
1029 add sp, sp, #8 /* スタック上の情報を捨てる */
1030
1031#if __TARGET_ARCH_ARM < 6
1032 ldmfd sp!, {r0} /* 戻り先のcpsrをspsrに設定 */
1033 msr spsr_cxsf, r0
1034 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
1035 /* ^付きなので,spsr → cpsr */
1036#else /* __TARGET_ARCH_ARM < 6 */
1037 ldmfd sp!, {r0-r5,r12,lr}
1038 rfefd sp!
1039#endif /* __TARGET_ARCH_ARM < 6 */
1040
1041/*
1042 * カーネル管理外のCPU例外の出入口処理
1043 */
1044ALABEL(nk_exc_handler_1)
1045 /*
1046 * 【この時点のレジスタ状態】
1047 * r1:CPU例外発生前のCPSRのFビットとIビットの値
1048 * r2:excpt_nest_countの番地
1049 * r3:excpt_nest_countの値
1050 * r4:CPU例外ハンドラ番号
1051 * r5:CPU例外の情報を記憶している領域の先頭番地
1052 */
1053
1054 /*
1055 * 例外ネストカウントをインクリメントする.
1056 */
1057 add r3, r3, #1
1058 str r3, [r2]
1059 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
1060 bne nk_exc_handler_2 /* ならnk_exc_handler_2に分岐 */
1061
1062 /*
1063 * 非タスクコンテキスト用のスタックに切り換える.
1064 */
1065 mov r3, sp /* この時点のスタックポインタをr3に */
1066 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
1067 ldr sp, [r2]
1068 push {r0,r3} /* 切換え前のスタックポインタを保存 */
1069 /* r0はスペース確保のため */
1070ALABEL(nk_exc_handler_2)
1071 /*
1072 * システム状態(コンテキストは除く)を,CPU例外発生時の状態へ
1073 */
1074 orr r1, r1, #CPSR_SVC_MODE
1075 msr cpsr_c, r1
1076
1077 /*
1078 * CPU例外ハンドラの呼出し
1079 */
1080 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1081 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1082 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1083 /* 先頭番地を第1パラメータに渡す */
1084 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1085 mov lr, pc /* CPU例外ハンドラの呼出し */
1086 bx r3
1087
1088 /*
1089 * 例外ネストカウントをデクリメントする.
1090 */
1091 ldr r2, =excpt_nest_count
1092 ldr r3, [r2]
1093 subs r3, r3, #1
1094 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1095 bne exc_handler_5 /* exc_handler_5に分岐 */
1096
1097 /*
1098 * タスク用のスタックに戻す.
1099 */
1100 pop {r0,r3}
1101 mov sp, r3
1102 b exc_handler_5
1103
1104/*
1105 * ステータスレジスタの操作関数
1106 *
1107 * Thumbモードではmrs/msr命令が使用できないため,関数として実現して,
1108 * ARMモードに移行して実行する.
1109 */
1110#ifdef __thumb__
1111
1112 ATEXT
1113 AALIGN(2)
1114 AWEAK(current_cpsr)
1115ALABEL(current_cpsr)
1116 mrs r0, cpsr_cxsf
1117 bx lr
1118
1119 AALIGN(2)
1120 AWEAK(set_cpsr)
1121ALABEL(set_cpsr)
1122 msr cpsr_cxsf, r0
1123 bx lr
1124
1125#endif /* __thumb__ */
1126
1127/*
1128 * 微少時間待ち
1129 *
1130 * キャッシュラインのどの場所にあるかのよって実行時間が変わるため,大
1131 * きめの単位でアラインしている.
1132 */
1133 ATEXT
1134 AALIGN(8)
1135 AGLOBAL(sil_dly_nse)
1136ALABEL(sil_dly_nse)
1137 mov r1, #0
1138 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1139 asm_inst_sync_barrier r3
1140 subs r0, r0, #SIL_DLY_TIM1
1141 bxls lr
1142ALABEL(sil_dly_nse1)
1143 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1144 asm_inst_sync_barrier r3
1145 subs r0, r0, #SIL_DLY_TIM2
1146 bhi sil_dly_nse1
1147 bx lr
Note: See TracBrowser for help on using the repository browser.