Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
カーネルVM関西 7回目 発表資料
Search
orumin
December 06, 2014
Technology
0
350
カーネルVM関西 7回目 発表資料
忙しい(言い訳)という事でした.カーネルVM関西 7回目の発表資料です. 発表で口頭だった部分をちゃんと書きました.
orumin
December 06, 2014
Tweet
Share
More Decks by orumin
See All by orumin
ヴィンテージマシンと付き合う - kernel/vm online 5
orumin
0
1k
むかしの RISC、むかしの Unix
orumin
7
3.5k
Fundamental of architecture to implementing OS on AArch64
orumin
3
4.8k
Kernel/VM Kansai #9
orumin
0
910
Kernel/VM #14 発表資料
orumin
1
550
Unikernels report
orumin
2
440
第13回Kernel/VM勉強会発表資料
orumin
1
1.6k
第12回カーネル/VM探検隊
orumin
0
350
第11回 Kernel/VM探検隊 発表資料
orumin
1
540
Other Decks in Technology
See All in Technology
システムとの会話から生まれる先手のDevOps
kakehashi
PRO
0
210
アジャイル脅威モデリング#1(脅威モデリングナイト#8)
masakane55
3
150
LLM as プロダクト開発のパワードスーツ
layerx
PRO
1
190
ブラウザのレガシー・独自機能を愛でる-Firefoxの脆弱性4選- / Browser Crash Club #1
masatokinugawa
1
390
OSSコントリビュートをphp-srcメンテナの立場から語る / OSS Contribute
sakitakamachi
0
1.3k
やさしいMCP入門
minorun365
PRO
146
95k
LLM とプロンプトエンジニアリング/チューターをビルドする / LLM, Prompt Engineering and Building Tutors
ks91
PRO
1
210
Amebaにおける Platform Engineeringの実践
kumorn5s
6
890
AWSのマルチアカウント管理 ベストプラクティス最新版 2025 / Multi-Account management on AWS best practice 2025
ohmura
3
200
FinOps_Demo
tkhresk
0
130
試験は暗記より理解 〜効果的な試験勉強とその後への活かし方〜
fukazawashun
0
340
JPOUG Tech Talk #12 UNDO Tablespace Reintroduction
nori_shinoda
1
110
Featured
See All Featured
VelocityConf: Rendering Performance Case Studies
addyosmani
328
24k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
13
660
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
21k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.3k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Into the Great Unknown - MozCon
thekraken
37
1.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
How GitHub (no longer) Works
holman
314
140k
BBQ
matthewcrist
88
9.6k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
52
2.4k
What's in a price? How to price your products and services
michaelherold
245
12k
Transcript
忙しくて時間がなくなったので 10 分でブートローダーをつくっ た話で茶濁す
• orumin (@kotatsu_mi) • Google Summer of Code 2014 で
OSv に Ruby を移植してました. • 以前 UEFI 遊びしてた
• UEFI! • BIOS もう捨てよう • GRUB も要らない (UEFI のブートセレクタで良
い )
• UEFI とは ? • UEFI Advent Calender 2014 参照
! • http://qiita.com/advent-calendar/2014/uefi • 質問でも BIOS なブートローダーでも u-boot で も良いのでそれっぽいネタ大募集中
• 本題,ブートローダー
• UEFI の基本スペック • C 言語な SDK , EDK(NTDDK 風味
) • FAT32 なシステムパーティションを高レイヤに 読み書きできる • stdio.h もつかえるぜ !
• でも今回は EDK つかいません
• 表題通り時間がなかったので
• 表題通り時間がなかったので • gnu-efi でお茶を濁す
• gnu-efi: • 名前が GNU なのに License は BSDL •
なぜ ???
• Binutils とこれをビルドする必要…… • 今はなくなってる (?) • apt-get install gnu-efi
• pacman -S gnu-efi-libs
• #include<efi.h> • #include<efilib.h> • リンカオプションに -lefi -lgnuefi • あとはコード書くだけ
!
• https://github.com/orumin/SimpleMyLoader
Makefile • ARCH = x86_64 • EFIROOT = /usr •
HDDRROOT = $(EFIROOT)/include/efi • INCLUDES = -I. -I$(HDDRROOT) -I$(HDDRROOT)/ $(ARCH) -I$(HDDRROOT)/protocol • EFIROOT は configure で /usr/local とかにインスト ール先指定してたらそこに変更
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)
Makefile • CFLAGS は -fPIC と -fshort-wchar ,あと x86_64 ならば
-DEFI_FUNCTION_WRAPPER を忘れなけ ればあとは好きなようにして大丈夫 • CPP にも FLAG を設定する必要アリ
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)
Makefile • リンカスクリプト,スタートアップルーチン, 共に gnu-efi のものを使うようにする • -nostdlib -shared •
先にも書いたように -lefi と -lgnuefi で gnu-efi をリンク
Makefile • prefix = • CC = $(prefix)gcc • AS
= $(prefix)as • LD = $(prefix)ld • AR = $(prefix)ar • RANLIB = $(prefix)ranlib • OBJCOPY = $(prefix)objcopy
Makefile • もし binutils や gcc を UEFI アプリケーションの ためにビルドしてどこか特定のディレクトリに
入れたなら prefix を指定.
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 $@
Makefile • C のソースをオブジェクトファイルにするとこ ろ,オブジェクトファイルを so なリロケータ ブルバイナリにするのには先に指定したフラグ を使う. •
とりたてて変わったことはしない.
Makefile • 最後 *.efi を作る時はちょっと特殊 • so なファイルから objcopy で,
ELF のセクショ ンの内必要な部分だけを取り出す
ソースコード ( 前知識 ) • efi.h , gnuefi.h をインクルード •
エントリポイントは efi_main(EFI_HANDLE, EFI_SYSTEM_TABLE) • UEFI は Protocol という API を使う • 基本, OpenProtocol で Protocol の Handle を開いて,必 要な Protocol の関数ポインタ群を対応する Protocol 構造 体に詰めて,そこから Protocol の関数を呼ぶ •
ソースコード ( 前知識 ) • 本来は,たとえば BS->OpenProtocol() みたいに Protocol から直接関数呼び出し
• しかし Microsoft な ABI……
ソースコード ( 前知識 ) • gnu-efi の場合 uefi_call_wrapper() で第一引数に UEFI
の Protocol の関数ポインタ指定してつかう • なお,ソースコード中の BS は BootServices で, EFI_BOOT_SERVICES というブートローダーに 必要なプロトコルのハンドラ.これは OpenProtocol とかしなくても最初からグローバルの BS という変 数に詰めてある ( でないと OpenProtocol が呼べな い )
ソースコード ( 前知識 ) • なお EDK での前準備については 過去発表を参照されたし •
https://speakerdeck.com/orumin/driver
ソースコード • efi_main の引数の ImageHandle , SystemTable • 前者は自分自身のハンドル,後者はデバイスへ のハンドルやパスを手繰るための親のハンドル
や関数が入ってる
ソースコード • uefi_call_wrapper(BS->OpenProtocol, 6, ImageHandle, &LoadedImageProtocol, &LoadedImageParent, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
• まず自分自身のハンドルから,既に読み込まれ てるメモリイメージ ( 実行バイナリイメージ ) についての Protocol を取得
ソースコード • Path = FileDevicePath(LoadedImageParent- >DeviceHandle, L"\\vmlinuz"); • 先ほど取得した Protocol
ハンドルにあるデバイ スへのハンドルと, Linux カーネルへのパスを 引数に,カーネルのファイルへのデバイスパス を取得
ソースコード • この時指定するパスは, EFI のシステムパーテ ィションのパス. • カーネルもそこに置かないといけない • もし普通に
ext4 とかに置かれたものを読みた ければ, ext4 について EFI_SIMPLE_FILESYSTEM プロトコルを提供でき るように EFI Driver を書くしかない
ソースコード • rEFInd のコードがファイルシステムドライバの 参考になります • https://github.com/falstaff84/rEFInd/tree/master /filesystems
ソースコード • uefi_call_wrapper(BS->LoadImage, 6, FALSE, ImageHandle, Path, NULL, 0, &Image);
• 取得したデバイスパスをつかって,新たにメモ リイメージ ( 実行バイナリイメージ ) をメモリ にロード
ソースコード • uefi_call_wrapper(BS->StartImage, 3, Image, NULL, NULL); • そして読み込んだイメージを起動 !
完了 !
ソースコード • というわけにいかない. • Linux の起動に root のパーティションとか指定 するカーネルコマンドライン (
起動オプショ ン ) を指定したい
ソースコード • StartImage を実行する前に……
ソースコード • uefi_call_wrapper(BS->OpenProtocol, 6, Image, &LoadedImageProtocol, &LoadedImage, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
• また LoadedImage の Protocol • 今度は自分自身のイメージではなく先ほど読み込 んだカーネルのイメージについて Protocol を取得
ソースコード • LoadedImage->LoadOptions = Options; • LoadedImage->LoadOptionsSize = (StrLen(LoadedImage->LoadOptions)+1) *
sizeof(CHAR16); • この Protocol のメンバに起動オプションのため のフィールドがあるので指定するだけ
ソースコード • LoadOptions に渡してる Options • CHAR16 *Options = L"root=/dev/sda2
rootfstype=btrfs rw quiet splash"; • こんな感じで CHAR16 型の文字列を指定すれば 良い • CHAR16 型なので文字列リテラルのプレフィク スに L を付けておく ← 大事
ソースコード • 今度こそブートローダーとしての仕事完了 ! • LoadOptions を指定してから, StartImage! • その後の
2,3 行は後処理コード
ブートローダー • initrd 対応サボってるのでファイルシステムのドラ イバが組み込みじゃなくてモジュールになっちゃっ てる ( よくあるディストリビューション標準の ) カ
ーネルは起動時に root mount でカーネルパニックし ます. • ハードコードしてるカーネルのファイルパスと起動 オプションは環境に合わせると誰でも使えると思 う.
ブートローダー • 自作 OS でブートローダー書く時点で満足とい う話はおおかった. • UEFI ではもはやそんな事はないよ !
• 自作 OS のカーネルも生バイナリつくって EFI システムパーティションに配置するだけで良い • とってもラク !
• ちなみにこの発表は先ほどコーディングしたブ ートローダーを用いて起動した ArchLinux で行 ないました. • CHAR16 の変数を作るのに L
を付けわすれてハ マった以外はバグが出ず,実行は一発で成功 • なんて簡単なんだ
• さいごに : • みんなもスライドはちゃんと用意しましょう