#include "Common.h"
-#セグメント
-#SEG_REG = 0x6000
-KERNEL_CS = 0x0008 #カーネル用コード・セグメント
-KERNEL_DS = 0x0010 #カーネル用データ・セグメント
-BOOT_CS = 0x0018 #ブートローダ用コード・セグメント(カーネル実行時には、このディスクリプタは削除する。)
+//セグメント
+//SEG_REG = 0x6000
+KERNEL_CS = 0x0008 //カーネル用コード・セグメント
+KERNEL_DS = 0x0010 //カーネル用データ・セグメント
+BOOT_CS = 0x0008 //ブートローダ用コード・セグメント(カーネル実行時には、このディスクリプタは削除する。)
-CR0_PE = 0x00000001 #プロテクト・イネーブル・フラグ
-#CR0_PG = 0x80000000 #ページング・フラグ
+CR0_PE = 0x00000001 //プロテクト・イネーブル・フラグ
+//CR0_PG = 0x80000000 //ページング・フラグ
- .section .text
- .code16
+.section .text
+.code16
-
- .global switchProtectMode
+/**
+ * プロテクトモード切り替え
+ *
+ * 汎用レジスタは破壊されます。
+ * スタックは初期化されます。
+ * CS は0x08がセットされます。
+ * DS, ES, SS には0x10がセットされます。
+ * FS, GS には、0x00がセットされます。
+ */
+.global switchProtectMode
switchProtectMode:
+ xorl %ebx, %ebx
+ popw %bx // 戻りアドレス
+
+
/*
1. 割り込みをディスエーブルにする。CLI 命令によってマスク可能ハードウェア割り込み
がディスエーブルになる。NMI 割り込みは、外部回路によってディスエーブルにでき
る。 (ソフトウェアは、モード切り替えの動作中に例外または割り込みが発生しないよ
うに保証する必要がある。 )
*/
-
- # 割り込み禁止
- cli
- # NMI割り込み禁止
+ // NMI割り込み禁止
call disableNMI
+
/*
2. LGDT 命令を実行して、GDTR レジスタに GDT のベースアドレスをロードする。
*/
- # GDT読み込み
- lgdt _GDTR_TEMP
+ // GDT読み込み
+ lgdt tempGDTR
/*
3. 制御レジスタ CR0 の PE フラグ(またオプションで PG フラグ)を設定する MOV CR0
命令を実行する。
*/
- # プロテクトモード移行
+
+ // プロテクトモード移行
movl %cr0, %eax
orl $CR0_PE, %eax
movl %eax, %cr0
4. MOV CR0 命令のすぐ後で、far JMP 命令または far CALL 命令を実行する。 (この操作
は通常、命令ストリーム内の次の命令への far ジャンプまたは far コールになる。 )
*/
- # パイプラインフラッシュ
+ // パイプラインフラッシュ
jmp pipelineFlush
pipelineFlush:
5. MOV CR0 命令の直後に JMP 命令または CALL 命令を実行すると、実行の流れが変化
し、プロセッサが順次処理される。
*/
- # 32bit移行
- .code32
+ // 32bit移行
+.code32
.byte 0x66
- ljmp $BOOT_CS, $setCodeSegment
+ ljmp $0x08, $setCodeSegment
setCodeSegment:
+
/*
6. ページングがイネーブルな場合、 MOV CR0 命令のコードと、 JMP 命令または CALL 命
令のコードは、アイデンティティ・マッピングされたページから得たものでなければ
メント・レジスタの値がリセットされ、新しいコード・セグメントに分岐する。
*/
+ // データ・セグメント初期化
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ // FS, GS は使わない。
+ xorl %eax, %eax
+ movw %ax, %fs
+ movw %ax, %gs
+
/*
10. LIDT 命令を実行して、IDTR レジスタに保護モード IDT のアドレスとリミットをロー
ある。システム管理モードで、メモリを参照する命令が手順 3 と手順 4 の間に挿入さ
れたときのような状況では、障害は直ちに認識される。
*/
-
-
-
- # 割り込み許可
- sti
- # NMI割り込み許可
+ // NMI割り込み許可
call enableNMI
- ret
-
-
-
-
- .global switchRealMode
-switchRealMode:
-
-/*
- 1. 割り込みをディスエーブルにする。CLI 命令によってマスク可能ハードウェア割り込み
- がディスエーブルになる。NMI 割り込みは、外部回路によってディスエーブルにでき
- る。
-*/
- # 割り込み禁止
- cli
- # NMI割り込み禁止
- call disableNMI
-
-
-
-/*
- 2. ページングがイネーブルである場合は、以下の各操作を行う。
- - プログラム制御を、物理アドレスにアイデンティティ・マッピングされている(つ
- まり物理アドレスと同一の)リニアアドレスに転送する。
- - GDT と IDT がアイデンティティ・マッピングされたページにあるようにする。
- - CR0 レジスタ内の PG ビットをクリアする。
- - 0H を CR3 レジスタに移動して TLB をフラッシュする。
-*/
-
-
-/*
- 3. プログラム制御を、64K バイト(FFFH)のリミットを持つ読み取り可能セグメントに
- 転送する。この動作によって、実アドレスモードで必要になるセグメント・リミット
- が CS レジスタにロードされる。
-*/
-
-
-/*
- 4. SS、DS、ES、FS、GS の各セグメント・レジスタに、以下の値(実アドレスモードに
- 適した値)をストアしているディスクリプタのセレクタをロードする。
- - リミット = 64 K バイト(0FFFFH)
- - バイト・グラニュラリティ(G = O)
- - 上方拡張(E = O)
- - 書き込み可能(W = 1)
- - 存在(P = 1)
- - ベース = 任意の値
-*/
-
-
-/*
- 5. セグメント・レジスタには、ヌル以外のセグメント・セレクタがロードされなければな
- らない。 そうしないと、 実アドレスモードでセグメント・レジスタを使用できなくなる。
- セグメント・レジスタが再ロードされない場合は、保護モード時にロードされたディス
- クリプタの属性によって実行が継続されることに注意しなければならない。
-*/
-
-
-
-/*
- 6. LIDT 命令を実行して、実アドレスモードの割り込みテーブルを指す。これは 1M バイ
- トの実アドレスモードのアドレス範囲内にある。
-*/
-
-
-
-/*
- 7. CR0 レジスタ内の PE フラグをクリアして、実アドレスモードに切り替える。
-*/
-
-
-/*
- 8. far JMP 命令を実行して実アドレスモードのプログラムにジャンプする。この動作に
- よって、命令キューがフラッシュされ、適切なベース値とアクセス権値が CS レジスタ
- にロードされる。
-*/
-
-
-
-/*
- 9. 実アドレスモードのコードに必要であれば、SS、DS、ES、FS、GS の各レジスタをロー
- ドする。これらのレジスタのどれかを実アドレスモードで使用しない場合は、そのレ
- ジスタに O を書き込む。
-*/
-
-
-
-/*
- 10. STI 命令を実行して、マスク可能ハードウェア割り込みをイネーブルにする。また必要
- なハードウェア動作を実行して NMI 割り込みをイネーブルにする。
-*/
- # 割り込み許可
- sti
- # NMI割り込み許可
- call enableNMI
+ // 呼び出し元に戻る
+ pushl %ebx
ret
-
-/*
- モード切り替え
-9.9.
- プロセッサを保護モードで使用するには、モードの切り替えを実アドレスモードから
- 実行しなければならない。いったん保護モードに移行した後は、通常の場合、ソフト
- ウェアが実アドレスモードに戻る必要はない。実アドレスモード(8086 モード)で実
- 行するように記述されたソフトウェアを実行するには、実アドレスモードに再度切り
- ソフトウェアを仮想 8086 モードで実行するほうが一般的には便利であ
- 替えるよりも、
- る。
-9-16
- 9
- プロセッサの管理と初期化
- 保護モードへの切り替え
-9.9.1.
- 保護モードに切り替える前に、システムデータ構造とコード・モジュールの必要最小
- 9.8. 「保護モー
- 限のセットをメモリにロードしなければならない。 詳細については、 節
- ド動作に対するソフトウェア初期化」 で説明している。 各テーブルが作成された後は、
- ソフトウェア初期化コードを保護モードに切り替えられる。
- CR0 レジスタ内の PE フラグを設定する MOV CR0 命令を実行
- 保護モードに入るには、
- (同じ命令で、レジスタ CR0 内の PG フラグを設定してページングをイネーブル
- する。
- )保護モードでの実行は 0 の CPL から開始する。
- にできる。
- 32 ビット IA-32 プロセッサでは、 保護モードへの切り替えに必要な条件が少し異なる。
- すべての 32 ビット IA-32 プロセッサ間でコードの上位互換性と下位互換性を確保する
- ためには、以下の操作手順を実行する。
- 1. 割り込みをディスエーブルにする。 命令によってマスク可能ハードウェア割り込み
- CLI
- がディスエーブルになる。NMI 割り込みは、外部回路によってディスエーブルにでき
- る。 (ソフトウェアは、モード切り替えの動作中に例外または割り込みが発生しないよ
- うに保証する必要がある。 )
- 2. LGDT 命令を実行して、GDTR レジスタに GDT のベースアドレスをロードする。
- 3. 制御レジスタ CR0 の PE フラグ(またオプションで PG フラグ)を設定する MOV CR0
- 命令を実行する。
- 4. MOV CR0 命令のすぐ後で、far JMP 命令または far CALL 命令を実行する。 (この操作
- は通常、命令ストリーム内の次の命令への far ジャンプまたは far コールになる。 )
- 5. MOV CR0 命令の直後に JMP 命令または CALL 命令を実行すると、実行の流れが変化
- し、プロセッサが順次処理される。
- 6. ページングがイネーブルな場合、 MOV CR0 命令のコードと、 JMP 命令または CALL 命
- 令のコードは、アイデンティティ・マッピングされたページから得たものでなければ
- ならない(つまり、ジャンプ前のリニアアドレスが、ページングと保護モードがイネー
- ブルになった後の物理アドレスと同一でなければならない) JMP 命令または CALL 命
- 。
- 令のターゲット命令は、アイデンティティ・マッピングされる必要はない。
- 7. ローカル ディスクリプタ テーブルを使用する場合には、 LLDT 命令を実行して LDTR
- ・ ・
- レジスタに LDT のセグメント・セレクタをロードする。
- 8. LTR 命令を実行して、 セグメント・セレクタ付きタスクレジスタを初期保護モード・タ
- スクへロードする。またはタスクスイッチに関する TSS 情報を保存できるメモリの書
- き込み可能領域へロードする。
- 9. 保護モードに移行した後、セグメント・レジスタは実アドレスモードで保持していた
- 内容をそのまま保持し続ける。操作手順 4 の JMP 命令または CALL 命令が CS レジス
- 9-17
-IA-32 インテル® アーキテクチャ・ソフトウェア・デベロッパーズ・マニュアル 下巻:システム・プログラミング・ガイド
- タをリセットする。以下のどれかを実行して、残りのセグメント・レジスタの内容を
- 更新する。
- - DS、SS、ES、FS、GS の各セグメント・レジスタを再ロードする。ES、FS、GS の
- 各レジスタのなかで使用しないものがある場合、そのレジスタにヌルセレクタを
- ロードする。
- - JMP 命令または CALL 命令を新しいタスクに対して実行する。これによって、セグ
- メント・レジスタの値がリセットされ、新しいコード・セグメントに分岐する。
- 10. LIDT 命令を実行して、IDTR レジスタに保護モード IDT のアドレスとリミットをロー
- ドする。
- 11. STI 命令を実行して、マスク可能ハードウェア割り込みをイネーブルにし、また必要な
- ハードウェア動作を実行して NMI 割り込みをイネーブルにする。
- 上記の手順 3 と手順 4 の間に他の命令が存在すると、不規則な障害が発生することが
- ある。システム管理モードで、メモリを参照する命令が手順 3 と手順 4 の間に挿入さ
- れたときのような状況では、障害は直ちに認識される。
- 実アドレスモードへの再切り替え
-9.9.2.
- ソフトウェアが MOV CR0 命令によって CRO レジスタ内の PE ビットをクリアした場
- 合、プロセッサは実アドレスモードに切り替えられる。実アドレスモードに再移行す
- るときは、以下の操作手順を実行する必要がある。
- 1. 割り込みをディスエーブルにする。 命令によってマスク可能ハードウェア割り込み
- CLI
- がディスエーブルになる。NMI 割り込みは、外部回路によってディスエーブルにでき
- る。
- 2. ページングがイネーブルである場合は、以下の各操作を行う。
- - プログラム制御を、物理アドレスにアイデンティティ・マッピングされている(つ
- まり物理アドレスと同一の)リニアアドレスに転送する。
- - GDT と IDT がアイデンティティ・マッピングされたページにあるようにする。
- - CR0 レジスタ内の PG ビットをクリアする。
- - 0H を CR3 レジスタに移動して TLB をフラッシュする。
- 3. プログラム制御を、64K バイト(FFFH)のリミットを持つ読み取り可能セグメントに
- 転送する。この動作によって、実アドレスモードで必要になるセグメント・リミット
- が CS レジスタにロードされる。
- 4. SS、DS、ES、FS、GS の各セグメント・レジスタに、以下の値(実アドレスモードに
- 適した値)をストアしているディスクリプタのセレクタをロードする。
- - リミット = 64 K バイト(0FFFFH)
-9-18
- 9
- プロセッサの管理と初期化
- - バイト・グラニュラリティ(G = O)
- - 上方拡張(E = O)
- - 書き込み可能(W = 1)
- - 存在(P = 1)
- - ベース = 任意の値
-5. セグメント・レジスタには、ヌル以外のセグメント・セレクタがロードされなければな
- らない。 そうしないと、 実アドレスモードでセグメント・レジスタを使用できなくなる。
- セグメント・レジスタが再ロードされない場合は、保護モード時にロードされたディス
- クリプタの属性によって実行が継続されることに注意しなければならない。
-6. LIDT 命令を実行して、実アドレスモードの割り込みテーブルを指す。これは 1M バイ
- トの実アドレスモードのアドレス範囲内にある。
-7. CR0 レジスタ内の PE フラグをクリアして、実アドレスモードに切り替える。
-8. far JMP 命令を実行して実アドレスモードのプログラムにジャンプする。この動作に
- よって、命令キューがフラッシュされ、適切なベース値とアクセス権値が CS レジスタ
- にロードされる。
-9. 実アドレスモードのコードに必要であれば、SS、DS、ES、FS、GS の各レジスタをロー
- ドする。これらのレジスタのどれかを実アドレスモードで使用しない場合は、そのレ
- ジスタに O を書き込む。
-10. STI 命令を実行して、マスク可能ハードウェア割り込みをイネーブルにする。また必要
- なハードウェア動作を実行して NMI 割り込みをイネーブルにする。
-
-
-*/