借り初めのひみつきち

仮ブログです。

ロングモードと64ビットモードの違い

ロングモードと64ビットモードの違い、分かりますか?

おそらく多くの人が混乱していると思うのでブログにまとめます。(そしてぼくは混乱してないことを祈る

極論を言うと、現代の x86 系プロセッサにはリアルモード、プロテクトモード、ロングモードの3つのモードしかありません *1
仮想8086モード、互換モード、64ビットモードなどというモードは存在しないのです。(え?

リアルモード、プロテクトモード、ロングモードの3つのモードを切り替えるにはシステムレジスタの CR0 の特定のフラグを操作する必要があります。逆にいうとそれ以外の方法では切り替わりません。

では、仮想8086モード、互換モード、64ビットモードはどうでしょう?
これらは eflags やコードセグメントのフラグを操作することで切り替わります。
つまり、割り込みで切り替わります。

一方、リアルモード、プロテクトモード、ロングモードはそれぞれ割り込みの仕組みが違います。(IDT からディスクリプタをロードする大まかな仕組みはよく似ていますが・・・)
割り込みでこれらのモードを行き来することはできません。

ここに大きな違いがあります。

システムとしてはリアルモード、プロテクトモード、ロングモードのどれかで動作しているのに対し、仮想8086モード、互換モード、64ビットモードの3つは単なるコンテキストの違いでしかありません。

最初の x86 系プロセッサの 8086 には制御フラグが flags レジスタしかありませんでした。
このレジスタの中には演算命令の結果でばたばた変わるフラグもあれば、割り込みを禁止するとても危険なフラグまですべてひとつのレジスタで管理していました。
今考えるととてもおろそしい仕様ですが、当時はこれが普通だったようです。

8086 が成功してマルチタスクのための大幅な拡張を施した 80286 が出たとき、この常識が覆されました。
システムの基本的な制御は MSW というレジスタで管理し、 flags レジスタはコンテキストごとの状態を保持するように明確に分離されました。
のちに MSW は 80386 が出たときに CR0 という名前に変わりましたが、基本的な路線は踏襲されました。

仮想8086モードに移行するには必ずプロテクトモードから切り替える必要があり、例外や割り込みが発生するとプロテクトモードの仕組みを使って基本的にはプロテクトモードに戻ります。*2
このことから eflags で切り替わる仮想8086モードはプロテクトモードで動作するシステムの中のコンテキストのひとつということがわかります。

一方、互換モードと64ビットモードはセグメントディスクリプタの L ビットの値で切り替わります。
ロングモードに移行直後は互換モードですが、例外や割り込みが発生するとロングモードの仕組みを使って64ビットモードに切り替わります。
やはりこの2つはロングモードで動作するシステムのコンテキストのひとつです。

プロテクトモードの時代にも16ビットで動作するモードと32ビットで動作するモードがありましたが両者を区別する正式な名前はありませんでした。*3
ロングモードの時代になってわざわざ64ビットモードだけ特別扱いするのはどうなのかな?と思いました。

*1:VMM や SMM は除く

*2:あくまで基本的なので割り込みでプロテクトモードに戻らない拡張機能があるし、タスクゲートで仮想8086モードのタスクに切り替えることは可能な気がします

*3:混在していたwin9Xは悪者扱いでした