diff options
author | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-11-09 18:25:39 +0300 |
---|---|---|
committer | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-11-09 18:25:39 +0300 |
commit | 905ebbbf91f2923612ae4d85b9f440e1955c8837 (patch) | |
tree | 8721e253ad4e428116a77a3b647dd0fa65719884 | |
parent | 316faf0520a407572138e31875a9276293613601 (diff) | |
download | UEFI-Lessons-905ebbbf91f2923612ae4d85b9f440e1955c8837.tar.gz UEFI-Lessons-905ebbbf91f2923612ae4d85b9f440e1955c8837.tar.bz2 UEFI-Lessons-905ebbbf91f2923612ae4d85b9f440e1955c8837.zip |
Add lesson 55
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
-rw-r--r-- | Lessons/Lesson_55/README.md | 272 | ||||
-rw-r--r-- | Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c | 71 | ||||
-rw-r--r-- | Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf | 27 | ||||
-rw-r--r-- | Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dec | 45 | ||||
-rw-r--r-- | Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dsc | 78 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c | 71 | ||||
-rw-r--r-- | UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf | 27 | ||||
-rw-r--r-- | UefiLessonsPkg/UefiLessonsPkg.dsc | 1 |
9 files changed, 593 insertions, 0 deletions
diff --git a/Lessons/Lesson_55/README.md b/Lessons/Lesson_55/README.md new file mode 100644 index 0000000..123f439 --- /dev/null +++ b/Lessons/Lesson_55/README.md @@ -0,0 +1,272 @@ +We know how to add font for the new language, and we now how to populate strings for some of the existing languages in the system dynamically. +Let's see if it is possible to create another language option dynamically. + +`Select Language` menu gets all possible language options from the value of the `PlatformLangCodes` EFI variable. And the current language option is reflected by the `PlatformLang` EFI option. + +Initially the values for these options are set with a help of PCD in the https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec: +``` + ## Default platform supported RFC 4646 languages: (American) English & French. + # @Prompt Default Value of PlatformLangCodes Variable. + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes|"en;fr;en-US;fr-FR"|VOID*|0x0000001e + + ## Default current RFC 4646 language: (American) English. + # @Prompt Default Value of PlatformLang Variable. + gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang|"en-US"|VOID*|0x0000001f +``` +You can look at the actual code in the `UiCreateLanguageMenu` function from the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c. + +Let's see if it is possible to modify `PlatformLangCodes` and add another language into it. + +First create an app that would print the value for the `PlatformLangCodes` option: +``` +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +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"Current value of the 'PlatformLangCodes' variable is '%a'\n", LanguageString); + + return EFI_SUCCESS; +} +``` +We've already used `gRT->GetVariable` protocol function directly before, so here we use `GetEfiGlobalVariable2` library function to the simplify code. This function is defined in the https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiLib/UefiLib.c: +``` +** + 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 + ) +``` + +If you build and run our application now, you would get the value from the PCD: +``` +FS0:\> AddNewLanguage.efi +Current value of the 'PlatformLangCodes' variable is 'en;fr;en-US;fr-FR' +``` + +Now let's try to add `;ru-RU` to the end of the variable and write it back. + +First construct new string and fill it with the necessary data: +``` +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); +``` +Just in case ASCII string functions are defined in the https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/String.c. +Also don't forget to include `Library/MemoryAllocationLib.h` header for the `AllocatePool` function and `Library/BaseMemoryLib.h` header for the `CopyMem` function. + +Now use `SetVariable` call to update variable: +``` +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` is a Runtime Service, you can find its definition in the UEFI specification: +``` +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. +``` +In case you forgot `gRT` is a shortcut for the `SystemTable->RuntimeServices` from the `UefiRuntimeServicesTableLib` library. So don't forget to include its library header `<Library/UefiRuntimeServicesTableLib.h>`. + +If you build and run our application now you would get: +``` +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 +``` + +Unfortunately it is not possible to add new language at runtime as 'PlatformLangCodes' EFI variable is write protected. Therefore it is not possible to add another localization language at runtime. + +If you look at the UEFI spec you'll see: +``` +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. +``` + +# EDKII_VARIABLE_POLICY_PROTOCOL + +The `PlatformLangCodes` is locked for modifications with a help of a `gEdkiiVariablePolicyProtocolGuid` protocol. This is a custom EDKII protocol for setting different policies on variables. + +You can read more about the UEFI Variable Policy protocol in the https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md + +The header file is placed under https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Protocol/VariablePolicy.h + +The policy for the `PlatformLangCodes` EFI variable is set in the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/BdsDxe/BdsEntry.c along with couple of other variables: +``` +/// +/// 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); + } + } +``` + +# Try to execute DisableVariablePolicy() + +We can try to perform `DisableVariablePolicy()` to disable `VariablePolicyProtocol`. + +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; + } +} +``` + +UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf: +``` +.... +[Packages] + ... + MdeModulePkg/MdeModulePkg.dec +... + +[Protocols] + gEdkiiVariablePolicyProtocolGuid +``` + +But unfortunately this call would fail: +``` +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 +``` + +This happend because in the end of the DXE UEFI stage 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 (); + ... +} +``` +Locking means that is no longer possible to change or disable policy for variables. Therefore there is no way to change `PlatformLangCodes` at runtime. + diff --git a/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c b/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c new file mode 100644 index 0000000..cd4920d --- /dev/null +++ b/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> + * + * SPDX-License-Identifier: MIT + */ + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Protocol/VariablePolicy.h> + + +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"Current value of the 'PlatformLangCodes' variable is '%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"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); + } + + 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; + } + + return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf b/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf new file mode 100644 index 0000000..1a34438 --- /dev/null +++ b/Lessons/Lesson_55/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf @@ -0,0 +1,27 @@ +## +# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = AddNewLanguage + FILE_GUID = 6790e268-0762-4ce8-8999-2ff2131e6512 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + AddNewLanguage.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + +[Protocols] + gEdkiiVariablePolicyProtocolGuid diff --git a/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dec new file mode 100644 index 0000000..40b351c --- /dev/null +++ b/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dec @@ -0,0 +1,45 @@ +## +# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+ Include
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+ gHIIStringsCGuid = { 0x8e0b8ed3, 0x14f7, 0x499d, { 0xa2, 0x24, 0xae, 0xe8, 0x9d, 0xc9, 0x7f, 0xa3 }}
+ gHIIStringsUNIGuid = { 0x6ee19058, 0x0fe2, 0x44ed, { 0x89, 0x1c, 0xa5, 0xd7, 0xe1, 0x08, 0xee, 0x1a }}
+ gHIIStringsUNIRCGuid = { 0x785693b4, 0x623e, 0x40fa, { 0x9a, 0x45, 0x68, 0xda, 0x38, 0x30, 0x89, 0xdd }}
+ gHIIAddRussianFontGuid = { 0x9fe2f616, 0x323c, 0x45a7, { 0x87, 0xa2, 0xdf, 0xef, 0xf5, 0x17, 0xcc, 0x66 }}
+
+[Protocols]
+ gSimpleClassProtocolGuid = { 0xb5510eea, 0x6f11, 0x4e4b, { 0xad, 0x0f, 0x35, 0xce, 0x17, 0xbd, 0x7a, 0x67 }}
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|42|UINT32|0x00000002
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|42|UINT32|0x00000003
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool|FALSE|BOOLEAN|0x00000004
+
+[PcdsPatchableInModule]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32|0x31313131|UINT32|0x10000001
+
+[PcdsFeatureFlag]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar|FALSE|BOOLEAN|0x20000001
+
+[PcdsDynamic]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32|0x38323232|UINT32|0x30000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32_1|42|UINT32|0x30000002
+
+[PcdsDynamicEx]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicExVar32|0x38333333|UINT32|0x40000001
diff --git a/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dsc new file mode 100644 index 0000000..85ea19a --- /dev/null +++ b/Lessons/Lesson_55/UefiLessonsPkg/UefiLessonsPkg.dsc @@ -0,0 +1,78 @@ +## +# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines] + DSC_SPECIFICATION = 0x0001001C + PLATFORM_GUID = 3db7270f-ffac-4139-90a4-0ae68f3f8167 + PLATFORM_VERSION = 0.01 + PLATFORM_NAME = UefiLessonsPkg + SKUID_IDENTIFIER = DEFAULT + SUPPORTED_ARCHITECTURES = X64 + BUILD_TARGETS = RELEASE + + +[LibraryClasses] + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + #PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf + ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf + FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + #SimpleLibrary|UefiLessonsPkg/Library/SimpleLibrary/SimpleLibrary.inf + #SimpleLibrary|UefiLessonsPkg/Library/SimpleLibraryWithConstructor/SimpleLibraryWithConstructor.inf + SimpleLibrary|UefiLessonsPkg/Library/SimpleLibraryWithConstructorAndDestructor/SimpleLibraryWithConstructorAndDestructor.inf + +[Components] + UefiLessonsPkg/SimplestApp/SimplestApp.inf + UefiLessonsPkg/HelloWorld/HelloWorld.inf + UefiLessonsPkg/ImageHandle/ImageHandle.inf + UefiLessonsPkg/ImageInfo/ImageInfo.inf + UefiLessonsPkg/MemoryInfo/MemoryInfo.inf + UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf + UefiLessonsPkg/ListVariables/ListVariables.inf + UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf + UefiLessonsPkg/InteractiveApp/InteractiveApp.inf + UefiLessonsPkg/PCDLesson/PCDLesson.inf + UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf + UefiLessonsPkg/ShowTables/ShowTables.inf + UefiLessonsPkg/AcpiInfo/AcpiInfo.inf + UefiLessonsPkg/SaveBGRT/SaveBGRT.inf + UefiLessonsPkg/ListPCI/ListPCI.inf + UefiLessonsPkg/SimpleDriver/SimpleDriver.inf + UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf + UefiLessonsPkg/Library/SimpleLibrary/SimpleLibrary.inf + UefiLessonsPkg/Library/SimpleLibraryWithConstructor/SimpleLibraryWithConstructor.inf + UefiLessonsPkg/SimpleLibraryUser/SimpleLibraryUser.inf + UefiLessonsPkg/SimpleClassProtocol/SimpleClassProtocol.inf + UefiLessonsPkg/SimpleClassUser/SimpleClassUser.inf + UefiLessonsPkg/HotKeyDriver/HotKeyDriver.inf + UefiLessonsPkg/ShowHII/ShowHII.inf + UefiLessonsPkg/HIIStringsC/HIIStringsC.inf + UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf + UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf + UefiLessonsPkg/HIIStringsMan/HIIStringsMan.inf + UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf + UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf + UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf + +[PcdsFixedAtBuild] + gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44 + @@ -58,6 +58,7 @@ These series of lessons are intendend to get you started with UEFI programming i - [Lesson 52](Lessons/Lesson_52): Add Russian font - Part 1: investigate `EFI_NARROW_GLYPH`/`EFI_WIDE_GLYPH` format, construct glyph array from the *.woff font file - [Lesson 53](Lessons/Lesson_53): Add Russian font - Part 2: construct `EFI_HII_SIMPLE_FONT_PACKAGE` and populate it to the HII database - [Lesson 54](Lessons/Lesson_54): Use `NewString` and `SetString` functions from the `EFI_HII_STRING_PROTOCOL` to add String Package for another language dynamically +- [Lesson 55](Lessons/Lesson_55): Try to modify `PlatformLangCodes` EFI variable and add another language dynamically. Variable protection with a help of `EDKII_VARIABLE_POLICY_PROTOCOL` _____ diff --git a/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c b/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c new file mode 100644 index 0000000..cd4920d --- /dev/null +++ b/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> + * + * SPDX-License-Identifier: MIT + */ + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Protocol/VariablePolicy.h> + + +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"Current value of the 'PlatformLangCodes' variable is '%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"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); + } + + 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; + } + + return EFI_SUCCESS; +} diff --git a/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf b/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf new file mode 100644 index 0000000..1a34438 --- /dev/null +++ b/UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf @@ -0,0 +1,27 @@ +## +# Copyright (c) 2021, Konstantin Aladyshev <aladyshev22@gmail.com> +# +# SPDX-License-Identifier: MIT +## + +[Defines] + INF_VERSION = 1.25 + BASE_NAME = AddNewLanguage + FILE_GUID = 6790e268-0762-4ce8-8999-2ff2131e6512 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +[Sources] + AddNewLanguage.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + +[Protocols] + gEdkiiVariablePolicyProtocolGuid diff --git a/UefiLessonsPkg/UefiLessonsPkg.dsc b/UefiLessonsPkg/UefiLessonsPkg.dsc index 48b78ca..85ea19a 100644 --- a/UefiLessonsPkg/UefiLessonsPkg.dsc +++ b/UefiLessonsPkg/UefiLessonsPkg.dsc @@ -71,6 +71,7 @@ UefiLessonsPkg/HIIStringsMan/HIIStringsMan.inf UefiLessonsPkg/HIIAddRussianFont/HIIAddRussianFont.inf UefiLessonsPkg/HIIAddLocalization/HIIAddLocalization.inf + UefiLessonsPkg/AddNewLanguage/AddNewLanguage.inf [PcdsFixedAtBuild] gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44 |