OSを作成するには、多くの詳細を理解する必要があります。 それでは、少しあなたに啓発させてください(しかし、あなたがマナを自分で読んで、話をすることに同意することにしましょう)。
正直なところ、ネットワークの広大さの中でPMには
大量の脂肪質の素材があり、
ileyと
pehatはこのモードについて少し
話しましたが、とにかく一般的なフレームワークでそれを説明するように頼まれました。 次に、理論を簡単に説明します(一般的に、Intelはこのために特別にマナを書きました)。次に、コードの記述を開始します。
プロテクトモードの概要。したがって、PMはDOSのリアルモード(RM)以降、通常のすべてとは大きく異なります。 慣れる必要があります。64キロバイトの静的セグメント、1キロバイトの割り込みテーブル、セグメントレジスタのデータベースベースのアドレスなど、まったく新しい世界です。
セグメントは現在、
グローバル記述子テーブル(GDT)に記述されています。 このテーブルは、1つのコピーにのみ含めることができます。 彼女は心の構造です。 セグメントではありません! メモリ内のどこにでも配置できますが、アドレスと制限はGDTRレジスタに記録されます。 その構造は次のとおりです。

テーブル自体は、次の構造のエントリで構成されています(ところで、nullエントリは空です。これは重要です。null記述子で「記述」されたメモリにアクセスする場合、#GP-General Protection Faultを取得します)
この構造を詳しく見てみましょう。
1.セグメント制限:このフィールドの目的は名前で明確ですが、微妙です。 犬はビットG(粒状性)に埋もれています。
インストールされていない場合、メモリはバイト単位で「カウント」されます。 この場合、セグメントサイズは、1バイトのサイズごとに1バイトから1メガバイトまで変化します。
1に設定すると、ページングメモリが入力されます。 次に、4キロバイト(ページサイズ)にサイズを変更して、4キロバイトから4ギガバイトのRAMをアドレス指定できます。 一般に、ページのアドレス指定が推奨されます((1MB + 64Kb-16byte)と4GBを比較してください)。 この投稿では、セグメント化されたアドレス指定についてのみ説明しましょう。 ページングについては、別の議論に値します。
2.ベースアドレス:ここでは、データベースの物理アドレスを示します。
3.タイプフィールド:ビットの組み合わせにより、セグメントのタイプが決まります。
4. S(記述子タイプ):Intelのドキュメントには、このビットが設定されていない場合、この記述子はシステムセグメント用であり、そうでない場合はコードまたはデータであると書かれています。 システムとは、LDT、TSS、割り込みゲート、およびそれらのような他のものを意味します(それらについては後で)。
5. DPL(記述子特権レベル):説明されたセグメントの特権。 誰もがリングを知っています。
6. P(セグメントが存在する):このビットが設定されている場合、プロセッサはセグメントが既にメモリ内にあることを「認識」します(ただし、有効と言う方が良いです)。 未定義のPビットを持つ記述子セレクターをセグメントレジスタにロードすると、#NP(存在しない)例外が発生します。 一般に、この華やかなフレーズの意味については少し後で説明します。
7. D / B:異なるタイプのセグメントでは、解釈が異なります。
1.コードセグメントの場合:32または16ビットの有効なアドレス長とオペランドサイズ。
(1-32; 0-16);
2.スタックの場合:スタックポインターは32ビットまたは16ビットです。 (1-32; 0-16);
8. G:セグメント制限が測定される単位(バイト、ページ)に影響します。 一般に、CR0レジスタの31ビットを設定することにより、PMに切り替えるときにページングを有効にできます。
詳細情報:グローバルという言葉は無駄ではなかったと思います。 そのため、まだ何らかの種類のタブレットがあります。 確かに、
ローカル記述子テーブルもあります。 非常に多くの可能性があります。 たとえば、タスクの実装などに使用できます。 しかし、
LDTはすでにセグメントです! 「ローカル記述子プレートのセグメント記述子」のようなフレーズに慣れてください。
テーブルについて説明した後、テーブルを
GDTRレジスタにロードする必要があります。 これはmovにはほど遠い。
GDTRには lgdt fwordコマンド(値) が入力され
ます 。 つまり、この構造を独立して形成し、前述のレジスタにロードする必要があります。 このレジスターで作業しているチームはまだありますが、ヨーロッパ中を駆け巡っています。
別のポイント。 PMでは、セグメントレジスタはセグメントのベースアドレス(RMなど)ではなく、
セレクターと呼ばれる特別にトレーニングされたピースを格納します。 その構造は次のとおりです。

ここで、インデックスはテーブル内の記述子のシリアル番号です。
TIは、記述子を探す場所を示します(
GDTまたは
LDTで )。
テーブルの作成方法がすでに明確になったので、PMに切り替える方法について説明します(これはRMからのみ実行できることに注意してください)。 一般的には、CR0制御レジスタのビット0を設定するだけです。 私は嘘をついていますが。 まず、すべての割り込み(
NMI (
マスク不可
割り込みを含む)を含む)を禁止し、
A20アドレス行を開いて(32ビットのアドレス指定が可能になるように)、
GDTRを読み込み、開始マークにジャンプする
必要があります。
ブートローダー(KOLIBRI'skyを使用できます)を使用して、アドレス1000h:0(RM'ovsky、アドレスをメモします)でコードをロードします。
ブートローダーから直接PMに切り替えると、それらの人ほどスムーズではありません。 すべてが少し複雑です。 しかし、最初に、ブートローダーがロードするコードを見てみましょう(すべてFASMに記述します)。 これは一種のhelloworldです。 起動し、PMに移動して挨拶を印刷します。 それだけです
format binary
xor ax,ax
cli ;
mov ss,ax
xor sp,sp
sti
mov ax,3
int 10h
jmp 1000h:r_start
r_start:
mov ax,1000h;
mov ds,ax
mov es,ax
in al, 0x92; A20
or al, 2
out 0x92, al
cli ;
mov al,8Fh; NMI
out 70h,al
in al,71h
lgdt fword [GDTR]; GDTR
mov eax,cr0
or al,1; 0-
mov cr0,eax; PM
jmp fword 08h:Startup32; PM
align 8 ;
GDT:
dq 0 ;
db 0FFh,0FFh,0,0,0,9Ah,0CFh,0 ;
db 0FFh,0FFh,0,0,0,92h,0CFh,0;
db 0FFh,0FFh,0,80h,0Bh,92h,40h,0 ;
label GDT_SIZE at $-GDT
GDTR:
dw GDT_SIZE-1
dd GDT+10000h
; 32- . 1000h, 1000h*10h ( ; ) => GDTR (!) = 10000h ( )+offset
virtual ;, ,
rb 10000h-$;
end virtual
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;PM32 Entry;;;;;;;;;;;;;;;;;;;
use32
org $+10000h; : PM Flat-, ; PM org', ; Flat . .
Startup32: ; PM
mov ax,10h ; . (!
mov es,ax ;) - 08h. - 10h, - 18h
mov ds,ax
mov fs,ax
mov ss,ax
mov esp,10000h;
mov ax,18h
mov gs,ax
mov esi,hi_string ;,
call print
jmp $
;ESI -
print:
pushad
xor ebx,ebx
mov ah,07h;
puts:
mov al,[esi+ebx]
mov [gs:(ebx*2)],ax
inc ebx
test al,al
jnz puts
popad
ret
hi_string db 'Welcome to PM, dude',0
私たちは何をしましたか? ブートローダーは1000h:0で正常にロードし、そこから実行を継続しました。 まず、
A20をオンにし、すべての割り込みを禁止し、適切な値を
GDTRにロードして、入力ラベルにジャンプしました。 飛びついたことに気づいた
jmp fword 08h:Startup32
つまり、08hはコード記述子セレクターです。 それに慣れてください。
次に、この奇跡を開始する方法。 個人的には、WinImageとVirtualBoxを使用しています。 ブートローダーをディスケットのブートセクターにプッシュし、.binファイルをルートに配置します。 .vfdに保存し、仮想マシンのプロパティにディスクイメージへのパスを書き込み、起動して結果を確認します。
次の号では、割り込み、フォールト、トラップ、アボート、およびそれらの動作、キャッチ、デバッグについて検討します。 アーキテクチャについて話を始めましょう。
情報源。
1)真の道を指摘し、最初に私を助けてくれたPhantom_84別名エゴに感謝したい。 それがなければ、私がそれを理解するのははるかに難しいでしょう。
2)
BrokenSword'aの記事BrokenSword'aの記事。 彼らは注意を払う価値があります。
3)
Intelシステムプログラミングガイド