“Unreal mode”と呼ばれているx86の状態について

Intel 80386以降において、リアルモードでありながらセグメントリミットを0ffffh以上(通常は0ffffffffh)に設定して、上位メモリを自由にアクセスすることを「Unreal mode」と呼称することがあるようです(実はこのような名前がついていることを最近まで私は知りませんでした)。これを「裏ワザ」扱いしているページもあるのですが、これは普通にマニュアルに書いてある動作なのです。

以前「Intelが予定していたIA-32の独自64ビット拡張の仕様を推測する」にも書いたのですが、セグメントレジスター(Segment Register)に書き込んだ値を元に、セグメントディスクリプターキャッシュレジスター(Segment Descriptor Cache Register)の値が更新されます。実際のアドレス計算の際に参照されるのはこのセグメントディスクリプターキャッシュレジスターの内容であり、セグメントレジスターの内容ではありません。

リアルモードであればベースアドレスをセグメントレジスターの値を16倍した値(4ビットシフトした値)に、セグメントリミットを0ffffhに、特権やタイプなどをその対象セグメントレジスターが従来のリアルモード互換になるようにセグメントディスクリプターキャッシュレジスターを設定します。プロテクトモードの非仮想8086タスクでは、セグメントレジスターに書き込まれた値の特権チェックを行い、問題がなければメモリ上のセグメントディスクリプターテーブルからセグメントレジスターに設定されたセグメントセレクター値に該当するセグメントディスクリプターを取り出して、セグメントディスクリプターキャッシュレジスターに設定を行います。プロテクトモードの仮想8086タスクの場合には、特権レベルが3になるように調整したうえで、リアルモードと同じようにベースアドレスとセグメントリミットをセグメントディスクリプターキャッシュレジスターに設定します(具体的にどのような設定が行われるかは、各モードについて説明する開発者向けドキュメントに記載があります)。

このセグメントディスクリプターキャッシュレジスターの値は、セグメントレジスターの更新時にのみ(一部例外あり)前述の変更が行われます。つまり、プロテクトモードとリアルモードの切り替えではフラッシュされません。このこともマニュアルに記載があります(なので、モードを変更したらすぐにセグメントレジスターなどの設定を更新すべし、といったようなことがいろいろと書いてあります)。

ですから、これは裏ワザではないんですよね…。

これが裏ワザ扱いされるようになってしまった背景には、おそらく386以降用仮想EMSドライバーやDPMIサーバーなどを使用するのが一般化したり、WindowsやLinuxなどの最初からプロテクトモードで動作するOSへと時代が移っていったりしたために、アプリケーションプログラムを書く人の間で、このプロテクトモードとリアルモードの切り替えに関する技術と知識の断絶が起き、いわばロストテクノロジー化してしまったことが原因としてあるのかもしれません。

確かに現在では自前でリアルモードとプロテクトモードの切り替えを行うこと自体、ほとんどありませんからね…。MS-DOS時代は結構みなさんいろいろとやってみていたんじゃないかと思います。

ちなみに、x86系CPUの起動時のモードはリアルモードで、実行開始実効アドレスは8086が0xffff0、80286が0xfffff0、80386/486/Pentiumが0xfffffff0(以下略)です。最初からリアルモードでありながら、1メガバイトのアドレスの範囲外なんですね。なので、この意味で起動時はリアルモードではなく、Unreal modeといえるのかもしれません 🙂