50.UEFI_HII_RESOURCE_SECTION을 사용하여 문자열 패키지와 함께 HII 패키지 목록 게시하기
이번 장에서는 애플리케이션이 HII 문자열 패키지를 게시할 수 있는 또 다른 방법을 살펴본다. 이번에는 결과 EFI 파일 PE/COFF 리소스에 HII 데이터를 포함하는 것에 대해 알아본다.
애플리케이션 만들기
스크립트를 써서 평소와 같이 애플리케이션을 만든다.
./createNewApp.sh HIIStringsUNIRC우리의 DSC 패키지 파일 UefiLessonsPkg/UefiLessonsPkg.dsc에 추가한다.
[Components]
...
UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf마지막으로 패키지 목록에 대한 GUID가 필요하며 패키지 DEC 파일인 UefiLessonsPkg/UefiLessonsPkg.dec에서 선언해준다.
[Guids]
...
gHIIStringsUNIRCGuid = { 0x785693b4, 0x623e, 0x40fa, { 0x9a, 0x45, 0x68, 0xda, 0x38, 0x30, 0x89, 0xdd }}이제 HIIStringsUNI 앱과 유사하도록 애플리케이션 파일을 수정해준다. Strings.uni 파일을 만들고 애플리케이션의 INF 및 *.c 파일을 수정해야한다.
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.infUefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.cUefiLessonsPkg/HIIStringsUNIRC/Strings.uni
모든 작업을 완료하면 HIIStringsUNI 애플리케이션과 동일한 결과를 얻을 수 있다.
FS0:\> HIIStringsUNIRC.efi
en-US ID=1: English
en-US ID=2: Hello!
en-US ID=3: Bye!
fr-FR ID=1: Francais
fr-FR ID=2: Bonjour!
fr-FR ID=3: Au revoir!
Best language ID=1: English
Best language ID=2: Hello!
Best language ID=3: Bye!
fr ID=3: Au revoir!이제 애플리케이션을 수정할 준비가 다 되었다.
UEFI_HII_RESOURCE_SECTION
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf에 다음을 추가한다.
[Defines]
...
UEFI_HII_RESOURCE_SECTION = TRUEUEFI_HII_RESOURCE_SECTION 플래그는 HII 리소스 섹션이 PE 이미지로 생성되는지 여부를 지정한다. 애플리케이션을 빌드하면 다음 오류로 인해 애플리케이션을 빌드할 수 없다.
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.c:15:42: error: ‘HIIStringsUNIRCStrings’ undeclared (first use in this function);Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC/DEBUG/HIIStringsUNIRCStrDefs.h를 보면 이 파일에 여전히 문자열 토큰이 포함되어 있지만 HIIStringsUNIRCStrings는 더 이상 여기에 존재하지 않는 것을 알 수 있다.
그리고 AutoGen.c 파일에는 더 이상 HIIStringsUNIRCStrings 배열 초기화 코드가 포함되어 있지 않다(Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC/DEBUG/AutoGen.c).
이제 우리의 문자열이 결과로 나오는 *.efi 이미지의 특수 섹션으로 인코딩되어 들어가는 것이다.
이를 우리가 얻으려면 애플리케이션 EFI_HANDLE ImageHandle에서 프로토콜 EFI_HII_PACKAGE_LIST_PROTOCOL을 검색해야 한다.
다음은 Shell이 모든 프로그램을 로드하는 데 사용하는 EFI_BOOT_SERVICES.LoadImage() 함수에 대한 UEFI 스펙의 관련 내용이다.
Once the image is loaded, LoadImage() installs EFI_HII_PACKAGE_LIST_PROTOCOL on the handle if
the image contains a custom PE/COFF resource with the type 'HII'. The protocol's interface pointer points
to the HII package list which is contained in the resource's datahttps://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec에 따르면 EFI_HII_PACKAGE_LIST_PROTOCOL은 gEfiHiiPackageListProtocolGuid로 식별된다.
[Protocols]
...
## Include/Protocol/HiiPackageList.h
gEfiHiiPackageListProtocolGuid = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}우리의 INF 파일의 [Packages] 섹션에 MdeModulePkg/MdeModulePkg.dec가 이미 있으므로 이 GUID를 [Protocols] 섹션에 추가하기만 하면 된다.
[Protocols]
gEfiHiiPackageListProtocolGuid코드에서는 OpenProtocol UEFI 부트 서비스의 도움으로 애플리케이션의 ImageHandle 에서 PackageList 프로토콜을 얻을 수 있다.
...
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HII_PACKAGE_LIST_HEADER *PackageList;
//
// Retrieve HII package list from ImageHandle.
//
Status = gBS->OpenProtocol (
ImageHandle,
&gEfiHiiPackageListProtocolGuid,
(VOID **)&PackageList,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
Print(L"Error! Can't open EFI_HII_PACKAGE_LIST_PROTOCOL\n");
return Status;
}
...결과의 PackageList는 HIIStringsUNI 애플리케이션의 경우와 같이 StrGather 스크립트의 결과인 일부 size 헤더가 있는 문자열 패키지가 아니다. HIIStringsC 애플리케이션에서 수동으로 구성한 것과 같은 일반 PackageList이다. 따라서 HiiAddPackages 라이브러리 함수를 사용하는 대신 EFI_HII_DATABASE_PROTOCOL.NewPackageList()를 직접 사용해야 한다.
EFI_HII_HANDLE Handle;
Status = gHiiDatabase->NewPackageList(gHiiDatabase, PackageList, NULL, &Handle);
if (EFI_ERROR(Status))
{
Print(L"Can't register HII Package list %g, status = %r\n", gHIIStringsUNIRCGuid, Status);
return Status;
}여기서는 gHiiDatabase를 사용했으므로 필요한 헤더인 #include <Library/UefiHiiServicesLib.h>를 추가하고 애플리케이션 INF 파일의 [LibraryClasses]에 UefiHiiServicesLib를 추가하는 것을 잊지 말자.
이제 애플리케이션을 빌드하고 실행해보면 모든 것이 정상인것을 확인할 수 있다.
FS0:\> HIIStringsUNIRC.efi
Status = Success
en-US ID=1: English
en-US ID=2: Hello!
en-US ID=3: Bye!
fr-FR ID=1: Francais
fr-FR ID=2: Bonjour!
fr-FR ID=3: Au revoir!
Best language ID=1: English
Best language ID=2: Hello!
Best language ID=3: Bye!
fr ID=3: Au revoir!유형이 'HII'인 PE/COFF 리소스
objdump를 사용하여 애플리케이션 헤더를 살펴보자. -x 옵션을 사용하여 모든 헤더의 내용을 출력할 수 있다.
objdump -x Build/UefiLessonsPkg/RELEASE_GCC5/X64/HIIStringsUNIRC.efi화살표 뒤의 사항에 주의하면서 보자.
...
The Data Directory
Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 0000000000000000 00000000 Import Directory [parts of .idata]
Entry 2 00000000000023c0 00000180 Resource Directory [.rsrc] <---------- Resource Directory 에 데이터가 존재한다.
Entry 3 0000000000000000 00000000 Exception Directory [.pdata]
Entry 4 0000000000000000 00000000 Security Directory
Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000000022cc 0000001c Debug Directory
Entry 7 0000000000000000 00000000 Description Directory
Entry 8 0000000000000000 00000000 Special Directory
Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls]
Entry a 0000000000000000 00000000 Load Configuration Directory
Entry b 0000000000000000 00000000 Bound Import Directory
Entry c 0000000000000000 00000000 Import Address Table Directory
Entry d 0000000000000000 00000000 Delay Import Directory
Entry e 0000000000000000 00000000 CLR Runtime Header
Entry f 0000000000000000 00000000 Reserved
...
The .rsrc Resource Directory section:
000 Type Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
010 Entry: name: [val: 80000048 len 3]: HII, Value: 0x80000018 <--------- Data 타입이 HII이다.
018 Name Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
028 Entry: name: [val: 80000050 len 3]: EFI, Value: 0x80000030
030 Language Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
040 Entry: name: [val: 80000058 len 3]: BIN, Value: 0x000060
060 Leaf: Addr: 0x002430, Size: 0x0000ea, Codepage: 0
String table starts at offset: 0x48
Resources start at offset: 0x70
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00001fc0 0000000000000240 0000000000000240 00000240 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 000001c0 0000000000002200 0000000000002200 00002200 2**4
CONTENTS, ALLOC, LOAD, DATA
2 .rsrc 00000180 00000000000023c0 00000000000023c0 000023c0 2**2 <----- 여기에도 .rsrc가 표시된다.
CONTENTS, ALLOC, LOAD, READONLY, DATA
SYMBOL TABLE:
no symbols이제 UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf에 UEFI_HII_RESOURCE_SECTION을 주석 처리해준다.
[Defines]
...
#UEFI_HII_RESOURCE_SECTION = TRUE애플리케이션 빌드 후에 objdump를 다시 한 번 실행해보면 다음과 같은 결과를 얻을 수 있다.
...
The Data Directory
Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 0000000000000000 00000000 Import Directory [parts of .idata]
Entry 2 0000000000000000 00000000 Resource Directory [.rsrc] <----- Resource directory 가 비어있다.
Entry 3 0000000000000000 00000000 Exception Directory [.pdata]
Entry 4 0000000000000000 00000000 Security Directory
Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000000022cc 0000001c Debug Directory
Entry 7 0000000000000000 00000000 Description Directory
Entry 8 0000000000000000 00000000 Special Directory
Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls]
Entry a 0000000000000000 00000000 Load Configuration Directory
Entry b 0000000000000000 00000000 Bound Import Directory
Entry c 0000000000000000 00000000 Import Address Table Directory
Entry d 0000000000000000 00000000 Delay Import Directory
Entry e 0000000000000000 00000000 CLR Runtime Header
Entry f 0000000000000000 00000000 Reserved
... <----- .rsrc 리소스 디렉터리 섹션이 없다.
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00001fc0 0000000000000240 0000000000000240 00000240 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 000001c0 0000000000002200 0000000000002200 00002200 2**4 <---- 여기에도 .rsrc 섹션이 없다.
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
no symbols이 버전의 애플리케이션을 실행하려고 하면 아래와 같이 실행된다.
FS0:\> HIIStringsUNIRC.efi
Error! Can't open EFI_HII_PACKAGE_LIST_PROTOCOLLast updated