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

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

arm向けASP3版ECNLを追加

  • 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 AWEAK(svc_handler)
553 AGLOBAL(svc_handler)
554ALABEL(svc_handler)
555 /*
556 * ここには,スーパバイザモードで分岐してくる.
557 */
558#if __TARGET_ARCH_ARM < 6
559 /*
560 * IビットとFビットをセットし,スクラッチレジスタを保存する.
561 */
562 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
563 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
564
565 /*
566 * 戻り番地とspsrを取得する.
567 */
568 mov r2, lr
569 mrs r1, spsr
570
571 /*
572 * 戻り番地とspsrを保存する.
573 */
574 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
575 push {r1} /* spsrをスタックに保存 */
576#else /* __TARGET_ARCH_ARM < 6 */
577 /*
578 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
579 * 保存する.
580 */
581 srsfd #CPSR_SVC_MODE!
582
583 /*
584 * スーパバイザモードで,スクラッチレジスタを保存する.
585 */
586 cps #CPSR_SVC_MODE /* 不要と思われる */
587 stmfd sp!, {r0-r5,r12,lr}
588#endif /* __TARGET_ARCH_ARM < 6 */
589 mov r4, #EXCNO_SVC
590 b exc_handler_1
591#endif /* OMIT_SVC_HANDLER */
592
593/*
594 * プリフェッチアボート
595 */
596#ifndef OMIT_PABORT_HANDLER
597 ATEXT
598 AALIGN(2)
599 AGLOBAL(pabort_handler)
600ALABEL(pabort_handler)
601 /*
602 * ここには,アボートモードで分岐してくる.
603 */
604#if __TARGET_ARCH_ARM < 6
605 /*
606 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
607 * ラッチレジスタを保存する.
608 */
609 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
610 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
611
612 /*
613 * アボートモードに戻して,戻り番地とspsrを取得する.
614 */
615 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
616 mov r2, lr
617 mrs r1, spsr
618
619 /*
620 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
621 */
622 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
623 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
624 push {r1} /* spsrをスタックに保存 */
625#else /* __TARGET_ARCH_ARM < 6 */
626 /*
627 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
628 * 保存する.
629 */
630 srsfd #CPSR_SVC_MODE!
631
632 /*
633 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
634 */
635 cps #CPSR_SVC_MODE
636 stmfd sp!, {r0-r5,r12,lr}
637#endif /* __TARGET_ARCH_ARM < 6 */
638 mov r4, #EXCNO_PABORT
639 b exc_handler_1
640#endif /* OMIT_PABORT_HANDLER */
641
642/*
643 * データアボート
644 */
645#ifndef OMIT_DABORT_HANDLER
646 ATEXT
647 AALIGN(2)
648 AGLOBAL(dabort_handler)
649ALABEL(dabort_handler)
650 /*
651 * ここには,アボートモードで分岐してくる.
652 *
653 * データアボートが,CPU例外の入口(start_exc_entryとend_exc_entry
654 * の間)で発生した場合には,fatal_dabort_handlerに分岐する.アボー
655 * トモードのspを汎用レジスタの代わりに使用する.
656 */
657 ldr sp, =start_exc_entry+8
658 cmp lr, sp
659 bcc dabort_handler_1
660 ldr sp, =end_exc_entry+8
661 cmp lr, sp
662 bcc fatal_dabort_handler
663
664ALABEL(dabort_handler_1)
665#if __TARGET_ARCH_ARM < 6
666 /*
667 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
668 * ラッチレジスタを保存する.
669 */
670 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
671 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
672
673 /*
674 * アボートモードに戻して,戻り番地とspsrを取得する.
675 */
676 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
677 mov r2, lr
678 mrs r1, spsr
679
680 /*
681 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
682 */
683 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
684 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
685 push {r1} /* spsrをスタックに保存 */
686#else /* __TARGET_ARCH_ARM < 6 */
687 /*
688 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
689 * 保存する.
690 */
691 srsfd #CPSR_SVC_MODE!
692
693 /*
694 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
695 */
696 cps #CPSR_SVC_MODE
697 stmfd sp!, {r0-r5,r12,lr}
698#endif /* __TARGET_ARCH_ARM < 6 */
699 mov r4, #EXCNO_DABORT
700 b exc_handler_1
701#endif /* OMIT_DABORT_HANDLER */
702
703/*
704 * CPU例外の入口で発生したデータアボート
705 */
706ALABEL(fatal_dabort_handler)
707#if __TARGET_ARCH_ARM < 6
708 /*
709 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
710 * クポインタを初期化し,スクラッチレジスタを保存する.
711 */
712 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
713 ldr sp, =istkpt
714 ldr sp, [sp]
715 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
716
717 /*
718 * アボートモードに戻して,戻り番地とspsrを取得する.
719 */
720 msr cpsr_c, #(CPSR_ABT_MODE AOR CPSR_FIQ_IRQ_BIT)
721 mov r2, lr
722 mrs r1, spsr
723
724 /*
725 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
726 */
727 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
728 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
729 push {r1} /* spsrをスタックに保存 */
730#else /* __TARGET_ARCH_ARM < 6 */
731 /*
732 * IビットとFビットをセットし,スーパバイザモードに切り換え,スタッ
733 * クポインタを初期化する.
734 */
735 cpsid if, #CPSR_SVC_MODE
736 ldr sp, =istkpt
737 ldr sp, [sp]
738
739 /*
740 * アボートモードに戻して,戻り先(lr)とspsr(cpsr_svc)をスーパ
741 * バイザモードのスタックに保存する.
742 */
743 cps #CPSR_ABT_MODE
744 srsfd #CPSR_SVC_MODE!
745
746 /*
747 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
748 */
749 cps #CPSR_SVC_MODE
750 stmfd sp!, {r0-r5,r12,lr}
751#endif /* __TARGET_ARCH_ARM < 6 */
752
753 /*
754 * 例外ネストカウントの最上位ビットを1にする.
755 */
756 ldr r2, =excpt_nest_count
757 ldr r3, [r2]
758 orr r3, r3, #0x80000000
759 str r3, [r2]
760
761 mov r4, #EXCNO_DABORT
762 b exc_handler_1
763
764/*
765 * FIQ
766 */
767#ifndef OMIT_FIQ_HANDLER
768 ATEXT
769 AALIGN(2)
770 AGLOBAL(fiq_handler)
771ALABEL(fiq_handler)
772 /*
773 * ここには,FIQモードで分岐してくる.
774 */
775#if __TARGET_ARCH_ARM < 6
776 /*
777 * IビットとFビットをセットし,スーパバイザモードに切り換え,スク
778 * ラッチレジスタを保存する.
779 */
780 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
781 stmfd sp!, {r0-r5,r12,lr,pc} /* pcはスペース確保のため */
782
783 /*
784 * FIQモードに戻して,戻り番地とspsrを取得する.
785 */
786 msr cpsr_c, #(CPSR_FIQ_MODE AOR CPSR_FIQ_IRQ_BIT)
787 mov r2, lr
788 mrs r1, spsr
789
790 /*
791 * スーパバイザモードに切り換え,戻り番地とspsrを保存する.
792 */
793 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_FIQ_IRQ_BIT)
794 str r2, [sp,#0x20] /* 戻り番地をスタックに保存 */
795 push {r1} /* spsrをスタックに保存 */
796#else /* __TARGET_ARCH_ARM < 6 */
797 /*
798 * 戻り先(lr)とspsr(cpsr_svc)をスーパバイザモードのスタックに
799 * 保存する.
800 */
801 srsfd #CPSR_SVC_MODE!
802
803 /*
804 * スーパバイザモードに切り換え,スクラッチレジスタを保存する.
805 */
806 cps #CPSR_SVC_MODE
807 stmfd sp!, {r0-r5,r12,lr}
808#endif /* __TARGET_ARCH_ARM < 6 */
809 mov r4, #EXCNO_FIQ
810 b exc_handler_1
811#endif /* OMIT_FIQ_HANDLER */
812
813ALABEL(end_exc_entry)
814
815/*
816 * CPU例外ハンドラ出入口処理の共通部分
817 *
818 * 【この時点のレジスタ状態】
819 * r4:CPU例外ハンドラ番号
820 */
821ALABEL(exc_handler_1)
822 /*
823 * CPU例外が発生した状況の判断に用いるために,CPU例外発生前の割
824 * 込み優先度マスクと例外ネストカウントをスタックに保存する.
825 */
826 bl irc_get_intpri
827 push {r0} /* 割込み優先度マスクを保存 */
828 ldr r2, =excpt_nest_count
829 ldr r3, [r2]
830 push {r3} /* 例外ネストカウントを保存 */
831 mov r5, sp /* CPU例外の情報を記憶している領域の */
832 /* 先頭番地をr5に保存 */
833 /*
834 * スタックポインタの調整
835 */
836 and r1, sp, #4
837 sub sp, sp, r1
838 push {r0,r1} /* r0はスペース確保のため */
839
840 /*
841 * カーネル管理外のCPU例外か判定する
842 *
843 * カーネル管理外のCPU例外は,カーネル実行中,全割込みロック状態,
844 * CPUロック状態,カーネル管理外の割込みハンドラ実行中に発生した
845 * CPU例外である.ARMコアの場合は,戻り先のCPSRのIビットかFビット
846 * のいずれかがセットされているなら,これ該当する.
847 */
848 ldr r1, [r5,#T_EXCINF_cpsr] /* 例外フレームからcpsrを取得 */
849 ands r1, r1, #CPSR_FIQ_IRQ_BIT
850 bne nk_exc_handler_1 /* カーネル管理外のCPU例外の処理へ */
851
852 /*
853 * 【この時点のレジスタ状態】
854 * r2:excpt_nest_countの番地
855 * r3:excpt_nest_countの値
856 * r4:CPU例外ハンドラ番号
857 * r5:CPU例外の情報を記憶している領域の先頭番地
858 */
859
860 /*
861 * 例外ネストカウントをインクリメントする.
862 */
863 add r3, r3, #1
864 str r3, [r2]
865 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
866 bne exc_handler_2 /* ならexc_handler_2に分岐 */
867
868#ifdef TOPPERS_SUPPORT_OVRHDR
869 /*
870 * オーバランタイマを停止する.
871 */
872 bl ovrtimer_stop
873#endif /* TOPPERS_SUPPORT_OVRHDR */
874
875 /*
876 * 非タスクコンテキスト用のスタックに切り換える.
877 */
878 mov r3, sp /* この時点のスタックポインタをr3に */
879 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
880 ldr sp, [r2]
881 push {r0,r3} /* 切換え前のスタックポインタを保存 */
882 /* r0はスペース確保のため */
883ALABEL(exc_handler_2)
884 /*
885 * 【この時点のレジスタ状態】
886 * r4:CPU例外ハンドラ番号
887 * r5:CPU例外の情報を記憶している領域の先頭番地
888 */
889
890 /*
891 * (必要なら)割込みコントローラを操作する.
892 */
893 bl irc_begin_exc
894
895 /*
896 * CPUロック解除状態にする.
897 *
898 * カーネル管理外のCPU例外ハンドラは別ルーチンで呼び出すため,単純
899 * に割込みを許可するだけでよい.
900 */
901#if __TARGET_ARCH_ARM < 6
902 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_UNLOCK)
903#else /* __TARGET_ARCH_ARM < 6 */
904#ifndef TOPPERS_SAFEG_SECURE
905 cpsie if
906#else /* TOPPERS_SAFEG_SECURE */
907 cpsie f
908#endif /* TOPPERS_SAFEG_SECURE */
909#endif /* __TARGET_ARCH_ARM < 6 */
910
911 /*
912 * ログ出力の呼出し
913 */
914#ifdef LOG_EXC_ENTER
915 mov r0, r4 /* CPU例外番号をパラメータに渡す */
916 bl log_exc_enter
917#endif /* LOG_EXC_ENTER */
918
919 /*
920 * CPU例外ハンドラの呼出し
921 */
922 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
923 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
924 mov r0, r5 /* CPU例外の情報を記憶している領域の */
925 /* 先頭番地を第1パラメータに渡す */
926 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
927 mov lr, pc /* CPU例外ハンドラの呼出し */
928 bx r3
929
930 /*
931 * ログ出力の呼出し
932 */
933#ifdef LOG_EXC_LEAVE
934 mov r0, r4 /* CPU例外番号をパラメータに渡す */
935 bl log_exc_leave
936#endif /* LOG_EXC_LEAVE */
937
938 /*
939 * カーネル管理の割込みを禁止する.
940 */
941#if __TARGET_ARCH_ARM < 6
942 msr cpsr_c, #(CPSR_SVC_MODE AOR CPSR_CPULOCK)
943#else /* __TARGET_ARCH_ARM < 6 */
944#ifndef TOPPERS_SAFEG_SECURE
945 cpsid i
946#else /* TOPPERS_SAFEG_SECURE */
947 cpsid if
948#endif /* TOPPERS_SAFEG_SECURE */
949#endif /* __TARGET_ARCH_ARM < 6 */
950
951 /*
952 * 割込みコントローラを操作して,割込み優先度マスクを,CPU例外発
953 * 生時の値に設定する.
954 */
955 bl irc_end_exc
956
957 /*
958 * 例外ネストカウントをデクリメントする.
959 */
960 ldr r2, =excpt_nest_count
961 ldr r3, [r2]
962 subs r3, r3, #1
963 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
964 bne exc_handler_5 /* exc_handler_5に分岐 */
965
966 /*
967 * タスク用のスタックに戻す.
968 */
969 pop {r0,r3}
970 mov sp, r3
971
972 /*
973 * p_runtskがNULLか判定する.
974 */
975 ldr r0, =p_runtsk /* p_runtsk → r0 */
976 ldr r0, [r0]
977 tst r0, r0 /* p_runtskがNULLでなければ */
978 bne exc_handler_3 /* exc_handler_3に分岐 */
979
980 /*
981 * タスクのスタックに保存したスクラッチレジスタ等を捨てる.
982 */
983 pop {r0,r1} /* スタックポインタの調整を元に戻す */
984 add sp, sp, r1
985 add sp, sp, #48 /* スクラッチレジスタとCPU例外が発生した */
986 b dispatcher_0 /* 状況を判断するための追加情報を捨てる */
987
988 /*
989 * ディスパッチが必要か判定する.
990 */
991ALABEL(exc_handler_3)
992 ldr r1, =p_schedtsk /* p_schedtsk → r1 */
993 ldr r1, [r1]
994 teq r0, r1 /* p_runtskとp_schedtskが同じなら */
995 beq exc_handler_4 /* exc_handler_4へ */
996
997 /*
998 * コンテキストを保存する.
999 */
1000 stmfd sp!, {r6-r11} /* 非スクラッチレジスタの保存 */
1001 str sp, [r0,#TCB_sp] /* スタックポインタを保存 */
1002 adr r1, ret_exc_r /* 実行再開番地を保存 */
1003 str r1, [r0,#TCB_pc]
1004 b dispatcher /* r0にはp_runtskが格納されている */
1005
1006ALABEL(ret_exc_r)
1007 /*
1008 * コンテキストを復帰する.
1009 */
1010 ldmfd sp!, {r6-r11} /* 非スクラッチレジスタの復帰 */
1011
1012ALABEL(exc_handler_4)
1013#ifdef TOPPERS_SUPPORT_OVRHDR
1014 /*
1015 * オーバランタイマを動作開始する.
1016 */
1017 bl ovrtimer_start
1018#endif /* TOPPERS_SUPPORT_OVRHDR */
1019
1020 /*
1021 * CPU例外処理からのリターン
1022 *
1023 * CPU例外処理からのリターンにより,CPUロック解除状態に遷移するよ
1024 * うにする必要があるが,ARMはCPSRのビットによってCPUロック状態を
1025 * 表しているため,CPSRを元に戻してリターンすればよい.
1026 */
1027ALABEL(exc_handler_5)
1028 pop {r0,r1} /* スタックポインタの調整を元に戻す */
1029 add sp, sp, r1
1030 add sp, sp, #8 /* スタック上の情報を捨てる */
1031
1032#if __TARGET_ARCH_ARM < 6
1033 ldmfd sp!, {r0} /* 戻り先のcpsrをspsrに設定 */
1034 msr spsr_cxsf, r0
1035 ldmfd sp!, {r0-r5,r12,lr,pc}^ /* コンテキストの復帰 */
1036 /* ^付きなので,spsr → cpsr */
1037#else /* __TARGET_ARCH_ARM < 6 */
1038 ldmfd sp!, {r0-r5,r12,lr}
1039 rfefd sp!
1040#endif /* __TARGET_ARCH_ARM < 6 */
1041
1042/*
1043 * カーネル管理外のCPU例外の出入口処理
1044 */
1045ALABEL(nk_exc_handler_1)
1046 /*
1047 * 【この時点のレジスタ状態】
1048 * r1:CPU例外発生前のCPSRのFビットとIビットの値
1049 * r2:excpt_nest_countの番地
1050 * r3:excpt_nest_countの値
1051 * r4:CPU例外ハンドラ番号
1052 * r5:CPU例外の情報を記憶している領域の先頭番地
1053 */
1054
1055 /*
1056 * 例外ネストカウントをインクリメントする.
1057 */
1058 add r3, r3, #1
1059 str r3, [r2]
1060 teq r3, #1 /* CPU例外発生前が非タスクコンテキスト */
1061 bne nk_exc_handler_2 /* ならnk_exc_handler_2に分岐 */
1062
1063 /*
1064 * 非タスクコンテキスト用のスタックに切り換える.
1065 */
1066 mov r3, sp /* この時点のスタックポインタをr3に */
1067 ldr r2, =istkpt /* 非タスクコンテキスト用のスタックに */
1068 ldr sp, [r2]
1069 push {r0,r3} /* 切換え前のスタックポインタを保存 */
1070 /* r0はスペース確保のため */
1071ALABEL(nk_exc_handler_2)
1072 /*
1073 * システム状態(コンテキストは除く)を,CPU例外発生時の状態へ
1074 */
1075 orr r1, r1, #CPSR_SVC_MODE
1076 msr cpsr_c, r1
1077
1078 /*
1079 * CPU例外ハンドラの呼出し
1080 */
1081 ldr r2, =exc_table /* CPU例外ハンドラテーブルの読込み */
1082 ldr r3, [r2,r4,lsl #2] /* CPU例外ハンドラの番地 → r3 */
1083 mov r0, r5 /* CPU例外の情報を記憶している領域の */
1084 /* 先頭番地を第1パラメータに渡す */
1085 mov r1, r4 /* CPU例外番号を第2パラメータに渡す */
1086 mov lr, pc /* CPU例外ハンドラの呼出し */
1087 bx r3
1088
1089 /*
1090 * 例外ネストカウントをデクリメントする.
1091 */
1092 ldr r2, =excpt_nest_count
1093 ldr r3, [r2]
1094 subs r3, r3, #1
1095 str r3, [r2] /* 戻り先が非タスクコンテキストなら */
1096 bne exc_handler_5 /* exc_handler_5に分岐 */
1097
1098 /*
1099 * タスク用のスタックに戻す.
1100 */
1101 pop {r0,r3}
1102 mov sp, r3
1103 b exc_handler_5
1104
1105/*
1106 * ステータスレジスタの操作関数
1107 *
1108 * Thumbモードではmrs/msr命令が使用できないため,関数として実現して,
1109 * ARMモードに移行して実行する.
1110 */
1111#ifdef __thumb__
1112
1113 ATEXT
1114 AALIGN(2)
1115 AWEAK(_kernel_current_cpsr)
1116ALABEL(_kernel_current_cpsr)
1117 mrs r0, cpsr_cxsf
1118 bx lr
1119
1120 AALIGN(2)
1121 AWEAK(_kernel_set_cpsr)
1122ALABEL(_kernel_set_cpsr)
1123 msr cpsr_cxsf, r0
1124 bx lr
1125
1126#endif /* __thumb__ */
1127
1128/*
1129 * 微少時間待ち
1130 *
1131 * キャッシュラインのどの場所にあるかのよって実行時間が変わるため,大
1132 * きめの単位でアラインしている.
1133 */
1134 ATEXT
1135 AALIGN(8)
1136 AGLOBAL(sil_dly_nse)
1137ALABEL(sil_dly_nse)
1138 mov r1, #0
1139 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1140 asm_inst_sync_barrier r3
1141 subs r0, r0, #SIL_DLY_TIM1
1142 bxls lr
1143ALABEL(sil_dly_nse1)
1144 mcr p15, 0, r1, c7, c5, 6 /* 分岐予測全体の無効化 */
1145 asm_inst_sync_barrier r3
1146 subs r0, r0, #SIL_DLY_TIM2
1147 bhi sil_dly_nse1
1148 bx lr
Note: See TracBrowser for help on using the repository browser.