UEFIアプリケーションの書き方/Hello Worldプログラム

どのような環境/言語であっても、最初にHello worldプログラムを書くことは作法になっています。

ソースコードを書く

編集

プログラミング言語はCを使用します。ホスト環境のCプログラムとは違い、標準Cライブラリは使用できず、ヘッダーファイルも float.h、limits.h、stdarg.h、stddef.h、iso646.h、stdbool.h、stdint.h以外は使用することはできません。

#include <efi.h>
#include <efilib.h>

EFI_STATUS
EFIAPI
efi_main (EFI_HANDLE hnd, EFI_SYSTEM_TABLE *SystemTable) {
        InitializeLib(hnd, SystemTable);
        Print(L"Hello, world!\n");
        while(1){}
   return EFI_SUCCESS;
}

ホスト環境のCプログラムではアプリケーションのエントリポイントはint main()ですが、フリースタンディング環境であるUEFIではEFI_STATUS efi_main()となります。 InitializeLib関数はすべてライブラリ関数の呼び出しの前に(efi_main関数の先頭で)呼び出す必要があります。Print()関数はprintf()同様、フォーマットを指定することが可能です。戻り値 EFI_SUCCESSは処理が正常に完了したことを示すステータスコードです。

Makefileの作成

編集
ARCH            = #<arch>

OBJS            = main.o
TARGET          = hello.efi

EFIINC          = /usr/include/efi
EFIINCS         = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol
LIB             = /usr/lib
EFILIB          = /usr/lib
EFI_CRT_OBJS    = $(EFILIB)/crt0-efi-$(ARCH).o
EFI_LDS         = $(EFILIB)/elf_$(ARCH)_efi.lds

CFLAGS          = $(EFIINCS) -fno-stack-protector -fpic \
		  -fshort-wchar -mno-red-zone -Wall 
ifeq ($(ARCH),x86_64)
  CFLAGS += -DEFI_FUNCTION_WRAPPER
endif

LDFLAGS         = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \
		  -Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS) 

all: $(TARGET)

hello.so: $(OBJS)
	ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi

%.efi: %.so
	objcopy -j .text -j .sdata -j .data -j .dynamic \
		-j .dynsym  -j .rel -j .rela -j .reloc \
		--target=efi-app-$(ARCH) $^ $@

上の内容をそのままコピーし、Makefileという名前でソースコードと同じディレクトリに配置してください。 ただし、#<arch>はコンパイルしたいアーキテクチャ(32bit環境ならx86、64bit環境ならx86_64)に置き換えます。また、LIBEFILIBは環境により異なる場合があるので 適宜変更してください。(locate efi.hと検索して、その親ディレクトリを指定します。)

コンパイルと実行

編集

UEFIアプリケーションを実行するには、二通りの方法があります。

実機上での実行

編集

実機上で実行するには、まずUSBメモリやハードディスク等のストレージに「EFIシステムパーティション」を作ります。
作成するストレージのデバイスファイルを/dev/sdcとします。

gdisk /dev/sdc

上のコマンドを実行すると、対話式でパーティションを作成します。指示に従い、EFIシステムパーティションを作成してください。100MB程度の容量が一般的です。
次に、ファイルシステムを作成します。/dev/sdc1にパーティションを作成したとします。

mkfs.vfat /dev/sdc1

最後にプログラムをコピーします。適当な場所にパーティションをマウントしましょう。

mkdir /mnt/esp
mount /dev/sdc1 /mnt/esp
mkdir /mnt/esp/efi/boot/
cp /path/to/program.efi /mnt/esp/efi/boot/bootx64.efi #32bit環境ではbootx86.efi

コンピューターを再起動し、ブートメニューでプログラムをコピーしたストレージを選択してください。Hello world!と表示されれば成功です。

ハードウェアエミュレータ上での実行

編集

ここからはターミナル単体では起動できません。また、お使いのデバイスが仮想化支援機能に対応していなければ動作が遅くなりますが仕様です。
UEFIをエミュレーションできるハードウェアエミュレータを利用し、システムを構築済みを前提とします。
まずディスクイメージエディタまたはディスクイメージクリエイターを起動します。 無い場合は、外部デバイスやホストのデバイスにアクセスできる事を確認して下さい。 対応している場合CD等を用意します
イメージエディタやCD等のルートディレクトリに efi/boot を作ってください そして boot ディレクトリに先ほど作成したefiファイルを bootx64.efi 32bit環境では bootx86.efi とリネームしコピーします。 そして書き込んで(イメージをセーブして)ください。
先ほどのシステムにマウントします。そのまま起動します。 Hello world!と表示されれば成功です

このページ「UEFIアプリケーションの書き方/Hello Worldプログラム」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。