読者です 読者をやめる 読者になる 読者になる

不確定特異点

広く深く、ところどころ超深く

軽量 RTOS の開発 (3)

タスクを特権モードではなくユーザモードで動作させるのは、ちょっとしたトリックを使うと簡単に実現できました。例外発生により割り込みがかかると、LR レジスタには EXC_RETURN という特殊な値が格納されます。この EXC_RETURN の値は、例外発生時点に復帰するためのモードやスタックポインタを表します。

  • EXC_RETURN = 0xFFFFFFF1

    ハンドラモードに復帰してスタックポインタは MSP を使用する

  • EXC_RETURN = 0xFFFFFFF9

    特権モードに復帰してスタックポインタは MSP を使用する

  • EXC_RETURN = 0xFFFFFFFD

    ユーザモードに復帰してスタックポインタは PSP を使用する

さてここで、特権モードから SVC 例外を起こしたとして、その例外ハンドラの中で EXC_RETURN の値をわざと 0xFFFFFFFD に書き換えて、さらにリターンアドレスを新たに実行したいタスクのアドレスに書き換えた上で、例外ハンドラからリターンさせます。すると、リターンアドレスで指定したタスクから制御が再開され、その上、ユーザモードに切り替わっていてスタックは PSP で指されるアドレスを使うことになります。つまり、PC と SP とモードを一挙に変更することができます。めでたし!

なのですが、現状の自作 RTOS はコンテキスト切り替えだけという単機能のものなのに、改めて考えると色々検討できてない部分があります。例えば、割り込みハンドラを実行中に多重割り込みが入った場合でも、元の割り込みハンドラに戻ったときに整合がとれるのか?(タスクを終了するシステムコール実行中はカレントタスクが存在しないので、SysTick 割り込みが入ったときに、TCB を参照してはいけない)とか、SVC ハンドラで必ず PendSV を実行してスケジューラを呼んでいるけど、本当は再スケジューリングが必要なところ、つまりタスクの状態に変化が起きた場合のみに限定するべきなのでは?とか…。その辺の細かい部分を地道に直しつつ、並行して既存の ITRON や OSEK/VDX などのメジャーな RTOS の仕様を覗いてみようと思います。