From f2ba80c920206ef17d59195b13b22e4c46ad9c9d Mon Sep 17 00:00:00 2001 From: Konstantin Aladyshev Date: Fri, 22 Oct 2021 11:45:34 +0300 Subject: Add lesson 47 Signed-off-by: Konstantin Aladyshev --- Lessons/Lesson_47/README.md | 146 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 Lessons/Lesson_47/README.md diff --git a/Lessons/Lesson_47/README.md b/Lessons/Lesson_47/README.md new file mode 100644 index 0000000..9a20add --- /dev/null +++ b/Lessons/Lesson_47/README.md @@ -0,0 +1,146 @@ +Now we can finally register our Package list in the HII database. Here is a description for the `NewPackageList` one more time: +``` +EFI_HII_DATABASE_PROTOCOL.NewPackageList() + +Summary: +Adds the packages in the package list to the HII database. + +Prototype: +typedef +EFI_STATUS +(EFIAPI *EFI_HII_DATABASE_NEW_PACK) ( + IN CONST EFI_HII_DATABASE_PROTOCOL *This, + IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList, + IN CONST EFI_HANDLE DriverHandle, OPTIONAL + OUT EFI_HII_HANDLE *Handle + ); + +Parameters: +This A pointer to the EFI_HII_DATABASE_PROTOCOL instance +PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure +DriverHandle Associate the package list with this EFI handle +Handle A pointer to the EFI_HII_HANDLE instance +Description This function adds the packages in the package list to the database and returns a handle. If there is a + EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will create a + package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list. +``` + +We've already filled PackageList array, so we can use this function like this: +``` + EFI_HII_HANDLE Handle; + EFI_STATUS Status = gHiiDatabase->NewPackageList(gHiiDatabase, PackageListHdr, NULL, &Handle); + if (EFI_ERROR(Status)) + { + Print(L"Can't register HII Package list %g, status = %r\n", gHIIStringsCGuid, Status); + } +``` + +Now when we have `EFI_HII_HANDLE Handle` for our package list it is time to try to get strings from the HII Database. For this we can utilize `GetString` from another of HII Database protocols - `EFI_HII_STRING_PROTOCOL`: +``` +EFI_HII_STRING_PROTOCOL.GetString() + +Summary: +Returns information about a string in a specific language, associated with a package list. + +Prototype: +typedef +EFI_STATUS +(EFIAPI *EFI_HII_GET_STRING) ( + IN CONST EFI_HII_STRING_PROTOCOL *This, + IN CONST CHAR8 *Language, + IN EFI_HII_HANDLE PackageList, + IN EFI_STRING_ID StringId, + OUT EFI_STRING String, + IN OUT UINTN *StringSize, + OUT EFI_FONT_INFO **StringFontInfo OPTIONAL + ); + +Parameters: +This A pointer to the EFI_HII_STRING_PROTOCOL instance. +PackageList The package list in the HII database to search for the specified string. +Language Points to the language for the retrieved string. Callers of interfaces that require RFC + 4646 language codes to retrieve a Unicode string must use the RFC 4647 algorithm to + lookup the Unicode string with the closest matching RFC 4646 language code. +StringId The string’s id, which is unique within PackageList. +String Points to the new null-terminated string. +StringSize On entry, points to the size of the buffer pointed to by String, in bytes. On return, + points to the length of the string, in bytes. +StringFontInfo Points to a buffer that will be callee allocated and will have the string's font + information into this buffer. The caller is responsible for freeing this buffer. If the + parameter is NULL a buffer will not be allocated and the string font information will + not be returned. + +Description: +This function retrieves the string specified by StringId which is associated with the specified +PackageList in the language Language and copies it into the buffer specified by String. +``` + +Once again here is a standard UEFI scheme for getting resources of unknown size. First we call `GetString` with a `StringSize=0`. The function returns `EFI_BUFFER_TOO_SMALL`, but fills the `StringSize` with a necessary value. Then we call `GetString` one more time, this time with a correct `StringSize`. +As we've included `UefiHiiServicesLib` in our application we don't need to perform `LocateProtocol` to find `EFI_HII_STRING_PROTOCOL` but simply can use `gHiiString` variable. +Here is a function `PrintStringFromHiiHandle` for printing strings from Package list with a `EFI_HII_HANDLE` by simply providing string (Id, Language) combination: +``` +EFI_STATUS PrintStringFromHiiHandle(EFI_HII_HANDLE* Handle, CHAR8* Language, UINTN StringId) +{ + EFI_STRING String = NULL; + UINTN StringSize = 0; + EFI_STATUS Status = gHiiString->GetString(gHiiString, Language, *Handle, StringId, String, &StringSize, NULL); + + if (Status != EFI_BUFFER_TOO_SMALL) { + return Status; + } + + String = AllocateZeroPool(StringSize); + if (String == NULL) { + return Status; + } + + Status = gHiiString->GetString(gHiiString, Language, *Handle, StringId, String, &StringSize, NULL); + + Print(L"Status = %r, %s\n", Status, String); + + FreePool(String); + + return EFI_SUCCESS; +} +``` + +After we've registered our package we can use it as simple as this: +``` + PrintStringFromHiiHandle(&Handle, "en-US", 1); + PrintStringFromHiiHandle(&Handle, "en-US", 2); + PrintStringFromHiiHandle(&Handle, "fr-FR", 1); + PrintStringFromHiiHandle(&Handle, "fr-FR", 2); +``` + +Now it is time to combine everything together and build our application. + +If we execute it under OVMF we would get: +``` +FS0:\> HIIStringsC.efi +Status = Success, English +Status = Success, Hello +Status = Success, French +Status = Success, Bonjour +``` + +So everything works correctly! + +We can even see our newly created package if we execute our `ShowHII` application: +``` +FS0:\> ShowHII.efi +... +PackageList[20]: GUID=8E0B8ED3-14F7-499D-A224-AEE89DC97FA3; size=0xC0 + Package[0]: type=STRINGS; size=0x53 + Package[1]: type=STRINGS; size=0x55 + Package[2]: type=END; size=0x4 +``` + +Keep in mind that if we will try to execute the `HIIStringsC` app again we would get an errror: +``` +FS0:\> HIIStringsC.efi +Can't register HII Package list 8E0B8ED3-14F7-499D-A224-AEE89DC97FA3, status = Invalid Parameter +``` + +It is happening, because it is not possible to register two Package lists with the same GUID. + + -- cgit v1.2.3-18-g5258