【EDK II】Module開発
引き続き第三弾。途中で力尽きて寝落ちすると思います。
EDK IIのModuleとは・・・?
EDK IIのModuleはソースファイルあるいはバイナリファイル,そしてModule定義ファイル(INFファイル)から構成されています。INFファイルはModuleの基本的な情報と,読み込む/生成するライブラリクラス・PCD・Protocol・PPI・GUIDといったインターフェースを記述しています(「EDK II Extended INF Specification」を参照下さい)。
典型的なEDK II Moduleは,ビルドされた後,FFS(Firmware File System)に置かれ,そしてFV(Firmware Volume) Imageに置かれたFirmware Componentです。
Componentとして考えられるのは次のようなものです。
・efiバイナリファイルにビルドされ,EFI_PE_SECTIONとしてFFSファイルに置かれるドライバやアプリケーション
・Rawデータバイナリ。例えば,$(WORKSPACE)/MdeModulePkg/Logo/Logo.infはbitmapイメージのロゴを含むRaw Binary Moduleです。
・Device's Option ROMに置かれるOption ROMドライバ
・スタンドアローンなUEFIドライバ
・スタンドアローンなUEFIアプリケーション
・ライブラリオブジェクトファイル(.lib)にビルドされ他のModuleに静的にリンクされる,ライブラリインスタンス
ModuleはソースコードのままやEFIバイナリフォーマットでリリースされます。
Module Type
EDK IIは多くのModule Typeを定義しています。
Module typeの用途は次のようなものです。
・Moduleのライフサイクルを示します。
例えば,PEIMはPEI Phaseでディスパッチされます。また,DXE_DRIVERやUEFI_DRIVERはDXE Phaseでディスパッチされます。
・Moduleのバイナリイメージ生成を示します。
例えば,PEIM/DXE_DRIVER TypeのModuleは.efiバイナリイメージに"depex"セクションがあります。UEFI_DRIVERは.efiバイナリイメージに.uiや.verセクションがあります。
・Moduleの適切なライブラリインスタンスを示します。ライブラリインスタンスは,INFファイル内でどんなModule Typeがサポートされるか指示しています。
MODULE_TYPE | DESCRIPTION |
SEC | このModuleはCPUのリセットベクタで実行を開始するよう設計されており,それらはPEI Phaseのためにプラットフォームを準備します。 SECのために定義された標準サービスはないので,このタイプのModuleは同じルールに従います。また,一般的には,スタック用Temporary Memoryを作るための特定のCPUアセンブリコードをいくつか含んでいます。 このModuleは,PEI PhaseにHOBs(Hand-Off-Blocks)という形式でパスされるサービスを生成します。なお,それらのサービスはPIの仕様に準拠していなければなりません。 |
PEI_CORE | このタイプのModuleは,PIの仕様に準拠したPEI Coreの実行により使用されます。 |
PEIM | このタイプのModuleは,PIの仕様に準拠したPEIMsによって使用されます。 |
DXE_CORE | このタイプのModuleは,PIの仕様に準拠したDXE Coreの実行により使用されます。 |
DXE_DRIVER | このタイプのModuleは,PIの仕様に準拠したDXEドライバに使用されます。 それらのModuleはブートサービス環境で実行されるだけでExitBootServices()がコールされた時にdestroyされます。 |
DXE_RUNTIME_DRIVER | このタイプのModuleは,PIの仕様に準拠したDXEドライバに使用されます。 これらのModuleはブートサービス環境でもランタイムサービス環境でも実行可能です。つまりこれは,サービスがExitBootServices()がコールされた後でも使用可能ということです。もし,SetVirtualAddressMap()がコールされたら,このModuleはOSが提供する仮想アドレスマップに従って再配置されます。 |
DXE_SAL_DRIVER | このタイプのModuleは,SetVirtualAddressMap()がコールされる前のPhysical Modeや,SetVirtualAddressMap()がコールされた後のPhysical ModeあるいはVirtual Modeで,DXEドライバに使用されます。このModuleはIPF CPUだけ実行可能です。つまりこれは,Moduleが生成するサービスがExitBootServices()がコールされた後でも実行可能ということです。 |
DXE_SMM_DRIVER | このタイプのModuleは,SMRAMにロードされるDXEドライバに使用されます。結果としてこのModuleはIA32,x64のCPUで実行可能です。これらのModuleはPhysical Modeでのみ実行され,destroyされることは決してありません。つまりこれは,Moduleが生成するサービスがExitBootServices()がコールされた後でも実行可能ということです。 |
UEFI_DRIVER | このタイプのModuleは,UEFIの仕様に準拠したUEFIドライバに使用されます。これらのModuleはBootService実行環境でサービスを提供します。EFI_SUCCESSを返すUEFIドライバはメモリからアンロードされません。一方,errorを返すUEFIドライバはメモリからアンロードされます。 |
UEFI_APPLICATION | このタイプのModuleは,UEFIの仕様に準拠したUEFIアプリケーションに使用されます。UEFIアプリケーションはそれらが終了した時,いつもメモリからアンロードされます。 |
Moduleの作成
ドライバやライブラリModuleは,下記に似たような手順に沿って作成されます。
1. Moduleを置くPackageを作成・選択する。
2. Module用のディレクトリを作成してディレクトリにINFファイルを置く。
3. INFファイルにPackageの依存情報を追記する。
4. INFファイルにPPI,Protorol,GUID,PCDあるいはライブラリクラスの依存情報を追記する。
5. もし,このModuleがPPI,ProtocolあるいはGUIDに依存しており,[depex]セクションをサポートしている場合,INFファイルに[depex]セクションを追記する。
6. ソースファイルを作成し,ソースファイルの相対パスをINFファイルに追記する。
位置
ModuleはリリースされるとPackage内に配布されるので,新しいModuleのために適切なPackageを作成したり選択することが最初のステップです。
Packageの選択
EDK IIのPackageは,似たような定義やModuleを含めるために使用されます。その”似たような”は,次のルールによって判断されるべきです。
Industry standard: 例えば,MdePkgは,PIWG,UEFI,SMBIOS,USB, PCIなど業界規範からの定義を含めています。 Similar technology: 例えば,OptionRomPkgは,Option ROM技術に関連する定義やModuleをグループ化しています。 Business reason: 例えば,IntelFrameworkPkgは,Intelフレームワーク実行のための定義やModuleをグループ化しています。 Platform: 例えば,Nt32PkgはNt32プラットフォームに必要な定義やModuleをグループ化しています。 さらに,Platform PackageはビルドのためにDSC・FDFファイルも提供しています。
Module開発の最初の段階では,Module開発者は適切なPackageを選択するために,目的やModuleのリリース過程を塾考する必要があります。
Moduleディレクトリの追加
Moduleディレクトリの適切なPackageへの追加は,次の方法でなされることが推奨されます。
・ライブラリModuleは"
・PROTOCOL,PPI,GUIDあるいはライブラリクラスの定義をそれぞれ,"
・ドライバModuleを"
・アプリケーションModuleを"
・次のようにModuleに推奨された名前を用いること
推奨されるディレクトリ名の慣習 | Module Type |
XxxPei | PEIM,PEI_CORE |
XxxDxe | DXE_DRIVER,UEFI_DRIVER |
XxxRuntimeDxe | DXE_RUNTIME_DRIVER |
XxxxDxeSal | DXE_SAL_DRIVER |
XxxxLib | Library Instance |
サンプル:Moduleメタファイル(INF)
Moduleは各々,ModuleのルートディレクトリにINFファイルが必要です。
Moduleは次のアイテムを含むINFファイル(たまにModuleメタファイルと言及される)
です。
・Module名,GUID,Module Typeなど,Moduleの基本情報
・Moduleが依存している任意のPackageのパス
・Module含まれているバイナリファイルあるいはソースファイルのパス
・Moduleに必要とされるProtocol,PPI,GUIDといったインターフェースすべてのリスト
・Moduleに必要とされるPCDやライブラリクラスすべてのリスト
・その他,Module Typeに依存するsectionなど
アプリケーションModule INFの例:
## [Defines] INF_VERSION = 0x00010005 BASE_NAME = HelloWorld FILE_GUID = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 UEFI_SPECIFICATION_VERSION = 0x0002001E ENTRY_POINT = 0x0002001E # # 次の情報はリファレンスのみでビルドツールには必要とされていません。 # # VALID_ARCHITECTURES = IA32 X64 IPF EBC # ## [Sources.common] Helloworld.c ## [Package] MdePkg/MdePkg.dec ## [LibraryClasses] UefiBootServicesTableLib UefiApplicationEntryPoint UefiLib DebugLib
下記はライブラリインスタンスPeiServicesTablePointerLib.infのサンプルINF:
[Defines] INF_VERSION = 0x00010005 BASE_NAME = PeiServicesTablePointerLib FILE_GUID = XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX MODULE_TYPE = PEIM VERSION_STRING = 1.0 LIBRARY_CLASS = PeiServicesTablePointerLib|PEIM PEI_CORE SEC CONSTRUCTOR = PeiServicesTablePointerLibConstructor # # VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only) # # [Sources.common] PeiServicesTablePointer.c [Packages] MdePkg/MdePkg.dec [LibraryClasses] DebugLib
Package依存情報の追加
INFファイルの[Packages]セクションは,このModuleのPackageへの依存情報をすべて記載します。依存するPackageのDECファイルのパスが,INFファイルの[Packages]セクションに記載されることになります。例えば下記のようになります。
[Packages] # パスは$WORKSPACEをルートとするパスなので注意してください。 MdePkg/MdePkg.dec IntelFrameworkPkg/IntelFrameworkPkg.dec
ModuleはPackageの依存情報を決定するのに以下のルールに従うべきです。
・MdePkgはすべてのModuleに必要になります。
・Intelフレームワークの仕様の定義を使用する場合は,IntelFrameworkPkgが必要になります。
・上記のルール以上に,Protocol,PPI,GUID,PCD,ライブラリクラスを参照することで,より多くのPackageへの依存があります。例えばもし,ModuleがMdeModulePackage内で定義される"HiiLib"クラスから,定義やインターフェースを参照すると,それは同時にMdeModulePkgに依存していることにもなります。
ソースファイルの追加
すべてのModuleのソースコードはINF内の[Sources]セクションに記載され,次のルールに基づいています。
・異なるアーキテクチャのソースは異なるソースセクションに記載されます。
[Sources.common] # すべてのアーキテクチャに有効 CheckSum.c ... [Sources.Ia32] # IA32アーキテクチャにのみ有効 Ia32/Wbinvd.c | MSFT ... Ia32/WriteMm7.S | GCC ... [Sources.X64] # X64アーキテクチャにのみ有効 X64/Thunk16.asm ... [Sources.IPF] # IPFアーキテクチャにのみ有効 Ipf/AsmCpuMisc.s ... [Sources.EBC] # EBCアーキテクチャにのみ有効 Synchronization.c ...
・Tool Tagはツールチェーン別にソースを指定するために使用します。
[Sources.Ia32] Ia32/Wbinvd.c | MSFT # MSFTツールを使用したとき,このソースがビルドされます。 ... Ia32/WriteMm7.S | GCC # GCCツールを使用したとき,このソースがビルドされます。 ... "$(CC)" -o ${dst} $(CC_FLAGS) $(INC) ${src}
・すべてのファイルはModuleのメインフォルダ以下に置くこと。"./"の表現は使わないこと。
・すべてのCインクルードファイルは[Sources]セクション内にリスト化されるべきです。
ライブラリクラスリファレンスの追加
ライブラリクラスはいくつかのマクロあるいは構造体定義と関数宣言を抽出します。ライブラリインスタンスは,異なるプラットフォームや一つのプラットフォーム内の異なるPhase(SEC,PEI,DXE)に対して,異なるものになります。それゆえ,ModuleはプラットフォームやPhase動作のライブラリクラスに依存しています。
Module内でライブラリクラスを使う手順は下記の通りです。
1. INF内に記載のライブラリクラスを含むPackageへの依存情報を追記します。 2. INF内に記載のライブラリクラスへの依存情報を追記します。 3. ソースコード中でライブラリクラスヘッダファイルをIncludeします。
C言語のソースファイル内でライブラリクラスヘッダをIncludeする際は,次のようなsyntaxを使用します。
#include <Library/OemHookStatusCodeLib.h>
ヘッダファイルのインクルードパスは,PackageのDEC内[Includes]セクションで定義されるPackageのパブリックインクルードパスからの相対で表します。
PCD(Platform Configuration Database)リファレンスの追加
マクロとグローバル変数は,異なるアーキテクチャや異なるプラットフォームでModuleをカスタマイズするために広く使用されます。EDK IIはこれらの手法を置き換えるPCDの概念を紹介しています。
例えば,"FeatureFlag"型のPCDは,いくつかの特徴や機能がPCDの値がTRUEの時に有効化されるという点で,マクロに似ています。逆の場合も同様です。
PCDエントリはPCDのToken Space GUID C Nameにより,"."とC Nameにより定義されます。一つのPCD Token Spaceの中で,PCDのC Nameは固有のものになります。
例えば,PCD gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevelを例に挙げてみると,gEfiMdePkgTokenSpaceGuidはToken Space名であり,PcdDebugPrintErrorLevelはPCDの名前です。なお,gEfiMdePkgTokenSpaceGuidはMdePkg内で定義されるGUIにマッピングされています。
gEfiMdePkgTokenSpaceGuid = {0x914AEBE7, 0x4635, 0x459B, {0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10}}
PCDのType
EDK IIは次のようなPCD Typeを提供しています。
Feature flag type PCD | このタイプのPCDは,特徴を有効化・無効化するswitch MACROの代替です。これはBOOL型で値はTRUEもしくはFALSEです。 |
Fixed at build type PCD | このタイプのPCDは,PCI Expressベースアドレスといったカスタマイズ可能な値を生成するマクロを代替します。 |
Patchable in module type PCD | このタイプのPCDは,Fixed at build型のPCDにとても似ていますが,値はModuleのPEイメージのコードセクションではなくデータセクションに保存されています。 |
Dynamic type PCD | このタイプのPCDは,他のタイプのPCDとは異なるものです。値は一つのModuleにより割り当てられ,実行中は他のModuleからアクセスされます。PEIMであるPcdPeimやDXEドライバであるPcdDXEは各々,それぞれのPhaseにおいて,使用するDynamic PCDの情報を含むデータベースを整備します。 |
Module INFファイルへのPCDの追加
PCDエントリを参考として引用するために,Token Space Guid NameとPCD NameがINFファイルの[PCD]セクションに追加されなければなりません。
[PCD.common] gEfiMdePkgTokenSpaceGuid.PcdMaximumLinkedListLength gEfiMdePkgTokenSpaceGuid.PcdMaximumAsciiStringLength gEfiMdePkgTokenSpaceGuid.PcdMaximumUnicodeStringLength
プラットフォームインテグレーターがいろんな用途で任意のPCDタイプを使用できるように,Module INFファイルでは一般的なタイプの"PCD"の使用が推奨されます。例えば,デスクトッププラットフォームでは,メモリー長が"Dynamic" PCDとして設計され,その値はMemory Discoveryドライバによって生成されます。しかしながら,いくつかの特殊な組み込みシステム内では,メモリー長が"FixedAtBuild"タイプのPCDとして設計され,その値はいつも固定されています。
PCD Typeを選択する際には制限があります。
もし,PCDの値が配列長のように定数として使用された場合,このPCDのタイプは"FixedPcd"であるべきです。例えば以下のような例があります。
UINT8 MySampleArray[FixedPcdGet16(PcdArrayLength)] = (0);
ライブラリインスタンスは異なるModuleにリンクしうるし,同一のPCDは異なるModuleで異なる値を持ちうるので,ライブラリインスタンスModuleには"FixedPcd"を用いることを避けてください。
単一のModuleでは,2つのPCDを同じ名前で使わず異なる,Token Spaceで使用してください。
PCD Type | INF File Section Name |
任意のPCD TypeにマッピングされるGeneral Type | PCD |
Feature Flag | FeaturePcd |
Fixed At Build | FixedPcd |
Patchable In Module | PatchPcd |
Dynamic | PCD |
CソースコードからPCDの値へのアクセス
ソースコードからPCDの値を得たりセットするには,次の手順にそうべきです。
1. Module INFファイルにPcdLibの依存情報を追記します。
2. MdePkgの依存情報を追記する。
3. ソースコード中に
4. PCDの値にアクセスするために,PcdLibを使用する
Function name | INF PCD Section Name |
PcdGetx()/PcdSetx() | Common get/set function for all PCDs type |
FixedPcdGetx() | Get/set function for "FeaturePcd" |
FixedPcdGetx() | Get function for "FixedPcd" |
PatchPcdGetx()/PatchPcdSetx | Get/set function for "PatchPcd" |
例えば,PcdGet32マクロは,PCDのすべてのTypeの値を,
32bit値で得るために使われます。
// // Check driver debug mask value and global mask // if ((ErrorLevel & PcdGet32(PcdDebugPrintErrorLevel)) == 0){ return; }
Protocol,PPI,GUIDの参照
Protocol,PPI,GUIDは,UEFIアーキテクチャインターフェースの細目であり,
ファームウェアの構成要素のインターフェースを抽出します。
以降は,Moduleからどのようにこれらのインターフェースを参照するのか見ていきましょう。
INFファイルへProtocol,PPI,GUIDの追加
Protocol,PPI,GUIDの名前は,Module INF内の[Protocol],[Ppi],[Guid]に追記する必要があります。例えば,次のようなものです。
[Protocol] gEfiSampleProtocol
ヘッダファイルをソースコードにインクルード
Protocol,PPI,GUIDのヘッダファイルは似たような構造を定義します。ヘッダファイルのパスを探すには次の手順を踏んでください。
・Ppiのヘッダファイルは,
・Protocolのヘッダファイルは,
・Guidのヘッダファイルは,
ヘッダファイルはModuleソースコードに明確にに含まれなければなりません。
つまり下記のように宣言します。
#include <Protocol/DeviceIo.h> #include <Ppi/Reset.h> #include <Guid/GlobalVariable.h>
Moduleの依存情報を追加
依存情報は,ドライバのエントリポイントで実行したりディスパッチする条件を与えることになります。これは,PEIMやDXE Moduleにディスパッチする順番を決めるのに役立ちます。
・Ppiのヘッダファイルは,
・Protocolのヘッダファイルは,
・Guidのヘッダファイルは,
ヘッダファイルはModuleのソースコードに明確に含まれなければなりません。例えば,次のようになります。
#include <Protocol/DeviceIo.h> #include <Ppi/Reset.h> #include <Guid/GlobalVariable.h>
ライブラリインスタンスへの追加の手順
生成されるライブラリクラスの定義
ライブラリインスタンスは,常に単一のライブラリクラスに関連づけられており,ライブラリクラスにより定義されるすべてのインターフェースを実装します。それゆえ,ライブラリクラス名は,ライブラリインスタンスのINFファイル内の[Defines]セクションに記載しなければなりません。例えば次のように記載します。
[Defines] LIBRARY_CLASS = UefiDriverEntryPoint | DXE_DRIVER DXE_RUNTIME_DRIVER
上記では,UefiDriverEntryPointはライブラリインスタンスにより作られたライブラリクラス名です。さらに,"DXE_DRIVER DXE_RUNTIME_DRIVER"はライブラリインスタンスをサポートするModuleのTypeです。
ライブラリコンストラクターの定義(Optional)
ライブラリインスタンスModuleは,各々リンクするModuleのエントリポイントによって呼び出されるライブラリコンストラクター関数を定義することができます。ライブラリコンストラクター関数には,任意のライブラリインターフェースが使用される前にいくつかの初期化処理があります。
[Defines] ... CONSTRUCTOR = HobLibConstructor
ライブラリコンストラクター関数のType
ライブラリインスタンスのModule Typeによって,ライブラリコンストラクター関数は3つのタイプに分けられます。
・BASE module typeのライブラリインスタンス:
EFI_STATUS EFIAPI BaseConstructor ( VOID )
・PEIM,PEI_CORE module typeのライブラリインスタンス:
EFI_STATUS EFIAPI PeiServiceTablePointerLibConstructor ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICE **PeiServices )
・DXE_DRIVER,DXE_CORE,DXE_RUNTIME_DRIVER,UEFI_APPLICATION,UEFI_DRIVER module typeのライブラリインスタンス:
EFI_STATUS EFIAPI DxeCorePerformanceLibConstructor ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable )
ドライバの手順のおまけ
ドライバのエントリポイントの定義
下記のようにPEIM,DXEドライバは,INFファイルの[Defines]セクションで定義されるエントリポイント関数を定義します。
[Defines] ... ENTRY_POINT = PcdDxeInit
Moduleエントリポイント関数は,そのModule Typeによって異なります。
詳細は下記のようになります。
Concept | Description |
PEIM Entry Point Library | PEIMのモジュールエントリポイントライブラリ。 |
UEFI Driver Entry Point Library | UEFIドライバ,DXEドライバ,DXEランタイムドライバ,DXE SMMドライバのモジュールエントリポイントライブラリ。 |
UEFI Application Entry Point Library | UEFIアプリケーションのモジュールエントリポイントライブラリ。 |
PEI Services Table Pointer Library | PEI Services Tableへのポインタを検索するサービスを提供します。 |
UEFI Boot Services Table Library | EFI Boot Services Tableへのポインタを検索するサービスを提供します。DXEとUEFIのModule Typeのみ実行可能です。 |
UEFI Runtime Services Table Library | EFI Runtime Services Tableへのポインタを検索するサービスを提供します。DXEとUEFIのModule Typeのみ実行可能です。 |
DXE Services Table Library | DXE Service Tableへのポインタを検索するサービスを提供します。DXEのModule Typeのみ実行可能です。 |
HII(Human Interface Infrastructure)を使用するModule
DXE Moduleは,BDS Phase中にブラウザで使用される次のリソースを公開したり更新することができます。
Forms: ユーザに映し出す必要のあるコンテンツのタイプを記述します。 Strings: 基本的にFormに参照される情報のテキストベース(UCS-2エンコード)表示。 Font/Image: ローカル上でレンダリングされるコンテンツ。
HIIの詳細は,「UEFI Specification」27章 Human Interface Infrastructure Overviewを参照ください。
Forms
VFRリソースファイルの作成
VFRファイルはFormリソースを記述します。VFRファイルはModuleのディレクトリに置かれ,INFファイル内[Sources]セクションで他のソースと一緒に参照されます。
VFR fileの一例:
#define FORMSET_GUID { 0x9e0c30bc, 0x3f06, 0x4ba6, 0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe } #define FRONT_PAGE_CLASS 0x0000 #define FRONT_PAGE_SUBCLASS 0x0002 #define FRONT_PAGE_FORM_ID 0x1000 #define FRONT_PAGE_ITEM_ONE 0x0001 #define FRONT_PAGE_ITEM_TWO 0x0002 #define FRONT_PAGE_ITEM_THREE 0x0003 #define FRONT_PAGE_ITEM_FOUR 0x0004 #define FRONT_PAGE_ITEM_FIVE 0x0005 #define FRONT_PAGE_KEY_CONTINUE 0x1000 #define FRONT_PAGE_KEY_LANGUAGE 0x1234 #define FRONT_PAGE_KEY_BOOT_MANAGER 0x1064 #define FRONT_PAGE_KEY_DEVICE_MANAGER 0x8567 #define FRONT_PAGE_KEY_BOOT_MAINTAIN 0x9876 #define LABEL_SELECT_LANGUAGE 0x1000 #define LABEL_TIMEOUT 0x2000 #define LABEL_END 0xffff formset guid = FORMSET_GUID, title = STRING_TOKEN(STR_FRONT_PAGE_TITLE), help = STRING_TOKEN(STR_NULL_STRING), classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, form formid = FRONT_PAGE_FORM_ID, title = STRING_TOKEN(STR_FRONT_PAGE_TITLE); banner title = STRING_TOKEN(STR_FRONT_PAGE_COMPUTER_MODEL), line 0, align left; banner title = STRING_TOKEN(STR_FRONT_PAGE_CPU_MODEL), line 1, align left; banner title = STRING_TOKEN(STR_FRONT_PAGE_CPU_SPEED), line 1, align right; banner title = STRING_TOKEN(STR_FRONT_PAGE_BIOS_VERSION), line 2, align left; banner title = STRING_TOKEN(STR_FRONT_PAGE_MEMORY_SIZE), line 2, align right; goto FRONT_PAGE_ITEM_ONE, prompt = STRING_TOKEN(STR_CONTINUE_PROMPT), help = STRING_TOKEN(STR_CONTINUE_HELP), flags = INTERACTIVE, key = FRONT_PAGE_KEY_CONTINUE; label LABEL_SELECT_LANGUAGE; // // This is where we will dynamically add a OneOf type op-code to select // Languages from the currently available choices // label LABEL_END; goto FRONT_PAGE_ITEM_THREE, prompt = STRING_TOKEN(STR_BOOT_MANAGER), help = STRING_TOKEN(STR_BOOT_MANAGER_HELP), flags = INTERACTIVE, key = FRONT_PAGE_KEY_BOOT_MANAGER; goto FRONT_PAGE_ITEM_FOUR, prompt = STRING_TOKEN(STR_DEVICE_MANAGER), help = STRING_TOKEN(STR_DEVICE_MANAGER_HELP), flags = INTERACTIVE, key = FRONT_PAGE_KEY_DEVICE_MANAGER; goto FRONT_PAGE_ITEM_FIVE, prompt = STRING_TOKEN(STR_BOOT_MAINT_MANAGER), help = STRING_TOKEN(STR_BOOT_MAINT_MANAGER_HELP), flags = INTERACTIVE, key = FRONT_PAGE_KEY_BOOT_MAINTAIN; endform; endformset;