SetVariable은 Runtime 서비스이며, UEFI 스펙에서 해당 정의를 찾을 수 있다.
gRT는 UefiRuntimeServicesTableLib 라이브러리의 SystemTable->RuntimeServices에 대한 바로가기이다. 따라서 라이브러리 헤더 <Library/UefiRuntimeServicesTableLib.h>를 포함하는 것을 잊지 않도록 하자.
애플리케이션을 빌드하고 실행하면, 다음과 같은 결과를 얻을 수 있다.
안타깝게도, 'PlatformLangCodes' EFI 변수가 쓰기 금지되어 있으므로 Runtime 시, 새 언어를 추가할 수 없다. 따라서 Runtime에 다른 로컬화 언어를 추가할 수 없다.
UEFI 스펙을 보면 다음과 같이 표시된다.
EDKII_VARIABLE_POLICY_PROTOCOL
PlatformLangCodes는 gEdkiiVariablePolicyProtocolGuid 프로토콜의 도움으로 수정할 수 있도록 잠겨 있다. 이는 변수에 대해 다른 정책을 설정하기 위한 사용자 정의 EDKII 프로토콜이다.
**
Returns a pointer to an allocated buffer that contains the contents of a
variable retrieved through the UEFI Runtime Service GetVariable(). This
function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
The returned buffer is allocated using AllocatePool(). The caller is
responsible for freeing this buffer with FreePool().
If Name is NULL, then ASSERT().
If Value is NULL, then ASSERT().
@param[in] Name The pointer to a Null-terminated Unicode string.
@param[out] Value The buffer point saved the variable info.
@param[out] Size The buffer size of the variable.
@return EFI_OUT_OF_RESOURCES Allocate buffer failed.
@return EFI_SUCCESS Find the specified variable.
@return Others Errors Return errors from call to gRT->GetVariable.
**/
EFI_STATUS
EFIAPI
GetEfiGlobalVariable2 (
IN CONST CHAR16 *Name,
OUT VOID **Value,
OUT UINTN *Size OPTIONAL
)
FS0:\> AddNewLanguage.efi
Current value of the 'PlatformLangCodes' variable is 'en;fr;en-US;fr-FR'
CHAR8* NewLanguageString = AllocatePool(AsciiStrLen(LanguageString) + AsciiStrSize(";ru-RU"));
if (NewLanguageString == NULL) {
Print(L"Error! Can't allocate size for new PlatformLangCodes variable\n");
FreePool(LanguageString);
return EFI_OUT_OF_RESOURCES;
}
CopyMem(NewLanguageString, LanguageString, AsciiStrLen(LanguageString));
CopyMem(&NewLanguageString[AsciiStrLen(LanguageString)], ";ru-RU", AsciiStrSize(";ru-RU"));
Print(L"Set 'PlatformLangCodes' variable to '%a'\n", NewLanguageString);
Status = gRT->SetVariable (
L"PlatformLangCodes",
&gEfiGlobalVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
AsciiStrSize(NewLanguageString),
NewLanguageString
);
if (EFI_ERROR(Status)) {
Print(L"Error! Can't set 'PlatformLangCodes' variable, status=%r\n", Status);
}
SetVariable()
Summary:
Sets the value of a variable.
Prototype:
typedef
EFI_STATUS
SetVariable (
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data
);
Parameters:
VariableName A Null-terminated string that is the name of the vendor’s variable. Each VariableName is unique for each VendorGuid.
VendorGuid A unique identifier for the vendor.
Attributes Attributes bitmask to set for the variable.
DataSize The size in bytes of the Data buffer.
Data The contents for the variable.
FS0:\> AddNewLanguage.efi
Current value of the 'PlatformLangCodes' variable is 'en;fr;en-US;fr-FR'
Set 'PlatformLangCodes' variable to 'en;fr;en-US;fr-FR;ru-RU'
Error! Can't set 'PlatformLangCodes' variable, status=Write Protected
The PlatformLangCodes variable contains a null- terminated ASCII string representing the language
codes that the firmware can support. At initialization time the firmware computes the supported
languages and creates this data variable. Since the firmware creates this value on each initialization, its
contents are not stored in nonvolatile memory. This value is considered read-only.
///
/// The read-only variables defined in UEFI Spec.
///
CHAR16 *mReadOnlyVariables[] = {
EFI_PLATFORM_LANG_CODES_VARIABLE_NAME, // L"PlatformLangCodes" The language codes that the firmware supports
EFI_LANG_CODES_VARIABLE_NAME,
EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,
EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME,
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME
};
...
// Mark the read-only variables if the Variable Lock protocol exists
//
Status = gBS->LocateProtocol(&gEdkiiVariablePolicyProtocolGuid,
NULL, (VOID**)&VariablePolicy);
DEBUG((DEBUG_INFO, "[BdsDxe] Locate Variable Policy protocol -
%r\n", Status));
if (!EFI_ERROR (Status)) {
for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {
Status = RegisterBasicVariablePolicy(
VariablePolicy,
&gEfiGlobalVariableGuid,
mReadOnlyVariables[Index],
VARIABLE_POLICY_NO_MIN_SIZE,
VARIABLE_POLICY_NO_MAX_SIZE,
VARIABLE_POLICY_NO_MUST_ATTR,
VARIABLE_POLICY_NO_CANT_ATTR,
VARIABLE_POLICY_TYPE_LOCK_NOW
);
ASSERT_EFI_ERROR(Status);
}
}
$ vi UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c
---
...
#include <Protocol/VariablePolicy.h>
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
...
EDKII_VARIABLE_POLICY_PROTOCOL* VariablePolicyProtocol;
Status = gBS->LocateProtocol(&gEdkiiVariablePolicyProtocolGuid,
NULL,
(VOID**)&VariablePolicyProtocol);
if (EFI_ERROR(Status)) {
Print(L"Error! Could not find Variable Policy protocol: %r\n", Status);
return Status;
}
Status = VariablePolicyProtocol->DisableVariablePolicy();
if (EFI_ERROR(Status)) {
Print(L"Error! Can't disable VariablePolicy: %r\n", Status);
return Status;
}
}
FS0:\> AddNewLanguage.efi
Current value of the 'PlatformLangCodes' variable is 'en;fr;en-US;fr-FR'
Set 'PlatformLangCodes' variable to 'en;fr;en-US;fr-FR;ru-RU'
Error! Can't set PlatformLangCodes variable, status=Write Protected
Error! Can't disable VariablePolicy: Write Protected