R-AXISのWin2000を仮想化!  

概要  

2019年夏、某所にあるR-AXIS 7のWindows 2000 PCが起動しなくなったから何とかして欲しい、という話がありました。
状況を見てみると、(懐かしの)OS起動画面の途中でフリーズしてしまう模様。以前は何度かリセットすると起動することがあったとのことでしたが、同じところで止まってしまう状態でした。サービスに見てもらったが、掃除などの応急処置でも回復せず、修理(交換?)にはウン百万円かかるとのこと。残念ながらそれだけのおカネは用意できないとのことで私にお声がかかったのでした。

ものすごい苦労したので、ひょっとしたら誰かが同じことをする際にヒントにでもなればいいなと思い、メモしておきます。前提としてLinuxの操作全般、仮想化(KVM、VT-d)、Win2000設定、おまけとしてBIOS設定の知識が必要となります。

結果  

戦略  

状況から考えると、PCのハードウェア周りの老朽化が考えられました。ハードディスクのクラッシュの可能性もありましたが、特有のカッシャン音(リードリトライ時のアクセス音)がしなかったために、とりあえず除外。まあ15年も前の機体なのでコンデンサ周りなのかなぁと判断しました。
考えられる戦略は以下です。

おそらく一番簡単なのは、本体の交換ですが、さすがに同じ機種(OPTIPLEX GX260)は手に入りにくいようです。Amazonで本体が25まんえんほど、海外のサイトで中身が数万円で売られていましたが、いかんせん古いため、ギャンブルをするにはちょっと高いかなぁということで断念。

続いて、Win2000が動く程度に古いPCということでPRECISION T3400を発掘してきて、CrystalClearの動作までは何とか持って行けたのですが、本体とSCSIがうまく通信できませんでした。これはPCが悪いのか、発生装置本体が悪いのか不明なのですが、とりあえず断念(さらりと書きましたが、めちゃくちゃ苦労した)。

ということで、長い目で見て代替が利きやすい「仮想化」をやってみました。

仮想化しよう!  

解決までに必要なこと  

そんなわけで仮想化作業を開始しました。仮想化して動作させるには以下の問題を解決する必要がありました。

仮想ホストの準備  

まずは仮想ホストがないと話になりません。ここで必要となるPCは、以下の条件を満たす必要があります。

シリアルとパラレルに関してはPCI Express用/USB用などがあるのでどうとでもなると思いますが、PCIスロットが2本というのが結構クセモノです。古いマザーボードなら付いていることが多いのですが、古すぎるとCPUがVT-dに対応していなかったりするので難しいところです。第2世代のCoreシリーズあたりからちらほら対応しているようですが、新しい方がいいでしょう。

本体が準備できたらOSをインストールします。今回は私が使い慣れているCentOS7のLiveDVDからインストールしました。続いてメディアをファイル化していきます。

システムリカバリー  

RAXIS本体とともに付属していたフロッピーディスクとCD-ROMからシステムを復元する必要があります。
仮想環境ですので、全てをイメージファイルにしてしまいます。むしろファイルになってしまえば、メディアで持っているよりも遙かに安心なのです!

ただ、フロッピードライブ(FDD)が手元にあるかどうか、という問題が発生します。ない場合はAmazonなどでUSBのフロッピードライブを手に入れましょう。用意したLinuxにフロッピードライブを取り付け、ddコマンドでファイルにします。調べればいろいろ出てきますが、単純には、dd if=/dev/fd0 of=fdimage.vfdで読み込めます。当然1.44MBサイズです。

続いて、付属CD-ROMをイメージ化するのですが、大きな問題がありました。なんと、CDがマルチセッションで書かれている!のです。マルチセッションだと、どうやらLinuxでは読めない(方法はあるのかもしれませんが)ので、Windows PCを使って読み込みます。結局Rawイメージで取り出す必要はなく、Windowsで読み込んだときに見える全てのファイルをコピーしてDVDイメージにしてしまいます。

以上より、必要なイメージは以下になります。

RAXISDriveImageAll.isoにはBACKUP.PQI〜BACKUP.009のファイルがあればよさそうです。ついでにBOOTCAT.BIN、BOOTIMG.BINというファイル、上記のフロッピーイメージ、RAXVideoのフロッピーイメージ、謎のデータフロッピーイメージなどを収録しました。

上記のファイルが揃えばリカバリーに入ることができます。
仮想環境として、IDE HDD(50GBぐらい)、FDDがついていればよさそうで、FDDにはRAXISDriveImageBoot.vfd、CDドライブにはRAXISDriveImageAll.isoをそれぞれマウントして、FDDからブートすると、リカバリーが始まります。PCの性能によりますが、3時間程度かかりました。

これでWin2000が起動する準備が整いました!
ちなみに、このDriveImageでリカバリーできるまで半日以上苦戦しました。マルチセッションCDのマルチセッションに何の意味もない、ということに気づいてからは早かったのですが。

この先も苦戦が続きます。

PCI Passthrough  

システムリカバリーデータからWin2000の仮想環境が構築されたところで、続いて、制御用I/Fカード(おそらくSCSI)およびビデオキャプチャーカードの認識が必要になります。
それらのカードはPCI Passthoughで仮想ホストのPCIスロットに挿入したカードを認識させます(そのためにVT-dが必要)。通常は、virt-managerでPCI Passthroughすれば認識されると思うのですが、以下のエラーメッセージでうまくいかず…

2019-09-26T18:39:31.065509Z qemu-kvm: -device vfio-pci,host=05:01.0,id=hostdev0,bus=pci.0,addr=0x8,rombar=1: vfio: Error: Failed to setup INTx fd: Device or resource busy
2019-09-26T18:39:32.199813Z qemu-kvm: -device vfio-pci,host=05:01.0,id=hostdev0,bus=pci.0,addr=0x8,rombar=1: Device initialization failed.
2019-09-26T18:39:32.199843Z qemu-kvm: -device vfio-pci,host=05:01.0,id=hostdev0,bus=pci.0,addr=0x8,rombar=1: Device 'vfio-pci' could not be initialized
2019-09-26 18:39:32.232+0000: shutting down, reason=failed

どうやらVFIOでエラーが出て起動できないようです。ここで出てくる単語などで検索したのですが、私が探した範囲ではこれといった解決方法は見つかりませんでした。が、dmesgを見ていると怪しげなカーネルエラーを発見しました。

[  114.355790] vfio-pci 0000:05:01.0: enabling device (0100 -> 0101)
[  114.356123] genirq: Flags mismatch irq 17. 00000000 (vfio-intx(0000:05:01.0)) vs. 00000080 (snd_hda_intel:card1)
[  114.356126] CPU: 6 PID: 3775 Comm: qemu-kvm Not tainted 3.10.0-1062.1.1.el7.x86_64 #1
[  114.356128] Hardware name: System manufacturer System Product Name/P8Z77-V, BIOS 2003 05/09/2013
[  114.356137] Call Trace:
[  114.356144]  [<ffffffffa0f792c2>] dump_stack+0x19/0x1b
[  114.356147]  [<ffffffffa09502ca>] __setup_irq+0x52a/0x590
[  114.356150]  [<ffffffffc0c7aba0>] ? virqfd_wakeup+0xc0/0xc0 [vfio_pci]
[  114.356152]  [<ffffffffa095048c>] request_threaded_irq+0xcc/0x180
[  114.356155]  [<ffffffffc0c7a83a>] vfio_intx_set_signal+0x10a/0x1f0 [vfio_pci]
[  114.356157]  [<ffffffffc0c7b2a8>] vfio_pci_set_intx_trigger+0xc8/0x1b0 [vfio_pci]
[  114.356159]  [<ffffffffa0a4521a>] ? __check_object_size+0x1ca/0x250
[  114.356161]  [<ffffffffc0c7b81e>] vfio_pci_set_irqs_ioctl+0x6e/0x110 [vfio_pci]
[  114.356172]  [<ffffffffa09dbe7f>] ? memdup_user+0x4f/0x80
[  114.356174]  [<ffffffffc0c78d33>] vfio_pci_ioctl+0x373/0xd30 [vfio_pci]
[  114.356176]  [<ffffffffa0a23622>] ? kmem_cache_alloc+0x1c2/0x1f0
[  114.356178]  [<ffffffffa0a4521a>] ? __check_object_size+0x1ca/0x250
[  114.356180]  [<ffffffffc0c6f296>] vfio_device_fops_unl_ioctl+0x26/0x30 [vfio]
[  114.356184]  [<ffffffffa0a5d9e0>] do_vfs_ioctl+0x3a0/0x5a0
[  114.356186]  [<ffffffffa0a48738>] ? vfs_write+0x168/0x1f0
[  114.356188]  [<ffffffffa0a5dc81>] SyS_ioctl+0xa1/0xc0
[  114.356191]  [<ffffffffa0f8cede>] system_call_fastpath+0x25/0x2a

この、メッセージの赤く示した部分に注目すると、genirq: Flags mismatch irq 17. 00000000 (vfio-intx(0000:05:01.0)) vs. 00000080 (snd_hda_intel:card1)で、IRQ 17で何らかの不都合が起こっているのではないかと読み取れます。ここのvfio-intx(0000:05:01.0)が認識させたい制御用カードで、それとsnd_hda_intel:card1(おそらくIntelのサウンド関係のチップ)がぶつかっているような気がします。

実際、/proc/interruptsを見ると、以下のようになっていました(一部省略)。

          CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       
12:          3          1          1          0          1          0          0          0  IR-IO-APIC-edge      i8042
16:         18          2          1          0          0          2          0          6  IR-IO-APIC-fasteoi   ehci_hcd:usb1, cx88[0]
17:        831         52         22         38        131         37         13         42  IR-IO-APIC-fasteoi   snd_hda_intel:card1
18:          0          0          0          0          0          0          0          0  IR-IO-APIC-fasteoi   i801_smbus

IRQ 16にビデオキャプチャーカードのcx88、IRQ 17に制御用カードなのですが、IRQ 16はehci_hcd、IRQ 17はsnd_hda_intelも割り当てられています。もっとスマートな解決方法があるかもしれませんが、面倒なので認識されているデバイスをアンバインドしてドライバを解放することにしました。

# cd /sys/bus/pci/drivers/snd_hba_intel
# ls  <-- 接続されているPCIデバイスIDが表示されるので、それらをアンバインドする
# echo "0000:00:1d.0" > unbind

これで解放されました。一方のIRQ 16はEHCIなので、解放するとどこかのUSBポートが使えなくなりますが、まあ仕方がないです(実際、キーボードとマウスをつないでいたポートが使えなくなりました…)。

# cd /sys/bus/pci/drivers/ehci-pci
# echo "XXX(詳しいIDを忘れた)" > unbind

この処理を行った後で、仮想Win2000を起動すると…起動しました!
ドキドキしながら起動を待つと、Win2000でも、制御用カードとビデオキャプチャカードが認識され、ドライバがインストールされました!
ただし、プリンタポートがないので、ドングルが認識されずCrystalClearが起動しないので、さらに続きます。
(シリアルポートとプリンタポートに続く)