/** @file SwitchMode.S * */ #include "Common.h" //セグメント //SEG_REG = 0x6000 KERNEL_CS = 0x0008 //カーネル用コード・セグメント KERNEL_DS = 0x0010 //カーネル用データ・セグメント BOOT_CS = 0x0008 //ブートローダ用コード・セグメント(カーネル実行時には、このディスクリプタは削除する。) CR0_PE = 0x00000001 //プロテクト・イネーブル・フラグ //CR0_PG = 0x80000000 //ページング・フラグ .section .text .code16 /** * プロテクトモード切り替え * * 汎用レジスタは破壊されます。 * スタックは初期化されます。 * CS は0x08がセットされます。 * DS, ES, SS には0x10がセットされます。 * FS, GS には、0x00がセットされます。 */ .global switchProtectMode switchProtectMode: xorl %ebx, %ebx popw %bx // 戻りアドレス /* 1. 割り込みをディスエーブルにする。CLI 命令によってマスク可能ハードウェア割り込み がディスエーブルになる。NMI 割り込みは、外部回路によってディスエーブルにでき る。 (ソフトウェアは、モード切り替えの動作中に例外または割り込みが発生しないよ うに保証する必要がある。 ) */ // NMI割り込み禁止 call disableNMI /* 2. LGDT 命令を実行して、GDTR レジスタに GDT のベースアドレスをロードする。 */ // 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 .byte 0x66 ljmp $0x08, $setCodeSegment setCodeSegment: /* 6. ページングがイネーブルな場合、 MOV CR0 命令のコードと、 JMP 命令または CALL 命 令のコードは、アイデンティティ・マッピングされたページから得たものでなければ ならない(つまり、ジャンプ前のリニアアドレスが、ページングと保護モードがイネー ブルになった後の物理アドレスと同一でなければならない) JMP 命令または CALL 命 。 令のターゲット命令は、アイデンティティ・マッピングされる必要はない。 */ /* 7. ローカル ディスクリプタ テーブルを使用する場合には、 LLDT 命令を実行して LDTR ・ ・ レジスタに LDT のセグメント・セレクタをロードする。 */ /* 8. LTR 命令を実行して、 セグメント・セレクタ付きタスクレジスタを初期保護モード・タ スクへロードする。またはタスクスイッチに関する TSS 情報を保存できるメモリの書 き込み可能領域へロードする。 */ /* 9. 保護モードに移行した後、セグメント・レジスタは実アドレスモードで保持していた 内容をそのまま保持し続ける。操作手順 4 の JMP 命令または CALL 命令が CS レジス タをリセットする。以下のどれかを実行して、残りのセグメント・レジスタの内容を 更新する。 - DS、SS、ES、FS、GS の各セグメント・レジスタを再ロードする。ES、FS、GS の 各レジスタのなかで使用しないものがある場合、そのレジスタにヌルセレクタを ロードする。 - 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 のアドレスとリミットをロー ドする。 */ /* 11. STI 命令を実行して、マスク可能ハードウェア割り込みをイネーブルにし、また必要な ハードウェア動作を実行して NMI 割り込みをイネーブルにする。 上記の手順 3 と手順 4 の間に他の命令が存在すると、不規則な障害が発生することが ある。システム管理モードで、メモリを参照する命令が手順 3 と手順 4 の間に挿入さ れたときのような状況では、障害は直ちに認識される。 */ // NMI割り込み許可 call enableNMI // 呼び出し元に戻る pushl %ebx ret