00001 /* 00002 * TOPPERS/ASP Kernel 00003 * Toyohashi Open Platform for Embedded Real-Time Systems/ 00004 * Advanced Standard Profile Kernel 00005 * 00006 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory 00007 * Toyohashi Univ. of Technology, JAPAN 00008 * Copyright (C) 2005-2008 by Embedded and Real-Time Systems Laboratory 00009 * Graduate School of Information Science, Nagoya Univ., JAPAN 00010 * 00011 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ 00012 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 00013 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. 00014 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 00015 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー 00016 * スコード中に含まれていること. 00017 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 00018 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 00019 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 00020 * の無保証規定を掲載すること. 00021 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 00022 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ 00023 * と. 00024 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 00025 * 作権表示,この利用条件および下記の無保証規定を掲載すること. 00026 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに 00027 * 報告すること. 00028 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 00029 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. 00030 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 00031 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを 00032 * 免責すること. 00033 * 00034 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お 00035 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 00036 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ 00037 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ 00038 * の責任を負わない. 00039 * 00040 * @(#) $Id: prc_config.h 759 2008-03-07 23:01:20Z hiro $ 00041 */ 00042 00043 /* 00044 * プロセッサ依存モジュール(M68040用) 00045 * 00046 * このインクルードファイルは,target_config.h(または,そこからインク 00047 * ルードされるファイル)のみからインクルードされる.他のファイルから 00048 * 直接インクルードしてはならない. 00049 */ 00050 00051 #ifndef TOPPERS_PRC_CONFIG_H 00052 #define TOPPERS_PRC_CONFIG_H 00053 00054 #ifndef TOPPERS_MACRO_ONLY 00055 00056 /* 00057 * プロセッサの特殊命令のインライン関数定義 00058 */ 00059 #include "prc_insn.h" 00060 00061 /* 00062 * タスクコンテキストブロックの定義 00063 */ 00064 typedef struct task_context_block { 00065 void *msp; /* スタックポインタ */ 00066 FP pc; /* プログラムカウンタ */ 00067 } CTXB; 00068 00069 #endif /* TOPPERS_MACRO_ONLY */ 00070 00071 /* 00072 * 割込み優先度マスク操作ライブラリ 00073 * 00074 * M68040では,ステータスレジスタ(SR)の下から8〜10ビットめの3ビット 00075 * に割込み優先度マスク(ハードウェアの割込み優先度マスク,IPM)が置か 00076 * れている.IPMを保存しておくために,割込み優先度の外部表現(-1から連 00077 * 続した負の値)を使うことも可能であるが,余計な左右ビットシフトと符 00078 * 号反転が必要になる.これを避けるために,IPMを保存する場合には,SRの 00079 * 8〜10ビットめを取り出した値を使うことにする.この値を割込み優先度マ 00080 * スクの内部表現と呼び,IIPMと書くことにする. 00081 */ 00082 00083 /* 00084 * 割込み優先度マスクの外部表現と内部表現の変換 00085 */ 00086 #define EXT_IPM(iipm) (-CAST(PRI, (iipm) >> 8)) /* 外部表現に変換 */ 00087 #define INT_IPM(ipm) (CAST(uint16_t, -(ipm)) << 8) /* 内部表現に変換 */ 00088 00089 #ifndef TOPPERS_MACRO_ONLY 00090 00091 /* 00092 * IPM(ハードウェアの割込み優先度マスク,内部表現)の現在値の読出し 00093 */ 00094 Inline uint16_t 00095 current_iipm(void) 00096 { 00097 return(current_sr() & 0x0700U); 00098 } 00099 00100 /* 00101 * IPM(ハードウェアの割込み優先度マスク,内部表現)の現在値の設定 00102 */ 00103 Inline void 00104 set_iipm(uint16_t iipm) 00105 { 00106 set_sr((current_sr() & ~0x0700U) | iipm); 00107 } 00108 00109 /* 00110 * TOPPERS標準割込み処理モデルの実現 00111 * 00112 * M68040は,ステータスレジスタ(SR)中に割込み優先度マスク(ハードウェ 00113 * アの割込み優先度マスク,IPM)を持っているが,CPUロックフラグに相当 00114 * する機能を持たない.そのため,CPUロックフラグの機能を,IPMによって 00115 * 実現する. 00116 * 00117 * まずCPUロックフラグの値(すなわち,CPUロック状態かCPUロック解除状態 00118 * か)は,そのための変数(lock_flag)を用意して保持する. 00119 * 00120 * CPUロックフラグがクリアされている間(すなわち,CPUロック解除状態の 00121 * 間)は,IPM(ハードウェアの割込み優先度マスク)を,モデル上の割込み 00122 * 優先度マスクの値に設定する.この間は,モデル上の割込み優先度マスク 00123 * は,IPMを用いて保持する. 00124 * 00125 * それに対してCPUロックフラグがセットされている間(すなわち,CPUロッ 00126 * ク状態の間)は,IPM(ハードウェアの割込み優先度マスク)を,カーネル 00127 * 管理の割込みをすべてマスクする値(TIPM_LOCK)と,モデル上の割込み優 00128 * 先度マスクとの高い方に設定する.この間のモデル上の割込み優先度マス 00129 * クは,そのための変数(saved_iipm,内部表現で保持)を用意して保持す 00130 * る. 00131 */ 00132 00133 /* 00134 * コンテキストの参照 00135 * 00136 * M68040では,タスクコンテキストをマスタモードで,非タスクコンテキス 00137 * トを割込みモードで実行する.マスタモードか割込みモードかは,ステー 00138 * タスレジスタ(SR)中の割込みモードビットにより判別できる. 00139 */ 00140 Inline bool_t 00141 sense_context(void) 00142 { 00143 return((current_sr() & 0x1000U) == 0U); 00144 } 00145 00146 #endif /* TOPPERS_MACRO_ONLY */ 00147 00148 /* 00149 * CPUロック状態での割込み優先度マスク 00150 * 00151 * TIPM_LOCKは,カーネル管理の割込みをすべてマスクする値に定義する.具 00152 * 体的には,TMIN_INTPRIが-6の時はTIPM_LOCKを-7に,そうでない場合には 00153 * TIPM_LOCKをTMIN_INTPRIに一致させる. 00154 */ 00155 #if TMIN_INTPRI == -6 /* NMI以外にカーネル管理外の割込みを設けない */ 00156 #define TIPM_LOCK (-7) 00157 #else /* TMIN_INTPRI == -6 */ 00158 #if (-1 >= TMIN_INTPRI) && (TMIN_INTPRI > -6) 00159 #define TIPM_LOCK TMIN_INTPRI 00160 #else /* (-1 >= TMIN_INTPRI) && (TMIN_INTPRI > -6) */ 00161 #error TMIN_INTPRI out of range. 00162 #endif /* (-1 >= TMIN_INTPRI) && (TMIN_INTPRI > -6) */ 00163 #endif /* TMIN_INTPRI == -6 */ 00164 00165 /* 00166 * CPUロック状態での割込み優先度マスクの内部表現 00167 */ 00168 #define IIPM_LOCK INT_IPM(TIPM_LOCK) 00169 00170 /* 00171 * TIPM_ENAALL(割込み優先度マスク全解除)の内部表現 00172 */ 00173 #define IIPM_ENAALL INT_IPM(TIPM_ENAALL) 00174 00175 #ifndef TOPPERS_MACRO_ONLY 00176 00177 /* 00178 * CPUロックフラグ実現のための変数 00179 * 00180 * これらの変数は,CPUロック状態の時のみ書き換えてよいものとする. 00181 */ 00182 extern volatile bool_t lock_flag; /* CPUロックフラグの値を保持する変数 */ 00183 extern volatile uint16_t saved_iipm; /* 割込み優先度マスクを保存する変数 */ 00184 00185 /* 00186 * CPUロック状態への移行 00187 * 00188 * IPM(ハードウェアの割込み優先度マスク)を,saved_iipmに保存し,カー 00189 * ネル管理の割込みをすべてマスクする値(TIPM_LOCK)に設定する.また, 00190 * lock_flagをtrueにする. 00191 * 00192 * IPMが,最初からTIPM_LOCKと同じかそれより高い場合には,それを 00193 * saved_iipmに保存するのみで,TIPM_LOCKには設定しない.これは,モデル 00194 * 上の割込み優先度マスクが,TIPM_LOCKと同じかそれより高いレベルに設定 00195 * されている状態にあたる. 00196 * 00197 * この関数は,CPUロック状態(lock_flagがtrueの状態)で呼ばれることは 00198 * ないものと想定している. 00199 */ 00200 Inline void 00201 x_lock_cpu(void) 00202 { 00203 uint16_t iipm; 00204 00205 /* 00206 * current_iipm()の返り値を直接saved_iipmに保存せず,一時変数iipm 00207 * を用いているのは,current_iipm()を呼んだ直後に割込みが発生し, 00208 * 起動された割込み処理でsaved_iipmが変更される可能性があるためで 00209 * ある. 00210 */ 00211 iipm = current_iipm(); 00212 #if TIPM_LOCK == -7 00213 disint(); 00214 #else /* TIPM_LOCK == -7 */ 00215 if (IIPM_LOCK > iipm) { 00216 set_iipm(IIPM_LOCK); 00217 } 00218 #endif /* TIPM_LOCK == -7 */ 00219 saved_iipm = iipm; 00220 lock_flag = true; 00221 Asm("":::"memory"); 00222 } 00223 00224 #define t_lock_cpu() x_lock_cpu() 00225 #define i_lock_cpu() x_lock_cpu() 00226 00227 /* 00228 * CPUロック状態の解除 00229 * 00230 * lock_flagをfalseにし,IPM(ハードウェアの割込み優先度マスク)を, 00231 * saved_iipmに保存した値に戻す. 00232 * 00233 * この関数は,CPUロック状態(lock_flagがtrueの状態)でのみ呼ばれるも 00234 * のと想定している. 00235 */ 00236 Inline void 00237 x_unlock_cpu(void) 00238 { 00239 Asm("":::"memory"); 00240 lock_flag = false; 00241 set_iipm(saved_iipm); 00242 } 00243 00244 #define t_unlock_cpu() x_unlock_cpu() 00245 #define i_unlock_cpu() x_unlock_cpu() 00246 00247 /* 00248 * CPUロック状態の参照 00249 */ 00250 Inline bool_t 00251 x_sense_lock(void) 00252 { 00253 return(lock_flag); 00254 } 00255 00256 #define t_sense_lock() x_sense_lock() 00257 #define i_sense_lock() x_sense_lock() 00258 00259 /* 00260 * chg_ipmで有効な割込み優先度の範囲の判定 00261 * 00262 * TMIN_INTPRIの値によらず,chg_ipmでは,-6〜TIPM_ENAALL(=0)の範囲 00263 * に設定できることとする(ターゲット定義の拡張). 00264 */ 00265 #define VALID_INTPRI_CHGIPM(intpri) \ 00266 ((-6 <= (intpri) && (intpri) <= TIPM_ENAALL)) 00267 00268 /* 00269 * (モデル上の)割込み優先度マスクの設定 00270 * 00271 * CPUロックフラグがクリアされている時は,ハードウェアの割込み優先度マ 00272 * スクを設定する.CPUロックフラグがセットされている時は,saved_iipm 00273 * を設定し,さらに,ハードウェアの割込み優先度マスクを,設定しようと 00274 * した(モデル上の)割込み優先度マスクとTIPM_LOCKの高い方に設定する. 00275 */ 00276 Inline void 00277 x_set_ipm(PRI intpri) 00278 { 00279 uint16_t iipm = INT_IPM(intpri); 00280 00281 if (!lock_flag) { 00282 set_iipm(iipm); 00283 } 00284 else { 00285 saved_iipm = iipm; 00286 #if TIPM_LOCK == -7 00287 /* 00288 * TIPM_LOCKが-7の場合には,この時点でハードウェアの割込み優先 00289 * 度マスクが必ず7に設定されているため,設定しなおす必要がない. 00290 */ 00291 #else /* TIPM_LOCK == -7 */ 00292 set_iipm(iipm > IIPM_LOCK ? iipm : IIPM_LOCK); 00293 #endif /* TIPM_LOCK == -7 */ 00294 } 00295 } 00296 00297 #define t_set_ipm(intpri) x_set_ipm(intpri) 00298 #define i_set_ipm(intpri) x_set_ipm(intpri) 00299 00300 /* 00301 * (モデル上の)割込み優先度マスクの参照 00302 * 00303 * CPUロックフラグがクリアされている時はハードウェアの割込み優先度マ 00304 * スクを,セットされている時はsaved_iipmを参照する. 00305 */ 00306 Inline PRI 00307 x_get_ipm(void) 00308 { 00309 uint16_t iipm; 00310 00311 if (!lock_flag) { 00312 iipm = current_iipm(); 00313 } 00314 else { 00315 iipm = saved_iipm; 00316 } 00317 return(EXT_IPM(iipm)); 00318 } 00319 00320 #define t_get_ipm() x_get_ipm() 00321 #define i_get_ipm() x_get_ipm() 00322 00323 /* 00324 * 最高優先順位タスクへのディスパッチ(prc_support.S) 00325 * 00326 * dispatchは,タスクコンテキストから呼び出されたサービスコール処理か 00327 * ら呼び出すべきもので,タスクコンテキスト・CPUロック状態・ディスパッ 00328 * チ許可状態・(モデル上の)割込み優先度マスク全解除状態で呼び出さな 00329 * ければならない. 00330 */ 00331 extern void dispatch(void); 00332 00333 /* 00334 * ディスパッチャの動作開始(prc_support.S) 00335 * 00336 * start_dispatchは,カーネル起動時に呼び出すべきもので,すべての割込 00337 * みを禁止した状態(割込みロック状態と同等の状態)で呼び出さなければ 00338 * ならない. 00339 */ 00340 extern void start_dispatch(void) NoReturn; 00341 00342 /* 00343 * 現在のコンテキストを捨ててディスパッチ(prc_support.S) 00344 * 00345 * exit_and_dispatchは,ext_tskから呼び出すべきもので,タスクコンテキ 00346 * スト・CPUロック状態・ディスパッチ許可状態・(モデル上の)割込み優先 00347 * 度マスク全解除状態で呼び出さなければならない. 00348 */ 00349 extern void exit_and_dispatch(void) NoReturn; 00350 00351 /* 00352 * カーネルの終了処理の呼出し(prc_support.S) 00353 * 00354 * call_exit_kernelは,カーネルの終了時に呼び出すべきもので,非タスク 00355 * コンテキストに切り換えて,カーネルの終了処理(exit_kernel)を呼び出 00356 * す. 00357 */ 00358 extern void call_exit_kernel(void) NoReturn; 00359 00360 /* 00361 * タスクコンテキストの初期化 00362 * 00363 * タスクが休止状態から実行できる状態に移行する時に呼ばれる.この時点 00364 * でスタック領域を使ってはならない. 00365 * 00366 * activate_contextを,インライン関数ではなくマクロ定義としているのは, 00367 * この時点ではTCBが定義されていないためである. 00368 */ 00369 extern void start_r(void); 00370 00371 #define activate_context(p_tcb) \ 00372 { \ 00373 (p_tcb)->tskctxb.msp = (void *)((char *)((p_tcb)->p_tinib->stk) \ 00374 + (p_tcb)->p_tinib->stksz); \ 00375 (p_tcb)->tskctxb.pc = (void *) start_r; \ 00376 } 00377 00378 /* 00379 * calltexは使用しない 00380 */ 00381 #define OMIT_CALLTEX 00382 00383 /* 00384 * 例外ベクタテーブルの構造の定義 00385 */ 00386 typedef struct exc_vector_entry { 00387 FP exc_handler; /* 例外ハンドラの起動番地 */ 00388 } EXCVE; 00389 00390 /* 00391 * 割込みハンドラ番号とCPU例外ハンドラ番号の範囲の判定 00392 */ 00393 #define VALID_INHNO_DEFINH(inhno) ((0x10U <= (inhno) && (inhno) <= 0x1fU) \ 00394 || (0x40U <= (inhno) && (inhno) <= 0xffU)) 00395 #define VALID_EXCNO_DEFEXC(excno) ((0x02U <= (excno) && (excno) <= 0x0fU) \ 00396 || (0x20U <= (excno) && (excno) <= 0x3fU)) 00397 00398 /* 00399 * 割込みハンドラの設定 00400 * 00401 * ベクトル番号inhnoの割込みハンドラの出入口処理の番地をint_entryに設 00402 * 定する. 00403 */ 00404 Inline void 00405 x_define_inh(INHNO inhno, FP int_entry) 00406 { 00407 EXCVE *excvt; 00408 00409 assert(VALID_INHNO_DEFINH(inhno)); 00410 00411 #ifdef EXCVT_KERNEL 00412 /* 00413 * EXCVT_KERNELが定義されている時は,初期化処理の中でVBRを 00414 * EXCVT_KERNELに設定するので,EXCVT_KERNELを使う. 00415 */ 00416 excvt = (EXCVE *) EXCVT_KERNEL; 00417 #else /* EXCVT_KERNEL */ 00418 excvt = (EXCVE *) current_vbr(); 00419 #endif /* EXCVT_KERNEL */ 00420 excvt[inhno].exc_handler = int_entry; 00421 } 00422 00423 /* 00424 * CPU例外ハンドラの設定 00425 * 00426 * ベクトル番号excnoのCPU例外ハンドラの出入口処理の番地をexc_entryに設 00427 * 定する. 00428 */ 00429 Inline void 00430 x_define_exc(EXCNO excno, FP exc_entry) 00431 { 00432 EXCVE *excvt; 00433 00434 assert(VALID_EXCNO_DEFEXC(excno)); 00435 00436 #ifdef EXCVT_KERNEL 00437 /* 00438 * EXCVT_KERNELが定義されている時は,初期化処理の中でVBRを 00439 * EXCVT_KERNELに設定するので,EXCVT_KERNELを使う. 00440 */ 00441 excvt = (EXCVE *) EXCVT_KERNEL; 00442 #else /* EXCVT_KERNEL */ 00443 excvt = (EXCVE *) current_vbr(); 00444 #endif /* EXCVT_KERNEL */ 00445 excvt[excno].exc_handler = exc_entry; 00446 } 00447 00448 /* 00449 * 割込みハンドラの出入口処理の生成 00450 */ 00451 00452 /* 00453 * 割込みハンドラの出入口処理のラベルを作るマクロ 00454 */ 00455 #define INT_ENTRY(inhno, inthdr) _kernel_##inthdr##_##inhno 00456 00457 /* 00458 * LOG_INH_ENTERがマクロ定義されている場合に,CALL_LOG_INH_ENTERを, 00459 * inhno_numをパラメータとしてlog_inh_enterを呼び出すアセンブリ言語コー 00460 * ドにマクロ定義する. 00461 */ 00462 #ifdef LOG_INH_ENTER 00463 00464 #define CALL_LOG_INH_ENTER(inhno_num) \ 00465 " move.l #" #inhno_num ", -(%sp) \n" /* inhno_numをパラメータに */ \ 00466 " jsr _kernel_log_inh_enter \n" /* log_inh_enterを呼び出す */ \ 00467 " addq.l #4, %sp \n" 00468 00469 #else /* LOG_INH_ENTER */ 00470 #define CALL_LOG_INH_ENTER(inhno_num) 00471 #endif /* LOG_INH_ENTER */ 00472 00473 #ifdef LOG_INH_LEAVE 00474 00475 /* 00476 * CALL_LOG_INH_LEAVEを,inhno_numをパラメータとしてlog_inh_leaveを呼 00477 * び出すアセンブリ言語コードにマクロ定義する. 00478 */ 00479 #define CALL_LOG_INH_LEAVE(inhno_num) \ 00480 " move.l #" #inhno_num ", -(%sp) \n" /* inhno_numをパラメータに */ \ 00481 " jsr _kernel_log_inh_leave \n" /* log_inh_leaveを呼び出す */ \ 00482 " addq.l #4, %sp \n" 00483 00484 /* 00485 * LOG_INH_LEAVEがマクロ定義されている場合の割込みハンドラの出入口処理. 00486 * 割込みハンドラをサブルーチンコールし,戻ってきたら,トレースログの 00487 * 取得後,ret_intに分岐する. 00488 */ 00489 #define INTHDR_ENTRY(inhno, inhno_num, inthdr) \ 00490 extern void _kernel_##inthdr##_##inhno(void); \ 00491 asm(".text \n" \ 00492 "_kernel_" #inthdr "_" #inhno ": \n" \ 00493 " movem.l %d0-%d1/%a0-%a1, -(%sp) \n" /* スクラッチレジスタを保存 */ \ 00494 CALL_LOG_INH_ENTER(inhno_num) \ 00495 " jsr " #inthdr " \n" /* 割込みハンドラを呼び出す */ \ 00496 CALL_LOG_INH_LEAVE(inhno_num) \ 00497 " jmp _kernel_ret_int \n");/* ret_intへ分岐 */ 00498 00499 #else /* LOG_INH_LEAVE */ 00500 00501 /* 00502 * LOG_INH_LEAVEがマクロ定義されていない場合の割込みハンドラの出入口処 00503 * 理.戻り番地としてret_intをスタックに積んだ後,割込みハンドラの起動 00504 * 番地に分岐する.割込みハンドラからのリターンにより,ret_intへ分岐す 00505 * る. 00506 */ 00507 #define INTHDR_ENTRY(inhno, inhno_num, inthdr) \ 00508 extern void _kernel_##inthdr##_##inhno(void); \ 00509 asm(".text \n" \ 00510 "_kernel_" #inthdr "_" #inhno ": \n" \ 00511 " movem.l %d0-%d1/%a0-%a1, -(%sp) \n" /* スクラッチレジスタを保存 */ \ 00512 CALL_LOG_INH_ENTER(inhno_num) \ 00513 " move.l #_kernel_ret_int, -(%sp) \n" /* 戻り番地をスタックに積む */ \ 00514 " jmp " #inthdr " \n");/* 割込みハンドラへ分岐 */ 00515 00516 #endif /* LOG_INH_LEAVE */ 00517 00518 /* 00519 * CPU例外ハンドラの出入口処理の生成 00520 * 00521 * CPU例外ハンドラは,非タスクコンテキストで実行する.そのため,CPU例 00522 * 外ハンドラを呼び出す前に割込みモードに移行し,リターンしてきた後に 00523 * 元のモードに戻す.元のモードに戻すために,割込みモードに移行する前 00524 * のSRを割込みスタック上に保存する(リターン先のSRを参照する手もある 00525 * が,タスクスタック上に保存される場合があり,参照するのが面倒). 00526 */ 00527 00528 /* 00529 * CPU例外ハンドラの出入口処理のラベルを作るマクロ 00530 */ 00531 #define EXC_ENTRY(excno, exchdr) _kernel_##exchdr##_##excno 00532 00533 /* 00534 * LOG_EXC_ENTERがマクロ定義されている場合に,CALL_LOG_EXC_ENTERを, 00535 * excno_numをパラメータとしてlog_exc_enterを呼び出すアセンブリ言語コー 00536 * ドにマクロ定義する. 00537 */ 00538 #ifdef LOG_EXC_ENTER 00539 00540 #define CALL_LOG_EXC_ENTER(excno_num) \ 00541 " move.l #" #excno_num ", -(%sp) \n" /* excno_numをパラメータに */ \ 00542 " jsr _kernel_log_exc_enter \n" /* log_exc_enterを呼び出す */ \ 00543 " addq.l #4, %sp \n" 00544 00545 #else /* LOG_EXC_ENTER */ 00546 #define CALL_LOG_EXC_ENTER(excno_num) 00547 #endif /* LOG_EXC_ENTER */ 00548 00549 #ifdef LOG_EXC_LEAVE 00550 00551 /* 00552 * CALL_LOG_EXC_LEAVEを,excno_numをパラメータとしてlog_exc_leaveを呼 00553 * び出すアセンブリ言語コードにマクロ定義する. 00554 */ 00555 #define CALL_LOG_EXC_LEAVE(excno_num) \ 00556 " move.l #" #excno_num ", -(%sp) \n" /* excno_numをパラメータに */ \ 00557 " jsr _kernel_log_exc_leave \n" /* log_exc_leaveを呼び出す */ \ 00558 " addq.l #4, %sp \n" 00559 00560 /* 00561 * LOG_EXC_LEAVEがマクロ定義されている場合のCPU例外ハンドラの出入口処 00562 * 理.CPU例外ハンドラをサブルーチンコールし,戻ってきたら,トレースロ 00563 * グの取得後,ret_excに分岐する. 00564 */ 00565 #define EXCHDR_ENTRY(excno, excno_num, exchdr) \ 00566 extern void _kernel_##exchdr##_##excno(void *sp); \ 00567 asm(".text \n" \ 00568 "_kernel_" #exchdr "_" #excno ": \n" \ 00569 " movem.l %d0-%d1/%a0-%a1, -(%sp) \n" /* スクラッチレジスタを保存 */ \ 00570 " lea.l 16(%sp), %a0 \n" /* 例外フレームの先頭をA0に */ \ 00571 " move.w %sr, %d0 \n" /* SRをD0に */ \ 00572 " and.w #~0x1000, %sr \n" /* 割込みモード(スタック切換え)*/ \ 00573 " move.l %d0, -(%sp) \n" /* 元のSRをスタックに保存 */ \ 00574 " move.l _kernel_lock_flag, %d0 \n" /* 元のlock_flagをスタックに保存 */ \ 00575 " move.l %d0, -(%sp) \n" \ 00576 " move.l %a0, -(%sp) \n" /* A0をパラメータとして渡す */ \ 00577 CALL_LOG_EXC_ENTER(excno_num) \ 00578 " jsr " #exchdr " \n" /* CPU例外ハンドラへ分岐 */ \ 00579 CALL_LOG_EXC_LEAVE(excno_num) \ 00580 " jmp _kernel_ret_exc \n");/* 戻り番地をスタックに積む */ 00581 00582 #else /* LOG_EXC_LEAVE */ 00583 00584 /* 00585 * LOG_EXC_LEAVEがマクロ定義されていない場合のCPU例外ハンドラの出入口 00586 * 処理.戻り番地としてret_excをスタックに積んだ後,CPU例外ハンドラの 00587 * 起動番地に分岐する.CPU例外ハンドラからのリターンにより,ret_excへ 00588 * 分岐する. 00589 */ 00590 #define EXCHDR_ENTRY(excno, excno_num, exchdr) \ 00591 extern void _kernel_##exchdr##_##excno(void *sp); \ 00592 asm(".text \n" \ 00593 "_kernel_" #exchdr "_" #excno ": \n" \ 00594 " movem.l %d0-%d1/%a0-%a1, -(%sp) \n" /* スクラッチレジスタを保存 */ \ 00595 " lea.l 16(%sp), %a0 \n" /* 例外フレームの先頭をA0に */ \ 00596 " move.w %sr, %d0 \n" /* SRをD0に */ \ 00597 " and.w #~0x1000, %sr \n" /* 割込みモード(スタック切換え)*/ \ 00598 " move.l %d0, -(%sp) \n" /* 元のSRをスタックに保存 */ \ 00599 " move.l _kernel_lock_flag, %d0 \n" /* 元のlock_flagをスタックに保存 */ \ 00600 " move.l %d0, -(%sp) \n" \ 00601 " move.l %a0, -(%sp) \n" /* A0をパラメータとして渡す */ \ 00602 CALL_LOG_EXC_ENTER(excno_num) \ 00603 " move.l #_kernel_ret_exc, -(%sp) \n" /* 戻り番地をスタックに積む */ \ 00604 " jmp " #exchdr " \n");/* CPU例外ハンドラへ分岐 */ 00605 00606 #endif /* LOG_EXC_LEAVE */ 00607 00608 /* 00609 * CPU例外の発生した時のコンテキストの参照 00610 * 00611 * CPU例外の発生した時のコンテキストが,タスクコンテキストの時にfalse, 00612 * そうでない時にtrueを返す. 00613 */ 00614 Inline bool_t 00615 exc_sense_context(void *p_excinf) 00616 { 00617 return((*((uint16_t *) p_excinf) & 0x1000U) == 0U); 00618 } 00619 00620 /* 00621 * CPU例外の発生した時のIPM(ハードウェアの割込み優先度マスク,内部表 00622 * 現)の参照 00623 */ 00624 Inline uint16_t 00625 exc_get_iipm(void *p_excinf) 00626 { 00627 return(*((uint16_t *) p_excinf) & 0x0700U); 00628 } 00629 00630 /* 00631 * CPU例外の発生した時のコンテキストと割込みのマスク状態の参照 00632 * 00633 * CPU例外の発生した時のシステム状態が,カーネル実行中でなく,タスクコ 00634 * ンテキストであり,割込みロック状態でなく,CPUロック状態でなく,(モ 00635 * デル上の)割込み優先度マスク全解除状態である時にtrue,そうでない時 00636 * にfalseを返す(CPU例外がカーネル管理外の割込み処理中で発生した場合 00637 * にもfalseを返す). 00638 * 00639 * M68040では,CPU例外の発生した時のIPM(ハードウェアの割込み優先度マ 00640 * スク)がすべての割込みを許可する状態であることをチェックすることで, 00641 * カーネル実行中でないこと,割込みロック状態でないこと,CPUロック状態 00642 * でないこと,(モデル上の)割込み優先度マスク全解除状態であることの 00643 * 4つの条件をチェックすることができる(CPU例外が発生した時の 00644 * lock_flagを参照する必要はない). 00645 */ 00646 Inline bool_t 00647 exc_sense_intmask(void *p_excinf) 00648 { 00649 return(!exc_sense_context(p_excinf) 00650 && exc_get_iipm(p_excinf) == IIPM_ENAALL); 00651 } 00652 00653 /* 00654 * CPU例外の発生した時のコンテキストと割込み/CPUロック状態の参照 00655 * 00656 * CPU例外の発生した時のシステム状態が,カーネル実行中でなく,タスクコ 00657 * ンテキストであり,割込みロック状態でなく,CPUロック状態でない時に 00658 * true,そうでない時にfalseを返す(CPU例外がカーネル管理外の割込み処 00659 * 理中で発生した場合にもfalseを返す). 00660 * 00661 * M68040では,CPU例外の発生した時のIPM(ハードウェアの割込み優先度マ 00662 * スク)がTIPM_LOCKより低いことをチェックすることで,カーネル実行中で 00663 * ないこと,割込みロック状態でないこと,CPUロック状態でないことの3つ 00664 * の条件をチェックしている(CPU例外が発生した時のlock_flagは参照して 00665 * いない).これにより,(モデル上の)割込み優先度マスクをTIPM_LOCKま 00666 * たはそれより高い値に設定してタスクを実行している時にもfalse が返っ 00667 * てしまうが,判断を正確にするためのオーバヘッドが大きいことから,許 00668 * 容することにする. 00669 */ 00670 Inline bool_t 00671 exc_sense_unlock(void *p_excinf) 00672 { 00673 return(!exc_sense_context(p_excinf) 00674 && exc_get_iipm(p_excinf) < IIPM_LOCK); 00675 } 00676 00677 /* 00678 * プロセッサ依存の初期化 00679 */ 00680 extern void prc_initialize(void); 00681 00682 /* 00683 * プロセッサ依存の終了時処理 00684 */ 00685 extern void prc_terminate(void); 00686 00687 /* 00688 * atexitの処理とデストラクタの実行 00689 */ 00690 Inline void 00691 call_atexit(void) 00692 { 00693 extern void software_term_hook(void); 00694 void (*volatile fp)(void) = software_term_hook; 00695 00696 /* 00697 * software_term_hookへのポインタを,一旦volatile指定のあるfpに代 00698 * 入してから使うのは,0との比較が最適化で削除されないようにするた 00699 * めである. 00700 */ 00701 if (fp != 0) { 00702 (*fp)(); 00703 } 00704 } 00705 00706 #endif /* TOPPERS_MACRO_ONLY */ 00707 #endif /* TOPPERS_PRC_CONFIG_H */
Copyright © 2008 by Kijineko Inc.