Systemd-boot の次回起動のエントリ指定の方法

作成/更新

したいこと

次回起動時に systemd-boot に読み込まれるエントリを変更したい。以降のデフォルト起動エントリを指定するのではなく、次回一度きりのエントリ指定を行いたい。

GRUB では次のように grub2-reboot コマンドをエントリ番号を引数として実行することで実現できます。

% grub2-reboot 2
% reboot

やりかた

お読みください:本記事の方法は試行錯誤をしてとりあえず動いたものです。筆者の環境では問題なく動作していますが、適切な方法ではないかもしれません。

方法としては EFI variable 「LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f」にエントリ名を指定することで、次回起動時に systemd-boot が読み込むエントリを指定することができます。

以下の説明では、読み込ませたいエントリ名が「auto-windows」だと仮定します。

  1. 読み込ませたいエントリ名に終端文字「\0」を加えたものを UTF-16LE で符号化し HEX 化します。
    % echo -n "auto-windows\0" | iconv -fASCII -tUTF16LE | xxd -g1
    00000000: 61 00 75 00 74 00 6f 00 2d 00 77 00 69 00 6e 00  a.u.t.o.-.w.i.n.
    00000010: 64 00 6f 00 77 00 73 00 00 00                    d.o.w.s...
    
  2. 得られた値の先頭にビットマスク 07 00 00 00 を追加します。
    07 00 00 00 61 00 75 00 74 00 6f 00 2d 00 77 00 69 00 6e 00 64 00 6f 00 77 00 73 00 00 00
    
  3. 得られた値を EFI variable の LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f に設定します。
    % cd /sys/firmware/efi/efivars
    % sudo printf '\x07\x00\x00\x00\x61\x00\x75\x00\x74\x00\x6f\x00\x2d\x00\x77\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x00\x00' \
    	> LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
    
  4. これで完了です。次の起動時には「auto-windows」エントリが読み込まれます。

試行錯誤の過程

環境

Arch Linux と Windows 10 とのデュアルブートを設定した X1 Carbon (2016). Systemd-boot はそれぞれの OS を次のエントリ名で扱う.

  • arch
  • auto-windows

対応する EFI Variable の特定

公式の systemd-boot のページによれば,

Some EFI variables control the loader or exported the loaders state to the started operating system. The vendor UUID 4a67b082-0a4c-41cf-b6c7-440b29bb8c4f and the variable names are supposed to be shared across all loaders implementations which follow this scheme of configuration:

とのことで, 「LoaderEntryOneShot」という EFI Variable を使って指定できそう. UUID 「4a67b082-0a4c-41cf-b6c7-440b29bb8c4f」も必要となるようだ. しかし, EFI Variable の指定方法がわからない.

EFI Variable の指定方法

Accessing UEFI Variables from Linux によれば, EFI Variables は /sys/firmware/efi/efivars にマウントされていてる. また,

Even though each of the files contains binary data (like the 'new_var', 'del_var' of the legacy interface), the data structure for efivarfs is much simpler, consisting only of 4 bytes for the UEFI variable attributes bitmask, and the rest is the UEFI variable data, e.g.

struct new_efi_variable {

u32 attributes; u8 data[0];

};

All other pieces of information, such as the variable name, GUID and size are inferred from the filename being read/written. This makes it trivial to create, or delete a UEFI variable by creating or deleting files.

For example, the following shell command creates a new variable,

printf "\x07\x00\x00\x00\x00" > myvar-12345678-1234-1234-1234-123456789abc

named 'myvar' with the GUID '12345678-1234-1234-1234-123456789abc', and the EFI_VARIABLE_NON_VOLATILE, EFI_VARIABLE_BOOTSERVICE_ACCESS and EFI_VARIABLE_RUNTIME_ACCESS bits set in the attribute bitmask, followed by 1 byte of data (the final \x00). -- quoted from Accessing UEFI Variables from Linux on Feb 22, 2018.

とのこと.

LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f という名前で,

  • 先頭 4 bytes の attribute
  • 5byte 以降がデータ

を書き込めばいいようだ.

ビットマスク

前述の表によれば「LoaderEntryOneShot」は「non-volatile」とあるので次のビットマスクで試してみる.

 07 00 00 00

データの形式と内容

前掲の記事では 5byte 以降のデータの書き方がわからないので, 適当にファイルを開けて調べてみた. テキストエディタで開いても文字化けするだけなので CLI で操作する.

% cat LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f | xxd -g1
00000000: 06 00 00 00 61 00 72 00 63 00 68 00 00 00        ....a.r.c.h...

xxd コマンドで 16 進数に変換して表示しています. 5byte 目以降をみると, 「arch\0」のそれぞれの文字のあとに「\0」が挿入されたものに見える.

% cat LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f | xxd -g1
00000000: 06 00 00 00 73 00 79 00 73 00 74 00 65 00 6d 00  ....s.y.s.t.e.m.
00000010: 64 00 2d 00 62 00 6f 00 6f 00 74 00 20 00 32 00  d.-.b.o.o.t. .2.
00000020: 33 00 31 00 00 00                                3.1...

他のファイルも同様だった. すこし調べたところ, 恐らく, これは「\0」が挿入されたのではなくて UTF-16LE での符号化によるようだ. この形式でデータを作ってみることにする.

さて, 記述する内容だが, 表には「LoaderEntryOneShot」について

entry identifier to select at the next and only the next bootup

とある.

% cat LoaderEntrySelected-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f | xxd -g1
00000000: 06 00 00 00 61 00 72 00 63 00 68 00 00 00        ....a.r.c.h...

このエントリ指定の EFI Variable の値は「arch\0」で, 「arch」という名のエントリも存在することから, エントリ名を指定することにする.

自動検出の Windows Boot Manager 「auto-windows」を指定してみることにしよう.

実践

文字列「auto-windows\0」を UTF-16LE に変換してこれを HEX で出力するには次を実行.

よって, 得られたデータは以下.

 61 00 75 00 74 00 6f 00 2d 00 77 00 69 00 6e 00 64 00 6f 00 77 00 73 00 00 00

これにビットマスクをつける.

 07 00 00 00 61 00 75 00 74 00 6f 00 2d 00 77 00 69 00 6e 00 64 00 6f 00 77 00 73 00 00 00

EFI Variable に書き込んで再起動.

% cd /sys/firmware/efi/efivars
% printf '\x07\x00\x00\x00\x61\x00\x75\x00\x74\x00\x6f\x00\x2d\x00\x77\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x00\x00' \
	> LoaderEntryOneShot-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
% reboot

起動すると Windows Boot Manager が選択され, 無事 Windows 10 を開くことができた.