x86_64アーキテクチャ

タスク

f:id:babyron64:20171225220310j:plain

タスクは、プロセッサがディスパッチ(=dispatch)・実行(=execute)・中断(=suspend)を行う処理単位。プロテクティッドモードでは、すべての処理はいずれかのタスク内で行われる。そして、OSは少なくとも一つのタスクを作らなくてはならない。タスクは、実行部とタスク状態セグメントに分けられる。実行部は、コードセグメントやスタックセグメント等から成っており、その中でタスクの処理が行われる。

タスクスイッチングは、64-Bitにおいてプロセッサが行うことはできない(ie. ソフトウェアが行う)ので、詳細は割愛する。

タスク状態セグメント(=task-state segment or TSS)

f:id:babyron64:20171225233708j:plain

タスク状態セグメントは、現在実行しているタスクの状態を保持する。32-BitのTSSで保持される情報は、上図参照。64-BitのTSSは、後述。LDTRレジスタとCR3レジスタが保持されているので、各タスクごとに別のセグメント機構とページング機構を用意できる。つまり、タスクごとに仮想メモリ空間を用意できる。SS0~SS2(一般にSS n)およびESP0~ESP2(一般にESP n)はそれぞれ、CPLがnの時に使われるスタックセグメントとスタックポインタ。今までの説明でいうと、特権レベルをまたぐコールで、スタックスイッチが起こった時にロードされるものだ。

f:id:babyron64:20171225224815j:plain

上図は64-BitのTSS。ISTは割り込み・例外処理に使われる。RSP0~RSP2(一般にRSP n)は、CPLがnの時に使われるスタックポインタ。スタックセグメントがないのは、64-Bitの時にはスタックセグメントのベースアドレスが0として扱われるので、指定する意味がないから(だと思う)。

f:id:babyron64:20171225233724j:plain 現在実行されているタスクのTSSのセレクタは、TR(=Tast register)レジスタに保持される。

ビジーフラグ(=busy flag)

TSSは、言うまでもなく一つのタスクの状態しか保持できない。それゆえ、同じタスクが再帰的に(=recursively)呼ばれると、元のタスクの情報が失われてしまう。これを防ぐために、プロセッサはタスクをディスパッチングする時にTSSディスクリプタのビジーフラグをセットし、再帰的に呼ばれるのを防ぐ。

タスクリンキング(=task linking)

f:id:babyron64:20171225232353j:plain CALL命令などによりタスクスイッチが起こると、プロセッサはEFLAGSレジスタのNTフラグをセットし、新しくディスパッチされたタスクのTSSのprevious task linkフィールドに、元のタスクのTSSセレクタを保存する。すなわち、EFLAGS.NTがセットされていることは、現在のタスクが他のタスクの入れ子になっていることを意味する。リターン時にEFLAGS.NTがセットされている場合、プロセッサはprevious task linkで示されているタスクに実行を移す。JMP命令によるタスクスイッチでは、この処理は行われない。そのため、タスクを完全に離れるためには、JMP命令のタスクスイッチを使う。

タスクゲート(=task gate)

タスクゲートは、コールゲートに似ている。使い方は同じだが、CALLとJMPの挙動の差がコールゲートの時よりも大きい(前述)。プロセッサによるタスクスイッチは64-Bitでは使えないため、64-BitにおいてCALL命令等でタスクゲートを指定することはできない。詳細は割愛。