問題は、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 互換です。