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
340
カーネルVM関西 7回目 発表資料
忙しい(言い訳)という事でした.カーネルVM関西 7回目の発表資料です. 発表で口頭だった部分をちゃんと書きました.
orumin
December 06, 2014
Tweet
Share
More Decks by orumin
See All by orumin
ヴィンテージマシンと付き合う - kernel/vm online 5
orumin
0
900
むかしの RISC、むかしの Unix
orumin
7
3.1k
Fundamental of architecture to implementing OS on AArch64
orumin
3
4.5k
Kernel/VM Kansai #9
orumin
0
810
Kernel/VM #14 発表資料
orumin
1
510
Unikernels report
orumin
2
410
第13回Kernel/VM勉強会発表資料
orumin
1
1.4k
第12回カーネル/VM探検隊
orumin
0
280
第11回 Kernel/VM探検隊 発表資料
orumin
1
490
Other Decks in Technology
See All in Technology
MapLibreとAmazon Location Service
dayjournal
1
140
少数チームで挑む: SwiftUI, TCA, KMPを用いた 新規動画配信アプリ 「ABEMA Live」の開発について
tomu28
0
620
レガシーをぶっ壊せ。AEONで始めるDevRelの話 / Qiita Night 2024-2-22
aeonpeople
3
1.2k
日本におけるデータエンジニアリングのこれまでとこれから
foursue
16
4.1k
Azure Container Apps + Bicep 〜 こんな感じで運用しています
kaz29
2
420
DevOpsメトリクスとアウトカムの接続にトライ!開発プロセスを通して計測できるメトリクスの活用方法
ham0215
2
230
継続的な改善 x ⾮連続的な進化
sansantech
PRO
3
130
ChatGPT for IT Service Management (IT Pro)
dahatake
7
1.5k
Algyan イベント振り返り
linyixian
0
210
Terraformあれやこれ/terraform-this-and-that
emiki
8
1.3k
Postman v10リリース後を振り返る
nagix
0
170
〜小さく始めて大きく育てる〜データ分析基盤の開発から活用まで
kniino
0
2.1k
Featured
See All Featured
Robots, Beer and Maslow
schacon
PRO
155
7.9k
Build your cross-platform service in a week with App Engine
jlugia
225
17k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
658
120k
The Brand Is Dead. Long Live the Brand.
mthomps
48
28k
Become a Pro
speakerdeck
PRO
10
4.5k
Raft: Consensus for Rubyists
vanstee
132
6.3k
Scaling GitHub
holman
457
140k
A Tale of Four Properties
chriscoyier
150
22k
Done Done
chrislema
178
15k
Rails Girls Zürich Keynote
gr2m
91
13k
Creatively Recalculating Your Daily Design Routine
revolveconf
209
11k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
352
28k
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
を付けわすれてハ マった以外はバグが出ず,実行は一発で成功 • なんて簡単なんだ
• さいごに : • みんなもスライドはちゃんと用意しましょう