Top / EBUG勉強会 / 20190223_UEFI_GPT

河豚板のUEFI/GPT対応

EBUG 第68回会合
2019年2月23日、(有)銀座堂
川俣吉広、kaw@on.rim.or.jp

発端

Twitterでのこのtweetがきっかけ。

このやりとりが発端となり、河豚板のUEFI対応を開始する。

UEFIとGPT

UEFI (Unified Extensible Firmware Interface)
OSとファームウェアとの間のソフトウェアインタフェースを定義する仕様(Wikipedia)
従来のBIOS (Legacy BIOS)による起動方法からの置換えを意図している。
・UEFI用のパーティション(ファイルシステムとしてはFAT)を持つ。
・そのパーティション内に起動用の実行バイナリが格納されている。このバイナリファイルは*.EFIの拡張子を持ち、UEFIアプリケーションと呼ばれる。
GPT (GUID (Globally Unique Identifier) Partition Table)
ストレージデバイス上のパーティションテーブルの配置に関する標準規格(Wikipedia)
Legacy BIOSで用いられてきたMBR (Master Boot Record)に替わるものとしてUEFIの一部として定義されている。
・MBRが扱えるのは最大2TBのディスクを4区画まで
・GPTでは最大8ZBを128区画まで分割可能

OpenBSDの場合に現状で考えられる起動方法とパーティショニングのパターンを以下に示す。

Legacy BIOS / MBR

MBR.png

UEFI登場以前から用いられてきた方法 (参考)

  • ハードウェア上のファームウェアがHDDのセクタ0にあるMBRブートコードを実行する。
  • MBRブートコードは、ブートフラグがONになっているパーティションの先頭セクタにあるPBR (Partition Boot Record)に実行を移す。
    • OpenBSDでは、PBRは/usr/mdec/biosbootが用いられる。
  • PBRはOpenBSDのルートファイルシステム上にある/bootを実行する。
    • この/bootが「boot>」プロンプトを表示し、カーネル起動に関するユーザからの指定を受け付ける。
  • bootは指定にしたがって、該当するカーネルを起動する。
  • なお、OpenBSD用と設定された区画(右図の例ではentry 3)は、同時にdisklabel(8)ユティリティによる管理範囲(OpenBSD Area)として設定される。 OpenBSD Areaの中にdisklabelによるBSDパーティションが作成され、ファイルシステムやスワップ領域として使われる(参考:他のBSDユーザのためのOpenBSD管理入門)。

UEFI / GPT

GPT.png

起動にUEFI、ディスクパーテショニングにGPTを用いるパターン

  • ハードウェア上のファームウェアがGPT内でEFI Sysパーティションを探し、この中に \efi\BOOT\BOOT*.EFIという実行ファイル(EFIアプリケーション)があれば実行する。
    このファイル名は、
    • i386ではBOOTIA32.EFI
    • amd64はBOOTX64.EFI
    • arm64はBOOTAA64.EFI

となっている。

  • OpenBSDのEFIアプリケーションは、「boot>」プロンプトを表示し、カーネル起動に関するユーザからの指定を受け付ける。
    これは、MBR起動の場合の/bootに相当する。
  • EFIアプリケーションは指定にしたがって、該当するカーネルを起動する。
  • なお、GPTの場合にも先頭セクタの部分に、従来のMBRとの互換性を考慮してprotective MBR (保護MBR)というものが書き込まれている。これはfdiskなどのMBRを扱うユティリティが誤ってMBRを書き換えないようにするためのものである。
  • OpenBSD Area内の管理については、MBRの場合と同じ。

UEFI / MBR

ARM64.png

UEFIとしてEFIアプリケーションがロードされるが、パーテショニングとしてMBRが使われるパターン。GPTは存在しない。
amd64のインストールメディアやarm64で使われている。

amd64のインストールメディアとarm64とでは細かい箇所で異なっている部分がある(右図はarm64)。

  • arm64ではUEFI用のパーティションIDは0C (FAT32L)、amd64インストーラではEF (EFI Sys)。
  • arm64ではUEFI用のパーティション内にはU-BOOTも書き込まれている。
  • amd64インストーラではMBR boot code、PBR、/bootもセットアップされ、Legacy BIOS・UEFIのどちらでも起動する。

Hybrid MBR

Hyb.png

MBRとGPTの両方に同じパーテショニング情報を書込み、ブートローダもLegacy BIOS, UEFI共にセットアップしたもの。

  • Legacy BIOS・UEFIのどちらでも起動することが期待できる。
  • 非標準。規格上は定義されていない方法。
  • 現状ではMBRとGPTとを同時に変更するツールがないため、作成後にパーテショニングを変更することが困難。

OpenBSDでのUEFI実装

2015年に安岡昌彦氏によりカーネルにUEFI対応の機能が実装された

現在では、インストーラ含め、関連ユティリティがUEFI/GPTに対応している。

インストーラ

前述のように、Legacy BIOS、UEFIのいずれからでも起動可。

Legacy BIOS、UEFIのどちらで起動したかによって、パーティショニングのデフォルトも変わる。

UEFIで起動した場合

Available disks are: wd0 wd1.
Which disk is the root disk? ('?' for details) [wd0] wd1
No valid MBR or GPT.
Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [gpt]       ←インストーラをUEFIで起動した
Setting OpenBSD GPT partition to whole wd1...done.              ので、GPTがデフォルト
The auto-allocated layout for wd1 is:
#                size           offset  fstype [fsize bsize   cpg]
  a:        819776.0K             1024  4.2BSD   2048 16384     1 # /
  b:         83090.0K          1640576    swap                    
  c:       2097152.0K                0  unused                    
  d:        930704.0K          1806784  4.2BSD   2048 16384     1 # /usr
  e:        263024.0K          3668192  4.2BSD   2048 16384     1 # /home
  i:           480.0K               64   MSDOS                             ←EFI Sys領域
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a]

Legacy BIOSで起動した場合

Available disks are: wd0 wd1.
Which disk is the root disk? ('?' for details) [wd0] wd1
No valid MBR or GPT.
Use (W)hole disk MBR, whole disk (G)PT or (E)dit? [whole]     ←MBRがデフォルト
Setting OpenBSD MBR partition to whole wd1...done.
The auto-allocated layout for wd1 is:
#                size           offset  fstype [fsize bsize   cpg]
  a:           800.6M               64  4.2BSD   2048 16384     1 # /
  b:            81.1M          1639616    swap                    
  c:          2048.0M                0  unused                    
  d:           908.9M          1805824  4.2BSD   2048 16384     1 # /usr
  e:           256.9M          3667232  4.2BSD   2048 16384     1 # /home
Use (A)uto layout, (E)dit auto layout, or create (C)ustom layout? [a] 

fdisk

パーティションのメンテナンスツールfdisk(8)は、パーティションの初期化時にオプションによってMBRかGPTかを指定する。

MBRで初期化

# fdisk -i wd1
Do you wish to write new MBR and partition table? [n] y
Writing MBR at offset 0.
# fdisk wd1
Disk: wd1       geometry: 520/128/63 [4194304 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
*3: A6      0   1   2 -    519 127  63 [          64:     4193216 ] OpenBSD     

GPTで初期化

# fdisk -i -g wd1
Do you wish to write new GPT? [n] y
Writing MBR at offset 0.
Writing GPT.
# fdisk wd1
Disk: wd1       Usable LBA: 64 to 4194240 [4194304 Sectors]
   #: type                                 [       start:         size ]
------------------------------------------------------------------------
   3: OpenBSD                              [          64:      4194177 ]
パーティションの詳細を見る
↓
# fdisk -v wd1
Primary GPT:
Disk: wd1       Usable LBA: 64 to 4194240 [4194304 Sectors]
GUID: 09d92128-d884-40f8-9e17-a606721cd8c7
   #: type                                 [       start:         size ]
      guid                                 name
------------------------------------------------------------------------
   3: OpenBSD                              [          64:      4194177 ]
      376b4152-9c45-4d7a-8392-5f0f3e015d51 OpenBSD Area                    

Secondary GPT:
Disk: wd1       Usable LBA: 64 to 4194240 [4194304 Sectors]
GUID: 09d92128-d884-40f8-9e17-a606721cd8c7
   #: type                                 [       start:         size ]
      guid                                 name
------------------------------------------------------------------------
   3: OpenBSD                              [          64:      4194177 ]
      376b4152-9c45-4d7a-8392-5f0f3e015d51 OpenBSD Area                    

MBR:
Disk: wd1       geometry: 520/128/63 [4194304 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
---------------------------------------------------------------------------
 0: EE      0   0   2 - 532610   4   4 [           1:  4294967295 ] EFI GPT
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] unused 
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] unused 
 3: 00      0   0   0 -      0   0   0 [           0:           0 ] unused 
# 

installboot

OpenBSDでは、ブートローダの書込みにinstallboot(8)を使用する。

  • 対象ディスクがMBRで区画分けされている場合、PBRと/bootを書込む
    # mount /dev/wd1a /mnt
    # installboot -r /mnt wd1 /usr/mdec/biosboot /usr/mdec/boot
                              ↑                 ↑
                              PBR                secondary loader
    # umount /mnt
  • 対象ディスクがGPTで区画分けされている場合、EFIアプリケーションをEFI Sysパーティションに\efi\boot\*.EFIとして書込む
    # installboot wd1

河豚板での実装

配布物

  • ISO版は変更しない。
  • img版は、以下のように対応する。
    • i386版は、Legacy BIOS/MBRにする(UEFIアプリケーションが供給されていないため)。
  • amd64版は、Hybrid MBRとし、Legacy BIOS/UEFIのいずれでも使用できるようにする。
  • arm64版は、UEFI/MBRにする(オリジナルのOpenBSD/arm64と同じ)。

usbfadm

usbfadm (USB Flashdrive ADMinistration tool) - 河豚板付属のUSBメモリ管理ツール
実際はUSBメモリに限らず、ストレージデバイス全般で使用可

用途

syncコマンド
TMPFS内のデータをUSBメモリに保存する
読み出しは次回起動時に「起動モード3」を指定する。
newdriveコマンド
LiveUSB版の河豚板を新規作成する
LiveUSB版河豚板のディスクイメージを作成する

UEFI/GPT対応として、newdriveコマンドに

  • 起動方法としてLegacy/BIOS and/or UEFIを指定出来るようにする
  • パーティショニングとしてMBR and/or GPTを指定出来るようにする
FuguIta.png

河豚板のパーティション構成

  • EFI sys ... UEFIブートの際に必要 (Legacy BIOS、データ保存専用デバイスでは不要)
  • OpenBSD Area
    • a
      • 河豚板のファイルツリー(実際にはlndirを使ってtmpfsにマッピング)
      • デバイスをファイル保存用のみに使う場合は不要
    • d
      • usbfadmを使ってTMPFS内のデータをUSBメモリに保存する場合に必要
  • FAT ... ユーザの指示がある場合、ディスクに空きがあれば作成

Hybrid MBRを用い、かつパーティションを全て作成する場合、右図のようになる。

プラットフォーム依存部 - 組み合わせとデフォルト

「プラットフォーム毎の対応表」を見るとわかるように、ブート方法、及びパーティションテーブルの選択肢はプラットフォーム毎に変わってくる。例えばi386ではUEFIが、arm64ではLegacy BIOSを選択できてもOSが対応していないため、意味がない。
さらに、ユーザが「データ保存のみ」を選択した場合はブートローダが不要となる。以上より選択の組合せは以下のようになる。

Legacy BIOSUEFIHybridnon-boot
(data only)
MBRi386, amd64amd64, arm64N/Aall
GPTN/Aamd64, arm64N/Aall
HybridN/AN/Aamd64all
プラットフォーム毎の対応表
  • i386はEFIアプリケーションが供給されていないため、UEFI起動不可
  • arm64はU-BOOT起動のため、Legacy BIOS起動不可

この複雑さを緩和するため、今回の改修では/usr/fugutia/etc/usbfadm.confというファイルを新設した。
例えば、i386の場合、このファイルに

disable_uefiboot=Yes

などと記述することで、UEFI起動を選択肢からはずせるようにした。 一方arm64の場合、Legacy BIOSでは起動できないので、

disable_legacyboot=Yes

となる。

またarm64の場合は以下の理由から、さらなる処理が必要となる。

  • 基本はUEFI/MBRの構成だが、MBRブートフラグとUEFI Sysのパーティションタイプを変更する必要がある。
  • OpenBSD/arm64はHDMI出力が実装されておらずシリアルコンソールとなるため、OpenBSD/arm64をインストールする際はピンヘッダにUSBシリアルなどを用意し、シリアル端末を接続する必要がある。
    • FuguIta/arm64では、インストール作業の敷居を下げるため、配布物をメディアに書き込んで起動した段階でSSHによるリモートアクセスが可能となっており、シリアルI/Fを用意せずとも使用できるようになっている。
  • そのため、FuguIta/arm64は他のプラットフォーム用と異なり、SSHアクセスを可能にするための各種設定や、その設定を用いて自動的に起動する設定がdパーティションに書き込まれている。
    arm64のusbfadmでnewdriveを実行してリマスタリングを行う場合、これらdパーティションに書き込まれている内容もセットアップする必要がある。
  • よって、新しいusbfadmでは、newdriveコマンドの実行の最後の部分に/usr/fuguita/etc/usbfadm_postproc.shというシェルスクリプトを実行するようにした。FuguIta/arm64では、usbfadm_postproc.shに上で説明したようなプラットフォーム固有の処理が書き込まれている。

Hybrid MBRの作成

OpenBSDでのUEFI実装で説明したように、OpenBSDのfdiskコマンドにはディスクをMBR、GPTそれぞれのパーティションで初期化する機能を持っているが、MBRとGPTを同時に作成しHybrid MBRとする機能は持っていない。

今回のUEFI対応では、以下のような方法でHybrid MBRを実装した。

mkHybrid.png
  • 1. ディスクをMBRで初期化する ... fdisk -i
  • 2a. パーティションを作成し、newfs, newfs_msdosを行う
  • 2b. installbootを実行する ... PBRと/bootが書き込まれる
  • 2c. MBRをddで吸出しファイルとして保存しておく
  • 3. ディスクをGPTで初期化する ... fdisk -i -g
  • 4a. MBRと同じ構成でGPTパーティションを作成する
  • 4b. installbootを実行する ... EFIアプリケーションが書き込まれる
  • 4c. 保存しておいたMBRをddでprotective MBRに上書きする

開発環境

初期

QEMU.png

開発の初期段階では、プロセッサエミュレータQEMUを用いて開発を行った。

  • 最初は、手動でfdiskなどを動かして挙動を調査したり、動作の安定していないスクリプトを動かしたりするため、実ディスクに誤ったパーテション情報を書き込んでしまうおそれがあるため。
  • Legacy BIOSとUEFIを頻繁に切り替えて作業をするため、実ハードウェアの作業では手間と時間が掛かるため。

QEMUは、デフォルトではLegacy BIOS (SMBIOS)として動作する。
UEFI起動を行うためには、-biosオプションでOVMF (Open Virtural Machine Firmware)を指定する。

Legacy BIOS起動

# qemu-system-x86_64 -m 512 -hda install64.fs -hdb testhdd.img

UEFI起動

# qemu-system-x86_64 -m 512 -hda install64.fs -hdb testhdd.img -bios OVMF.fd

パーティション操作を行う対象となるディスクイメージファイルはrawイメージとした。
これにより、vnconfig(8)を用いてvnodeデバイスのディスクとして実環境でも扱えるようになった。

中期以降

usbfadmが一通り動作するようになってからはプラットフォーム依存部分を開発・動作確認したり、河豚板のリリースに組込む必要があるため、実ハードウェアにて開発を行った。

手順は概ね以下のとおり;

RealDev.png
  • 河豚板のソースコードはfuguita.org上のCVSリポジトリで管理されている。ここから同じfuguita.org上でcvs checkoutし、working copyを作成する。
  • 各プラットフォームの開発/テスト機はworking copyをNFSマウントし、ソースコードを共有する。
    →開発者は一人だけなので、同じファイルを同時に編集することはない。
  • すべてのプラットフォームでの作業が終了したら、fuguita.org上でcommitを行い、CVSリポジトリを更新する。
  • プラットフォーム毎のビルドマシンでcvs updateを行い。更新を取り込む。その後、各プラットフォーム用のリリースを作成する。
  • リリースの動作テストがOKなら、完成したリリースをMirror Originに転送する。
  • mirror.ginzado.ne.jpとlivecd-mirror.ebug.jpの2つのミラーサーバからは一定間隔でrsyncにより接続が行われ。各ミラーとOriginとの同期が取れる。
    この時点で河豚板が一般公開されたことになる。
  • 一方、CVSリポジトリは、git cvsimportによりGitに変換され、git pushによりGitHub上のリポジトリも更新される。

その他諸々

OVMFの不具合(?)

開発当初、OVMFを使ってQEMUを起動したところ不具合が発生。

  • /bootが河豚板のカーネルを読み込んでいる途中で、読込みが停止する。
  • 発生するのは河豚板のカーネルのみ、OpenBSDのGENERICカーネルや、インストール用カーネルは正常に起動

何回か試行を行っていたところ正常に起動し、その後現象の再発なし。結局原因は不明

installbootの不具合

installbootは、EFIアプリケーションのインストールに失敗する。

# installboot -v -r /mnt vnd0 /fuguita/usr/mdec/biosboot /fuguita/usr/mdec/boot 
Using /mnt as root
installing bootstrap on /dev/rvnd0c
using first-stage /fuguita/usr/mdec/biosboot, second-stage /fuguita/usr/mdec/boot
newfs_msdos: /dev/rdfe15236c496b5df.i: No such file or directory   ←デバイスの指定がDUIDで行われている
installboot: unable to mount EFI System partition: No such file or directory

newfs_msdosによりEFI Sysのパーティションをフォーマットする段階で、なぜかデバイス名の指定でDUIDが使われるが、ここでコマンドが異常終了するため、処理が正常に完了しない。

UEFIのセットアップはEFI SysのパーティションをFATでフォーマットし、その中にディレトクトリを掘ってEFIアプリケーションを/usr/mdecからこのディレクトリにコピーするだけなので、installbootが失敗した場合に上記処理を行うworkaroundコードを追加した。


Top / EBUG勉強会 / 20190223_UEFI_GPT

Attach file: fileRealDev.fig 77 download [Information] fileRealDev.png 151 download [Information] fileQEMU.fig 65 download [Information] fileQEMU.png 149 download [Information] filemkHybrid.fig 70 download [Information] filemkHybrid.png 148 download [Information] fileMBR.fig 72 download [Information] fileMBR.png 152 download [Information] fileGPT.fig 71 download [Information] fileGPT.png 156 download [Information] fileARM64.fig 75 download [Information] fileARM64.png 149 download [Information] fileHyb.fig 72 download [Information] fileHyb.png 148 download [Information] fileFuguIta.fig 71 download [Information] fileFuguIta.png 163 download [Information]
Reload  New Edit Freeze Diff Attach Copy Rename  Top Index Search Recent Backups  Help  RSS
Last-modified: 2019-02-21 (Thu) 19:43:29 (208d)