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.inf
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.c
UefiLessonsPkg/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 = TRUE
UEFI_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 data
https://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_PROTOCOL
Last updated