Introduction for developping UEFI app/driver

Introduction for developping UEFI app/driver

UEFIを,UDK(EDKII)で開発するための最初のステップについて
解説+α

F28abade40c3fa0565f578f7dbae6560?s=128

orumin

May 25, 2014
Tweet

Transcript

  1. 自己紹介 • orumin – 学生 • sepcamp2012, GSoC(now) • twitter:

    @kotatsu_mi
  2. 自己紹介 • orumin – 学生 • sepcamp2012, GSoC(now) • twitter:

    @kotatsu_mi • 側転できなさそうな顔の人とか TL 大破とか
  3. 自己紹介 • orumin – 学生 • sepcamp2012, GSoC(now) • twitter:

    @kotatsu_mi • 側転できなさそうな顔の人とか TL 大破とか • ておくれではない
  4. ておくれではないので, みんなにわかりやすいネタ, やります 既に知ってたらごめんなさい

  5. ておくれではないので, みんなにわかりやすいネタ, やります 既に知ってたらごめんなさい

  6. UEFI

  7. Introduction for developping UEFI app/driver

  8. UEFI • 初出 - “Play with UEFI” カーネル VM 関西

    4 • “ いじぇくと的ななにか” カーネル /VM 探検隊 第九回
  9. UEFI • ベタ C 移植 ? • Python? • EFI

    Protocol? • なぞのシェル
  10. UEFI • わからん • どう開発してるのか • どう動くのか • ておくれ

  11. UEFI • UEFI は真面目に利便性の高いもの • ておくれてないよ !

  12. UEFI( 加筆 ) • そもそも UEFI とは, BIOS をおきかえるもの •

    UEFI 自体にブートローダーやシェルのような ものが実装されている • 自作のアプリケーション,ドライバが簡単に作 れ動かせる ← ココ重要
  13. First Step

  14. First Step • まずは SDK のインストール 今回は UDK について説明します UDK

    は EDK(II) の stable で,現在 2014 が最新 (syuu1228 さん,情報提供ありがとうございます )
  15. First Step $ mkdir ~/src $ cd ~/src $ svn

    co https://edk2.svn.sourceforge.net/svnroot/ edk2/trunk/edk2 $ make -C edk2/BaseTools $ cd ~/src/edk2 $ export EDK_TOOLS_PATH=$HOME/src/edk2/BaseTools $ source edksetup.sh BaseTools
  16. FirstStep • ${EDK_TOOLS_PATH}/Conf • TOOLS_CHAIN_TAG 変数 • ACTIVE_PLATFORM 変数

  17. FirstStep • ${EDK_TOOLS_PATH}/Conf/target.txt • TOOLS_CHAIN_TAG 変数 -> GCC47 • ACTIVE_PLATFORM

    変数 -> FooPkg/FooPkg.dec
  18. FirstStep • ${EDK_TOOLS_PATH}/Conf/target.txt • TOOLS_CHAIN_TAG 変数 -> GCC47 • ACTIVE_PLATFORM

    変数 -> FooPkg/FooPkg.dec • 準備完了
  19. FirstStep • ${EDK_TOOLS_PATH}/Conf/target.txt • TOOLS_CHAIN_TAG 変数 -> GCC47 • ACTIVE_PLATFORM

    変数 -> FooPkg/FooPkg.dec • 準備完了 • build コマンドでビルドしはじめる
  20. Second Step

  21. Second Step • プロジェクトの設定 • 設定ファイルは基本的には ini ファイルの変種

  22. Second Step • プロジェクトの設定 • 設定ファイルは基本的には ini ファイルの変種 • UNIX-Like

    OS で開発してても,滲み出る そこはかとない Windows っぽさ
  23. Second Step • *.dec [Defines] DEC_SPECIFICATION = 0x00010005 PACKAGE_NAME =

    AppPkg PACKAGE_GUID = B3E3D3D5-D62B-4497-A175-264F489D127E PACKAGE_VERSION = 0.01
  24. Second Step • たった 4 行 • 設定ファイルのバージョン • プロジェクト名

    • UUID • プロジェクトのバージョン
  25. Second Step • *.dsc [Defines] PLATFORM_NAME = AppPkg PLATFORM_GUID =

    0458dade-8b6e-4e45-b773-1b27cbda3e06 PLATFORM_VERSION = 0.01 DSC_SPECIFICATION = 0x00010006 OUTPUT_DIRECTORY = Build/AppPkg SUPPORTED_ARCHITECTURES = IA32|IPF|X64 BUILD_TARGETS = DEBUG|RELEASE SKUID_IDENTIFIER = DEFAULT
  26. Second Step • プロジェクト名 • UUID(*.dec とは違うもの ) • プロジェクトのバージョン

    • 設定ファイルのバージョン • ビルドの出力先 • ターゲットアーキテクチャ • ビルドターゲット
  27. Second Step • まだまだ続く

  28. Second Step [LibraryClasses] UefiApplicationEntryPoint| MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf ShellCEntryLib| ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf UefiDriverEntryPoint| MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf

  29. Second Step • この LibraryClasses セクションは, foo|path/to/libraryfolder という形 • foo

    はなんでも良いけれど, UDK 内の既存プ ロジェクトに従ったほうが良い
  30. Second Step • 最初の 3 つはエントリポイントについての ライブラリをプロジェクトに読み込む • これをしないとエントリポイントつくれない •

    3 つのエントリポイントの違いは後ほど
  31. Second Step BaseLib|MdePkg/Library/BaseLib/BaseLib.inf BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf UefiLib|MdePkg/Library/UefiLib/UefiLib.inf PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf MemoryAllocationLib| MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf UefiBootServicesTableLib|

    MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf UefiRuntimeServicesTableLib| MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
  32. Second Step • その他必要ライブラリのみなさん • 必ずしもこれらが必要なわけではない • UDK 内の既存プロジェクトとそのヘッダを 見てどんなユーティリティがあるか判断

  33. None
  34. Second Step [Components] AppPkg/Applications/Hello/Hello.inf …

  35. Second Step • [Components] セクション • プロジェクトを更にモジュール毎に分割した 小さいプロジェクトの設定ファイルのパス この設定ファイルは *.inf

  36. Second Step • dsc ファイルについて最後に • libc とか web socket

    を使う場合だけ !include StdLib/StdLib.inc !include AppPkg/Applications/Sockets/Sockets.inc • この 2 行で設定の読み込みが必要
  37. Second Step

  38. Second Step [Defines] INF_VERSION = 0x00010006 BASE_NAME = Hello FILE_GUID

    = a912f198-7f0e-4803-b908-b757b806ec83 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 ENTRY_POINT = ShellCEntryLib
  39. Second Step • inf ファイルの [defines] セクション • dsc の

    [defines] と大差なし • ポイントは,ここで MODULE_TYPE と ENTRY_POINT を指定
  40. Second Step • MODULE_TYPE は UEFI_APPLICATION か UEFI_DRIVER • ENTRY_POINT

    は dsc ファイルに書いて 読み込んだ 3 つ, ShellCLibEntryPoint UefiApplicationEntryPoint UefiDriverEntryPoint
  41. Second Step [Sources] Hello.c [Packages] MdePkg/MdePkg.dec ShellPkg/ShellPkg.dec [LibraryClasses] UefiLib ShellCEntryLib

  42. Second Step • リンク / コンパイルするソース全て • 使用するライブラリを含むパッケージの プロジェクト設定へのパス •

    LibraryClasses ここでは, dsc に既に書いたので省略形で 記述
  43. Second Step • dsc の Components でモジュール分割するほどのプ ロジェクトでなければ, dsc のほうに

    MODULE_TYPE やら ENTRY_POINT や ら書いてしまって, inf には [Sources] だけというのも可能 • inf を応用して,ソースコードだけ別フォルダに 分けるときに使うという使用方法もあり
  44. エントリポイントについて UefiApplication 〜は UEFI の API 独自の作法に 従うエントリポイント EFI_IMAGE_HANDLE,EFI_SYSTEM_TABLE という型の引数で呼ばれる

  45. エントリポイントについて • ShellCLib 〜の場合は普通の main から スタート • ほぼ完全にコード変更なしに pure

    C が動作 • UEFI Protocol(API) を呼ぶのがちと面倒
  46. エントリポイントについて • UefiDriver 〜はいわずもがな, UEFI ドライバを記述するときの エントリポイント • 引数は UefiApplication

    〜と同様 • ドライバはこれしかない • UnEntryPoint の設定も必要
  47. Let's coding

  48. Let's coding • さあ後はコーディングするだけ ! • inf に適宜ソースファイル追加しつつ コーディングしましょう

  49. Let's coding • さあ後はコーディングするだけ ! • inf に適宜ソースファイル追加しつつ コーディングしましょう •

    Happy Hacking!!!
  50. おわり

  51. なワケないでショー !?

  52. なワケないでショー !?

  53. Let's coding • UEFI Protocol について • UEFI の API

    のこと • なんで Protocol なんでしょうね • データ駆動型 API です
  54. Let's coding • 基本的には, HandleProtocol() で特定の デバイス等の Handle を取得 •

    その Handle を OpenProtocol() にぶちこんで Protocol 構造体にデータを詰め込んでもらう • 構造体に詰められた関数ポインタを通して API コール
  55. None
  56. Let's coding typedef struct { EFI_TABLE_HEADER Hdr*; CHAR16 *FirmwareVendor; UINT32

    FirmwareRevision; EFI_HANDLE ConsoleInHandle; EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn; EFI_HANDLE ConsoleOutHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
  57. Let's coding EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; EFI_RUNTIME_SERVICES *RuntimeServices; EFI_BOOT_SERVICES *BootServices;

    UINTN NumberOfTableEntries; EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE; •
  58. Let's coding EFI_HANDLE StandardErrorHandle; EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr; EFI_RUNTIME_SERVICES *RuntimeServices; EFI_BOOT_SERVICES *BootServices;

    UINTN NumberOfTableEntries; EFI_CONFIGURATION_TABLE *ConfigurationTable; } EFI_SYSTEM_TABLE; •
  59. Let's coding • gST,gRS,gBS … 既に宣言 • gBS が特に重要 LocateHandle()

    , Open/CloseProtocol() 他にも LoadImage() , StartImage() ExitBootServices() 等 • 最悪 EFI_SYMPLE_FILE_SYSTEM_PROTOCOL と EFI_BOOT_SERVICES だけでブートローダ書ける
  60. • ドライバの場合,加えてヘッダで自身の プロトコルのデータ構造を公開 • DRIVER_BINDING_PROTOCOL で プロトコルをデバイスに対して使えるかの チェック,プロトコル開始時の資源確保, プロトコル終了時の資源解放を記述

  61. Let's coding • 実際のコードを見てみよう https://github.com/tianocore/edk2-FatPkg *.dec と *.dsc と *.inf

    が設定, Fat.h に各種宣言, Fat.c が EntryPoint 他にも Fat.c でつかわれる Lock が Misc.c デバイスのアロケートを Init.c Read/Write を ReadWrite.c… という具合
  62. おわりに • 駆け足だったので伝わらない部分もあったはず • スライド上げとくのでどうぞ読み直して下さい • デモ用意できませんでした • 最小限のプロジェクトのテンプレートを GitHub

    に上げとく ( 予定 )
  63. おわりに • UDK は VisualStudio でも使えます (Windows ユーザーさんどうぞ ) •

    UNIX Like な OS で動作させる前提のツールは gnu-efi のほうが楽かもしれません GrowBuffer() や LocateHandlebyDiskSignature() とか • rEFInd とか参考にしてね ! http://sourceforge.net/projects/refind/files/
  64. 余談 • Hibernation 中の swap パーティションの snapshot を UEFI app

    で弄ったりして, secure boot の secure さを壊せるのでは ? https://lkml.org/lkml/2013/8/22/218 • 発端 http://lists.opensuse.org/opensuse-kernel/ 2013-09/msg00068.html