/* * TOPPERS/ASP Kernel * Toyohashi Open Platform for Embedded Real-Time Systems/ * Advanced Standard Profile Kernel * * Copyright (C) 2000-2004 by Embedded and Real-Time Systems Laboratory * Toyohashi Univ. of Technology, JAPAN * Copyright (C) 2006-2012 by Embedded and Real-Time Systems Laboratory * Graduate School of Information Science, Nagoya Univ., JAPAN * Copyright (C) 2014,2015 by Naoki Saito * Nagoya Municipal Industrial Research Institute, JAPAN * * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー * スコード中に含まれていること. * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 * の無保証規定を掲載すること. * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ * と. * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 * 作権表示,この利用条件および下記の無保証規定を掲載すること. * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに * 報告すること. * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを * 免責すること. * * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ * の責任を負わない. * * @(#) $Id: core_support.S 619 2014-03-18 06:10:27Z nmir-saito $ */ /* * コア依存モジュール アセンブリ言語部(ARM用) */ #define TOPPERS_MACRO_ONLY #define TOPPERS_ASM_MACRO #define UINT_C(val) (val) /* uint_t型の定数を作るマクロ */ #define ULONG_C(val) (val) /* ulong_t型の定数を作るマクロ */ #include "kernel_impl.h" /* * 例外ベクタ */ .section vector, "a" .global vector_table vector_table: ldr pc, reset_vector /* リセット */ ldr pc, undef_vector /* 未定義命令 */ ldr pc, swi_vector /* ソフトウェア割込み */ ldr pc, prefech_vector /* プリフェッチアボート */ ldr pc, data_abort_vector /* データアボート */ ldr pc, reset_vector ldr pc, irq_vector /* IRQ */ ldr pc, fiq_vector /* FIQ */ /* * 例外ベクタの命令から参照される * ジャンプ先アドレス */ .global vector_ref_tbl vector_ref_tbl: reset_vector: .long start undef_vector: .long undef_handler swi_vector: .long swi_handler prefech_vector: .long prefetch_handler data_abort_vector: .long data_abort_handler irq_vector: .long irq_handler fiq_vector: .long fiq_handler /* * タスクディスパッチャ */ .text .align 2 /* * ディスパッチャの動作開始 */ .global start_dispatch .type start_dispatch, function start_dispatch: /* * このルーチンは,カーネル起動時に,すべての割込みを禁止した状態 * (割込みロック状態と同等)で呼び出される.また,割込みモード(非 * タスクコンテキストと同等)で呼び出されることを想定している. * * dispatcherは,CPUロック状態,(モデル上の)割込み優先度マスク全 * 解除状態,例外(割込み/CPU例外)のネスト回数0で呼び出す. * target_initializeでは,(モデル上の)割込み優先度マスク全解除 * とし,カーネル管理外の割込みであるFIQを許可することで, * CPUロック状態・(モデル上の)割込み優先度マスク全解除状態になる. * また,initialize_taskでdisdspをfalseに初期化しているため,ディ * スパッチ許可状態になっている. * */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_CPULOCK | CPSR_ALWAYS_SET) /* CPUロック状態へ */ ldr r2, =excpt_nest_count /* 例外(割込み/CPU例外)のネスト回数を0に */ mov r0, #0 str r0, [r2] ldr r0, =_kernel_istkpt /* スタックポインタを初期化(戻ってこないので) */ ldr sp, [r0] b dispatcher /* * カーネルの終了処理の呼出し * * モードとスタックを非タスクコンテキスト用に切り替え. */ .global call_exit_kernel .type call_exit_kernel, function call_exit_kernel: msr cpsr_cxsf, #(CPSR_SVC | CPSR_ALWAYS_SET | CPSR_IRQ_BIT | CPSR_FIQ_BIT) ldr r0, =_kernel_istkpt /* スタックポインタを初期化 */ ldr sp, [r0] b exit_kernel /* * 割込みハンドラ/CPU例外ハンドラ出口処理 * * ret_intは,割込みハンドラから戻った直後に実行するルーチンで, * 割込みハンドラ終了後,ターゲット依存の処理を実行した後, * カーネル管理の割込みを禁止,スタックを割込み前のスタックにした * 状態で呼び出される. */ .text .global ret_int .type ret_int, function .global ret_exc .type ret_exc, function ret_int: ret_exc: /* * 例外・割込みのネストカウント(excpt_nest_count)のデクリメント */ ldr r0, =excpt_nest_count /* r0 <-excpt_nest_count */ ldr r1, [r0] sub r2, r1, #1 str r2, [r0] cmp r2, #0 /* 戻り先が非タスクコンテキストなら */ bne ret_int_1 /* すぐにリターン */ /* * reqflgをチェックする前に割込みを禁止するのは,reqflgをチェック * した直後に割込みハンドラが起動され,その中でディスパッチが要求 * された場合に,すぐにディスパッチされないという問題が生じるため * である. */ ldr r0, =reqflg ldr r1, [r0] cmp r1, #0 /* reqflgがtrueであればret_int_2へ */ bne ret_int_2 ret_int_1: /* * 割込み処理からのリターンにより,CPUロック解除状態に移行しなければ * ならない. * ARMでは,CPSRのIRQビットでCPUロック解除状態とするため,単にリターン * すればよい. */ ldmfd sp!, {r1} /* CPSRの復帰処理 */ msr spsr_cxsf, r1 /* 戻り先のcpsrをspsrに設定 */ ldmfd sp!, {r0-r3,ip,lr,pc}^ /* コンテキストの復帰,^付きなので、cpsr <- spsr */ ret_int_2: ret_int_3: /* * ここへは,CPU例外ハンドラの出口処理からも分岐してくる. * * ここでは,戻り先がタスクであり,スタックは,タスクスタックの上 * にスクラッチレジスタのみが保存された状態になっている.また, * プロセッサは,スーパーバイザーモード・カーネル管理の割込みを禁止 * した状態となっている. */ ldr r0, =reqflg /* reqflgをfalseに */ mov r1, #0 str r1, [r0] /* * CPUロック状態に移行し,割込み優先度マスクを割込み処理前の値に * 設定する. * * この時点でCPUロック状態とするのは,dispatcherへ分岐する時と, * call_texrtnを呼び出す時に,CPUロック状態になっている必要がある * ためである. * * CPUロック状態に関しては,ARMでは,CPSRのIRQビットでCPUロック * 状態を表現するため,ここでは,特に何も行わない. * * 割込み優先度マスクに関しては,ターゲット毎に操作が異なるため, * 割込みハンドラ終了直後にターゲット依存部で割込み処理前の値に * 設定する. */ /* * disdsp が trueである場合には,ディスパッチを行わない. */ ldr r0, =disdsp ldr r2, [r0] cmp r2, #0 /* disdsp がtrueならret_int_4へ */ bne ret_int_4 /* * ディスパッチ */ /*** タスク起動は関数呼び出しなので,r4-r11 の保存/復帰は必要ないかもしれない ***/ stmfd sp!, {r4-r11} /* 残りのレジスタを保存 */ /* CPUロック状態にしておく */ msr cpsr, #(CPSR_SVC | CPSR_IRQ_BIT) /* 最高優先タスクをサーチして,タスク起動 */ bl _kernel_search_schedtsk bl _kernel_run_task ldmfd sp!, {r4-r11} /* レジスタの復帰 */ ret_int_4: /* * 割込み処理からのリターンにより,CPU ロック解除状態に移行するよ * うにする.ARM は CPSR の IRQ ビットによって CPU ロック状態を表してい * るため,そのままリターンすればよい. */ ldmfd sp!, {r0} /* spsr を復帰 */ msr spsr,r0 /* 戻り先のcpsrをspsrに設定 */ ldmfd sp!,{r0-r3,ip,lr,pc}^ /* タスクに復帰 ^付きなので、cpsr <- spsr */ /* * CPU例外ハンドラ * * CPU例外ハンドラは,非タスクコンテキストで実行する. * */ /* * 未定義命令 例外ハンドラ */ .text .align 2 .global undef_handler .type undef_handler, function undef_handler: /* * タスクの動作時モード(スーパーバイザーモード)へ */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_CPULOCK | CPSR_ALWAYS_SET) stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */ /* * spsrと戻り番地を取得するために未定義モードへ */ msr cpsr_cxsf, #(CPSR_UND | CPSR_CPULOCK | CPSR_ALWAYS_SET) mov r0, lr mrs r1, spsr mov r2, #EXCH_NO_UNDEF b target_exc_handler /* * SWI 例外ハンドラ */ .text .align 2 .global swi_handler .type swi_handler, function swi_handler: /* * タスクの動作時モード(スーパーバイザーモード)へ * 元々スーパーバイザーモードだが,CPUロック状態とする */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_CPULOCK | CPSR_ALWAYS_SET) stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */ mov r0, lr mrs r1, spsr mov r2, #EXCH_NO_SVC b target_exc_handler /* * プリフェッチアボード 例外ハンドラ */ .text .align 2 .global prefetch_handler .type prefetch_handler, function prefetch_handler: /* * タスクの動作時モード(スーパーバイザーモード)へ */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_CPULOCK | CPSR_ALWAYS_SET) stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */ /* * spsrと戻り番地を取得するためにアボートモードへ */ msr cpsr_cxsf, #(CPSR_ABT | CPSR_CPULOCK | CPSR_ALWAYS_SET) mov r0, lr mrs r1, spsr mov r2, #EXCH_NO_PABORT b target_exc_handler /* * データアボード 例外ハンドラ */ .text .align 2 .global data_abort_handler .type data_abort_handler, function data_abort_handler: /* * タスクの動作時モード(スーパーバイザーモード)へ */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_CPULOCK | CPSR_ALWAYS_SET) stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */ /* * spsrと戻り番地を取得するためにアボートモードへ */ msr cpsr_cxsf, #(CPSR_ABT | CPSR_CPULOCK | CPSR_ALWAYS_SET) mov r0, lr mrs r1, spsr mov r2, #EXCH_NO_DABORT b target_exc_handler #ifndef TARGET_FIQ_HANDLER /* * FIQ 例外ハンドラ */ .text .align 2 .global fiq_handler .type fiq_handler, function fiq_handler: /* * タスクの動作時モード(スーパーバイザーモード)へ */ msr cpsr_cxsf, #(CPSR_SVC | CPSR_FIQ_BIT | CPSR_CPULOCK | CPSR_ALWAYS_SET) stmfd sp!, {r0-r3,ip,lr,pc} /* pcはダミー */ /* * spsrと戻り番地を取得するためにFIQモードへ */ msr cpsr_cxsf, #(CPSR_FIQ | CPSR_FIQ_BIT | CPSR_CPULOCK | CPSR_ALWAYS_SET) mov r0, lr mrs r1, spsr mov r2, #EXCH_NO_FIQ b target_exc_handler #endif /* TARGET_FIQ_HANDLER */ /* * 微少時間待ち */ .global _sil_dly_nse .type _sil_dly_nse, function _sil_dly_nse: sub r0, r0, #SIL_DLY_TIM1 cmp r0, #0 bgt _sil_dly_nse1 bxle lr _sil_dly_nse1: sub r0, r0, #SIL_DLY_TIM2 cmp r0, #0 bgt _sil_dly_nse1 bxle lr #ifdef __thumb__ .text .align 2 AWEAK(current_sr) current_sr: mrs r0, cpsr bx lr .weak set_sr set_sr: msr cpsr_cxsf, r0 bx lr #endif /* __thumb__ */