U-EFI bootで起動するNetBSD USBメモリを作ってみる

これはNetBSD Advent Calendar 2017の21日めの記事です。

はじめに

最近のPCは従来BIOSと呼ばれていたOSを起動する仕組みに、U-EFIという新しい方式に変わりつつあります。 U-EFIになることで機能的にもできることが色々増えたりするのですが、ユーザー側から見てもっともわかりやすい変更は以下の点でしょう。

従来のBIOSではmbrというディスク管理の仕組みで記録された情報で起動していましたが、これはパーティション情報として格納できる最大値が2TBであったため、これ以上大きなディスクを正しく扱えませんでした。 既に一部のノートパソコン、特にタブレットPC等はレガシーBIOS互換機能が無く従来のMBR形式では起動できないマシンが存在します(MicrosoftのSurface系がそうらしい)。 また、Intelは2020年にレガシーBIOS互換機能のサポートを中止するという話もあります。

ということで、来るべきレガシーBIOS無し時代に向けて、U-EFI環境にNetBSDをインストールしてみます。

環境について

下準備

U-EFIではセキュアブートという機能があり、登録された署名チェックにパスしたOSしか起動できません。当然NetBSDが登録されているわけはないのでこの機能をBIOS/U-EFIメニューから無効にします。無効の方法は機種に依存するのでここでは言及しません。また、無効にできないマシンでは通常NetBSDを起動することはできません。

NetBSDのインストール方法

NetBSDをUSBメディアにインストールするには、適切にパーティションを設定し、NetBSDのディストリビューションバイナリを展開し、適切に設定をし、適切にブートローダを登録しなければなりません。通常のインストールではインストールメディアを起動してインストーラを使うものです。

インストールメディアを使用する

実はNetBSD 8.0(まだBETAで正式リリース前)以降、NetBSD/amd64ではU-EFIで起動するインストールメディアイメージが提供されています。 例えばdaily snapshotでは、http://nycdn.netbsd.org/pub/NetBSD-daily/netbsd-8/201712201920Z/images/の下にあるNetBSD-8.0_BETA-amd64-uefi-install.img.gzがそれです(daily snapshotは更新されていくため、日付部分は変わって行き、しばらくすると参照できなくなるので注意)。

これをdd(1)等でUSBに書き込んでやればU-EFIブートでNetBSDが起動し、今までどおりのNetBSDインストーラsysinst(8)が起動します。やったね!

しかしここで、大きな問題があります。少なくとも2017/12現在のNetBSD 8.0_BETAではsysinstでインストールを始めると従来通りの方法でdisklabelを書き、なぜかmbrでboot loaderがインストールされます。つまり、U-EFI boot環境に対応していません(たぶん。対応済みだったらごめんなさい)。これでは仮にインストールが終わっても、マシンによってはリブート後に起動できないというとても悲しい事態に陥ります。

ではどうするか。インストールイメージは使わず、NetBSDではお馴染みの手動コマンドによる設定と展開を行います。

手動インストール

手動インストール作業自体はOSは何でもいいのですが、ファイルやツールの準備も含めて全部既に動作しているNetBSD/amd64 8.0_BETA上で行います(旧バージョンのNetBSD 7.1等の場合でもたぶん同じように実行できますが、一部別途build toolsが必要かもしれません。また、amd64以外では未確認)。

USBメモリの初期化

まずディスクとして利用するUSBメモリを初期化します。USBメモリは購入時はFAT32等のシングルパーティションとなっていてこれでは使えないので以下の様に3つのパーティションを作ります。

従来のmbrパーティションでは、disklabelでBSDラベルを追加していましたが、U-EFIではdkを増やしていく形になるようです。/var等他にパーティションを分けたい場合はこのdkを増やして対応します。

# gpt show sd0
     start      size  index  contents
         0         1         MBR
         1        63         Unused
        64  59391936      1  MBR part 12
# gpt destroy sd0
gpt: /dev/rsd0d: Device doesn't contain a GPT
# dd if=/dev/zero of=/dev/sd0d count=1
1+0 records in
1+0 records out
512 bytes transferred in 0.014 secs (36571 bytes/sec)
# gpt create sd0
# gpt add -s 64m -t efi -l EFISYSTEM sd0
/dev/rsd0d: Partition 1 added: c12a7328-f81f-11d2-ba4b-00a0c93ec93b 34 131072
# gpt add -s 24G -t ffs -l ROOT sd0
/dev/rsd0d: Partition 2 added: 49f48d5a-b10e-11dc-b99b-0019d1879648 131106 50331648
# gpt add -s 4G -t swap -l SWAP sd0
/dev/rsd0d: Partition 3 added: 49f48d32-b10e-11dc-b99b-0019d1879648 50462754 8388608

途中でddを実行しているのは既にかかれているmbrを消すためです。他にマシな消し方がありそうですが、ここでは先頭セクタを0クリアしてます。 dk0のEFI Systemパーティションはそんなに容量は必要無いので、ここでは64MB指定しています。 dk1とdk2の容量は結構適当です。

U-EFI Systemパーティションの作成とブートローダーの配置

U-EFI SystemパーティションはU-EFIで決められたフォーマットであるFATでフォーマットします。ここにブートローダを置きます。

# newfs_msdos /dev/rdk0
/dev/rdk0: 130904 sectors in 16363 FAT16 clusters (4096 bytes/cluster)
MBR type: 6
bps=512 spc=8 res=1 nft=2 rde=512 mid=0xf0 spf=64 spt=32 hds=64 hid=0 bsec=131072

次にboot loader本体をここにコピーします。 従来はこれをgrubやrEFInd等で別途用意する必要があったようですが、NetBSD/amd64 8.0以降ではこのブートローダは既にシステムの一部として用意されています。既にNetBSD/amd64 8.0で作業している場合、以下のファイルが該当します。

# file /usr/mdec/*efi
/usr/mdec/bootia32.efi: PE32 executable (EFI application) Intel 80386 (stripped to external PDB), for MS Windows
/usr/mdec/bootx64.efi:  PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows

他のarchやバージョンの場合、このファイルはインストールするディストリビューションファイルのうち、boot.tgzから展開できます。

# mkdir /tmp/efiboot
# tar zxf (where/to/)base.tgz -C efiboot ./usr/mdec

これらをEFI Systemパーティションの以下のようにコピーします。

# mount -t msdos /dev/dk0 /mnt
# mkdir -p /mnt/EFI/boot/
# cp (where/to/efiboot)/usr/mdec/*.efi /mnt/EFI/boot/
# umount /mnt

また、gptの起動設定を行います。

# gpt biosboot -A -c /usr/mdec/gptmbr.bin sd0
# gpt set -a bootme -i 2 sd0

NetBSDパーティションの作成

ここから先はほぼいつものNetBSDと同じです。dk1をffsにフォーマットしてディストリビューションファイルを展開、最低限のシステム設定を行います。

# newfs -O 2 /dev/rdk1
# mount /dev/dk1 /mnt
# tar zxpf (where/to/binary/sets/)kern-GENERIC.tgz -C /mnt
# tar zxpf (where/to/binary/sets/)base.tgz -C /mnt
# tar zxpf (where/to/binary/sets/)etc.tgz -C /mnt
  : (必要なsets分)
# cp /mnt/usr/mdec/boot /mnt/
# mkdir /mnt/kern /mnt/proc
# cd /mnt/dev
# ./MAKEDEV all
# cd /mnt/etc
# cat > fstab <<EOF
NAME=ROOT	/	ffs	rw,log,noatime 1 1
NAME=SWAP	none	swap	sw,dp 0 0
kernfs		/kern	kernfs	rw
ptyfs		/dev/pts	ptyfs	rw
procfs		/proc	procfs	rw
tmpfs		/var/shm	tmpfs	rw,-m1777,-sram%25
EOF

さらにrc.confに色々設定してrc_configured=YESにすればマルチユーザーモードで起動するようになります。

動作確認

書き込んだイメージを使って起動してみます。なお、順序不定です。

ASUS TransBook Mini T102HA

電源ON->F2キーでBIOS設定メニューを出し、Save & Exit項目のBOot OverrideでUSBメモリを選ぶとそこから起動できました。

但しこのPC(タブレット)の画面は縦長(800x1280pixel)でキーボードをつけると常に横向きになってしまいます。また、画面も800x600と認識していること、内蔵無線NICも見えないなど、NetBSDをちゃんと動かすことは今のところ難しそうです。

Mousecomputer LuvBook LuvBook LB-J300X

このマシンはMBRブートとEFIブートが排他のようで、BIOS設定でどちらかでしか起動できないようです。いつもはMBRブートで使っているので、メニューからEFIブートを有効に切り替えます。なお、この状態では内蔵SSDにMBRでインストールしてあるNetBSDが起動できません。

EFIブートでNetBSDが起動することは確認できました。2560x1440pixelという高解像度液晶もintelfb/i915drmkmsで認識されてます(GENERICでは字がとても小さい…)。

ただし。一見MBRブートと同じに見えて、EFIブートの時は内蔵の無線NICのiwm(4)が使えません。EFIの場合ハードウェアの初期化が異なるのだと思いますが詳細は分かりません。今回はNetBSD 8.0_BETAですが、-currentだと改善されてるのかもしれません。

ASUS PRIME B350M-A + AMD Ryzen 7 1700

色々と今年ありましたが、それでも圧倒的なパフォーマンスを誇るRyzenマシンです。当然今時のMotherboard, かなり派手なUEFI-BIOS設定画面です。Bootデバイスの優先順位等もマウスでドラッグアンドドロップでできてしまいます。

起動してみると特に問題なくloginプロンプトまで進みました。各種デバイスの細かいところまでは見ていませんが、とりあえず最低限は使えそうです。なお、Ryzen7は内蔵VideoChipなんてないのでこのマシンはPCIeのRadeon HD 5000シリーズを載せています。世代的にアンバランスですが、NetBSDで真っ当に使える外付けVideoではこのあたりが限界だったりします。

その他のマシン

この他にもざっくりと数台で起動してみましたが、ここ5年前以上くらいのマシンでEFIブート対応している機械ではそこそこ動くようです。
  • Lenovo Ideapad s205
    AMD E-350を搭載したnote pcです。画面は1366x768。Boot loaderからkernelを起動してしばらくの間(わさび色のところで)画面が砂の嵐になります。radeonfbを認識して描画が切り替わると正常な画面になります。
  • Intel NUC5i3RY
    第5世代intel Core i3を搭載したちっこいdesktop pcです。これもUSBメモリのEFI bootを認識し、マウス操作のカッコいい画面から起動指示できます。起動後intelfbも認識して画面もちゃんと表示されます。デバイス(無線LANなど)は未確認。なお、intelfbで高解像度になっており、Xを起動してみるとちゃんとIntel driverで動作します。これまでのMBRブートで使っていた際、アクセラレーションを有効にするとGPU側がハングアップしてまともに描画されないという現象が確認されていましたが、EFIブートでこれが変わったりするのかもまだ未確認(あまり期待はしてませんが)。

終わりに

若干意味がわからない部分も残っているのですが、とりあえずU-EFI環境で起動できるNetBSD/amd64のUSBメモリが作れました。こいつを持ち歩けば新しいマシンを触れる機会があればとりあえずNetBSDの起動確認に使えるんじゃないかと思います(もちろん、起動設定変更してもいい場合に限りますが)。