質問: 現在、「作りながら学ぶOSカーネル 保護モードプログラミングの基本と実践」という本でOSの仕組みについて学んでいます。 そこで、x86プロセッサについてリアルモードから保護モードへ移行する際にCR0の最下位ビット(PEビット)を1にすることでCPUが保護モードとして動作するようになるという記載がありました。 しかし、その後の32ビットコード部分へのジャンプ命令では、prefix(0x66, 0x67)をつけているようです。 CPUはすでに保護モード(32ビット)として動いているはずなのでprefixは不要と思えるのですが、なぜ必要となるのでしょうか? 確かに、prefixを外して実行するとうまくいきませんでした。 実際のNASMのコードは下記となります。 ``` mov eax, cr0 or eax, 0x00000001 mov cr0, eax jmp $+2 nop nop db 0x66 # <- ここ db 0x67 # <- ここ db 0xEA dd PM_Start dw SysCodeSelector ```
回答: 動作としては PE ビットをセットした瞬間に protected mode に移行しています。 この結果としてセグメントレジスタの使い方が変わります。 (real mode であればアドレスラインの上位を直接指定していますが、protected mode では GDT を指します) が、CPU はパイプライン(命令プリフェッチキュー)を持っているため、protected mode に移行する前にプリフェッチされた命令群は、リアルモードの CS のつもりで動作しようとしてしまいます。既に GDT に切り替わっているのに、です。当然うまく動いてくれません。 かといって protected mode に移行する前に CS を書き換えてもダメです(そうしたらそのあとの命令がうまく動かない)。 これを回避するために、キューをクリアするための方法として far jump を使うというテクニックなのです。 ※far jump は同時に CS を変更できる(GDTのロードも同時に行える)ので推奨されています