Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
忙しくて時間がなくなったので 10 分でブートローダーをつくっ た話で茶濁す
Slide 2
Slide 2 text
● orumin (@kotatsu_mi) ● Google Summer of Code 2014 で OSv に Ruby を移植してました. ● 以前 UEFI 遊びしてた
Slide 3
Slide 3 text
● UEFI! ● BIOS もう捨てよう ● GRUB も要らない (UEFI のブートセレクタで良 い )
Slide 4
Slide 4 text
● UEFI とは ? ● UEFI Advent Calender 2014 参照 ! ● http://qiita.com/advent-calendar/2014/uefi ● 質問でも BIOS なブートローダーでも u-boot で も良いのでそれっぽいネタ大募集中
Slide 5
Slide 5 text
● 本題,ブートローダー
Slide 6
Slide 6 text
● UEFI の基本スペック ● C 言語な SDK , EDK(NTDDK 風味 ) ● FAT32 なシステムパーティションを高レイヤに 読み書きできる ● stdio.h もつかえるぜ !
Slide 7
Slide 7 text
● でも今回は EDK つかいません
Slide 8
Slide 8 text
● 表題通り時間がなかったので
Slide 9
Slide 9 text
● 表題通り時間がなかったので ● gnu-efi でお茶を濁す
Slide 10
Slide 10 text
● gnu-efi: ● 名前が GNU なのに License は BSDL ● なぜ ???
Slide 11
Slide 11 text
● Binutils とこれをビルドする必要…… ● 今はなくなってる (?) ● apt-get install gnu-efi ● pacman -S gnu-efi-libs
Slide 12
Slide 12 text
● #include ● #include ● リンカオプションに -lefi -lgnuefi ● あとはコード書くだけ !
Slide 13
Slide 13 text
● https://github.com/orumin/SimpleMyLoader
Slide 14
Slide 14 text
Makefile ● ARCH = x86_64 ● EFIROOT = /usr ● HDDRROOT = $(EFIROOT)/include/efi ● INCLUDES = -I. -I$(HDDRROOT) -I$(HDDRROOT)/ $(ARCH) -I$(HDDRROOT)/protocol ● EFIROOT は configure で /usr/local とかにインスト ール先指定してたらそこに変更
Slide 15
Slide 15 text
Makefile ● CFLAGS = -O2 -fPIC -Wall -fshort-wchar -fno-strict-aliasing -fno-merge-constants -mno- red-zone ● ifeq ($(ARCH),x86_64) ● CFLAGS += -DEFI_FUNCTION_WRAPPER ● endif ● ● CPPFLAGS = -DCONFIG_$(ARCH)
Slide 16
Slide 16 text
Makefile ● CFLAGS は -fPIC と -fshort-wchar ,あと x86_64 ならば -DEFI_FUNCTION_WRAPPER を忘れなけ ればあとは好きなようにして大丈夫 ● CPP にも FLAG を設定する必要アリ
Slide 17
Slide 17 text
Makefile ● CRTOBJS= $(EFIROOT)/lib/crt0-efi-$(ARCH).o ● FORMAT = efi-app-$(ARCH) ● INSTALL = install ● LDFLAGS = -nostdlib ● LDSCRIPT = $(EFIROOT)/lib/elf_$(ARCH)_efi.lds ● LDFLAGS += -T $(LDSCRIPT) -shared -Bsymbolic -L$(EFIROOT)/lib $(CRTOBJS) ● LOADLIBS = -lefi -lgnuefi $(shell $(CC) -print- libgcc-file-name)
Slide 18
Slide 18 text
Makefile ● リンカスクリプト,スタートアップルーチン, 共に gnu-efi のものを使うようにする ● -nostdlib -shared ● 先にも書いたように -lefi と -lgnuefi で gnu-efi をリンク
Slide 19
Slide 19 text
Makefile ● prefix = ● CC = $(prefix)gcc ● AS = $(prefix)as ● LD = $(prefix)ld ● AR = $(prefix)ar ● RANLIB = $(prefix)ranlib ● OBJCOPY = $(prefix)objcopy
Slide 20
Slide 20 text
Makefile ● もし binutils や gcc を UEFI アプリケーションの ためにビルドしてどこか特定のディレクトリに 入れたなら prefix を指定.
Slide 21
Slide 21 text
Makefile ● %.efi: %.so ● $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \ ● -j .rela -j .reloc --target=$(FORMAT) $*.so $@ ● ● %.so: %.o ● $(LD) $(LDFLAGS) $^ -o $@ $(LOADLIBS) ● ● %.o: %.c ● $(CC) $(INCLUDES) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
Slide 22
Slide 22 text
Makefile ● C のソースをオブジェクトファイルにするとこ ろ,オブジェクトファイルを so なリロケータ ブルバイナリにするのには先に指定したフラグ を使う. ● とりたてて変わったことはしない.
Slide 23
Slide 23 text
Makefile ● 最後 *.efi を作る時はちょっと特殊 ● so なファイルから objcopy で, ELF のセクショ ンの内必要な部分だけを取り出す
Slide 24
Slide 24 text
ソースコード ( 前知識 ) ● efi.h , gnuefi.h をインクルード ● エントリポイントは efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE) ● UEFI は Protocol という API を使う ● 基本, OpenProtocol で Protocol の Handle を開いて,必 要な Protocol の関数ポインタ群を対応する Protocol 構造 体に詰めて,そこから Protocol の関数を呼ぶ ●
Slide 25
Slide 25 text
ソースコード ( 前知識 ) ● 本来は,たとえば BS->OpenProtocol() みたいに Protocol から直接関数呼び出し ● しかし Microsoft な ABI……
Slide 26
Slide 26 text
ソースコード ( 前知識 ) ● gnu-efi の場合 uefi_call_wrapper() で第一引数に UEFI の Protocol の関数ポインタ指定してつかう ● なお,ソースコード中の BS は BootServices で, EFI_BOOT_SERVICES というブートローダーに 必要なプロトコルのハンドラ.これは OpenProtocol とかしなくても最初からグローバルの BS という変 数に詰めてある ( でないと OpenProtocol が呼べな い )
Slide 27
Slide 27 text
ソースコード ( 前知識 ) ● なお EDK での前準備については 過去発表を参照されたし ● https://speakerdeck.com/orumin/driver
Slide 28
Slide 28 text
ソースコード ● efi_main の引数の ImageHandle , SystemTable ● 前者は自分自身のハンドル,後者はデバイスへ のハンドルやパスを手繰るための親のハンドル や関数が入ってる
Slide 29
Slide 29 text
ソースコード ● uefi_call_wrapper(BS->OpenProtocol, 6, ImageHandle, &LoadedImageProtocol, &LoadedImageParent, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); ● まず自分自身のハンドルから,既に読み込まれ てるメモリイメージ ( 実行バイナリイメージ ) についての Protocol を取得
Slide 30
Slide 30 text
ソースコード ● Path = FileDevicePath(LoadedImageParent- >DeviceHandle, L"\\vmlinuz"); ● 先ほど取得した Protocol ハンドルにあるデバイ スへのハンドルと, Linux カーネルへのパスを 引数に,カーネルのファイルへのデバイスパス を取得
Slide 31
Slide 31 text
ソースコード ● この時指定するパスは, EFI のシステムパーテ ィションのパス. ● カーネルもそこに置かないといけない ● もし普通に ext4 とかに置かれたものを読みた ければ, ext4 について EFI_SIMPLE_FILESYSTEM プロトコルを提供でき るように EFI Driver を書くしかない
Slide 32
Slide 32 text
ソースコード ● rEFInd のコードがファイルシステムドライバの 参考になります ● https://github.com/falstaff84/rEFInd/tree/master /filesystems
Slide 33
Slide 33 text
ソースコード ● uefi_call_wrapper(BS->LoadImage, 6, FALSE, ImageHandle, Path, NULL, 0, &Image); ● 取得したデバイスパスをつかって,新たにメモ リイメージ ( 実行バイナリイメージ ) をメモリ にロード
Slide 34
Slide 34 text
ソースコード ● uefi_call_wrapper(BS->StartImage, 3, Image, NULL, NULL); ● そして読み込んだイメージを起動 ! 完了 !
Slide 35
Slide 35 text
ソースコード ● というわけにいかない. ● Linux の起動に root のパーティションとか指定 するカーネルコマンドライン ( 起動オプショ ン ) を指定したい
Slide 36
Slide 36 text
ソースコード ● StartImage を実行する前に……
Slide 37
Slide 37 text
ソースコード ● uefi_call_wrapper(BS->OpenProtocol, 6, Image, &LoadedImageProtocol, &LoadedImage, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); ● また LoadedImage の Protocol ● 今度は自分自身のイメージではなく先ほど読み込 んだカーネルのイメージについて Protocol を取得
Slide 38
Slide 38 text
ソースコード ● LoadedImage->LoadOptions = Options; ● LoadedImage->LoadOptionsSize = (StrLen(LoadedImage->LoadOptions)+1) * sizeof(CHAR16); ● この Protocol のメンバに起動オプションのため のフィールドがあるので指定するだけ
Slide 39
Slide 39 text
ソースコード ● LoadOptions に渡してる Options ● CHAR16 *Options = L"root=/dev/sda2 rootfstype=btrfs rw quiet splash"; ● こんな感じで CHAR16 型の文字列を指定すれば 良い ● CHAR16 型なので文字列リテラルのプレフィク スに L を付けておく ← 大事
Slide 40
Slide 40 text
ソースコード ● 今度こそブートローダーとしての仕事完了 ! ● LoadOptions を指定してから, StartImage! ● その後の 2,3 行は後処理コード
Slide 41
Slide 41 text
ブートローダー ● initrd 対応サボってるのでファイルシステムのドラ イバが組み込みじゃなくてモジュールになっちゃっ てる ( よくあるディストリビューション標準の ) カ ーネルは起動時に root mount でカーネルパニックし ます. ● ハードコードしてるカーネルのファイルパスと起動 オプションは環境に合わせると誰でも使えると思 う.
Slide 42
Slide 42 text
ブートローダー ● 自作 OS でブートローダー書く時点で満足とい う話はおおかった. ● UEFI ではもはやそんな事はないよ ! ● 自作 OS のカーネルも生バイナリつくって EFI システムパーティションに配置するだけで良い ● とってもラク !
Slide 43
Slide 43 text
● ちなみにこの発表は先ほどコーディングしたブ ートローダーを用いて起動した ArchLinux で行 ないました. ● CHAR16 の変数を作るのに L を付けわすれてハ マった以外はバグが出ず,実行は一発で成功 ● なんて簡単なんだ
Slide 44
Slide 44 text
● さいごに : ● みんなもスライドはちゃんと用意しましょう