タスク状態セグメント( TSS ) は、タスクに関する情報を保持するx86ベースのコンピュータ上の構造体です。これは、タスク管理のためにオペレーティング システムカーネルによって使用されます。具体的には、次の情報が TSS に保存されます。
- プロセッサレジスタの状態
- I/Oポートの権限
- 内部レベルのスタックポインタ
- 以前のTSSリンク
この情報はすべて、 IA-32マニュアルに指定されているように、TSS 内の特定の場所に保存する必要があります。
TSSの場所
TSS はメモリ内のどこにでも配置できます。タスク レジスタ (TR) と呼ばれるセグメント レジスタには、GDT内に存在する有効な TSS セグメント記述子を指すセグメント セレクタが保持されます (TSS 記述子はLDT内には配置できません)。したがって、TSS を使用するには、オペレーティング システム カーネルで次の操作を実行する必要があります。
- GDTにTSS記述子エントリを作成する
- そのセグメントのセグメントセレクターを使用してTRをロードします
- 必要に応じてメモリ内のTSSに情報を追加する
セキュリティ上の理由から、TSS はカーネルのみがアクセスできるメモリに配置する必要があります。
タスクレジスタ
TR レジスタは、TSS のセグメント セレクタを保持する 16 ビット レジスタです。LTR命令を使用してロードできます。LTR は特権命令であり、他のセグメント レジスタのロードと同様に動作します。タスク レジスタには 2 つの部分があります。プログラマが表示およびアクセスできる部分と、TSS 記述子から自動的にロードされる非表示の部分です 。
登録状態
TSS には、すべてのx86レジスタの保存された値が含まれる場合があります。これはタスク切り替えに使用されます。オペレーティングシステムは、新しいタスクに必要なレジスタの値を TSS にロードし、ハードウェアタスクスイッチ (IRET 命令など) を実行した後、x86 CPU は TSS から保存された値を適切なレジスタにロードします。WindowsやLinux [1]などの一部の最新のオペレーティングシステムでは、ソフトウェアタスク切り替えを実装しているため、TSS のこれらのフィールドを使用しないことに注意してください。
ハードウェア タスクの切り替え中は、新しいTSSの値が読み取られる前に、古いTSS の特定のフィールドが CPU の現在のレジスタの内容で更新されることに注意してください。したがって、一部の TSS フィールドは読み取り/書き込み可能で、その他のフィールドは読み取り専用です。
- 読み取り/書き込みフィールド: ハードウェア タスクの切り替え中に読み取りおよび書き込みが行われます。
- すべての汎用レジスタ(
EAX、、、、、、、、、)EBXECXEDXESIEDIEBPESP - すべてのセグメントレジスタ(
CS、、、、、、)。DSESFSGSSS - 現在の実行状態 (
EIP、EFlags); - タスク切り替えがではなくまたはによるものである場合、新しい
LinkTSSのフィールド。CALLINTJMP
- すべての汎用レジスタ(
- 読み取り専用フィールド: 示されているように、必要な場合にのみ読み取ります。
- 制御レジスタ 3 (
CR3)。ページ ディレクトリ ベース レジスタ ( ) とも呼ばれますPDBR。- ハードウェア タスクの切り替え中に読み取ります。
- ローカル記述子テーブルレジスタ(
LDTR)- ハードウェア タスクの切り替え中に読み取ります。
- 3 つの特権レベル スタック ペア ( 、、
SS0:ESP0) 。SS1:ESP1SS2:ESP2- レベル間で読み取り
CALL、またはINT新しいスタックを確立します。
- レベル間で読み取り
- IO ポート ビットマップ ポインタ (
IOPB) と I/O ポート ビットマップ自体。IN、、または命令の実行中にOUT、命令が正当であるかどうかを確認するために読み取ります(以下の I/O ポート権限を参照)。INSOUTSCPL > IOPL
- 制御レジスタ 3 (
フィールドPDBRは、実際には新しい TSS から読み取られる最初のフィールドです。ハードウェア タスク スイッチによって完全に異なるページ テーブル マッピングに切り替えることもできるため、他のすべてのフィールド (特にLDTR) は新しいマッピングを基準とします。
I/Oポートの権限
TSS には、現在のタスクの I/O ポート許可ビットマップへの 16 ビット ポインタが含まれています。このビットマップは、通常、タスクの開始時にオペレーティング システムによって設定され、プログラムがアクセスする必要がある個々のポートを指定します。I/O ビットマップは、ポート アクセス許可のビット配列です。プログラムがポートにアクセスする許可を持っている場合は、対応するビット インデックスに「0」が格納され、プログラムが許可を持っていない場合は、「1」が格納されます。TSS のセグメント制限が完全なビットマップより小さい場合は、不足しているすべてのビットが「1」であると見なされます。
この機能は次のように動作します。プログラムが IN や OUT などの x86 I/O ポート命令を発行すると ( x86 命令リストを参照してください。バイト、ワード、および dword の長さのバージョンがあることに注意してください)、ハードウェアは I/O 特権レベル (IOPL) チェックを実行して、プログラムがすべての I/O ポートにアクセスできるかどうかを確認します。プログラムの現在の特権レベル (CPL)が I/O 特権レベル (IOPL) よりも数値的に大きい場合 (プログラムの特権が IOPL で指定されているものよりも低い場合)、プログラムはすべてのポートに I/O ポート アクセスできません。次に、ハードウェアは TSS の I/O 許可ビットマップをチェックして、そのプログラムが IN または OUT 命令の特定のポートにアクセスできるかどうかを確認します。I/O ポート許可ビットマップの関連ビット (すべて) がクリアされている場合、プログラムはポートへのアクセスを許可され、命令の実行が許可されます。関連するビットが設定されている場合、またはビットが TSS のセグメント制限を超えている場合、プログラムはアクセスできず、プロセッサは一般保護違反を生成します。この機能により、オペレーティング システムはユーザー プログラムに選択的なポート アクセスを許可できます。
内部レベルのスタックポインタ
TSS には、特権レベルの変更が発生したときに新しいスタック ポインターを指定するための 6 つのフィールドが含まれています。フィールド SS0 には CPL=0 のスタック セグメント セレクターが含まれ、フィールド ESP0/RSP0 には CPL=0 の新しい ESP/RSP 値が含まれます。保護 (32 ビット) モードで割り込みが発生すると、 x86 CPU は TSS で SS0 と ESP0 を検索し、その値をそれぞれ SS と ESP にロードします。これにより、カーネルはユーザー プログラムとは異なるスタックを使用でき、このスタックを各ユーザー プログラムごとに一意にすることができます。
AMD64拡張機能で導入された新しい機能は、割り込みスタック テーブル (IST) と呼ばれ、これも TSS 内に存在し、論理 (セグメント + オフセット) スタック ポインターを含んでいます。割り込み記述子テーブルが使用する IST エントリ (7 つあります) を指定している場合、プロセッサは代わりに IST から新しいスタックをロードします。これにより、重大なエラー ( NMIやDouble Faultなど) が発生した場合に、既知の正常なスタックを使用できます。以前は、IDT 内の例外または割り込みのエントリがタスク ゲートを指していたため、プロセッサはタスク ゲートによって指されているタスクに切り替えていました。元のレジスタ値は、割り込みまたは例外が発生した時点での TSS に保存されていました。次に、プロセッサは SS:ESP を含むレジスタを TSS で指定された既知の値に設定し、セレクターを以前の TSS に保存しました。ここでの問題は、ハードウェア タスク切り替えが AMD64 ではサポートされていないことです。
以前のTSSリンク
これは、この TSS を前の TSS にリンクできるようにする 16 ビット セレクタです。これは、ハードウェア タスクの切り替えにのみ使用されます。詳細については、 IA-32 のマニュアルを参照してください。
Linux での TSS の使用
TSS はコンピュータ上で実行されているタスクごとに作成できますが、Linux カーネルは各 CPU に対して 1 つの TSS のみを作成し、それをすべてのタスクに使用します。このアプローチが選択された理由は、他のアーキテクチャへの移植性が容易になり (たとえば、AMD64アーキテクチャはハードウェア タスク スイッチをサポートしていません)、パフォーマンスと柔軟性が向上するためです。Linux は、TSS の I/O ポート パーミッション ビットマップと内部スタック機能のみを使用します。その他の機能はハードウェア タスク スイッチにのみ必要であり、Linux カーネルは使用しません。[2]
TSSに関連する例外
x86例外ベクター 10 は、無効 TSS 例外 (#TS) と呼ばれます。これは、TSS アクセスで問題が発生するたびにプロセッサによって発行されます。たとえば、CPL=3 で割り込みが発生し、制御が CPL=0 に転送される場合、TSS を使用してスタック スイッチの SS0 と ESP0/RSP0 が抽出されます。タスク レジスタに不正な TSS セレクタが保持されている場合、#TS フォールトが生成されます。無効 TSS 例外は、通常のオペレーティング システム操作中に発生することはなく、常にカーネル バグまたはハードウェア障害に関連しています。
TSS例外の詳細については、IA-32マニュアルの第3a巻第6章を参照してください。[3]
x86-64 モードの TSS
x86-64アーキテクチャはハードウェア タスク スイッチをサポートしていません。ただし、TSS は 64 ビット拡張モードで実行されているマシンでも使用できます。これらのモードでは、TSS は次のものを保存できるので便利です。
- 各特権レベルのスタック ポインター アドレス。
- 割り込みスタック テーブルのポインタ アドレス (上記の内部レベル スタック ポインタのセクションで、これの必要性について説明しています)。
- IO 許可ビットマップのオフセット アドレス。
また、これらのモードではタスク レジスタが拡張され、64 ビットのベース アドレスを保持できるようになります。
参考文献
外部リンク
- TSSを使用したデモンストレーションプログラム
