GDTR,IDTRとは
Pentiumなどx86系のCPUの解説を読んでいると,ときどきGDTRやIDTRという言葉が出てきますが,詳しく教えてください。
GDTRやIDTRはIA-32のレジスタのうち,システムレジスタ群に属しています。システムレジスタは一般にOSだけが操作可能なレジスタですから,プログラマが触ることは滅多にありません。
まず,GDTRから説明しましょう。インテルCPUの源流となった8086では,メモリは64KB単位のセグメントブロックで管理されていました。メモリアドレスは,コードセグメント(CS),データセグメント(DS),スタックセグメント(SS),拡張セグメント(ES)の各16ビットレジスタに格納されているセグメントベースアドレス(の上位16ビット)からの16ビットオフセットとして表現されます。
しかし,80286から扱えるメモリが16MBに拡張され,さらにIA-32では最大4GBのメモリが扱えるようになりました。その結果,前述したようなセグメントの切り方は事実上,不可能になってしまいます。
そこでインテルは,セグメントレジスタの代わりに,セグメントレジスタに指し示されるセグメントディスクリプタテーブルによってメモリを管理する仕組みを取り入れました。従来のセグメントレジスタに格納されている16ビット値は「セグメントディスクリプタテーブルのオフセット」となります。そして,GDTRに入っている値はメモリ中に設けられたセグメントディスクリプタテーブルのアドレス(と大きさ)を表しています。
GDTRは48ビットのレジスタで,そのうち16ビットがセグメントディスクリプタテーブルの大きさ(リミット値),残り32ビットにセグメントディスクリプタテーブルのアドレスが格納されます。
例えば,セグメントレジスタ(IA-32ではセレクタという)の値が1だったとき,CPUはまずGDTRに指し示されているセグメントディスクリプタテーブルの1番めの「セグメントディスクリプタ」を参照します。
一つのセグメントディスクリプタは次のような構造を持っています。
オフセット |
内 容 |
0 |
セグメントリミットの下位16ビット |
1 |
2 |
セグメントベースの下位24ビット |
3 |
4 |
5 |
セグメント属性の下位8ビット |
6 |
下位4ビットはセグメントリミットの上位4ビット,
上位4ビットはセグメント属性の上位4ビット |
7 |
セグメントベースの上位8ビット |
かなりあっちこっち錯綜した内容ですが,これはIA-32が80286のセグメントディスクリプタと厳密に互換性を持たせようとした結果です。セグメントリミットは,そのセグメントの最大値を4KB単位で表します。IA-32から上位4ビットが補われた結果,4KB×20ビット=4GBとなり,一つのセグメントの最大値=IA-32のメモリアドレスの最大値が取れるようになりました。
セグメントベースアドレスも同じように8ビットが追加され,32ビットで表現されます。したがって,セグメントはリニアアドレス上のセグメントベースからの32ビットのオフセットとなる仕組みです。
さて,もう一つのIDTRは割り込みに関連したレジスタです。16ビット時代,割り込みが発生すると0番地(メモリの先頭)から順に割り込み番号に格納されている割り込み処理ルーチンが呼び出されました。IA-32では,この動作が拡張され,割り込み処理ルーチンのアドレスを格納するテーブル……割り込みディスクリプタテーブルをOSが任意のアドレスに設定できるようになっています。
IDTRはGDTRと同じく48ビットのレジスタで,上位16ビットに割り込みディスクリプタテーブルの大きさ,下位32ビットに割り込みディスクリプタテーブルのリニアアドレスが格納されます。
割り込みが発生するとIDTRが参照され,割り込みディスクリプタテーブルの割り込み番号に格納された情報に従って,割り込み処理ルーチンにジャンプします。
一つの割り込みディスクリプタには,割り込み処理ルーチンがあるセグメントディスクリプタ(16ビット),割り込み処理ルーチンのオフセット値(32ビット)のほかに,その割り込みディスクリプタの種類(トラップゲート,割り込みゲートなど)を表す8ビット値と,コピーカウント値が格納されています(IA-32のゲートディスクリプタと同じ内容です)。
種類というのは,プロセッサで定義されているトラップゲートか割り込みゲートかのタイプ番号と実行特権レベルを表す2ビットの値を組み合わせたものです。ゲートは,設定されている特権レベルより低い動作レベルでは機能しないようになっています(これはIA-32の保護機能の一つです)。
割り込みゲートを通ると,特権レベルやセグメントが切り替わります。そのため,呼び出し前のスタックの値を,割り込み処理のスタック空間にコピーしておかなければなりません。コピーカウントというのは,スタックの値をコピーする数です。
IA-32の動作は相当に複雑で,割り込み一つとっても何段階もの動作を引き起こします。より詳しく知りたい人は,インテルが出している(英語版はPDFでダウンロード可能)デベロッパマニュアルや参考書籍を参照するとよいでしょう。
(米田 聡)
