72. label 키워드를 이용하여 HII 양식에 동적 요소 추가하기

이 장을 통해 아래 항목을 표시하는데 이용할 수 있다.

  • 현재 가능한 부팅 소스

  • 현재 존재하는 PCI 장치

  • 현재 메모리 정보

  • ...

이러한 것들은 UEFI 부트 프로세스에서 결정되고 하드웨어 장비 구성에 따른 부팅마다 다를 수 있다. 따라서 이러한 정보를 HII 양식에 추가하려면 동적으로 수행할 필요가 있다.

이 작업을 위해서 EDKII의 lable 메커니즘을 이용할 것이다.

그 전에 먼저 간단하게 빈 양식으로 저장소를 사용하지 않는 HIIFormLabel 애플리케이션을 생성해보자.

Initial code

아래는 빈 양식을 추가하는 드라이버 코드이다.

UefiLessonsPkg/HIIFormLabel/HIIFormLabel.inf:

[Defines]
  INF_VERSION                    = 1.25
  BASE_NAME                      = HIIFormLabel
  FILE_GUID                      = a869c42c-fd49-469d-b6ab-b37569c0e90d
  MODULE_TYPE                    = UEFI_DRIVER
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = HIIFormLabelEntryPoint
  UNLOAD_IMAGE                   = HIIFormLabelUnload

[Sources]
  HIIFormLabel.c
  Strings.uni
  Form.vfr

[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  UefiDriverEntryPoint
  UefiLib
  HiiLib

UefiLessonsPkg/HIIFormLabel/HIIFormLabel.c:

UefiLessonsPkg/HIIFormLabel/Data.h:

UefiLessonsPkg/HIIFormLabel/Form.vfr:

UefiLessonsPkg/HIIFormLabel/Strings.uni:

해당 코드를 빌드한 결과이다.

Add label

이제 위 양식에 동적인 콘텐츠를 추가해보자.

UefiLessonsPkg/HIIFormDataElements/Form.vfr 내부에 2개의 label 요소를 추가한다.

이 두 요소는 동적 콘텐츠를 위해 시작과 끝 영역을 정의한다.

LABEL_STARTLABEL_ENDUINT16의 숫자 값을 가진다. UefiLessonsPkg/HIIFormDataElements/Data.h 에 아래처 정의를 작성한다.

실제 label 번호는 중요하지 않지만 해당 label 번호는 반드시 대상 양식 범위 내에서 고유한 번호여야 한다.

IFR

모듈을 빌드하고 IFR 코드를 살펴보자. Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIFormDataElements/HIIFormDataElements/DEBUG/Form.lst:

Label들은 EFI_IFR_GUID_OP opcode로 인코딩 되어졌다. 해당 opcode는 vendor가 UEFI 스펙에 정의되지 않은 새로운 IFR opcode를 추가할 수 있도록 돕는다. 이는 UEFI 스펙의 확장을 위한 수단이다.

만약 binary의 데이터를 분석하면 이 경우 Guid가 다음과 같다는 것을 알 수 있다.

이 값은 opcode의 끝(Header.Length 에 의해 결정된다) 다음에 오는 나머지 모든 opcode 데이터의 모든 형식을 정의한다. 이 경우 00 11 11 또는 00 22 22 이다.\

IFR에 존재하는 GUID는 ./MdeModulePkg/MdeModulePkg.dec 에 정의되었다.

./MdeModulePkg/Include/Guid/MdeModuleHii.h 내부에도 있다.

EDKII에는 몇몇 특수한 IFR opcode가 있다. 이러한 것들은 모두 EFI_IFR_TIANO_GUID 아래에 정의되어 있다. GUID가 opcode를 정의하고 각 첫 번째 바이트를 서로 구분하기 위해 다음과 같이 정의한다.

우리의 경우는 다음 바이트는 EFI_IFR_EXTEND_OP_LABEL 에 해당하는 0x00 이다.

이렇게 전체 opcode는 다음 구조로 정의 된다.

C code

C 코드의 콘텐츠를 label로 정의된 섹션에 추가하려면 HiiLib 에 존재하는 HiiUpdateForm 함수를 활용해야 한다. https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Library/HiiLib.h

보다시피 이 함수에는 두 개의 opcode 핸들이 필요하다.

  • StartOpCodeHandle - 대체 section의 시작을 표시하는 IFR과 넣으려고 하는 모든 opcode를 포함하는 opcode 버퍼에 대한 핸들,

  • EndOpCodeHandle - 대체 section의 끝을 표시하는 IFR을 포함하는 opcode 버퍼에 대한 핸들

이러한 OpCode 핸들을 생성하기 위해 HiiLib 의 특별한 함수를 살펴보자.

여기서 중요한 점은 이 함수는 어떠한 크기도 허용하지 않는다는 점이다. 왜냐하면 이 작업에서 해당 buffer는 항상 고정이기 때문이다. HiiAllocateOpCodeHandle 은 다음과 같이 정의된 새로 할당되는 구조인 HII_LIB_OPCODE_BUFFER 에 대한 포인터를 반환한다.

모든 동적 할당되어진 opcode들은 사전에 할당된 버퍼 크기에 맞아야 한다.

물론 HiiAllocateOpCodeHandle 로 할당된 모든 버퍼를 해제해야 한다.

따라서 만들 드라이버 내부에 다음과 같은 코드를 포함해야 한다.

이제 StartOpCodeHandleEndOpCodeHandle 에 올바른 데이터를 만들어야 한다. 첫번째로 우리는 lable IFR을 추가해야 한다. 이 작업은 HiiCreateGuidOpCode 함를 활용한다.

이 함수는 opcode 버퍼에 대한 포인터를 반환하는데 우리의 경우에는 EFI_IFR_GUID_LABEL opcode로 시작하는 버퍼가 된다. 따라서 버퍼를 EFI_IFR_GUID_LABEL 구조로 캐스팅하고 올바른 데이터로 채워야 한다. 만약 HiiCreateGuidOpCodeNULL 을 반환한다면 오류가 발생한 것이다.

이 코드에서 gEfiIfrTianoGuid 를 사용하므로 코드에 적절한 헤더 파일 정보(#include <Guid/MdeModuleHii.h>)와 *.inf 파일의 Guid 섹션에 정보를 추가해야 한다.

마지막 작업은 IFR 코드에 새 코드를 포함하는 것이다. 따라서 우리는 Label 외에도 StartOpCodeHandle 이 참조하는 버퍼에 실제 새로운 IFR 코드를 추가해야 한다. HiiCreateTextOpcode 함수를 사용해 VFR text 요소를 추가해보자.

보다시피 이 함수는 새 text 요소에 대해 EFI_STRING_ID 가 필요하다. 우리는 이 요소를 동적으로 생성하므로 HII 데이터베이스에 새 문자열도 동적으로 추가해보자.

이 함수를 이용하여 새로운 문자열을 다음과 같이 간단하게 만들 수 있다.

이제 HiiCreateTextOpCode 함수를 이용해 StartOpCodeHandle 이 참조하는 opcode 버퍼에 더 많은 opcode를 추가할 수 있다.

예제에 또 다른 text 요소를 추가하기 위해 앞선 과정을 한번 더 반복한다.

StartOpCodeHandleEndOpCodeHandle 이 채워졌기 때문에HiiUpdateForm 호출에 성공해야 한다. 드라이버를 빌드하고 로드해보자.

양식을 보면 의도한 대로 2개의 text 요소가 존재하는 것을 볼 수 있다.

HIICreate*

예제에서는 HiiCreateTextOpCode 함수만을 사용하여 text 요소(EFI_IFR_TEXT_OP)를 생성했었다. 하지만 HiiLib 에는 여러 종류의 요소를 생성하는 많은 함수가 존재한다. https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Library/HiiLib.h https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c

이 외에도 HiiLib 라이브러리에는 raw opcode 버퍼를 추가하는 함수도 있다.

Last updated