15. gRT->GetVariable API를 사용하여 부팅 변수 가져오기 및 구문 분석

이번에는 UEFI에서 부팅 옵션을 정의하는 변수의 내용을 출력해보자.

이를 위해서는 EFI Runtime Services에서 제공하는 GetVariable()API 함수를 사용해야한다.

GetVariable()

Summary:
Returns the value of a variable.

Prototype:
typedef
EFI_STATUS
GetVariable (
 IN CHAR16 *VariableName,
 IN EFI_GUID *VendorGuid,
 OUT UINT32 *Attributes OPTIONAL,
 IN OUT UINTN *DataSize,
 OUT VOID *Data OPTIONAL
 );

Parameters:
VariableName    A Null-terminated string that is the name of the vendor’s variable.
VendorGuid      A unique identifier for the vendor
Attributes      If not NULL, a pointer to the memory location to return the
                attributes bitmask for the variable.
                If not NULL, then Attributes is set on output both when
                EFI_SUCCESS and when EFI_BUFFER_TOO_SMALL is returned.
DataSize        On input, the size in bytes of the return Data buffer.
                On output the size of data returned in Data.
Data            The buffer to return the contents of the variable. May be NULL
                with a zero DataSize in order to determine the size buffer needed.

Description:
Each vendor may create and manage its own variables without the risk of name conflicts by using a
unique VendorGuid. When a variable is set its Attributes are supplied to indicate how the data variable
should be stored and maintained by the system. The attributes affect when the variable may be accessed
and volatility of the data

If the Data buffer is too small to hold the contents of the variable, the error EFI_BUFFER_TOO_SMALL is
returned and DataSize is set to the required buffer size to obtain the data.

Status Codes Returned:
EFI_SUCCESS 		The function completed successfully.
EFI_NOT_FOUND 		The variable was not found.
EFI_BUFFER_TOO_SMALL 	The DataSize is too small for the result. DataSize has been
			updated with the size needed to complete the request. If
			Attributes is not NULL, then the attributes bitmask for the
			variable has been stored to the memory location pointed-to by
			Attributes.
...

이전 장에서 다음 옵션들이 GUID EFI_GLOBAL_VARIABLE(gEfiGlobalVariableGuid) 아래 환경에 있음을 발견했다.

UEFI 스펙을 찾아보면 이러한 옵션들에 대한 보다 자세한 설명을 찾을 수 있다.

ShowBootVariables애플리케이션을 만들어보자.

먼저 간단한 UINT16 BootCurrent 옵션을 가져와 보는 것을 목표로 한다.

이 프로그램에서 변수를 많이 가져올 것이므로 GetVariable()함수를 호출할 때 필요한 사항을 추상화하여 함수를 만드는 것이 가장 좋은 방법이다.

다른 많은 UEFI API와 마찬가지로 첫 번째 GetVariable 호출은 EFI_BUFFER_TOO_SMALL 오류를 발생시키지만 우리가 할당해야 할 배열의 크기로 Size변수를 초기화 시키고 올바른 실행을 위해 함수에 전달한다.

이전 레슨에서 했던 것처럼 AllocateZeroPool 호출로 필요한 크기를 할당한다. 그런 다음 EFI_SUCCESS 상태를 기대하면서 두 번째로 GetVariable 함수를 호출한다.

애플리케이션의 메인함수는 다음과 같다.

빌드 후 OVMF에서 실행시키면 다음과 같은 결과가 나올 것이다.

이것은 Boot0003이 활성 상태임을 의미한다.

이제 UINT16 BootOrder[]변수를 가져와보자. 이것은 부팅 옵션 순서를 나타내는 XXXX숫자의 배열이다. 예를 들어 {0,2,4,1,3}은 다음 순서를 의미한다.

다음 코드는 위 배열을 출력하기 위한 코드이다.

OVMF에서 실행시켜 보면 다음 과 같은 결과가 나온다.

이제 모든 Boot####옵션에 대한 정보를 출력해보자.

UEFI 스펙에 따르면 이러한 옵션은 EFI_LOAD_OPTION 구조체에 저장된다.

EDKII에서는 다음의 파일에 정의되어 있다.

https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiSpec.h

이 구조체의 일부 필드가 주석처리되어 있는 것에 주의해야한다.

이 필드들은 가변 크기 배열이기 때문에 동적으로 오프셋을 구해야 한다.

Boot 변수의 이름(예: "Boot0003")을 받아들이고 이에 대한 모든 필요한 정보를 출력하는 함수를 만든다.

이 코드는 위에서 논의한 포인터 산술을 사용한다. Description 필드의 크기를 구하려면 Description 필드가 항상 Null로 끝나므로 StrSize(Description)를 호출하여 구하면 된다.

DevicePath를 문자열로 출력하기 위해 ConvertDevicePathToText 호출을 사용한다(ImageInfo 애플리케이션에서 사용함). 이를 사용하려면 프로그램에 #include <Library/DevicePathLib.h>를 추가해야 한다.

이제 BootOrder 번호에서 "BootXXXX" 변수를 구성해야 한다.

이를 위해 https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.hUnicodeSPrint 함수를 사용한다.

동일한 파일에 ASCII를 위한 비슷한 함수도 있다.

이제 BootOrder 반복문 내부의 코드는 다음과 같다.

파일 시작 부분에 #include <Library/PrintLib.h>를 추가하는 것을 잊지 말자.

애플리케이션을 컴파일 후 OVMF로 실행하면 다음과 같은 결과가 나온다.

우리는 현재 UEFI Shell로 부팅했으므로 BootCurrent가 정확하게 표시(*)된 것을 알 수 있다.

Last updated