0

問題は、Intel i386 でリアル モードからプロテクト モードに切り替える際のコード セグメント セレクターの永続的な有効性に関するものです。bootasm.S切り替えコードは次のとおりです ( xv6 x86 バージョンからの抜粋)。

9138 # Switch from real to protected mode. Use a bootstrap GDT that makes
9139 # virtual addresses map directly to physical addresses so that the
9140 # effective memory map doesn’t change during the transition.
9141 lgdt gdtdesc
9142 movl %cr0, %eax
9143 orl $CR0_PE, %eax
9144 movl %eax, %cr0
9150 # Complete the transition to 32−bit protected mode by using a long jmp
9151 # to reload %cs and %eip. The segment descriptors are set up with no
9152 # translation, so that the mapping is still the identity mapping.
9153 ljmp $(SEG_KCODE<<3), $start32

GDT レイアウトは次のとおりです。

9182 gdt:
9183 SEG_NULLASM # null seg
9184 SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
9185 SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg

行 9144 を実行した後、プロセッサは、単なるセグメント メモリ管理が有効になる保護モードに切り替わります (ただし、ページングは​​まだ有効になっていません)。私の理解では、セグメント MM が有効になっているため、後続の命令のフェッチはセグメント MM のルールに従う必要があります。ただし、この時点 (9153 行の直前) では、コード セレクターは 0 のままです。これは、コード セグメントが GDT の 0 番目の記述子 (null) を選択する必要があることを意味します。しかし、私の質問は自然に出てきます。そのようなヌル記述子が想定されるljmp命令をどのようにロードできるのでしょうか? 私はグーグルで質問に答えようとしましたが、ドキュメントには次のような説明があります

セグメント レジスタは、実アドレス モードと同じリニア アドレスを指し続けます。

この文は私の質問に答えているようです: セグメント レジスタが同じ線形アドレスを指し続ける場合、次の命令はリアル モードと同じ、つまりljmp. しかし、すぐに一連の新しい質問があります。セグメント セレクターが「同じ線形アドレスを指し続ける」ことができるのはなぜですか? プロセッサがプロテクト モードに変更されていませんか? 0 の値は、命令%csをフェッチするための想定される記述子である 1 番目 (9184 行で設定) ではなく、0 番目の記述子を指していませんか? x86 CPUは、次の命令を実行する必要があることをljmp魔法のようにどのように認識しますか? ljmpこの魔法を説明しているマニュアルの説明はどこにありますか? 私は、ljmpはプロセッサの命令キューでプリフェッチされていますが、同じ Web ページの 2 番目の段落には、プリフェッチljmpされた が無効になっていることが示されているため、CPU は次の命令を新たにフェッチする必要があります。「セグメントレジスタがリアルアドレスモードと同じリニアアドレスを指し続ける」魔法のような方法を説明していただけますか? ありがとうございました。

PS、私が取り組んでいる CPU は Intel i386 互換です。

4

1 に答える 1