リアル・モードとプロテクト・モードに対応
 さて,MS-DOSは大成功となったが,この成功はIntelにとっても追い風となった。そこで1982年,Intelはさらなる高機能CPU「80286」を発表する。このCPUは,「プロテクト・モード」と呼ぶモードを持ち,メモリーの保護機能やマルチタスクが利用でき,アドレスも16Mバイトまで拡張された。そして特筆すべきは,8086と互換性のある「リアル・モード」という動作モードを備えていることだった。

 先ほども説明したように,8086は8080との互換性を維持するため,16ビットのレジスタを2つ使ってアドレスを指定する。このようなプログラムを,アドレス空間も命令も違うCPUで,そのまま動かすことはできない。そこでIntelは,8086と互換性のある命令とアドレス空間を提供する「リアル・モード」を用意した。しかもリセット時はリアル・モードから起動するため,MS-DOSにとっては,CPUが80286であることすら気付かない。

 ただリアル・モードを使用するだけなら,単に動作周波数の高い8086に過ぎない。80286を使う理由は,もう1つの動作モード「プロテクト・モード」にあるのだから,Intelは次世代のOSでは,ぜひこの機能を使ってほしいと考えていた。そうはいっても,まずは80286を搭載したパソコンが無ければ始まらない。そこで80286を搭載した「IBM PC AT」が1984年に登場する。コンピュータの世界で,一度は耳にする「PC AT互換機」という言葉は,このパソコンが元祖である。

 そのころMicrosoftは,MS-DOSにグラフィカルなユーザー・インターフェースを搭載するため「Windows」というアプリケーションを開発していた。この初代Windowsは,PC ATで動作したが,プロテクト・モードは使用せず,MS-DOS上のリアル・モードで動作した。つまり最初のWindowsは,Windows上でMS-DOSを起動するのではなく,あくまでもMS-DOS上で動作するアプリケーションの1つだった。


△ 図をクリックすると拡大されます
図4●Windows 2.x実行時の80286のメモリー空間
 後に本命のプロテクト・モードを利用するWindows 2.x(Windows/286)も登場するのだが,残念ながら日本ではほとんど注目を集めなかった。Windows 2.xは,下位1Mバイトのメモリー空間にMS-DOSを残したまま,その上に広がるアドレス空間でプロテクト・モードを利用した。しかし,MS-DOSを使いたいときは,リアル・モードに戻すために「リセット」するという「荒技」を使った。これは,一度プロテクト・モードになった80286は,リセットするしかリアル・モードに戻す方法が無かったからだ。確かにリセットすれば下位1MバイトのMS-DOSが使えるとはいえ,WindowsよりMS-DOSを使う頻度の方が多かった当時の日本では,人気が出ないのもうなずけるだろう(図4)。

 しかしこの状況は1985年,80386(以降386)と呼ぶCPUが発表されて一変した。なぜなら386は「仮想8086モード」と呼ぶ新機能を保持していたからだ。実はこの機能こそが,現在のWindowsにつながる,最重要な動作モードなのである。

リセットなしにMS-DOSを実行できる仮想8086
 仮想8086モードとは386以降,現在のPentium 4まで続く,CPUの動作モードの一つである。このモードの特徴は,プロテクト・モード環境でもそのまま8086のコードが実行できる点にある。これにマルチタスク機能を組み合わせると,仮想的な8086マシンをシステム上に複数作り出せた。


△ 図をクリックすると拡大されます
図5●仮想8086モードを利用して動作する仮想MS-DOS
 仮想8086モードは,実行タスクである「仮想8086タスク」と,それを監視する「仮想8086モニター」で構成される。仮想8086タスクとは,基本的に8086と同じ動作をするタスクなのだが,割り込みなどの特殊な命令では,仮想8086モニターへ処理が切り替わり,8086をエミュレーションする。さらにこのような仮想8086マシンをページングによって複数のアドレス空間に配置し,そこにMS-DOSを読み込めば,それぞれが単独のアドレス空間を持った仮想MS-DOSマシンになるのである(図5)。

 この仮想8086モードは,オーバーヘッドが大きく処理速度が遅い。そのため,最新のPentiumでは「拡張仮想8086モード」と呼ぶ高速な仮想8086モードが用意されている。

 このような特殊なモードを386に搭載することにより,WindowsからリセットなしにMS-DOSを実行できるようになった。IntelとMicrosoftの関係は,CPUの新技術を新しいOS(Windows)が利用することで,繁栄してきたのだ。

 仮想8086モードが使えるようになると,WindowsとMS-DOSの融合は加速する。MicrosoftはWindows/386を発表しWindows上でMS-DOSを起動して見せた。この機能は,後のWindows 3.x/9xで,ほぼ完成の域に達することになる。

 Windows 9xを例にすれば,DOSプロンプトは複数起動してマルチタスクで実行でき,さらに640Kバイト以上の利用を可能にする「EMS(Expanded Memory Specification)」や,MS-DOSから1Mバイト以上の領域を利用できるようにする「XMS(eXtended Memory Specification)」といった機能まで利用できた。

 これほどまでにWindows 9xとMS-DOSの互換性が高かったのは,本物のMS-DOSを使っていたからに,ほかならない。Windows 9xは,起動こそMS-DOSが必要ないものの,内部ではMS-DOSのコードを利用していた。このようにWindows 9xは,仮想8086モードによるCPUの助けと,本物のMS-DOSのコードにより,その互換性を維持していたのだ。

 ここまでの話で,Windows上でMS-DOSを利用する方法は,ほぼ完成したかに見える。ところがWindwos 9xには,別の問題が残っていた。それはアプリケーションとシステムが完全に分離されていないという根本的な問題である。これはシステムの中にMS-DOSのコードがそのまま残っていることとも無縁ではなかった。ただこれだけは,NT系のOSを利用するほかに,解決策はないのである。

仮想的なDOSを作るNTVDM.EXE
 Windows XPを含めたNT系のWindowsには,MS-DOSはおろか一切16ビット・コードが含まれていない。では,どのようにMS-DOSアプリケーションを動作させているのだろうか。この答えの鍵を握るのは「NTVDM.EXE」というプログラムである。このプログラムは,ファイル名が「NT Virtual DOS Machine」の頭文字であることからも分かるように,MS-DOSのマシン環境をエミュレーションする“仮想DOSマシン”なのだ。もちろん仮想DOSマシンを作る方法は,Windows 9xと同じように仮想8086モードを利用している。

 MS-DOSのプログラムを32ビット・プロテクト・モードで動作させる一番の問題点は,プログラムの中に出てくる16ビット・アドレスを,どうやって32ビット・アドレスに変換するかということだ。これは単純に,ビットを増やしたり減らしたりすればいいわけではない。なぜなら8086のアドレスは,16ビットのセグメント・レジスタに入っている値を16倍したものに,さらに16ビットのオフセット・アドレスを加算するという方法を採用しているためだ(図3)。これは,32ビット・プロテクト・モードのアドレス方式とは異なっている。

 また,割り込みの問題もある。割り込みは,CPUのレジスタの状態を一時退避させ,割り込み処理が終了したら再びCPUを,割り込み前の状態に戻してから処理を再開する。MS-DOSプログラムなら,INT21を使うが,これをエミュレーションできないと,Windows 9xではMS-DOSのコードが実行できない。仮想8086モードは,これら面倒な処理を一手に引き受けてくれる。

 ただここまではNTVDM.EXEも,Windows 9xも基本的に同じだ。NTVDM.EXEが,Windows 9xと大きく違うところは,この一連の処理の中で,MS-DOSアプリケーション以外に,MS-DOSのコードが一切登場しない点にある。NTVDM.EXEは,完全なる32ビットWindowsアプリケーションである。これにより互換性は多少落ちるものの,安定性はほかのアプリケーションと変わらないものになる。

 NTVDM.EXEは,起動するとページングの機能を利用して1Mバイトのメモリー空間を作り出す。次にこのメモリー空間をMS-DOSと同じ配置で区切り,割り込みベクターやROM BIOSなどを割り当てる。ここまでは,Windows 9xと同じだ。しかし読み込むファイルは,「NTDOS.SYS」と「NTIO.SYS」というファイルであり,Windows 9xとは異なる。この2つのファイル名を聞いて,ピンとくるかもしれない。このファイルは,MS-DOSが起動するときに必要なMSDOS.SYSとIO.SYSの役割をするファイルである。


△ 図をクリックすると拡大されます
図6●NT系WindowsにおけるMS-DOSアプリケーション実行の仕組み
 このようにして仮想的なMS-DOSを作り上げると,後はMS-DOSのプログラムを読み込み,仮想86モードの助けを借りながら実行するだけだ。またプログラム・コードは,すべてNTVDM.EXEと仮想8086モードの管理下にあるため,ハードウエアへのアクセスや割り込みなども,可能な限りエミュレーションされる。そしてMS-DOSと同じ結果がコマンド・プロンプトのウインドウに表示されるように,Windows APIを呼び出す。こうなってしまうと,それ以降の処理は前回の解説と同じである。つまり,NTVDM.EXEがWindowsアプリケーションとしてAPIを呼び出すのであれば,発行されたAPIは割り込みにより,LPC(ローカル・プロシージャ・コール)が受け取り,再びWin32サブシステムへ伝えられ,カーネル・モードで動作するシステムへとつながるのである。これが,NT系のWindowsでMS-DOSプログラムを動作させる仕組みである(図6)。

 最後になるが,386以降のCPUを利用している限り,リアル・モードに遭遇することはもうないのだろうか。実は今でも一度だけ目にしているのである。それはマシンを起動した直後だ。このときだけは,最新のPentium 4であってもリアル・モードで起動する。まさに20年前のPC ATそのままの姿である。