Top Banner
UEFI時代のブート ローダ @syuu1228
38

UEFI時代のブートローダ

Jul 11, 2015

Download

Technology

Takuya Asada
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: UEFI時代のブートローダ

UEFI時代のブートローダ@syuu1228

Page 2: UEFI時代のブートローダ

自己紹介

• Software Engineer at Cloudius Systems (OSv)

• FreeBSD developer (bhyve, network stack..)

Page 3: UEFI時代のブートローダ

UEFIのおさらい

Page 4: UEFI時代のブートローダ

BIOSブート• MBRからブートセクタをロード

• プログラム領域が足りないのでMBRの次のセクタなどを利用して更に大きなブートローダをロード(多段ブート)

• /bootファイルシステムをパースしてLinuxカーネルを見つけてロード&実行

←ディスクに1個

Page 5: UEFI時代のブートローダ

UEFIブート• ブートセクタなどなかった

• EFIパーティーション(FATファイルシステム)にブートローダ(UEFIイメージ)を配置

• NVRAMに設定がある→設定されたパスからブートローダをロード&実行

• NVRAMに設定がない→デフォルトパスからブートローダをロード&実行

• プロテクテッドモード、UEFI API

←ディスクにn個(いくらでも)

Page 6: UEFI時代のブートローダ

BIOSのブートイメージ• ブートセクタなどのとても狭い領域に固定的に配置

• リアルモード

• アドレッシング出来るメモリに大きな制約

• アセンブリ

• 古くさいBIOSコールによる限られたAPI

Page 7: UEFI時代のブートローダ

UEFIイメージ• PEバイナリ

(Windowsアプリと似たようなヘッダ)

• 32/64bitプロテクテッドモード(※但し両対応ファームはない)

• サイズ制限、メモリ容量制限なし

• 全てC言語で記述可能

• 豊富なAPI

Page 8: UEFI時代のブートローダ

参考:Runtime Services• ExitBootServices()後もUEFIがOSに対して提供するサービス

• 最低限の機能のみ

• Time (GetTime, SetTime...)

• Virtual Memory (SetirtualAddressMap...)

• Variable Services (GetVariable...)

• Miscellaneous Services(ResetSystem...)

Page 9: UEFI時代のブートローダ

参考:Boot Services• ExitBootServices()までUEFI Applicationに提供するサービス

• Task Priority Services (RaiseTPL...)

• Memory Services (AllocatePages...)

• Event & Timer Services (CreateEvent, SetTimer...)

• Protocol Handler Services (HandleProtocol...)

• Image Services (LoadImage, StartImage...)

• Miscellaneous Services (Stall, CopyMem...)

• Open and Close Protocol Services (OpenProtocol...)

• Library Services (LocateProtocol...)

• 32bit CRC Services (CalculateCrc32...)

Page 10: UEFI時代のブートローダ

参考:Procotols

• ネットワークプロトコルスタックのことではない

• UEFI上で提供される様々なサービスの事

• UEFI Driverを実装しUEFIへロードする事により、自作のProtocolを提供する事も可能

Page 11: UEFI時代のブートローダ

参考:定義されているProtocol

• EFI Loaded Image

• Device Path Protocol

• UEFI Driver Model

• Console Support

• Media Access

• PCI Bus Support

• SCSI Driver Models and Bus Support

• iSCSI Boot

• USB Support

• Debugger Support

• Compression Algorithm

• ACPI Protocols

• TCP/IP, IPSec, FTP

• ARP & DHCP

• UDP & MTFTP

• etc...

Page 12: UEFI時代のブートローダ

UEFIからのブート手順(デフォルト)

BootManagerの設定がデフォルト値の場合

1. UEFIがHDDを検出、GPTをロード

2. EFI System Partitionを検索

3. \EFI\BOOT\BOOTX64.EFIをロード(32bit UEFIならBOOTX86.EFI)

Page 13: UEFI時代のブートローダ

UEFIからのブート手順(カスタム)

以下の様な値をUEFI NVRAM variableに設定(efibootmgrなど)

• Boot####:ロードするUEFI applicationのPATH・又はディスクのデバイスPATH

• BootOrder:Boot####の試行順序(配列で指定)

• BootNext:次回起動時にロードするBoot####

(BootOrderより優先、一度起動すると削除)

• Timeout:設定秒数だけBoot Menuを表示(自動起動を遅延)

Page 14: UEFI時代のブートローダ

設定例

• efibootmgrで編集

• /sys/firmware/efi/vars, /sys/firmware/efi/efivars経由でUEFI NVRAM Variableへアクセス

Page 15: UEFI時代のブートローダ

/sys/firmware/efi/efivarssyuu@ubuntu:~$ ls /sys/firmware/efi/efivarsBoot0000-8be4df61-93ca-11d2-aa0d-00e098032b8cBoot0001-8be4df61-93ca-11d2-aa0d-00e098032b8cBoot0002-8be4df61-93ca-11d2-aa0d-00e098032b8cBoot0003-8be4df61-93ca-11d2-aa0d-00e098032b8cBoot0004-8be4df61-93ca-11d2-aa0d-00e098032b8cBootCurrent-8be4df61-93ca-11d2-aa0d-00e098032b8c...

$ sudo cat /sys/firmware/efi/efivars/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c@EFI VMware Virtual SCSI Hard Drive (0.0) ?

Page 16: UEFI時代のブートローダ

Boot Manager

ブート項目の選択画面。OSは自分のブートローダをここに登録する

Page 17: UEFI時代のブートローダ

UEFI Shell

• 運が良ければROMに乗ってる無ければUSBからロード

Page 18: UEFI時代のブートローダ

さまざまなUEFIブート手順

Page 19: UEFI時代のブートローダ

UEFIでのLinuxブート方法(1)

• shim→grub2→Linux bzImage

• shim→grub2→Linux EFI Stub

• grub2→Linux bzImage

• grub2→Linux EFI Stub

• gummiboot→Linux EFI Stub

• Linux EFI Stub

←SecureBoot

Page 20: UEFI時代のブートローダ

UEFIでのLinuxブート方法(2)

• LinuxカーネルにEFI Stubを用意すれば直接Boot

Managerからロード出来る

• UEFIイメージから更に別のUEFIイメージをロード&実行できる

• UEFI APIがサポートしていないバイナリフォーマットよりもサポートが容易サポートすることによるデメリットも少ない

Page 21: UEFI時代のブートローダ

なるほど~?

Page 22: UEFI時代のブートローダ

非対応フォーマットの ロード&実行

• ヘッダのパース• メモリへの展開• CPUレジスタの初期化、辻褄合わせ

• エントリポイントへのジャンプ_人人人人人人_ > 結構面倒 < ‾Y^Y^Y^Y^Y‾

Page 23: UEFI時代のブートローダ

UEFIイメージのロード&実行

• UEFIイメージファイルをロードするAPI

にファイル名渡して終わりでは?

_人人人人人人_ > 簡単そう < ‾Y^Y^Y^Y^Y‾

Page 24: UEFI時代のブートローダ

ところで

• mrubyはUEFIで動く(mruby on EFI shell)

Page 25: UEFI時代のブートローダ

ということは

• mrubyにローダAPIを足せばmrubyスクリプトでブートローダを簡単に実装出来るのでは?

Page 26: UEFI時代のブートローダ

UEFI APIサポートon mruby

class BlockIoProtocol < UEFI::Protocol GUID = UEFI::Guid.new("964e5b21-6459-11d2-8e39-00a0c969723b") define_variable(:revision, :u64) define_variable(:media, :p) define_function(:reset, :e, [:p, :b]) define_function(:read_blocks, :e, [:p, :u32, :u64, :u64, :p]) end class Media < UEFI::Protocol define_variable(:media_id, :uint32) end handles = UEFI::BootService.locate_handle_buffer(BlockIoProtocol::GUID) handle = handles.first puts "handle: #{handle}" ptr = UEFI::BootService.handle_protocol(handle, BlockIoProtocol::GUID) bp = BlockIoProtocol.new(ptr) media = Media.new(bp.media) puts "media_id: #{media.media_id}"

Page 27: UEFI時代のブートローダ

これを使ってmrubyでローダを書けばいいんじゃね?

Page 28: UEFI時代のブートローダ

Cで書く→mrubyに起こす

• Cで書いてみたhttps://gist.github.com/syuu1228/d7ce6b949cbeec887ea0

Page 29: UEFI時代のブートローダ

どのAPIをmrubyでどう置き換えれば良いのか分からない

…(゜Д゜)

Page 30: UEFI時代のブートローダ

方針転換• 足りない機能は皆C拡張にしてしまえ

• さっきのコードをコピペしてmrubyのクラス化 →実行

• 何故かエラー…

• (゜Д゜)

Page 31: UEFI時代のブートローダ

む?

Page 32: UEFI時代のブートローダ

良くみたらsystem(3)あったわ

• EDK2にはlibc + BSD socketのテスト実装が載ってる(非公式あつかい)

• どうせmrubyは初めからこれをリンクしている

• system(3)もある

• 文字列組み立てて渡せば一行のCコードでバイナリ実行できんじゃん…

• 何を苦労していたんだろう

Page 33: UEFI時代のブートローダ

が…• mruby on EFI shellはmrubyの標準ビルドシステムを迂回してEDKのビルドシステムでビルドされてる

• mrubyのビルドシステムを使わないとmrbgemsを追加出来ない

• 殆どAPIが無い&簡単に足せない…

Page 34: UEFI時代のブートローダ

応急処置的に足す

• さっきのsystem(3)を呼び出すShell.exec()

• キーボード入力を受け付けるShell.gets()

• Dirクラス

Page 35: UEFI時代のブートローダ

完成!

• https://github.com/syuu1228/mruby_on_efi_shell/blob/862b7d95e399dc23744c589220e59d6e6f0adff3/example/bootloader.rb

Page 36: UEFI時代のブートローダ

デモ

Page 37: UEFI時代のブートローダ

TODO• mrbgems問題をどうにかするべき

• HTTPクライアントをポーティングしてカーネルもスクリプトも外から落としてきて実行させたい

• ファイルシステムドライバをインストールしてext[2-4]の/bootからカーネルをロードしたい

• ブートしたらツイートしたい

• もうちょっと整備すると結構便利になると思う

Page 38: UEFI時代のブートローダ

URL

• https://github.com/syuu1228/mruby_on_efi_shell/tree/devel