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()の実行例