MS-DOS 4.0 がオープンソースになったのでビルドしてみる

MS-DOS 4.0 のソースコードが発掘されたそうです。

https://pc.watch.impress.co.jp/docs/news/1587762.html

MS-DOS 4.0 のリリースは 1986 年、あの[ハレー彗星](https://ja.wikipedia.org/wiki/ハレー彗星)がやってきた年です。もはや古典ですね。

# ビルドしてみる
せっかくなのでビルドして遊んでみましょう。なお以下では Ubuntu（正確には Windows 上の WSL）を使用しました。

## FreeDOS 環境を用意する
大昔の OS というだけあってビルドも一筋縄ではいきません。まずは MS-DOS 互換である **FreeDOS** の仮想環境を作ります。[公式サイトのダウンロードページ](https://www.freedos.org/download/)から LiveCD データをダウンロードしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/ecccd6ce-3983-a71a-efca-ea5fee7d3d7d.png)

ダウンロードした zip ファイルを解凍します。

```console
$ unzip FD13-LiveCD.zip
Archive:  FD13-LiveCD.zip
  inflating: FD13BOOT.img
  inflating: FD13LIVE.iso
  inflating: readme.txt
```

`FD13LIVE.iso` というのが入っているので、こいつを後で使います。

次に、プロセッサエミュレータ **QEMU**（きゅーえみゅ）をインストールします。

```console
$ apt install qemu-system
```

QEMU で使う用のディスクイメージを作成します。

```console
$ qemu-img create -f qcow2 freedos.1.3.qcow2 500M
```

ディスクサイズ 500 メガバイトのイメージを qcow2 フォーマット で作成し、`freedos.1.3.qcow2` に保存します。ファイル名はお好みで変更してください。また FreeDOS はインストール要件として 20 メガバイト以上のディスク容量を要求しているので、500 メガバイトもあれば十分すぎるくらいでしょう。~~ちなみに Windows 11 は 64 **ギガ**バイト要求します~~

そしたら今度は FreeDOS のエミュレートを開始します。

```console
$ qemu-system-x86_64 -boot order=d -cdrom FD13LIVE.iso freedos.1.3.qcow2
```

このように打つと、CD ドライブに FreeDOS のインストール用 CD が入っている「かのように」エミュレートしてくれます。起動したら "Install to harddisk" を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/851cac81-a5fa-7d95-8bfe-2a02f98dfe33.png)

次に言語を選択します。ほとんどの方は英語でよいでしょう。~~日本語なんてあるわけなかった~~

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/4de94601-a68d-5c45-43ca-db7b3b50912d.png)

これ以降いくつか質問されますがすべて Yes と回答すれば OK です。途中で C ドライブをパーティション分割したりフォーマットしたりするか尋ねられますが、これはあくまでも仮想環境の内部での話なので安心して Yes と答えてください。また途中で再起動を求められるので、一回最初からやり直しになります。面倒ですが同じ手続きを繰り返してください。

インストールを進めるとキーボードレイアウトの選択ができます。"More keyboard choices..." からは Japanese も選択できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/8476a63e-49bf-22e5-1489-419d9e9919d4.png)

最後にインストール形式を決めます。今回は MS-DOS をビルドするための環境として使うだけなので、Plain DOS system で十分でしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/ed05f3c6-5225-586e-5f07-680eb39a9f23.png)

plain とはいえ結構時間がかかります。私の環境では 25 分ほどかかりました。気長に待ちましょう。

インストールが完了したら最初の画面に戻ってきます。"Boot from system harddisk" を選択しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/aea137d2-0215-a62a-10a9-85c78ceba50d.png)


その次はこんな画面になるのですが、~~よくわからないので~~デフォルトの 2 番を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/b6e3cc20-11a0-f15c-7229-d34c614adac3.png)

すると、このようにプロンプトが表示されます。無事 FreeDOS がインストールできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507500/074e4365-7755-c09c-fa93-c1f8bf8339cc.png)

`shutdown` コマンドで FreeDOS を終了させることができます（QEMU のウィンドウ自体を閉じてしまってもいいのですが）。またこれで（仮想環境上の）C ドライブへのインストールが完了したので、以降は以下のコマンドで FreeDOS 環境を起動できます。

```console
$ qemu-system-x86_64 freedos.1.3.qcow2
```

## MS-DOS をダウンロードする
GitHub 上で MS-DOS のソースコードが公開されています。

https://github.com/microsoft/MS-DOS

これをダウンロードします。

```console
$ git clone https://github.com/microsoft/MS-DOS
```

今回ビルドするソースコードは `MS-DOS/v4.0/src` ディレクトリに入っています。

```console
$ cd MS-DOS/v4.0/src
```

ですが、このソースコードは一部文字化けを起こしています。それを修正します。

```bash
for f in MAPPER/GETMSG.ASM SELECT/SELECT2.ASM SELECT/USA.INF ; do
  sed --in-place --regexp-extended 's/\xEF\xBF\xBD|\xC4\xBF|\xC4\xB4/#/g' $f ;
done
```

また FreeDOS 環境でビルドできるように改行コードの変換も行う必要があります。これには `unix2dos` コマンドが使えます。

```console
$ apt install dos2unix
```

```bash
find . -iname '*.BAT' \
  -o -iname '*.ASM' \
  -o -iname '*.SKL' \
  -o -iname 'ZERO.DAT' \
  -o -iname 'LOCSCR' \
  | xargs unix2dos --force
```

次にビルド用スクリプトを少々書き換える必要があります。まず `src/SETENV.BAT` を一つ上のディレクトリへコピーします。

```console
$ cp SETENV.BAT ..
```

そしたら（コピー先の方を）以下のように変更します。

```diff_batchfile
@echo off
echo setting up system to build the MS-DOS 4.01 SOURCE BAK...
set CL=
set LINK=
set MASM=
set COUNTRY=usa-ms
- set BAKROOT=d:
+ set BAKROOT=C:
rem BAKROOT points to the home drive/directory of the sources.
- set LIB=%BAKROOT%\src\tools\lib
+ set LIB=%BAKROOT%\src\tools\bld\lib
set INIT=%BAKROOT%\src\tools
- set INCLUDE=%BAKROOT%\src\tools\inc
- set PATH=%BAKROOT%\src\tools
+ set INCLUDE=%BAKROOT%\src\tools\bld\inc
+ set PATH=%BAKROOT%\src\tools;C:\freedos\bin
```

# MS-DOS ソースコードを FreeDOS 環境下に移動する
最後に FreeDOS 環境下へソースコードを移動します。

まずはマウントポイントとして使うための適当なディレクトリを作ります。必ず中身が空になっていることを確認してください。

```console
$ mkdir /tmp/freedos
$ ls -la /tmp/freedos/
total 16
drwxr-xr-x  2 root root  4096 May  3 11:42 .
drwxrwxrwt 13 root root 12288 May  6 17:13 ..
```

次に FreeDOS 環境をマウントします。これには `guestmount` コマンドを使います。

```console
$ apt install libguestfs-tools
$ apt install linux-image-generic
```

マウント後、必要なファイルをコピーします。それが済んだらマウントを解除します。

```console
$ guestmount --add ../../../freedos.1.3.qcow2 --mount /dev/sda1 /tmp/freedos/
$ cp ../SETENV.BAT /tmp/freedos
$ mkdir /tmp/freedos/SRC
$ cp --recursive . /tmp/freedos/SRC
$ guestunmount /tmp/freedos
```

## ビルド
コピーが済んだら再度 FreeDOS 環境を起動します。

```console
$ qemu-system-x86_64 ../../../freedos.1.3.qcow2
```

その後ビルドを行います（以下のコマンドは FreeDOS 環境で打つコマンドであることに注意してください）。

```console
> SETENV
> cd SRC
> nmake
```

このビルドにも時間がかかります。私の環境では約 1 時間かかりました。気長に待ちましょう。

次に生成されたファイルを適当なディレクトリに移動します。

```console
> mkdir \DOS4
> cpy \DOS4
> cd \DOS4
```

最後にシェルを呼び出します。これで MS-DOS 4.0 環境が動きます。お疲れさまでした。

```console
> callver 4.00 command.com

Microsoft(R) MS-DOS(R) Version 4.00
             (C)Copyright Microsoft Corp 1981-1988
```

# HelloWorld してみる
せっかくなので HelloWorld してみたいと思います。ただし C コンパイラなんて贅沢なものはあるわけないのでアセンブリで書いていきます。ただ現在の状態だと FreeDOS 環境下のプログラムも呼び出せてしまい、それではあまり意味がないので環境変数を少々書き換えます。

```console
> path C:\DOS4
> set comspec=C:\DOS4\command.com
> set dosdir=C:\DOS4
```

次に `debug` コマンドを呼び出します。これを使うとアセンブリをその場で実行することができます。以下のようなコードを書いてみましょう。

```console
> debug
-A
0B41:0100 MOV AH, 9
0B41:0102 MOV DX, 108
0B41:0105 INT 21
0B41:0107 RET
0B41:0108 DB 'hello, world' D, A, '$'
0B41:0117
-G
hello, world
```

無事 HelloWorld できました。

# おわりに
無事に MS-DOS 4.0 環境を再現できました。ただ今やっていることは FreeDOS 環境から MS-DOS 環境へのシェルを呼び出すことなので、正直ほんとうに MS-DOS という OS そのものを復元したとはいいがたいところです。ぜひ有識者の方の意見を伺わせていただきたいところです🙇

# 参考
https://www.youtube.com/watch?v=X7r76V_gWQ8