EFI_BOOT_SERVICESや、まだ機能の紹介はしていなかったEFI_RUNTIME_SERVICESには、他にも色々な機能があります。この章ではそれらの一部を紹介します。
UEFIのファームウェアはメモリアロケータを持っていて、EFI_BOOT_SERVICESのAllocatePool()とFreePool()で利用できます(リスト5.1)。
サンプルのディレクトリは"050_bs_malloc"です。
リスト5.1: AllocatePool()とFreePool()の定義(efi.hより)
enum EFI_MEMORY_TYPE { ・・・ EfiLoaderData, /* ロードされたUEFIアプリケーションのデータと * UEFIアプリケーションのデフォルトのデータアロケーション領域 */ ・・・ }; struct EFI_SYSTEM_TABLE { ・・・ struct EFI_BOOT_SERVICES { ・・・ // // Memory Services // unsigned long long _buf3[3]; unsigned long long (*AllocatePool)( enum EFI_MEMORY_TYPE PoolType, /* どこのメモリプールから確保するかを指定 * この節では"EfiLoaderData"を指定 */ unsigned long long Size, /* 確保するサイズをバイト単位で指定 */ void **Buffer /* 確保した領域の先頭アドレスを格納するポインタ * のポインタを指定 */ ); unsigned long long (*FreePool)( void *Buffer /* 開放したい領域のポインタを指定 */ ); ・・・ } *BootServices; };
AllocatePool()第1引数の"PoolType"について、"enum EFI_MEMORY_TYPE"には他にもメモリタイプがありますが、仕様書を読む限り、UEFIアプリケーションのデータを配置する領域は"EfiLoaderData"であるようで、この節では"EfiLoaderData"を使用しています。その他のメモリタイプについては仕様書の"6.2 Memory Allocation Services"を見てみてください。
使用例はリスト5.2の通りです。
リスト5.2: AllocatePool()とFreePool()の使用例(main.cより)
1: #include "efi.h" 2: #include "common.h" 3: #include "graphics.h" 4: 5: #define IMG_WIDTH 256 6: #define IMG_HEIGHT 256 7: 8: void efi_main(void *ImageHandle __attribute__ ((unused)), 9: struct EFI_SYSTEM_TABLE *SystemTable) 10: { 11: unsigned long long status; 12: struct EFI_GRAPHICS_OUTPUT_BLT_PIXEL *img_buf, *t; 13: unsigned int i, j; 14: 15: efi_init(SystemTable); 16: ST->ConOut->ClearScreen(ST->ConOut); 17: 18: /* 画像バッファ用のメモリを確保 */ 19: status = ST->BootServices->AllocatePool( 20: EfiLoaderData, 21: IMG_WIDTH * IMG_HEIGHT * 22: sizeof(struct EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 23: (void **)&img_buf); 24: assert(status, L"AllocatePool"); 25: 26: /* 画像を生成 */ 27: t = img_buf; 28: for (i = 0; i < IMG_HEIGHT; i++) { 29: for (j = 0; j < IMG_WIDTH; j++) { 30: t->Blue = i; 31: t->Green = j; 32: t->Red = 0; 33: t->Reserved = 255; 34: t++; 35: } 36: } 37: 38: /* 画像描画(フレームバッファへ書き込み) */ 39: blt((unsigned char *)img_buf, IMG_WIDTH, IMG_HEIGHT); 40: 41: /* 確保したメモリを解放 */ 42: status = ST->BootServices->FreePool((void *)img_buf); 43: assert(status, L"FreePool"); 44: 45: while (TRUE); 46: }
リスト5.2では、255x255の画像用バッファ(img_buf)を確保してピクセルデータを配置し、blt()でフレームバッファへの書き込みを行っています。
生成している画像はX軸に青色を、Y軸に緑色を、それぞれ255階調で表示するものです。
試してみると図5.1のような感じです。印刷は白黒なので、ぜひご自身で試してみてください。
図5.1: AllocatePool()とFreePool()の実行例
メモリ上で動作するだけのUEFIアプリケーションならば電源ボタンで終了しても良いのですが、EFI_RUNTIME_SERVICESのResetSystem()を使用するとPCをシャットダウンしたり、再起動したりできます。
サンプルのディレクトリは"051_rs_resetsystem"です。
EFI_RUNTIME_SERVICESもEFI_BOOT_SERVICES同様にEFI_SYSTEM_TABLEのメンバです。EFI_BOOT_SERVICESはブートローダーに対して機能を提供しているのに対し、EFI_RUNTIME_SERVICESはOS起動後も使用できるという違いがあります。
具体的な契機はEFI_BOOT_SERVICESのExitBootServices()で、この関数を呼ぶと、それ以降EFI_BOOT_SERVICESの機能は無効になりますが、EFI_RUNTIME_SERVICESの機能は引き続き使用可能です。
そして、ResetSystem()はEFI_RUNTIME_SERVICES内でリスト5.3の様に定義されています。
リスト5.3: ResetSystem()の定義(efi.hより)
enum EFI_RESET_TYPE { /* 説明は仕様書("7.5.1 Reset System")の意訳です。 */ EfiResetCold, /* システム全体のリセット。 * システム内の全ての回路を初期状態へリセットする。 * (追記: いわゆる再起動で、CPU以外の回路も * 電気的に遮断するコールドリセット) * このリセットタイプはシステム操作に対し非同期で、 * システムの周期的動作に関係なく行われる。 */ EfiResetWarm, /* システム全体の初期化。 * プロセッサは初期状態へリセットされ、 * 保留中のサイクルは破壊されない(?)。 * (追記: いわゆる再起動で、CPUのみリセットするウォームリセット) * もしシステムがこのリセットタイプをサポートしていないならば、 * EfiResetColdが実施されなければならない。 */ EfiResetShutdown, /* システムがACPI G2/S5あるいはG3状態に相当する電源状態へ * 遷移する(追記: いわゆるシャットダウンの状態)。 * もしシステムがこのリセットタイプをサポートしておらず、 * システムが再起動した時、EfiResetColdの振る舞いを示すべき。 */ EfiResetPlatformSpecific /* システム全体のリセット。 * 厳密なリセットタイプは引数"ResetData"に従うEFI_GUID * により定義される。 * プラットフォームがResetData内のEFI_GUIDを認識できないならば、 * サポートできるリセットタイプを選択しなければならない。 * プラットフォームは発生した非正常なりセットから * パラメータを記録することができる(?)。 */ }; struct EFI_SYSTEM_TABLE { ・・・ struct EFI_RUNTIME_SERVICES { ・・・ // // Miscellaneous Services // unsigned long long _buf_rs5; void (*ResetSystem)( enum EFI_RESET_TYPE ResetType, /* 実施されるリセットタイプ * この節ではEfiResetShutdownを使用 */ unsigned long long ResetStatus, /* リセットのステータスコードを指定 * システムのリセットが * 正常なものならばEFI_SUCCESS、 * 異常によるものならばエラーコードを指定 * この節ではEFI_SUCCESS(=0)を指定 */ unsigned long long DataSize, /* ResetDataのデータサイズをバイト単位で指定 * この節ではResetDataは使用しないので0を指定 */ void *ResetData /* ResetTypeがEfiResetCold・EfiResetWarn * ・EfiResetShutdownの時、 * ResetStatusがEFI_SUCCESSで無いならば、 * ResetDataへNULL終端された文字列を指定することで、 * 後々、呼び出し元へリセット事由を通知できる * (ようである) * ResetTypeがEfiResetPlatformSpecificの時、 * EFI_GUIDをNULL終端文字列として指定する事で、 * プラットフォーム依存のリセットを行える * この節ではResetStatusはEFI_SUCCESSなので、 * 使用しない(NULLを指定する) */ ); } *RuntimeServices; };
使用例はリスト5.4の通りです。
リスト5.4: ResetSystem()の使用例(main.cより)
1: #include "efi.h" 2: #include "common.h" 3: 4: void efi_main(void *ImageHandle __attribute__ ((unused)), 5: struct EFI_SYSTEM_TABLE *SystemTable) 6: { 7: efi_init(SystemTable); 8: ST->ConOut->ClearScreen(ST->ConOut); 9: 10: /* キー入力待ち */ 11: puts(L"何かキーを押すとシャットダウンします。。。\r\n"); 12: getc(); 13: 14: /* シャットダウン */ 15: ST->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, 16: NULL); 17: 18: while (TRUE); 19: }
リスト5.4は何かキーを入力するとシャットダウンします。
実行例は図5.2の通りです。
図5.2: ResetSystem()の実行例