ColdFire V1がやって来た スーパーバイザーでラウンドロビン [ColdFire V1]
全然終わっていないじゃん。
さて、某企みの為にタスクスイッチ周りを研究している訳です。
前回まで行ったラウンドロビンでは、タスクをユーザーモードで動かしていました。なんとなく、ただなんとなくそれが正当なやり方に思えたからですけれど。
しかし某企みでは、タスクコンテキスト部の中からも、一時的に割り込み禁止にする必要が有ります。これがSRレジスタをいじる必要性からユーザーモードでは出来ないんです。
そこで今度はスーパーバイザーモードでラウンドロビンを行ってみます。
まずmainの中の初期化ですが、
/*タスクの初期化*/
for( i = 1; i < MAX_TID_NUMBER; i++ )
{
/*2番目のタスクから、既にスタック上にコンテキストが保存されている様に見せかける*/
c_text = (TASK_CONTEXT *)((char *)tcb[ i ].sp - sizeof(TASK_CONTEXT));
c_text->pc = tcb[ i ].fn; /*起動関数のアドレス*/
c_text->ccr = 0x40002000; /*SRレジスタの初期値*/
c_text->d[0] = tcb[ i ].exinf; /*起動時パラメータ*/
c_text->a[5] = _A5; /*?*/
tcb[ i ].sp = c_text; /*これらが保存された後のスタックアドレス*/
}
また、最初のタスクの起動部分は、
__asm {
move.l sp,INT_SSP //割り込みスタックポインタを保存する領域にコピー
movea.l tcb[0].sp,sp //タスクコントロールブロックからタスクスタックを取得する
movea.l tcb[0].fn,a0 //タスクコントロールブロックから起動関数のアドレスを取得する
move.l tcb[0].exinf,d0 //起動時パラメータ
move.w SR,d1 //
andi.l #0xF8FF,d1 //割り込み許可
move.w d1,SR
jmp (a0) //最初のタスクへジャンプ
};
と、微妙に変更されているのが判ります。また、ユーザーモードに入らないので、SRレジスタのSbitのクリアは行っていません。
”exceptios.c”ではアセンブラのハンドラを以下の様に変更しています。
asm void asm_isr_handler( void )
{
move.w #0x2700,SR /*一時的に多重割り込みを禁止している*/
lea -60(sp),sp /*スタックに、汎用レジスタを保存する領域の確保*/
movem.l d0-d7/a0-a6,(sp) /*汎用レジスタの保護*/
lea 60(sp),a0 /*A0レジスタにフレームポインタを代入*/
move.l sp,a1 /*カレントユーザースタックを取得*/
move.l INT_SSP,sp /*割り込みスタックに切り換え*/
jsr C_isr_handler /*C言語での処理ルーチン*/
movea.l a0,sp /*戻り値のユーザースタックをSSPに代入*/
movem.l (sp), d0-d7/a0-a6 /*汎用レジスタの復帰*/
lea 60(sp), sp /*使用スタックの破棄*/
rte /*・・・ヽ (´ー`)┌ */
}
大体同じなのですが、タスクスタックにレジスタ類を保存後、割り込み専用スタックに切り換えを行っています。
C言語のハンドラですが、ここが最も大きく変更された所です。変更の有ったタスクスイッチのところだけ掻い摘んで紹介すると、
if( DelayedDispatch == TRUE ) /*遅延ディスパッチが必要な時*/
{
/*コンテキストの保存*/
tcb[ RunningTaskID ].sp = usp; /*スタックポインタをタスクコントロールブロックに保存*/
/*次のタスクIDを取得*/
if( ++RunningTaskID >= MAX_TID_NUMBER ) RunningTaskID = 0;
/*次のコンテキストの取り出し*/
usp = tcb[ RunningTaskID ].sp; /*タスクコントロールブロックからスタックポインタの取り出し*/
}
とやけに短くなっています。要するにユーザーモードで行っていたメモリ/メモリ間の転送が無くなったのです。
マルチタスクシステムではどうしてもタスクスイッチの切り換え時間が性能として出てしまいますので、今度の方式は期待できるでしょう。
と言う訳で、参考のプロジェクトはここから。
> タスクコンテキスト部の中からも、一時的に
> 割り込み禁止にする必要が有ります。
1) 「割り込みをレベルを設定するサービスコールを新設する」
2) 「一時的に割り込み禁止にする部分をサービスコールにまとめる」
というのは、いかがでしょうか。1)案は、RTOSとしては、どうなんでしょう。
とにかく、「おバカなプログラムが暴れてもオペレーティング・システムは止まらない」というのが、ユーザ・モードの存在意義ですので、優秀なプログラムだけ使うのであれば、スーパバイザ・モードだけでも十分だと思います。
68000の場合には、メモリ空間まで別々にして保護していましたが、QE128の場合には、そこまで分離されてはいませんね。
by noritan (2008-01-22 08:13)
> 「おバカなプログラムが暴れてもオペレーティング・システムは止まらない」
実は、μITRON仕様の基本にあるのは、「おバカなプログラムが暴れてもオペレーティング・システムは止まらない」様に、リリース前にきっちり詰めて置けよ!だと思うんです。
これはμITRONの歴史的な経緯だと思います。つまり、始めに8bitとか16bitの小規模なマイコンを対象にしたμITRON系と、32bit以上の大規模なマイコン?を対象にしたITRON系が有りましたが、ver.3からはこれらが統合され、その際、実装を軽くする為にμITRON系の考え方を取ったのだと思われます。
しかし近年大規模プログラミングでこの考え方が上手く行かない事が顕在化してきたので、拡張仕様としてメモリ保護仕様が出ています。
あのOSの実装依存部だけで、ユーザーモードから上手い事割り込みマスクを掛けられる方法が見つかれば良いのですが。
by hamayan (2008-01-22 09:22)
なるほど、安全第一のUNIXの考え方とは違うのかもしれないですね。UNIXの時代は、メモリさえ安全ではないと思われていたらしく、何でもファイルに入っていたのを思い出しました。
「おバカなプログラムが暴れてもオペレーティング・システムは止まらない」を犠牲にしたオペレーティング・システムは、16-bitの時代にもありましたよね。MS-D*SとかWind*wsとか。
X68000の資料をを調べたところ、"DOS _SUPER"というサービス・コールがありました。「スーパバイザ・モードとユーザ・モードを切り替える」機能だそうです。だったら、ユーザ・モードなんか、いらないジャン。
by noritan (2008-01-22 12:19)