GitHubに置いてある軽量ハイパーバイザxhyveにはテスト用に軽量LinuxのTinyCoreが含まれています。
xhyveをビルドしてTinyCoreを起動、プロンプトが出たらsudo haltする、というページは見かけるのですが、
実際に使ってみる例はDockerしか見当たりません。
そこで、Linux用のBasiliskIIを走らせ、VNC接続で使えるようにしてみました。
そんなことしなくてもmacOS用のBasiliskIIはあります。
ところが、64ビット版のBasiliskIIにはJITコンパイラがありません。
そこで、TinyCoreでJITコンパイラありのものを走らせることで、高速化できると考えたのです。
まあ、xhyveを使ってみたいという動機の方が大きいですが。

xhyveの準備

ビルド環境がある場合は以下のようにして準備します。
$ git clone https://github.com/machyve/xhyve.git
$ cd xhyve
$ make
ビルド環境がない場合、Homebrewを使えば
$ brew install xhyve
でインストールできます。
この場合は後述の実行用スクリプトのパスを適宜変更してください。

TinyCoreのインストール

xhyveに同梱されているTinyCoreは64ビット版なので、TinyCoreのサイトから32ビット版のバージョン9.0を落としてきます。
それより新しい版ではudevdがエラーを吐き続けるので、9.0にしました。
$ curl http://tinycorelinux.net/9.x/x86/archive/9.0/Core-9.0.iso > Core-9.0.iso
$ open Core-9.0.iso
xhyveは自前でウィンドウを開く機能がなく、VNCが使えるようになるまではシリアルでログインしている状態です。
ブート中にrootが自動ログインできるようにパッチを当てる必要があります。
そのためのスクリプトをpatch.shとして保存します。
#! /bin/sh
rm -f core.gz initrd.gz vmlinuz
rm -fr initrd
cp -p /Volumes/Core/boot/{core.gz,vmlinuz} .
mkdir initrd
cd initrd
gzip -dc ../core.gz | cpio -idm
sed -i -e '/^# ttyS0$/s#^..##' etc/securetty 
sed -i -e '/^tty1:/s#tty1#ttyS0#g' etc/inittab
find . | cpio -o -H newc | gzip -c > ../initrd.gz
スクリプトを実行します。cpioで適切なowner/groupを設定するため、sudoが必要です。
$ chmod +x patch.sh
$ sudo ./patch.sh
空のディスクイメージを作ります。200Mバイトあれば十分です。
$ dd if=/dev/zero of=TinyCore.img bs=200m count=1
以下の実行用スクリプトをrun.shとして保存します。
#! /bin/sh
build/xhyve \
	-A \
	-m 256 \
	-s 0:0,hostbridge \
	-s 2,virtio-net \
	-s 3,ahci-cd,Core-9.0.iso \
	-s 4,virtio-blk,TinyCore.img \
	-s 31,lpc \
	-l com1,stdio \
	-U deadbeef-dead-dead-dead-deaddeafbeef \
	-f kexec,vmlinuz,initrd.gz,"quiet home=vda1 opt=vda1 tz=JST-9 waitusb=1 console=ttyS0"
実行します。ネットワークを使う場合はsudoが必要です。
$ chmod +x run.sh
$ sudo ./run.sh
CDをマウントし、インストーラをダウンロードして実行します。
tc@box:$ sudo mount /dev/sr0
tc@box:$ tce-load -wil tc-install
tc@box:$ sudo tc-install.sh
以下の順に入力します。
[C]drom enter
[H]dd enter
enter
[3] (ext4) enter
enter
[Y] enter
enter
バックアップするファイルリストを空にして終了します。
tc@box:$ echo > /opt/.filetool.lst
tc@box:$ sudo halt

VNC接続

VNCで接続できるようにします。
tc@box:$ tce-load -wi Xlibs realvnc aterm twm
~/.profileに以下の行を追加します。
ps | grep Xvnc4 | grep -v grep > /dev/null || vnc4server -ac -depth 24
~/.vnc/xstartupを以下のようにします。
#! /bin/sh
xterm -geometry 80x24+0+0 &
twm &
vnc4serverスクリプトにはTinyCoreに合わない部分があるので、/opt/bootlocal.shに以下の行を追加します。
cd /usr/bin
ln -s ../local/bin/mcookie
cd ..
mkdir X11R6
cd X11R6
ln -s ../local/lib
一旦終了して再起動すると、VNC用のパスワード入力を求められます(初回のみ)。
tc@box:$ ifconfig
でeth0のIPアドレスを確認し、macOS側でcommand+Kでvnc://IPアドレス:5901と入力すればVNCが繋がります。
ちなみに、run.shの-Uで適当なUUIDを指定してIPアドレスが変わるのを防いでいます。
また、複数のxhyveを同時に使うときは各々UUIDを変える必要があります。



この画面、私が初めてSunのワークステーションに触れたときにそっくりです。懐かしい。
(スクリーンショットを撮るためにvnc4serverのコマンドラインオプションに-geometry 640x480を追加しています)
懐かしいのはいいのですが、このバックグラウンドの模様、適度にボケたCRTと違って液晶だと目がチカチカするので、
tc@box:$ tce-load -wi xsetroot
でxsetrootをインストールして、~/.vnc/xstartupに
xsetroot -solid gray20
を追加しました。
ところで、ネット越しにVNCを使うと画質が落ちることがありますが、同一マシン上なのでそのようなことはありませんでした。

ファイル共有

ホストとファイル共有できるようにします。
tc@box:$ tce-load -wi cifs-utils
以下のようなスクリプトをsmb.shとして保存します。
<host><sharename><username>の部分はホストに合わせてください。
#! /bin/sh
mkdir -p /mnt/smb
sudo mount.cifs //<host>/<sharename> /mnt/smb -o uid=1001,gid=50,username=<username>
実行します。
tc@box:$ chmod +x smb.sh
tc@box:$ ./smb.sh
パスワードを入力すると、(ioctl errorが出ますが)/mnt/smb下にマウントされます。

BasiliskIIのビルド

ビルド環境をインストールします。
tc@box:$ tce-load -wi SDL2
tc@box:$ tce-load -wo compiletc automake SDL2-dev
tc@box:$ tce-load -wil zip-unzip
tce-loadのオプションを使い分けてみました。
-wiは、tce-load時の他、ブートの度にロードします(onboot)。
-woは、パッケージ名をコマンドとして実行するとロードします(ondemand)。
-wilは、tce-load時だけロードします。

https://github.com/kanjitalk755/macemuからZIPを落としてきて、TinyCore側に展開します。
tc@box:$ /usr/local/bin/unzip /mnt/smb/Downloads/macemu-master.zip
tc@box:$ cd macemu-master/BasiliskII/src/Unix
ビルド環境をロードします。
tc@box:$ compiletc; automake; SDL2-dev
パッケージとコマンドが同じ名前の場合、そのコマンドを実行する仕様のため、automakeでエラーが出ますが、気にせずreturnを押します。
続いてビルドします。
tc@box:$ ./autogen.sh --enable-jit-compiler
tc@box:$ make
tc@box:$ ./BasiliskII
とするとCannot open ROM file.で終了しますが、これでダミーの初期設定ファイル(~/.basikisk_ii_prefs)ができるので、以下の行を追加します。
disk /mnt/smb/path_to_MacintoshHD
rom /mnt/smb/path_to_ROM
screen dga/1024/768
これでとりあえず走りますが、すでにある行を以下のように書き換えるとより良いでしょう。
extfs /mnt/smb
ramsize 32
frameskip 0
modelid 14
cpu 4
fpu true
jitcachesize 16384
ホスト側の上記で指定した場所にROMとMacintoshHDを用意し、
tc@box:$ ./BasiliskII
で起動します。
画面にBasiliskIIと書いてある小さな矩形が現れたら、それをクリックします。
画面が真っ黒の場合はマウスをちょっと動かしてみてください。
起動してから気がついたのですが、run.shで指定したインストールCDがBasiliskII上でマウントされていました。
"Unix"フォルダもホスト側のものなので、使い勝手はmacOS版とほぼ同じです。

Mac mini 2014 (i7/3GHz)で上記の設定で実行すると、アイドリング時、
xhyveのCPU使用率は4%程度、メモリ使用量は340MB程度でした。
macOS用だとCPU使用率は10%程度、メモリ使用量は60MB程度でした。
メモリが余分に必要なのは仕方ないですが、今時のマシンなら問題ない量です。
CPU利用率はなぜか減少しています。

BasiliskIIが走っている状態の使用メモリです。
再起動してondemandパッケージが入っていない状態です。
tc@box:$ free -m
             total       used       free     shared    buffers     cached
Mem:           246        153         92         17          9         61
-/+ buffers/cache:         82        163
Swap:           55          0         55
ディスク使用量は以下の通り。
Filesystem                Size      Used Available Use% Mounted on
/dev/vda1               189.7M    140.8M     44.9M  76% /mnt/vda1
さすがTinyCore、どちらもコンパクトです。

ベンチマーク

MacBenchの結果です。



赤がxhyve+TinyCore版、黄色がmacOS版です。
JITコンパイラでCPU性能は4倍以上になっていますが、(共有ではない)ディスクアクセスが1/7程度と遅い結果となりました。
.basikisk_ii_prefsのjitcachesizeは16384です。この値を小さくするとCPU性能は下がるのですが、なぜかディスクアクセスは速くなります。
今回はCPU性能優先としました。
ファイルキャッシュが十分に取れるように使用メモリを1Gバイトにしてもほとんど変わりませんでした。

次に実使用のスピードを調べます。
昔仕事で書いたプロジェクトをビルドするのにかかった時間は以下のようになりました。
xhyve jit true : 21秒
xhyve jit false: 66秒
macOS jit false: 27秒
残念ながら期待したほど速くなりませんでした。
ファイルアクセスが足を引っ張っています。ただ、ファイル共有が遅いわけではありません。
ext4にコピーして、そのディスクイメージを使ってもほとんど速くなりませんでした。

SheepShaverの場合

SheepShaverはアドレス0から読み書きできる必要があります。
TinyCoreにはvm.mmap_min_addrの設定がないようなのでrootで実行する必要があります。
そのためにちょっと変更を加えます。
tc@box:$ cd macemu-master/SheepShaver/src/Unix
このディレクトリにあるprefs_unix.cppの
char *home = getenv("HOME");

char *home = "/home/tc";
に書き換え、ビルドします。
tc@box:$ ./autogen.sh
tc@box:$ make
tc@box:$ ./SheepShaver
これでダミーの初期設定ファイル(~/.sheepshaver_prefs)ができるので、BasiliskIIと同様の変更を加えます。
ramsizeは128くらいがいいでしょう。
modelid,cpu,fpu,jitcachesizeの項目は不要です。
tc@box:$ sudo ./SheepShaver
で起動します。

トラブルシューティング

偽のキー入力が続いたり、クリックが異常な場合があります。
このような場合は一旦VNCウィンドウを閉じて再度接続すると直ります。

免責

このページの内容を試した結果、何らかの損害を受けたとしても、免責とします。