正直なところ、ネットワークの広大さの中で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システムプログラミングガイド