経緯

現作業環境はArch LinuxとWindowsのデュアルブートで運用しています.が,メインはLinuxで事足りてます.つまりrEFIndのOS選択画面がうざいです.

根本的解決のためWindows on Archlinux KVMがしたい! | kaniyama.netをしたいのですが,そこまでのつなぎとして 「Linux側で switch windows でwindowsに切り替えてrEFIndの画面を表示しない」 ようにしたいと考えるようになりました.

あるやん

すぐにしたいことができそうな記事を発見します.

が,電子系の学科に入ったがためにブータルのなんたるかを義務教育過程で学んでいないため,書いていることがチョットヨクワカラナイ.

このあたり

EFIVAR_NAME = 'PreviousBoot'
EFIVAR_GUID = '36d08fa7-cf0b-42f5-8f14-68df73ed3740'
EFIVAR_PREFIX = '/sys/firmware/efi/efivars'

がワカラナイ.

自環境で ls /sys/firmware/efi/efivars してみるも, 'Microsoft Windows-{}' なフォーマットのファイル群は一個も見つかりませんでした.

┌──[~]
└(ノ≧∇≦)ノ $ ls /sys/firmware/efi/efivars
ConIn-8be4df61-93ca-11d2-aa0d-00e098032b8c
ConOut-8be4df61-93ca-11d2-aa0d-00e098032b8c
CurrentPolicy-77fa9abd-0359-4d32-bd60-28f4e78f784b
DeploymentModeNv-97e8965f-c761-4f48-b6e4-9ffa9cb2a2d6
KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c
PK-8be4df61-93ca-11d2-aa0d-00e098032b8c
SecureBootSetup-7b59104a-c00d-4158-87ff-f04d6396a915
StdDefaults-4599d26f-1a11-49b8-b91f-858745cff824
db-d719b2cb-3d3a-4596-a3bc-dad00e67656f
dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f

Document: Reboot to {OS}

閑話休題,やはりドキュメントを斜め読みしても/sys/firmware/efi/efivarsにWindowsのファイルがあるように思えませんでした,ので,ドキュメントをちょっとずつ読んでいきます.

以下意訳です,

General Information

rEFIndには Reboot to {OS} する機能はありません.ただし,rEFInd起動時には前回起動時に選択されたOSが自動的にセレクト状態になるので,前回の選択したOSを騙してやる&OS選択画面の待機時間を0にすることで,擬似的に切り替えすることができます!

参照ドキュメントに添付のプログラムで前回の選択OSを書き換えることが出来ます.このプログラムにはいくつか変数が存在しています.

Reboot to {OS} を成し遂げるためには, 変数 EFIVAR_GUID (*1)をセレクト状態にしたいOSの値に変えてやる必要があります.このとき + プレフィクスを使用するとrEFIndに設定されているデフォルトのOSを選択したことと同値になります

ドキュメント添付のプログラムに指定する変数には制約があるよ!

  • 4byteであること!(Ex. 07 00 00 00 )
    • ※但しWindowsはこの制約を無視するよ!
  • 変数はUTF-16 Little Endianのstring型文字列で記載する必要があるよ!(BOMはダメ)
  • 4byteであること!(Ex. 20 00 00 00 )
    • ※スペースやNUL文字も1byteにカウントされるよ!
    • (なんで2回同じこと書いてるんだろう(心の声))

プログラムに指定する変数には,必ずしも完全な値を入れる必要はありません.部分一致でも動作します.ただ複数候補が出たときrEFIndがどういった挙動をするかは知らないよ!多分マッチした最初のエントリが選択されるんじゃないかな?完全な値を入れるか部分的な値でスリルを楽しむかはキミ次第だ!

Select Next Boot OS from Linux

Linuxでは,すべてのEFI変数(*1)がefivarfs経由で /sys/firmware/efi/efivars/ にマウントされます.このファイル名の形式は {name}-{GUID} です.添付プログラムをそのまま実行した場合は /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740 というエントリがセレクト状態になります.これらのファイルには NVRAM設定変数 (*2) が格納されており,root権限にて編集することが出来ます.これらファイルの多くには普遍のフラグが設定されており,エラー防止の為ファイル変更前にはchattr -i /path/to/efivarコマンドを実行する必要が有ります.

デフォルトのrEFIndエントリを変更するだけでも十分です:選択したいエントリの名前とポイントを指定された特定のフォーマットに則りefivarファイルに書き込んでください.EFIVAR_*変数に指定する値が決まったら,添付のプログラム(Linux用)を見てください.

添付プログラムにパスを通したら,以下のコマンドからReboot to {OS}を実現することが出来ます.

sudo refind-next-boot 'Microsoft'
systemctl reboot

これをデスクトップ等の任意の地点に置くことでいい感じにOS切り替えができるようになります.実行アカウントがsudoers fileに定義されている場合,パスワードなしで実行が可能です.もし実行をroot権限に限定したい場合は,以下のコマンドを実行してください.

chown root /path/to/refind-next-boot
chmod 0755 /path/to/refind-next-boot

じゃあそもそも...

(*1)EFIvar(s)とは?

EFIvarとは,OSインターフェイスを使ってEFI変数を扱うために用いられる値です.この値は基本的には efiboot によって追加され,使用されます.

  • Linuxの場合: 擬似的なefivarfs(ファイルシステムかな?)がマウントされます.大抵のOSではマウント先パスは /sys/firmware/efi/efivars です. efivars -l コマンドでも一覧を見ることが出来ます.
  • Windowsの場合: Get/SetFirmwareEnvironmentVariable が管理権限で使われるようです.これには,SeSystemEnvironmentPrivilege(※ファームウェアの値を変更するために必要なWindows上の権限) を現在のスレッドで動作させるため適切な security token が必要です.通常この処理はSystemManagerinitialization処理中に完了させるようです.

メモリ内部とファイルシステムのストレージは試験目的という条件でも,この値を特定のファイルに出力する手段が有ります.

参考:

(*2)NVRAM設定変数(NVRAM variable)とは?

そもそもNVRAMとはHDD, SSD,SDカード,USBメモリ等の不揮発性メモリ(電力が無くなってもデータが消えない)のことです.

参考:

つまり

efivarsを各OSで調べてそれぞれディレクトリに追加してやることで切り替えれる

...ようです.

実施手順

1. Linux環境のEFIvarsを確認

2. Windows環境のEFIvarsを確認

参考:

3. Windows環境にOS切替用のスクリプトを配置

4. Linux環境にOS切り替え用のスクリプトを配置

5. テスト

6. OS選択時間を0に変更

完成!

まとめ