アットウィキロゴ

6th-Day

GDTとIDT

  • セグメンテーション 4GBあるメモリを好きなように切り分け、各ブロックの先頭番地を0として扱うことが出来る機能

セグメント1つを表すには以下の情報が必要

・セグメントの大きさ
・セグメントがどの番地から始まるか
・セグメントの属性情報

CPUでは上記の情報を8バイトであらわす。しかしセグメントレジスタは16ビットである。

そこでセグメントレジスタにはセグメントセレクタを格納しておいて、実際の情報はメモリ上に設置する。

セグメントレジスタは仕様上13ビットしか使用できないので、8192個のセグメントを作成することができる。

したがって8192*8バイト=64KBのメモリが必要となる。このスペースをGDT(Global Description Table)と呼ぶ。

CPUのGTDR(レジスタ)にGDTの先頭番地と有効設定個数をセットする。


  • IDT マウスやキーボード、HDDなどに変化が生じた場合、「割込み」が発生する。

割込みが発生するとCPUは現在実行中の処理を中断し、あとで再開可能となるように準備をして、割り込みの種類に応じてあらかじめ設定してある関数を実行する。

IDTは割込みと関数の対応表のようなもの。harib02iはGDTとIDTを初期化するプログラムである。


  • harib02のメモ SEGMENT_DESCRIPTORはCPUを参考に構成した8バイトのセグメント情報。

メモリ1番地に1バイト(=8ビット)格納することができるので、0x00270000~0x0027ffffffを利用することにする。

同様にIDTは0x0026f800~0x0026ffffを利用することにする。理由はメモリマップ上で誰も使ってないから。

次のループでセグメントのリミット(セグメントのバイト数-1)、ベース(番地)、アクセス権属性を0にセットする。

セグメント1番と2番をセットする。そしてGTDRに情報をセットする。IDTについてもほぼ同様の動作をする。


  • set_segmdescについて リミットが1MBより大きい場合は、アクセス権属性をいじる。リミットを8192バイトで割る。<理由がよくわからん。

まずはベース番地(セグメントか格納されるメモリアドレス)から

sd->base_low = base & 0xffff ← baseの下位16ビットをbase_lowに格納
sd->base_mid = (base >> 16) & 0xff ← baseの中位8ビット(17~24ビット)をbase_midに格納
sd->base_high = (base >> 24) & 0xff ← baseの上位8ビット(25~36ビット)をbase_highに格納

3つに分断するのは286CPUとの互換性確保のため。

次にリミットについて

sd->limit_low = limit & 0xffff ← limitの下位16ビットをlimit_lowに格納
sd->limit_high = ((limit >> 16) & 0x0f)|((ar >> 8) & 0xf0) ← limitの17~20ビットをlimit_highの下位4ビットに格納。arの上位4ビットをlimit_highの上位4ビットに格納

リミットは20ビットで表現。通常これだと1MBまで表現できないように思われるが、Gビットというフラグをセットすることにより、リミットをページ単位に換算することが出来る。 1ページ4KBであるので、4KB×1M=4GBのリミットを表現することが出来る。またlimit_highの上位4ビットにはセグメント属性が書き込まれるので注意

最後にセグメントのアクセス属性について、xxxx0000xxxxxxxxの16ビットで表現。上位4ビットは拡張アクセス権。GD00として使用される。GにはGビット、Dには286との互換性についての情報を入れる。

下位8ビットのアクセス属性の代表例は以下の通り

00000000(0x00):未使用
10010010(0x92):システム専用。読み書き可能。実行不可。
10011010(0x9a):システム専用。読み込み、実行可能。書き込み不可。
11110010(0xf2):アプリケーション専用。読み書き可能。実行不可。
11111010(0xfa):アプリケーション専用。読み込み、実行可能。書き込み不可。

CPUにはOSなどのプログラムを動かしているシステムモードと、アプリケーションを動かしているアプリケーションモードが存在する。

判断基準は実行しているプログラムが置いてあるセグメントの属性を見て判断する。


  • load_gtdr 48ビットレジスタであるGDTRにGDTRのリミットと番地をセットする。ちなみに今回のGDTRは64KBとなるのでリミットは64KB=65536バイト=0xffffとなる。

GDTRをセットする番地は0x00270000。最初はESP+4にリミットがESP+8に番地が入っている。

問題は64ビット分の情報をどうやって48ビットのレジスタに格納するか。

16ビットレジスタであるAXにESP+4を2バイト分読み込む。

ESP+6にAXをMOVすればESP+6から6バイト分がGTDRにセットする内容となる。厳密には下位16ビットがリミットで残り32ビットが番地となる。

実際にはLGDTでGDTRにセットする。

prev→5th-Day next→7th-Day

最終更新:2011年03月26日 18:03