割込み管理機能

割込み管理機能は、外部割込みおよびCPU例外に対するハンドラの定義などの操作を行うための機能である。

割込みハンドラは、タスク独立部として扱われる。タスク独立部でも、タスク部と同じ形式でシステムコールを発行することが可能であるが、タスク独立部で発行できるシステムコールには以下のような制限がつく。

タスク独立部の実行中はタスクの切り換え(ディスパッチ)は起らず、システムコールの処理の結果ディスパッチの要求が出されても、タスク独立部を抜けるまでディスパッチが遅らされる。これを遅延ディスパッチ(delayed dispatching)の原則と呼ぶ。

tk_def_int - 割込みハンドラ定義

C言語インタフェース

#include <tk/tkernel.h>

ER ercd = tk_def_int (UINT intno , CONST T_DINT *pk_dint );

パラメータ

UINT intno Interrupt Number割込み番号
CONST T_DINT* pk_dint Packet to Define Interrupt Handler割込みハンドラ定義情報

pk_dint の内容

ATR intatr Interrupt Handler Attribute割込みハンドラ属性
FP inthdr Interrupt Handler Address割込みハンドラアドレス
──(以下に実装独自に他の情報を追加してもよい)──

リターンパラメータ

ER ercd Error Codeエラーコード

エラーコード

E_OK 正常終了
E_NOMEM メモリ不足(管理ブロック用の領域が確保できない)
E_RSATR 予約属性(intatr が不正あるいは利用できない)
E_PAR パラメータエラー(intno, pk_dint, inthdr が不正あるいは利用できない)

利用可能なコンテキスト

タスク部準タスク部タスク独立部
×

関連するサービスプロファイル

TK_SUPPORT_ASM TA_ASMのアラームハンドラ属性指定が可能

解説

割込みには、デバイスからの外部割込みと、CPU例外による割込みの両方を含む。

intno で示される割込み番号に対して割込みハンドラを定義し、割込みハンドラを使用可能にする。すなわち、intno で示される割込み番号と割込みハンドラのアドレスや属性との対応付けを行う。

intno は、割込みの種類を区別するための番号である。その具体的な意味は実装ごとに定義されるが、一般には、CPUハードウェアの割込み処理で定義される割込み番号(IRQ番号など)をそのまま使うか、その番号との対応付けが可能な何らかの番号を使う。

intatr は、下位側がシステム属性を表し、上位側が実装独自属性を表す。intatr のシステム属性の部分では、次のような指定を行う。

intatr := (TA_ASM || TA_HLNG)

TA_ASM 対象ハンドラがアセンブリ言語で書かれている
TA_HLNG 対象ハンドラが高級言語で書かれている

#define TA_ASM          0x00000000      /* アセンブリ言語によるプログラム */
#define TA_HLNG         0x00000001      /* 高級言語によるプログラム */

TA_ASM 属性の場合、原則として、割込みハンドラの起動時にはカーネルが介入しない。割込み発生時には、CPUハードウェアの割込み処理機能により、このシステムコールで定義した割込みハンドラが直接起動される(実装によってはプログラムによる処理が含まれる場合もある)。したがって、割込みハンドラの先頭と最後では、割込みハンドラで使用するレジスタの退避と復帰を行う必要がある。割込みハンドラは、tk_ret_int システムコールまたはCPUの割込みリターン命令(またはそれに相当する手段)によって終了する。

tk_ret_int を使用せずにカーネルを介すことなく割込みハンドラから復帰する手段は必須である。ただし、tk_ret_int を使用しない場合は、遅延ディスパッチが行われなくてもよい。

tk_ret_int による割込みハンドラからの復帰も必須であり、この場合は遅延ディスパッチが行われなければならない。

TA_HLNG 属性の場合は、高級言語対応ルーチンを経由して割込みハンドラを起動する。高級言語対応ルーチンによって、レジスタの退避と復帰が行われる。割込みハンドラは、C言語関数からのリターンによって終了する。TA_HLNG 属性の場合の割込みハンドラは次の形式となる。

void inthdr( UINT intno )
{
        /*
                割込み処理
        */

        return; /* 割込みハンドラの終了 */
}

割込みハンドラに渡される intno は、発生した割込みの種類を区別するための番号で、tk_def_int で指定するものと同一である。実装によっては、intno 以外にも発生した割込みに関する情報が渡される場合がある。このような情報がある場合は、割込みハンドラの2番目以降のパラメータとして実装ごとに定義する。

TA_HLNG 属性の場合、割込み発生から割込みハンドラが呼び出されるまで、CPUの割込みフラグは割込み禁止状態であるものとする。つまり、割込み発生直後から多重割込みが禁止された状態であり、多重割込みが禁止された状態のまま割込みハンドラが呼び出される。多重割込みを許可する場合は、割込みハンドラ内でCPUの割込みフラグを操作して許可する必要がある。

また、TA_HLNG 属性の場合は、割込みハンドラに入った時点で、システムコールの呼出が可能な状態となっていなければならない。ただし、上述の機能を標準とした上で、多重割込みを許可した状態で割込みハンドラに入る機能を追加するなどの拡張は許される。

TA_ASM 属性の場合、割込みハンドラに入った時点の状態は実装ごとに定義される。割込みハンドラに入った時点のスタックやレジスタの状態、システムコールの呼出の可否、システムコールを呼び出せるようにする方法、および割込みハンドラからカーネルを介さずに復帰する方法などが明確に定義されていなければならない。

TA_ASM 属性の場合、実装によっては、割込みハンドラ実行中もタスク独立部として判定されない場合がある。タスク独立部として判定されない場合は、次の点に注意が必要である。

  • 割込みを許可すると、タスクディスパッチが発生する可能性がある。

  • システムコールを呼び出した場合、タスク部または準タスク部から呼び出したものとして処理される。

なお、割込みハンドラ内で何らかの操作を行ってタスク独立部として判定させる方法がある場合は、実装ごとにその方法を示すものとする。

TA_HLNG, TA_ASM 属性のいずれの場合も、割込みハンドラに入った時点では、割込みが発生した時点の論理空間を維持している。また、割込みハンドラからの復帰時に論理空間を割込み発生時点の状態に戻す処理は行われない。割込みハンドラ内での論理空間の切替は禁止されないが、論理空間を切り替えた場合の影響もカーネルでは関知しない。

割込みハンドラの中でシステムコールを発行することにより、それまで実行状態(RUNNING)であったタスクがその他の状態に移行し、代わりに別のタスクが実行状態(RUNNING)となった場合でも、割込みハンドラ実行中はディスパッチ(実行タスクの切り替え)が起こらない。ディスパッチングが必要になっても、まず割込みハンドラを最後まで実行することが優先され、割込みハンドラを終了する時にはじめてディスパッチが行われる。すなわち、割込みハンドラ実行中に生じたディスパッチ要求はすぐに処理されず、割込みハンドラ終了までディスパッチが遅らされる。これを遅延ディスパッチの原則と呼ぶ。

割込みハンドラはタスク独立部として実行される。したがって、割込みハンドラの中では、待ち状態に入るシステムコールや、自タスクの指定を意味するシステムコールを実行することはできない。

pk_dintNULL とした場合には、前に定義した割込みハンドラの定義解除を行う。割込みハンドラの定義解除状態では、システムの定義するデフォルトハンドラが設定される。

既に定義済みの割込み番号に対して、割込みハンドラを再定義することも可能である。再定義のときにも、あらかじめその番号のハンドラの定義解除を行っておく必要はない。既に割込みハンドラが定義された intno に対して新しいハンドラを再定義しても、エラーにはならない。

補足事項

TA_ASM 属性に関する種々の規定は、主に割込みのフックを行うためのものである。例えば、不正アドレスのアクセスによる例外の場合、通常は上位のプログラムで定義した割込みハンドラによって例外を検出してエラー処理を行うが、デバッグ中の場合は上位のプログラムでエラー処理を行う代りに、システムの定義するデフォルトの割込みハンドラに処理させてデバッガを起動するというようなことを行う。この場合、上位のプログラムで定義した割込みハンドラは、システムの定義するデフォルトの割込みハンドラをフックする形になる。そして、状況に応じてデバッガ等のシステムプログラムに割込み処理を引き渡すか、そのまま自身で処理することになる。

tk_ret_int - 割込みハンドラから復帰

C言語インタフェース

#include <tk/tkernel.h>

void tk_ret_int ( void );

C言語インタフェースは形式として定義されるが、高級言語対応ルーチンを使用した場合には呼び出されることがない。

リターンパラメータ

※ システムコールを発行したコンテキストには戻らない

エラーコード

※ 次のようなエラーを検出する可能性があるが、エラーを検出した場合でも、システムコールを発行したコンテキストには戻らない。したがって、システムコールのリターンパラメータとして直接エラーコードを返すことはできない。万一エラーを検出した場合の動作は、実装依存となる。

E_CTX コンテキストエラー(割込みハンドラ以外から発行,実装依存)

利用可能なコンテキスト

タスク部準タスク部タスク独立部
××

関連するサービスプロファイル

以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。

TK_SUPPORT_ASM TA_ASM属性の割り込みハンドラをサポート

解説

割込みハンドラを終了する。

割込みハンドラの中でシステムコールを実行してもディスパッチは起らず、tk_ret_int によって割込みハンドラを終了するまでディスパッチが遅延させられる(遅延ディスパッチの原則)。そのため、tk_ret_int では、割込みハンドラの中から発行されたシステムコールによるディスパッチ要求がまとめて処理される。

tk_ret_intTA_ASM 属性の割込みハンドラの場合にのみ呼び出す。TA_HLNG 属性の割込みハンドラの場合は、高級言語対応ルーチン内で暗黙に tk_ret_int 相当の機能が実行されるので、tk_ret_int を明示的には呼び出さない(呼び出してはいけない)。

TA_ASM 属性の場合、原則として、割込みハンドラの起動時にはカーネルが介入しない。割込み発生時には、CPUハードウェアの割込み処理機能により、割込みハンドラが直接起動される。そのため、割込みハンドラで使用するレジスタの退避や復帰は割込みハンドラの中で行わなければならない。

また、この理由により、tk_ret_int を発行した時のスタックやレジスタの状態は、割込みハンドラへ入った時と同じでなければならず、この関係で tk_ret_int では機能コードを使用できないことがある。この場合は、他のシステムコールとは別ベクトルのトラップ命令を用いて tk_ret_int を実現する。

補足事項

tk_ret_int は発行元のコンテキストに戻らないシステムコールである。したがって、何らかのエラーを検出した場合にエラーコードを返しても、これらのシステムコールを呼んだ側ではエラーのチェックを行っていないのが普通であり、プログラムが暴走する可能性がある。そこで、これらのシステムコールでは、エラーを検出した場合にも、システムコール発行元へは戻らないものとする。

割込みハンドラから戻っても、ディスパッチが起こらない(必ず同じタスクが実行を継続する)ことがはっきりしている、またはディスパッチしなくても構わない場合には、tk_ret_int ではなく、アセンブリ言語の割込みリターン命令によって割込みハンドラを終了しても構わない。

また、CPUのアーキテクチャやカーネルの構成法によっては、アセンブリ言語の割込みリターン命令によって割込みハンドラを終了しても、遅延ディスパッチが可能となる場合がある。このような場合は、アセンブリ言語の割込みリターン命令がそのまま tk_ret_int のシステムコールであると解釈しても構わない。

タイムイベントハンドラから tk_ret_int を呼んだ場合の E_CTX のエラーチェックは実装依存である。実装によっては、種類の違うハンドラからそのままリターンしてしまう場合がある。