Date
1 - 2 of 2
Adding another platform language
Konstantin Aladyshev
Hello!
I was investigating the possibility of adding localization strings at runtime. Is it possible to create another translation language at runtime (UEFI Shell)? From my understanding OVMF gets the list of supported languages from the `PlatformLangCodes` variable. So I've decided to create an UEFI shell application that would add another language to this variable. But it looks like it is not possible to modify this variable. I'm getting `Write Protected` error. Here is my code: ``` EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; CHAR8* LanguageString; Status = GetEfiGlobalVariable2(L"PlatformLangCodes", (VOID**)&LanguageString, NULL); if (EFI_ERROR(Status)) { Print(L"Error! Can't perform GetEfiGlobalVariable2, status=%r\n", Status); return Status; } Print(L"Before: %a\n", LanguageString); 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"After: %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); } FreePool(NewLanguageString); FreePool(LanguageString); return EFI_SUCCESS; } ``` And here is the output: ``` FS0:\> HIIAddLocalization.efi Before: en;fr;en-US;fr-FR After: en;fr;en-US;fr-FR;ru-RU Error! Can't set PlatformLangCodes variable, status=Write Protected ``` I'm not sure, but I guess the limitation comes from the `AutoUpdateLangVariable` function from the https://github.com/tianocore/edk2/blob/1bc232aae32e812341f10c9b938350cd93308eee/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c#L1375 Am I correct? Is it really impossible to add a new translation language at runtime? What is the reason for blocking `PlatformLangCodes` variable from modifying? Best regards, Konstantin Aladyshev |
|
Konstantin Aladyshev
It looks like L"PlatformLangCodes" is blocked by a variable policy
enforced to this variable in the BdsDxe: https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/BdsDxe/BdsEntry.c ``` /// /// 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); } } ``` In the end of DXE variable policy is locked in the MdeModulePkg/Universal/Variable/RuntimeDxe/VariableDxe.c : ``` VOID EFIAPI OnEndOfDxe ( EFI_EVENT Event, VOID *Context ) { EFI_STATUS Status; DEBUG ((EFI_D_INFO, "[Variable]END_OF_DXE is signaled\n")); ... Status = LockVariablePolicy (); ... } ``` So it looks like it is not possible to disable this policy at runtime and modify L"PlatformLangCodes". Therefore it is not possible to add another localization language at runtime. I think this limitation comes from the fact that UEFI specification marks this variable as read-only: ``` 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 ``` But what is the reason for such a limitation? Wouldn't it be good if there would be a possibility to add new localization languages at runtime? Best regards, Konstantin Aladyshev On Sat, Oct 30, 2021 at 2:14 PM Konstantin Aladyshev <aladyshev22@...> wrote:
|
|