GDTUtil グローバルデスクリプタ再設定用の関数群 void GDTUtil::setup() Kernel.cpp の startkernelから呼び出される。行っていることは新しいGDTを 確保したメモリ領域g_gdtに設定している。g_gdt[0]には0番目のデスクリプタが、 g_gdt[1]には1番目のデスクリプタが・・・となる。また、g_TSSにタスクステート セグメント情報を格納している。 g_gdt = (SegDesc*)malloc(sizeof(SegDesc) * GDT_ENTRY_NUM); checkMemoryAllocate(g_gdt, "GDT Memory allocate"); /* NULL */ setSegDesc(&g_gdt[0], 0, 0, 0); g_gdt[0].limitH = 0; /* allcate TSS */ g_tss = (TSS*)malloc(sizeof(TSS)); 必要なデータを確保したら、GDTの設定を行う。GDTの内訳は次のとおり g_gdt[1]は特権レベル0のコードセグメント /* SYS CS 0-4GB */ setSegDesc(&g_gdt[1], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL0 | 0x10 | 0x0A); g_gdt[2]は特権レベル0の読み書きができるコードセグメント /* SYS DS 0-4GB */ setSegDesc(&g_gdt[2], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL0 | 0x10 | 0x02); g_gdt[3]は特権レベル0の読み書きができるコードセグメント /* SYS SS 0-4GB */ setSegDesc(&g_gdt[3], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL0 | 0x10 | 0x02); 以上は実アドレスモードで設定したセグメントと同じ構造になっている。スタックの 定義が違うが、リニアアドレス全部を使うという点では同じ構造になっている。 作った人が違うのかな? システムセグメントのひとつタスク・ステート・セグメント。タスク情報は106バイトあるので リミットは0x00000067 = 106 - 1 /* TSS. Mona has only one TSS */ setSegDesc(&g_gdt[4], (dword)g_tss, 0x00000067, SEGMENT_PRESENT | SEGMENT_DPL0 | 0x00 | 0x09); 次の3つがユーザー用(特権レベル3)のコード、データ、スタック情報 /* USER CS 0-4GB */ setSegDesc(&g_gdt[5], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL3 | 0x10 | 0x0A); /* USER DS 0-4GB */ setSegDesc(&g_gdt[6], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL3 | 0x10 | 0x02); /* USER SS 0-4GB */ setSegDesc(&g_gdt[7], 0, 0xFFFFF, SEGMENT_PRESENT | SEGMENT_DPL3 | 0x10 | 0x02); グローバルデスクリプタテーブルの再設定と(限界の8192個分とっている) タスクステートセグメントの設定(セレクタは0x20になる)をしている。 /* lgdt */ GDTR gdtr; gdtr.base = (dword)g_gdt; gdtr.limit = sizeof(SegDesc) * GDT_ENTRY_NUM - 1; lgdt(&gdtr); /* setup TSS */ setupTSS(0x20); return; void GDTUtil::setSegDesc(SegDesc* desc, dword base, dword limit, byte type); 指定されたデスクリプタを設定する。グラニュラリティとD/Bフラグは勝手にセットされる。 base・・・ベーステーブルアドレス limit ・・リミット type・・・セグメントのタイプ。マクロを使って設定したほうが安全。 void GDTUtil::setupTSS(word selector); setup()で確保したg_tss(何でグローバル変数なんだ)を0に初期化して スタックトップとスタックセグメントを設定して、それをタスクレジスタに設定している。 /* prepare dpl0 stack */ memset(g_tss, 0, sizeof(TSS)); g_tss->esp0 = 0x90000; g_tss->ss0 = KERNEL_SS; /* load TSS */ ltr(selector); return;