source: azure_iot_hub_f767zi/trunk/asp_baseplatform/arch/arm_m_gcc/common/core_support_v6m.S@ 457

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

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/plain;charset=UTF-8
File size: 31.8 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) 2008-2015 by Embedded and Real-Time Systems Laboratory
7 * Graduate School of Information Science, Nagoya Univ., JAPAN
8 *
9 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
10 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
11 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
12 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
13 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
14 * スコード中に含まれていること.
15 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
16 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
17 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
18 * の無保証規定を掲載すること.
19 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
20 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
21 * と.
22 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
23 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
24 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
25 * 報告すること.
26 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
27 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
28 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
29 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
30 * 免責すること.
31 *
32 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
33 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
34 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
35 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
36 * の責任を負わない.
37 *
38 * @(#) $Id$
39 */
40
41/*
42 * プロセッサ依存モジュール アセンブリ言語部(ARMv6-M用)
43 */
44
45#define TOPPERS_MACRO_ONLY
46#define UINT_C(val) (val) /* uint_t型の定数を作るマクロ */
47#define ULONG_C(val) (val) /* ulong_t型の定数を作るマクロ */
48#define CAST(type, val) (val) /* 型キャストを行うマクロ */
49
50#include "kernel_impl.h"
51#include "arm_m.h"
52#include "offset.h"
53#include "target_asm.inc"
54
55#if __TARGET_ARCH_THUMB != 3
56#error The core_support.S support ARMv6-M only.
57#endif /* __TARGET_ARCH_THUMB != 3 */
58
59/*
60 * タスクディスパッチャ
61 */
62 ATEXT
63 ABALIGN(4)
64 ATHUMB(dispatch)
65 AGLOBAL(dispatch)
66ALABEL(dispatch)
67 /*
68 *
69 * このルーチンは,タスクコンテキスト・CPUロック状態・ディパッチ許可状態
70 * ・(モデル上の)割込み優先度マスク全開状態で呼び出される.
71 */
72 mov r0, r8 /* レジスタの保存 */
73 mov r1, r9
74 mov r2, r10
75 mov r3, r11
76 push {r0-r7,lr}
77 ldr r0, =p_runtsk /* p_runtskを読み込む */
78 ldr r1, [r0]
79 mov r2, sp
80 str r2, [r1,#TCB_sp] /* タスクスタックを保存 */
81 ldr r3, =dispatch_r /* 実行再開番地を保存 */
82 str r3, [r1,#TCB_pc]
83 b dispatcher
84
85 ATHUMB(dispatch_r)
86 AGLOBAL(dispatch_r)
87ALABEL(dispatch_r)
88 pop {r0-r7} /* レジスタの復帰 */
89 mov r8, r0
90 mov r9, r1
91 mov r10, r2
92 mov r11, r3
93 /*
94 * タスク例外処理ルーチンの起動
95 */
96 ldr r0, =p_runtsk /* p_runtskを読み込む */
97 ldr r1, [r0]
98 ldrb r0, [r1,#TCB_enatex]
99 movs r2, #TCB_enatex_mask
100 tst r0, r2
101 beq dispatch_r_1 /* enatex が false ならリターン */
102 ldr r0, [r1,#TCB_texptn] /* texptn が 0 ならリターン */
103 tst r0, r0
104 beq dispatch_r_1
105 ldr r1, =ipmflg /* ipmflgが false ならリターン */
106 ldr r0, [r1]
107 tst r0, r0
108 beq dispatch_r_1
109 ldr r0, =call_texrtn /* タスク例外ルーチンの呼び出し */
110 bx r0
111ALABEL(dispatch_r_1) /* タスクへのcall_textnから戻る */
112 pop {pc}
113
114/*
115 * CPU例外エントリ
116 *
117 * 割込みエントリと処理の内容は同等だが,ログの種類が異なるため,
118 * 分けている.
119 */
120 ABALIGN(4)
121 ATEXT
122 ATHUMB(core_exc_entry)
123 AGLOBAL(core_exc_entry)
124ALABEL(core_exc_entry)
125 /*
126 * 例外/割込みが発生すると,発生時にアクティブなスタックにスクラ
127 * ッチレジスタ等が保存される.
128 * この内容に加えて,CPU例外ハンドラへの情報として,basepri の値と,
129 * EXC_RETURNの情報を加えて保存する.basepriの値は,CPU例外からの
130 * リターン時に割込み優先度マスクの値を元に戻すためにも用いられる.
131 *
132 * -----------
133 * | iipm |
134 * -----------
135 * | EXC_RETURN|
136 * -----------
137 * | R0 |
138 * -----------
139 * | R1 |
140 * -----------
141 * | R2 |
142 * -----------
143 * | R3 |
144 * -----------
145 * | R12 |
146 * -----------
147 * | LR |
148 * -----------
149 * | PC |
150 * -----------
151 * | xPSR |
152 * -----------
153 *
154 */
155
156 /*
157 * カーネル管理外の例外かチェック
158 * カーネル内のクリティカルセクションの実行中,全割込みロック状態,
159 * CPUロック状態,カーネル管理外の割込みハンドラ実行中のいずれかで
160 * 発生したCPU例外を,カーネル管理外のCPU例外と呼ぶ
161 * 全割込みロック状態はFAULTMASKが'1'の場合
162 * CPUロック状態はbasepriがIIPM_LOCKかで判断する.
163 */
164 ldr r3, =iipm /* 後で使用するため読み込む */
165 ldrb r0, [r3]
166 mrs r2, primask /* CPUロック状態ならカーネル管理外例外処理へ */
167 cmp r1, #1
168 beq core_nonkernel_exc_entry
169
170 /*
171 * スタックを変更する必要があるかチェック
172 * EXC_RETURN(割込み時にLRに設定される値)をチェックして,例外発生時に
173 * アクティブなスタックを特定することで多重割込みか判定する.
174 */
175 movs r1, #EXC_RETURN_PSP /* 割込み元がMSPなら多重割込み */
176 mov r2, lr
177 tst r2, r1
178 beq core_exc_entry_1 /* 多重割込みならcore_exc_entry_1へ */
179 mrs r3, psp /* 一段目の割込みの場合はPSP上に */
180 subs r3, #(0x04*2) /* 割込み発生時の割込み優先度マスク(r2),EXC_RETURN(r0)の順にPSP上に積む */
181 str r2, [r3, 0x04]
182 str r0, [r3, 0x00]
183 msr psp, r3
184 push {r0, r2} /* MSPにも割込み発生時の割込み優先度マスク(r0)とEXC_RETURN(r2)を積む */
185 mov lr, r3 /* 未定義の割込みが発生した場合の情報とする */
186 b core_exc_entry_2
187ALABEL(core_exc_entry_1) /* 多重割込みの場合 */
188 push {r0,r2} /* 割込み発生時の割込み優先度マスク(r0),EXC_RETURN(r2)の順にPSP上に積む */
189 mov lr, sp /* CPU例外ハンドラへの引数となる */
190
191 /*
192 * 共通処理
193 */
194ALABEL(core_exc_entry_2)
195 /*
196 * CPU例外からリターンする際に割込み優先度マスクを戻すためのデータを保存
197 */
198 ldr r3, =SYSTIC_CONTROL_STATUS
199 ldr r2,[r3]
200 ldr r3, =NVIC_SETENA0
201 ldr r1,[r3]
202 push {r1,r2}
203
204 mrs r3, ipsr /* ハンドラアドレスを取得 */
205 ldr r1, =_kernel_exc_tbl
206 lsls r0, r3, #2
207 ldr r2, [r1, r0]
208
209#ifdef LOG_EXC_ENTER
210 push {r0,r2,r3}
211 mov r0, r3 /* 例外番号をパラメータに */
212 bl log_exc_enter /* log_exc_enterを呼び出す */
213 pop {r0,r2,r3}
214 push {r3} /* 例外番号をスタックへ */
215#endif /* LOG_EXC_ENTER */
216
217 /*
218 * CPU例外ハンドラの呼び出し
219 */
220 mov r0, lr
221 blx r2
222
223#ifdef LOG_EXC_ENTER
224 pop {r0} /* 例外番号を引数に */
225 bl log_exc_leave /* log_exc_leaveを呼び出す */
226#endif /* LOG_EXC_ENTER */
227
228 b ret_exc
229
230/*
231 * カーネル管理外のCPU例外の出入口処理
232 */
233ALABEL(core_nonkernel_exc_entry)
234 movs r1, #EXC_RETURN_PSP /* 割込み元がMSPなら多重割込み */
235 mov r2, lr
236 tst r2, r1
237 beq core_nonkernel_exc_entry_1 /* 多重割込みなら */
238 mrs r3, psp /* 一段目の割込みの場合はPSP上に */
239 subs r3, #(0x04*2)
240 str r2, [r3, 0x04]
241 str r0, [r3, 0x00]
242 msr psp, r3
243 push {r0, r2} /* MSPにも割込み発生時の割込み優先度マスク(r0)とEXC_RETURN(r2)を積む */
244 mov r0, r3 /* CPU例外ハンドラへの引数となる */
245 b core_nonkernel_exc_entry_2
246ALABEL(core_nonkernel_exc_entry_1) /* 多重割込みの場合 */
247 push {r0, r2} /* 割込み発生時の割込み優先度マスク(r0)とEXC_RETURN(r2)を積む */
248 mov r0, sp /* CPU例外ハンドラへの引数となる */
249
250 /*
251 * 共通処理
252 */
253ALABEL(core_nonkernel_exc_entry_2)
254 /*
255 * 割込みからリターンする際に割込み優先度マスクを戻すためのデータを保存
256 */
257 ldr r3, =SYSTIC_CONTROL_STATUS
258 ldr r2,[r3]
259 ldr r3, =NVIC_SETENA0
260 ldr r1,[r3]
261 push {r1,r2}
262
263 mrs r3, ipsr /* CPU例外ハンドラのアドレスを取得 */
264 ldr r1, =_kernel_exc_tbl
265 lsls r4, r3, #2
266 ldr r2, [r1, r4]
267
268 /*
269 * CPU例外ハンドラの呼び出し
270 */
271 blx r2
272
273 /*
274 * CPUロック状態の場合に呼び出されているため,CPU例外ハンドラからのリターン
275 * のために元に戻す
276 */
277 cpsid i
278
279 /*
280 * 割込み優先度マスクを元に戻す
281 */
282 ldr r1, =0xffffffff
283 ldr r2, =NVIC_CLRENA0 /* 一旦IRQ割り込みを全て禁止 */
284 str r1, [r2]
285 pop {r0,r1} /* スタックから例外発生時のNVIC_SETENA0(r0),SYSTIC_CONTROL_STATUS(r1)の値を取得 */
286 ldr r2, =NVIC_SETENA0 /* NVIC_SETENA0を元に戻す */
287 str r0, [r2]
288 ldr r3, =SYSTIC_CONTROL_STATUS /* SYSTIC_CONTROL_STATUSを元に戻す */
289 ldr r0,[r3]
290 movs r2, #SYSTIC_TICINT
291 orrs r1, r1, r2
292 bics r0, r2
293 orrs r0, r1
294 str r0, [r3]
295 pop {r0} /* iipmを戻す */
296 ldr r1, =iipm
297 strb r0, [r1]
298
299 /*
300 * 戻り先のコンテキストの判定
301 *
302 * 割込みハンドラ実行にLRにセットされるEXC_RETURNをチェックして,戻り
303 * 先でMSPが使われていれば,割込み先が非タスクコンテキストと判定する.
304 */
305 pop {r3} /* lrをスタックから取得 */
306 movs r1, #EXC_RETURN_PSP /* 割込み元がMSPなら多重割込み */
307 tst r3, r1
308 bne core_nonkernel_ret_exc_1
309 b core_nonkernel_ret_exc_2 /* の値をMSPから取得 */
310ALABEL(core_nonkernel_ret_exc_1)
311 /*
312 * PSP上からEXC_RETURN/元の割込み優先度マスク(iipm)を削除
313 */
314 mrs r2, psp
315 adds r2, r2, #8
316 msr psp, r2
317
318ALABEL(core_nonkernel_ret_exc_2)
319 bx r3 /* リターン */
320
321/*
322 * 割込みエントリ
323 */
324 ATHUMB(core_int_entry)
325 AGLOBAL(core_int_entry)
326ALABEL(core_int_entry)
327 /*
328 * 割込み発生時の割込み優先度マスクをスタックに保存するため取得
329 */
330 ldr r3, =iipm /* 後で使用するため読み込む */
331 ldrb r0, [r3]
332
333 /*
334 * 多重割込みかチェック
335 * EXC_RETURN(割込み時にLRに設定される値)をチェックして,例外発生時に
336 * アクティブなスタックを特定することで多重割込みか判定する.
337 */
338 movs r1, #EXC_RETURN_PSP /* 割込み元がMSPなら多重割込み */
339 mov r2, lr
340 tst r2, r1
341 beq core_int_entry_1 /* 多重割込みならcore_int_entry_1へ */
342 mrs r3, psp /* 一段目の割込みの場合はPSP上に */
343 subs r3, #(0x04*2)
344 str r2, [r3, 0x04]
345 str r0, [r3, 0x00]
346 msr psp, r3
347 push {r0, r2} /* MSPにも割込み発生時の割込み優先度マスク(r0)とEXC_RETURN(r2)を積む */
348 mov lr, r3 /* 未定義の割込みが発生した場合の情報とする */
349 b core_int_entry_2
350ALABEL(core_int_entry_1) /* 多重割込みの場合 */
351 push {r0, r2} /* 割込み発生時の割込み優先度マスク(r0)とEXC_RETURN(r2)を積む */
352 mov lr, sp /* 未定義の割込みが発生した場合の情報とする */
353
354 /*
355 * 共通処理
356 */
357ALABEL(core_int_entry_2)
358 /*
359 * 割込みからリターンする際に割込み優先度マスクを戻すためのデータを保存
360 */
361 ldr r3, =SYSTIC_CONTROL_STATUS
362 ldr r2,[r3]
363 ldr r3, =NVIC_SETENA0
364 ldr r1,[r3]
365 push {r1,r2}
366
367 mrs r3, ipsr /* 割込み要因番号の取得 */
368
369 /*
370 * basepriの設定
371 * NVIC優先度マスクが自動的に設定されるため優先度マスクの点では必要な
372 * いが,x_get_ipm()がbasepriを参照するため,basepriも更新する.
373 */
374 ldr r1, =_kernel_int_iipm_tbl
375 ldrb r2, [r1, r3]
376 ldr r0, =iipm
377 strb r2, [r0]
378
379 ldr r1, =_kernel_exc_tbl /* ハンドラアドレスを取得 */
380 lsls r0, r3, #2
381 ldr r2, [r1, r0]
382
383#ifdef LOG_INH_ENTER
384 push {r0,r2,r3}
385 mov r0, r3 /* 例外番号をパラメータに */
386 bl log_inh_enter /* log_exc_enterを呼び出す */
387 pop {r0,r2,r3}
388#endif /* LOG_EXC_ENTER */
389
390#ifdef LOG_INH_LEAVE
391 mrs r3, ipsr /* 割込み要因番号の取得 */
392 push { r3 } /* 割込み番号をスタックへ */
393#endif /* LOG_INT_LEAVE */
394
395 /*
396 * 割込みハンドラの呼び出し
397 */
398 mov r0, lr
399 blx r2
400
401#ifdef LOG_INH_LEAVE
402 pop {r0} /* 例外番号を引数に */
403 bl log_exc_leave /* log_exc_leaveを呼び出す */
404#endif /* LOG_INH_LEAVE */
405
406
407/*
408 * 割込み/例外出口
409 *
410 * ret_exc/ret_intは,CPU例外/割込みハンドラから戻った直後に実行する
411 * ルーチンである.
412 */
413ALABEL(ret_exc)
414ALABEL(ret_int)
415 /*
416 * 割込みロック状態とする.この時点では,CPUロック状態にはならない
417 * (basepriとlock_flagとsaved_iipmは更新しない).
418 *
419 * 割込みロック状態とするのは,戻り先のコンテキストのチェックと,
420 * 戻り先が非タスクコンテキストであった場合のリターンをアトミック
421 * に行うためである.bsepriをCPUロックの値にすることでもアトミッ
422 * クなチェックと復帰は可能であるが,割込みからリターンしても,
423 * basepri の設定内容は元に戻らないため,使用することができない.
424 * 一方,FAULTMASKは,割込みからのリターン処理によって,'0'にクリ
425 * アされる.
426 */
427 cpsid i
428
429 /*
430 * 割込み優先度マスクを元に戻す
431 */
432 ldr r1, =0xffffffff
433 ldr r2, =NVIC_CLRENA0 /* 一旦IRQ割り込みを全て禁止 */
434 str r1, [r2]
435 pop {r0,r1} /* スタックから例外/割込み発生時のNVIC_SETENA0(r0),SYSTIC_CONTROL_STATUS(r1)の値を取得 */
436 ldr r2, =NVIC_SETENA0 /* NVIC_SETENA0を元に戻す */
437 str r0, [r2]
438 ldr r3, =SYSTIC_CONTROL_STATUS /* SYSTIC_CONTROL_STATUSを元に戻す */
439 ldr r0,[r3]
440 movs r2, #SYSTIC_TICINT
441 orrs r1, r1, r2
442 bics r0, r2
443 orrs r0, r1
444 str r0, [r3]
445 pop {r0} /* iipmを戻す */
446 ldr r1, =iipm
447 strb r0, [r1]
448
449 /*
450 * 戻り先のコンテキストの判定
451 *
452 * 割込みハンドラ実行にLRにセットされるEXC_RETURNをチェックして,戻り
453 * 先でMSPが使われていれば,割込み先が非タスクコンテキストと判定する.
454 */
455 pop {r3} /* lrをスタックから取得 */
456 movs r1, #EXC_RETURN_PSP /* 戻り先がPSPなら ret_int_1 へ */
457 tst r3, r1
458 bne ret_int_1
459 b ret_int_2
460
461 /*
462 * 一段目の割込みの出口処理
463 */
464ALABEL(ret_int_1)
465 /*
466 * PSP上から,EXC_RETURN(r0)と元の割込み優先度マスク(basepri)(r1)
467 * を取得
468 */
469 mrs r2, psp
470 adds r2, r2, #(0x04*2)
471 msr psp, r2
472
473 /*
474 * reqflgをチェックする
475 *
476 * カーネル管理内の割込みは禁止した状態で実行する必要があるため,
477 * FAULTMASKを'1'にした状態で実行する.
478 * reqflgをチェックする前に割込みを禁止するのは,reqflgをチェック
479 * した直後に割込みハンドラが起動され,その中でディスパッチが要求
480 * された場合に,すぐにディスパッチされないという問題が生じるため
481 * である.
482 */
483 ldr r0, =reqflg /* reqflgがfalseならそのまま戻る */
484 ldr r2, [r0]
485 cmp r2, #1 /* trueならret_int_3へ */
486 beq ret_int_3
487
488ALABEL(ret_int_2)
489 /*
490 * ここには割込みロック状態(FAULTMASKがセット)された状態で来る.
491 * Threadモードからのリターンにより自動的に割込みロック解除状態になる.
492 * 割込み優先度マスクは割込み前に状態に戻す.
493 */
494 cpsie i /* 割込みのリターンでクリアされないためクリア */
495 bx r3 /* リターン */
496
497ALABEL(ret_int_3)
498 /*
499 * ここでは,戻り先がタスクであり,PSP上にスクラッチレジスタと割
500 * 込み優先度マスク(basepri)が保存された状態になっている.また,
501 * プロセッサは,Handlerモード・割込みロック状態となっている.
502 * また,r0には,reqflgのアドレス,r3には割込み受付時のlrの値が保
503 * 持されている.
504 */
505 /*
506 * タスク例外ハンドラやディスパッチをする際にThreadモードへ遷移する
507 * ダミーのスタックフレームを作成して,bx命令でHandlerモードからリ
508 * ターンする.また,遅延ディスパッチする場合も,再び割り込んだタス
509 * クに戻る際には,svc命令で,svc_handlerを呼び出す.
510 * スタックフレームは,Configureation and Control Register(CCR)の
511 * STKALIGNが'1'の場合は,8byte境界にアラインされる.
512 * 参考 : DDI0403B_arm_architecture_v7m_reference_manual(P.220)
513 * そのため,この時点のスタックは割込みや例外発生時に作成された
514 * スタックフレームから,8byte境界のサイズにしておくと,svc_handler
515 * 等でスタックフレームのアライメントの有無の確認を省略できる.
516 * ただし,システム起動後は,動的にCCRのSTKALIGNの設定を変更するのは
517 * 禁止とする.
518 * この時点は標準のスタックフレームは,割込み・例外発生時と同等であ
519 * るため,タスクスタック(PSP)は8byte境界になっている.
520 */
521 movs r1, #0 /* reqflgをfalseに */
522 str r1, [r0]
523
524 /*
525 * CPUロック状態に移行する.
526 *
527 * カーネルの管理内の割込みを禁止するようにbasepriを設定し,
528 * lock_flag と saved_iipm を更新する.saved_iipmは,戻り先の割込み
529 * 優先度マスク(の内部表現)に設定する.
530 * この時点でCPUロック状態とするのは,dispatcherへ分岐する時と,
531 * call_texrtnを呼び出す時に,CPUロック状態になっている必要がある
532 * ためである.
533 * なお,この処理の後,Threadモードへの移行処理を行なうため,割込み
534 * ロック状態(FAULTMASKを"1")は保持する.
535 */
536
537 /*
538 * 割込み優先度マスクを,全解除状態(TIPM_ENAALL)に設定する
539 * すでにCPUロック状態なので,saved_iipmをIIPM_ENAALLとする.
540 */
541
542 /*
543 * Threadモードへ移行する.
544 *
545 * dispatcherやcall_texrnを呼び出す場合は,Threadモードである必
546 * 要があるため,PSPスタック上にダミーの例外フレームを置いて,
547 * 擬似的に割込みハンドラからリターンする.
548 * リターンと同時にFAULTMASKが自動的にクリアされ,カーネル管理外の
549 * 割込みが許可される.
550 */
551 ldr r0, =ret_int_4 /* PC */
552 ldr r1, =EPSR_T /* xPSR(Tビットが'1'である必要がある) */
553 mrs r2, psp
554 subs r2, #(0x04*2)
555 str r1, [r2, 0x04]
556 str r0, [r2, 0x00]
557 subs r2, #(EXC_FRAME_SIZE - (4*2)) /* r0-r3,r12,lrの内容は設定する必要がない */
558 msr psp,r2
559 bx r3 /* Threadモードへ移行 */
560
561ALABEL(ret_int_4)
562 /*
563 * 上記の処理により,Threadモードで実行される.
564 * dspflgがfalseである場合と,p_runtskとp_schedtskが同じ場合には,
565 * ディスパッチを行わない.このチェックが必要なのは,タスク例外処
566 * 理ルーチンの呼出しが必要な場合に,ディスパッチが必要なくても,
567 * reqflgをtrueにするためである.
568 */
569 ldr r0, =p_runtsk /* ディスパッチを行わない場合でも,r1にp_runtsk の値(TCB) */
570 ldr r1, [r0] /* が入っている必要があるので,先に読み込む */
571 ldr r0, =dspflg
572 ldr r2, [r0]
573 cmp r2, #0x01 /* dspflgがfalseならret_int_r_1へ */
574 bne ret_int_r_1
575 ldr r0, =p_schedtsk
576 ldr r2, [r0]
577 cmp r1, r2 /* p_runtskとp_schedtskが同じなら */
578 beq ret_int_r_1 /* ret_int_r_1へ */
579 mov r0, r8
580 mov r1, r9
581 mov r2, r10
582 mov r3, r11
583 push {r0-r7}
584 ldr r2, =p_runtsk
585 ldr r1, [r2]
586 mov r0, sp
587 str r0, [r1,#TCB_sp] /* タスクスタックを保存 */
588 ldr r2, =ret_int_r /* 実行再開番地を保存 */
589 str r2, [r1,#TCB_pc]
590 b dispatcher /* ディスパッチャへ */
591
592/*
593 * 割込みによりプリエンプトされたタスクへのリターン処理
594 *
595 * Threadモードで,ディスパッチャや割込みの出口処理から呼び出される.
596 * 割込みによりプリエンプトされたタスクへリターンするには,いったん
597 * Handlerモードに移行し,PCに0xfffffffdを代入してリターンする必要
598 * がある.そのため,SVCにより,SVCハンドラを呼び出し,Handlerモー
599 * ドへ移行する.
600 */
601 ATHUMB(ret_int_r)
602 AGLOBAL(ret_int_r)
603ALABEL(ret_int_r)
604 pop {r0-r7}
605 mov r8, r0
606 mov r9, r1
607 mov r10, r2
608 mov r11, r3
609ALABEL(ret_int_r_1)
610 /*
611 * enatexがtrueで,texptnが0でなければ,タスク例外処理ルーチンを
612 * 呼び出す.
613 * dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
614 */
615 ldr r2, =p_runtsk
616 ldr r1, [r2]
617 ldrb r0, [r1,#TCB_enatex]
618 movs r2, #TCB_enatex_mask
619 tst r0, r2
620 beq ret_int_r_2 /* enatex が false なら ret_int_r_2へ */
621 ldr r0, [r1,#TCB_texptn] /* texptn が 0 ならリターン */
622 cmp r0, #0x00
623 beq ret_int_r_2
624 ldr r1, =ipmflg /* ipmflgが false ならリターン */
625 ldr r0, [r1]
626 cmp r0, #0x00
627 beq ret_int_r_2
628 bl call_texrtn /* タスク例外ルーチンの呼び出し */
629ALABEL(ret_int_r_2)
630 ldr r0, =NVIC_ICSR
631 ldr r1, =NVIC_PENDSVSET
632 str r1, [r0]
633 cpsie i /* PRIMASKをクリアしてPendSVCを受け付ける */
6341: /* ここには来ない */
635 b 1b
636
637/*
638 * SVCハンドラ
639 */
640 ATHUMB(svc_handler)
641 AGLOBAL(svc_handler)
642ALABEL(svc_handler)
6431:
644 b 1b
645
646/*
647 * PendSVCハンドラ
648 */
649 ATHUMB(pendsvc_handler)
650 AGLOBAL(pendsvc_handler)
651ALABEL(pendsvc_handler)
652 /*
653 * 割込み処理からのリターンにより,CPUロック解除状態に移行するよ
654 * う準備する.
655 */
656 mrs r0, psp
657 adds r0, #EXC_FRAME_SIZE /* スタックを捨てる */
658 msr psp, r0
659 movs r0, #0
660 bx lr /* リターン */
661
662/*
663 * ディスパッチャの動作開始
664 */
665 ATHUMB(start_dispatch)
666 AGLOBAL(start_dispatch)
667ALABEL(start_dispatch)
668 /*
669 * このルーチンは,カーネル起動時に,すべての割込みを禁止した状態
670 * (割込みロック状態と同等)で呼び出される.また,割込みモード(非
671 * タスクコンテキストと同等)で呼び出されることを想定している.
672 *
673 * core_initializeで,lock_flagをtrueに,saved_iipmをIIPM_ENAALLに
674 * 初期化しているため,カーネル管理外の割込みを許可することで,
675 * CPUロック状態・(モデル上の)割込み優先度マスク全解除状態になる.
676 * また,task_initializeでdisdspをfalseに初期化しているため,ディ
677 * スパッチ許可状態になっている.
678 */
679 ldr r0,=istkpt /* MSPを初期化 */
680 ldr r1,[r0] /* start_dispatch呼び出し時に呼び出し用に */
681 msr msp, r1 /* 使用しているため初期化する */
682 movs r0, #CONTROL_PSP /* PSPを有効に */
683 msr control, r0
684 isb /* control の操作後に必要 */
685
686/*
687 * 現在のコンテキストを捨ててディスパッチ
688 */
689 ATHUMB(exit_and_dispatch)
690 AGLOBAL(exit_and_dispatch)
691ALABEL(exit_and_dispatch)
692 /* ディスパッチャ本体(dispatcher)へ */
693
694
695/*
696 * ディスパッチャ本体
697 */
698ALABEL(dispatcher)
699 /*
700 * このルーチンは,タスクコンテキスト・CPUロック状態・ディスパッチ
701 * 許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さ
702 * れる.
703 *
704 * すなわち,Threadモード・lock_flagがtrue・disdspがfalse・dspflg
705 * がtrue・saved_iipmがIIPM_ENAALLとなっている.実行再開番地へもこ
706 * の状態のまま分岐する.
707 */
708#ifdef LOG_DSP_ENTER
709 ldr r1, =p_runtsk /* p_runtskをパラメータに */
710 ldr r0, [r1]
711 bl log_dsp_enter
712#endif /* LOG_DSP_ENTER */
713ALABEL(dispatcher_0)
714 ldr r0, =p_schedtsk /* p_schedtskをp_runtskに */
715 ldr r1, [r0]
716 ldr r2, =p_runtsk
717 str r1, [r2]
718 cmp r1, #0x00 /* p_runtskがNULLならdispatcher_1へ */
719 beq dispatcher_1
720 ldr r2, [r1,#TCB_sp] /* タスクスタックを復帰 */
721 mov sp, r2
722#ifdef LOG_DSP_LEAVE
723 mov r0, r1 /* p_runtskをパラメータに */
724 mov r4, r1 /* r1はスクラッチレジスタなので保存 */
725 bl log_dsp_leave
726 mov r1, r4
727#endif /* LOG_DSP_LEAVE */
728 ldr r2, [r1,#TCB_pc] /* 実行再開番地を復帰 */
729 mov pc, r2
730ALABEL(dispatcher_1)
731 /*
732 * CPUロック状態の解除と,非タスクコンテキスト実行状態への
733 * 準備をする
734 */
735 movs r0, #CONTROL_MSP /* MSPを有効に */
736 msr control, r0
737 isb /* control の操作後に必要 */
738 movs r4, #0 /* r4 <- '0' */
739 ldr r6, =reqflg /* r6 <- reqflg */
740ALABEL(dispatcher_2)
741 /*
742 * 割込みを許可し,非タスクコンテキスト実行状態とし割込みを待つ.
743 *
744 * ここで非タスクコンテキスト実行状態に切り換えるのは,ここで発生
745 * する割込み処理にどのスタックを使うかという問題の解決と,割込み
746 * ハンドラ内でのタスクディスパッチの防止という2つの意味がある.
747 *
748 * プロセッサを割込み待ちに移行させる処理と,割込み許可とは,不可
749 * 分に行なう必要がある.
750 * これを不可分に行なわない場合,割込みを許可した直後に割込
751 * みが入り,その中でタスクが実行可能状態になると,実行すべきタス
752 * クがあるにもかかわらずプロセッサが割込み待ちになってしまう.
753 * ARM-Mでは,PRIMASKをセットした状態でWFIを呼び出すことで実現できる.
754 * この状態で割込みが入ると,割込みは実行されず,WFIからリターンす
755 * ることになるので,一旦割込みを許可して割込みハンドラを実行する.
756 *
757 * 割込み待ちの間は,p_runtskをNULL(=0)に設定しなければならな
758 * い.このように設定しないと,割込みハンドラからiget_tidを呼び出
759 * した際の動作が仕様に合致しなくなる.
760 *
761 * ターゲットによっては,省電力モード等に移行するため,標準の方法と
762 * 異なる手順が必要な場合がある.
763 * そのようなターゲットでは,ターゲット依存において,TOPPERS_CUSTOM_IDLE
764 * を定義し,アセンブラマクロとして,toppers_asm_custom_idle を用意
765 * すればよい.
766 *
767 * なお,toppers_asm_custom_idle の記述にあたっては,次のレジスタは
768 * toppers_asm_custom_idleの前後で使用するため,
769 * toppers_asm_custom_idle 内で使用する場合は,前後で保存復帰すること.
770 * これらのレジスタは Calee saved レジスタであるため,
771 * toppers_asm_custom_idle として関数呼び出しをした場合は,呼び出した
772 * 関数で自動的に保存復帰されるため,アセンブラレベルでの保存復帰は必
773 * 要ない.
774 *
775 * レジスタ : 内容
776 * r4 : '0'
777 * r5 : 'IIPM_LOCK'
778 * r6 : reqflgのアドレス
779 * r7 : lock_flgのアドレス
780 * sp : 非タスクコンテキスト用のスタックの先頭アドレス(msp)
781 */
782#ifdef TOPPERS_CUSTOM_IDLE
783 toppers_asm_custom_idle
784#else
785 wfi
786 cpsie i /* PRIMASK をクリア(割込みを受け付ける) */
787 cpsid i /* PRIMASK をセット */
788#endif /* TOPPERS_CUSTOM_IDLE */
789
790 ldr r0, [r6] /* reqflgがfalseならdispatcher_2へ */
791 cmp r0, #0
792 beq dispatcher_2
793 str r4, [r6] /* reqflgをfalseに */
794
795 /*
796 * CPUロック状態に戻す.割込み待ちの間に実行した割込みハンドラによ
797 * り,saved_iipmが書き換えられる可能性があるため,元の値に戻す必
798 * 要がある.dispatcherが実行される時は,saved_iipmがIIPM_ENAALL
799 * となっているため,ここではsaved_iipmをIIPM_ENAALL(=0)に戻せ
800 * ばよい.
801 */
802 movs r0, #CONTROL_PSP /* PSPを有効に */
803 msr control, r0
804 isb /* control の操作後に必要 */
805 b dispatcher_0
806
807/*
808 * カーネルの終了処理の呼出し
809 *
810 * スタックを非タスクコンテキスト用に切り替え.
811 *
812 */
813 ATHUMB(call_exit_kernel)
814 AGLOBAL(call_exit_kernel)
815ALABEL(call_exit_kernel)
816 movs r0, #CONTROL_MSP
817 msr control, r0 /* MSPを有効に */
818 isb /* control の操作後に必要 */
819 ldr r0, =exit_kernel /* カーネルの終了処理を呼ぶ */
820 bx r0
821
822/*
823 * タスク起動処理
824 *
825 * dispatcherから呼び出されるため,TCBのアドレスはr1に入っている
826 *
827 */
828 ATHUMB(start_r)
829 AGLOBAL(start_r)
830ALABEL(start_r)
831 movs r0, #0
832 cpsie i /* 割込み許可 */
833 ldr r0, =ext_tsk /* 戻り番地設定 */
834 mov lr, r0
835 ldr r2, [r1, #TCB_p_tinib] /* p_runtsk->p_tinibをr2に */
836 ldr r0, [r2, #TINIB_exinf] /* exinfを引数レジスタr0に */
837 ldr r1, [r2, #TINIB_task] /* タスク起動番地にジャンプ */
838 bx r1
839
840/*
841 * 微少時間待ち
842 */
843 ABALIGN(4)
844 ATEXT
845 ATHUMB(sil_dly_nse)
846 AGLOBAL(sil_dly_nse)
847ALABEL(sil_dly_nse)
848 ldr r1, =SIL_DLY_TIM1
849 subs r0, r0, r1
850 cmp r0, #0
851 bgt sil_dly_nse1
852 bx lr
853ALABEL(sil_dly_nse1)
854 ldr r1, =SIL_DLY_TIM2
855ALABEL(sil_dly_nse2)
856 subs r0, r0, r1
857 cmp r0, #0
858 bgt sil_dly_nse2
859 bx lr
860
Note: See TracBrowser for help on using the repository browser.