aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lessons/Lesson_48/README.md381
-rw-r--r--Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c32
-rw-r--r--Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf24
-rw-r--r--Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/Strings.uni8
-rw-r--r--Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dec37
-rw-r--r--Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dsc67
-rw-r--r--README.md2
-rw-r--r--UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c32
-rw-r--r--UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf24
-rw-r--r--UefiLessonsPkg/HIIStringsUNI/Strings.uni8
-rw-r--r--UefiLessonsPkg/UefiLessonsPkg.dec1
-rw-r--r--UefiLessonsPkg/UefiLessonsPkg.dsc1
12 files changed, 617 insertions, 0 deletions
diff --git a/Lessons/Lesson_48/README.md b/Lessons/Lesson_48/README.md
new file mode 100644
index 0000000..4b81b47
--- /dev/null
+++ b/Lessons/Lesson_48/README.md
@@ -0,0 +1,381 @@
+It was pretty hard to add new string packages using `NewPackageList` function directly.
+Keep in mind that we've only added a couple of strings and we didn't even calculate the necessary data array for the Package list dynamically. Also if we would want to add fonts/forms/images/... we would need to investigate format of these packages and write necessary functions for them as well.
+
+Let's check what EDKII can offer us to simplify these tasks. In this lesson particularly we would talk about how we can simplify our string packages creation.
+
+# Create application
+
+As usual create new application:
+```
+./createNewApp.sh HIIStringsUNI
+```
+
+Add it to our DSC package file UefiLessonsPkg/UefiLessonsPkg.dsc:
+```
+[Components]
+ ...
+ UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
+```
+
+As last time, we would need a GUID for our package list, declare it in package DEC file UefiLessonsPkg/UefiLessonsPkg.dec:
+```
+[Guids]
+ ...
+ gHIIStringsUNIGuid = { 0x6ee19058, 0x0fe2, 0x44ed, { 0x89, 0x1c, 0xa5, 0xd7, 0xe1, 0x08, 0xee, 0x1a }}
+```
+
+And add it to the application INF file UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf:
+```
+[Packages]
+ ...
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+...
+
+[Guids]
+ gHIIStringsUNIGuid
+```
+
+# UNI file
+
+In EDKII you can define all translation strings in the files of a special UNI format. EDKII build utilities will parse data in these files and create array with String packages content.
+
+Let's add `Strings.uni` file to the `Sources` section in our application INF file `UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf`. Keep in mind that you can use any name for the *.uni file and you can have as many *.uni as you want in your `Sources`:
+```
+[Sources]
+ ...
+ Strings.uni
+```
+
+Fill the content of this file `UefiLessonsPkg/HIIStringsUNI/Strings.uni`:
+```
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_HELLO #language en-US "Hello!"
+ #language fr-FR "Bonjour!"
+
+#string STR_BYE #language en-US "Bye!"
+ #language fr-FR "Au revoir!"
+```
+
+This file would be a source for 2 string packages:
+```
+1) 'en-US' string package
+ID 1: "English"
+ID 2: "Hello!"
+ID 3: "Bye!"
+2) 'fr-FR' string package
+ID 1: "Francais"
+ID 2: "Bonjour!"
+ID 3: "Au revoir!"
+```
+You can read more about UNI file format in the [Multi-String .UNI File Format Specification](https://edk2-docs.gitbook.io/edk-ii-uni-specification/).
+
+If you build our application now, this file would be generated along with the usual build files
+`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI/DEBUG/HIIStringsUNIStrDefs.h`. The name of this file is formed from the `BASE_NAME` value in our INF file and basically it is `<BASE_NAME>StrDefs.h`.
+
+If you look at this file you'll see:
+```
+extern unsigned char HIIStringsUNIStrings[];
+```
+This is the array with String packages data that we need. It is imposed that you would pass it to the `HiiAddPackages` function from the `HiiLib` to add HII packages to the database and essentially create new Package list:
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Library/HiiLib.h
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
+```
+/**
+ Registers a list of packages in the HII Database and returns the HII Handle
+ associated with that registration. If an HII Handle has already been registered
+ with the same PackageListGuid and DeviceHandle, then NULL is returned. If there
+ are not enough resources to perform the registration, then NULL is returned.
+ If an empty list of packages is passed in, then NULL is returned. If the size of
+ the list of package is 0, then NULL is returned.
+ The variable arguments are pointers that point to package headers defined
+ by UEFI VFR compiler and StringGather tool.
+ #pragma pack (push, 1)
+ typedef struct {
+ UINT32 BinaryLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ } EDKII_AUTOGEN_PACKAGES_HEADER;
+ #pragma pack (pop)
+ @param[in] PackageListGuid The GUID of the package list.
+ @param[in] DeviceHandle If not NULL, the Device Handle on which
+ an instance of DEVICE_PATH_PROTOCOL is installed.
+ This Device Handle uniquely defines the device that
+ the added packages are associated with.
+ @param[in] ... The variable argument list that contains pointers
+ to packages terminated by a NULL.
+ @retval NULL An HII Handle has already been registered in the HII Database with
+ the same PackageListGuid and DeviceHandle.
+ @retval NULL The HII Handle could not be created.
+ @retval NULL An empty list of packages was passed in.
+ @retval NULL All packages are empty.
+ @retval Other The HII Handle associated with the newly registered package list.
+**/
+EFI_HII_HANDLE
+EFIAPI
+HiiAddPackages (
+ IN CONST EFI_GUID *PackageListGuid,
+ IN EFI_HANDLE DeviceHandle OPTIONAL,
+ ...
+ )
+;
+```
+
+With these things package list creation can be as simple as this:
+```
+...
+
+#include <Library/HiiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HII_HANDLE Handle = HiiAddPackages(&gHIIStringsUNIGuid,
+ NULL,
+ HIIStringsUNIStrings,
+ NULL);
+
+ if (Handle == NULL)
+ {
+ Print(L"Error! Can't perform HiiAddPackages\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+```
+
+Don't forget to include `HiiLib` in the `LibraryClasses` section of our application INF file:
+```
+[Packages]
+ ...
+ MdeModulePkg/MdeModulePkg.dec
+
+...
+
+[LibraryClasses]
+ ...
+ HiiLib
+```
+
+If you build our application and run it under OVMF you coud see that indeed our code creates new Package list with 2 string packages:
+```
+FS0:\> HIIStringsUNI.efi
+FS0:\> ShowHII.efi
+...
+PackageList[20]: GUID=6EE19058-0FE2-44ED-891C-A5D7E108EE1A; size=0xA6
+ Package[0]: type=STRINGS; size=0x46
+ Package[1]: type=STRINGS; size=0x48
+ Package[2]: type=END; size=0x4
+```
+
+# HiiGetString
+
+As we've already included `HiiLib` library, let's use its `HiiGetString` function to print our strings:
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Library/HiiLib.h
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/UefiHiiLib/HiiLib.c
+```
+/**
+ Retrieves a string from a string package in a specific language specified in Language
+ or in the best lanaguage. See HiiGetStringEx () for the details.
+ @param[in] HiiHandle A handle that was previously registered in the HII Database.
+ @param[in] StringId The identifier of the string to retrieved from the string
+ package associated with HiiHandle.
+ @param[in] Language The language of the string to retrieve. If this parameter
+ is NULL, then the current platform language is used. The
+ format of Language must follow the language format assumed in
+ the HII Database.
+ @retval NULL The string specified by StringId is not present in the string package.
+ @retval Other The string was returned.
+**/
+EFI_STRING
+EFIAPI
+HiiGetString (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN EFI_STRING_ID StringId,
+ IN CONST CHAR8 *Language OPTIONAL
+ );
+```
+
+Let's add this code to our application:
+```
+Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
+Print(L"en-US ID=2: %s\n", HiiGetString(Handle, 2, "en-US"));
+Print(L"en-US ID=3: %s\n", HiiGetString(Handle, 3, "en-US"));
+Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
+Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, 2, "fr-FR"));
+Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, 3, "fr-FR"));
+```
+
+If you build and execute our app now you would get:
+```
+FS0:\> HIIStringsUNI.efi
+en-US ID=1: English
+en-US ID=2: <null string>
+en-US ID=3: <null string>
+fr-FR ID=1: Francais
+fr-FR ID=2: <null string>
+fr-FR ID=3: <null string>
+```
+
+What is wrong? Why only the language strings (ID=1) were populated to String packages?
+
+Let's look at the actual `HIIStringsUNIStrings` array data that is present in the file
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI/DEBUG/AutoGen.c
+```
+//
+//Unicode String Pack Definition
+//
+unsigned char HIIStringsUNIStrings[] = {
+
+// STRGATHER_OUTPUT_HEADER
+ 0x92, 0x00, 0x00, 0x00,
+
+// PACKAGE HEADER
+
+ 0x46, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x65, 0x6E,
+ 0x2D, 0x55, 0x53, 0x00,
+
+// PACKAGE DATA
+
+// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
+ 0x14, 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68, 0x00, 0x00,
+ 0x00,
+ 0x00,
+// PACKAGE HEADER
+
+ 0x48, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, 0x72,
+ 0x2D, 0x46, 0x52, 0x00,
+
+// PACKAGE DATA
+
+// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
+ 0x14, 0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x61, 0x00, 0x69, 0x00, 0x73,
+ 0x00, 0x00, 0x00,
+ 0x00,
+
+};
+```
+Couple of things to notice:
+- array contains only String data packages, it doesn't contain neither Package list header, nor End Package
+- array has special 4 byte header `STRGATHER_OUTPUT_HEADER` - it contains size of the array including this header
+- array indeed has only Language name strings in itself
+
+The first two observations just to point out the format of the incoming argument for the `HiiAddPackages` function. You could look at the function implementation to see how the `STRGATHER_OUTPUT_HEADER` is used to construct Package list and call `NewPackageList` with appropriate data.
+
+Now let's look at the `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI/DEBUG/HIIStringsUNIStrDefs.h` one more time, this time pay attention to this piece of code:
+```
+//
+//Unicode String ID
+//
+// #define $LANGUAGE_NAME 0x0000 // not referenced
+// #define $PRINTABLE_LANGUAGE_NAME 0x0001 // not referenced
+// #define STR_HELLO 0x0002 // not referenced
+// #define STR_BYE 0x0003 // not referenced
+```
+
+This is the source of our problem, strings didn't go to the array, because their tokens simply weren't refernced.
+
+The build tool `StrGather.py` that is responsible for the array data creation (https://github.com/tianocore/edk2/blob/master/BaseTools/Source/Python/AutoGen/StrGather.py) simply checks for macros `STRING_TOKEN(...)` in the application code, and populates only strings that are refernced in code:
+```
+STRING_TOKEN = re.compile('STRING_TOKEN *\(([A-Z0-9_]+) *\)', re.MULTILINE | re.UNICODE)
+```
+But as full language name is a mandatory field, it always gets populated. That is why we saw only it in our first application run.
+
+Let's change our print code to this:
+```
+Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
+Print(L"en-US ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "en-US"));
+Print(L"en-US ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "en-US"));
+Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
+Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "fr-FR"));
+Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "fr-FR"));
+```
+
+Now build the application and look at the generated files:
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI/DEBUG/HIIStringsUNIStrDefs.h
+```
+//
+//Unicode String ID
+//
+// #define $LANGUAGE_NAME 0x0000 // not referenced
+// #define $PRINTABLE_LANGUAGE_NAME 0x0001 // not referenced
+#define STR_HELLO 0x0002
+#define STR_BYE 0x0003
+```
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI/DEBUG/AutoGen.c
+```
+//
+//Unicode String Pack Definition
+//
+unsigned char HIIStringsUNIStrings[] = {
+
+// STRGATHER_OUTPUT_HEADER
+ 0xD6, 0x00, 0x00, 0x00,
+
+// PACKAGE HEADER
+
+ 0x60, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x65, 0x6E,
+ 0x2D, 0x55, 0x53, 0x00,
+
+// PACKAGE DATA
+
+// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
+ 0x14, 0x45, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x6C, 0x00, 0x69, 0x00, 0x73, 0x00, 0x68, 0x00, 0x00,
+ 0x00,
+// 0x0002: STR_HELLO:0x0002
+ 0x14, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x21, 0x00, 0x00, 0x00,
+// 0x0003: STR_BYE:0x0003
+ 0x14, 0x42, 0x00, 0x79, 0x00, 0x65, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x00,
+// PACKAGE HEADER
+
+ 0x72, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x66, 0x72,
+ 0x2D, 0x46, 0x52, 0x00,
+
+// PACKAGE DATA
+
+// 0x0001: $PRINTABLE_LANGUAGE_NAME:0x0001
+ 0x14, 0x46, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x61, 0x00, 0x69, 0x00, 0x73,
+ 0x00, 0x00, 0x00,
+// 0x0002: STR_HELLO:0x0002
+ 0x14, 0x42, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x6A, 0x00, 0x6F, 0x00, 0x75, 0x00, 0x72, 0x00, 0x21,
+ 0x00, 0x00, 0x00,
+// 0x0003: STR_BYE:0x0003
+ 0x14, 0x41, 0x00, 0x75, 0x00, 0x20, 0x00, 0x72, 0x00, 0x65, 0x00, 0x76, 0x00, 0x6F, 0x00, 0x69,
+ 0x00, 0x72, 0x00, 0x21, 0x00, 0x00, 0x00,
+ 0x00,
+
+};
+```
+
+As you can see this time our strings got into the `HIIStringsUNIStrings` array.
+
+If you execute our application under OVMF now you would get:
+```
+FS0:\> HIIStringsUNI.efi
+en-US ID=1: English
+en-US ID=2: Hello!
+en-US ID=3: Bye!
+fr-FR ID=1: Francais
+fr-FR ID=2: Bonjour!
+fr-FR ID=3: Au revoir!
+```
diff --git a/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c
new file mode 100644
index 0000000..160108b
--- /dev/null
+++ b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c
@@ -0,0 +1,32 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HiiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HII_HANDLE Handle = HiiAddPackages(&gHIIStringsUNIGuid,
+ NULL,
+ HIIStringsUNIStrings,
+ NULL);
+
+ if (Handle == NULL)
+ {
+ Print(L"Error! Can't perform HiiAddPackages\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
+ Print(L"en-US ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "en-US"));
+ Print(L"en-US ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "en-US"));
+ Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
+ Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "fr-FR"));
+ Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "fr-FR"));
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
new file mode 100644
index 0000000..42b01a7
--- /dev/null
+++ b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIStringsUNI
+ FILE_GUID = d6c2599a-096f-4644-af1c-aee12e320fb0
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ HIIStringsUNI.c
+ Strings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ HiiLib
+
+[Guids]
+ gHIIStringsUNIGuid
diff --git a/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/Strings.uni b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/Strings.uni
new file mode 100644
index 0000000..2bce7e3
--- /dev/null
+++ b/Lessons/Lesson_48/UefiLessonsPkg/HIIStringsUNI/Strings.uni
@@ -0,0 +1,8 @@
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_HELLO #language en-US "Hello!"
+ #language fr-FR "Bonjour!"
+
+#string STR_BYE #language en-US "Bye!"
+ #language fr-FR "Au revoir!"
diff --git a/Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..6d44885
--- /dev/null
+++ b/Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,37 @@
+[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 }}
+
+[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_48/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..6a331f2
--- /dev/null
+++ b/Lessons/Lesson_48/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,67 @@
+[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
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44
+
diff --git a/README.md b/README.md
index c78ab9e..18119a1 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,8 @@ These series of lessons are intendend to get you started with UEFI programming i
- [Lesson 45](Lessons/Lesson_45): Use `NewPackageList` from the `EFI_HII_DATABASE_PROTOCOL` directly to publish HII Package list with Strings packages. Part 1: Investigate common aspects of Package List data generation
- [Lesson 46](Lessons/Lesson_46): Use `NewPackageList` from the `EFI_HII_DATABASE_PROTOCOL` directly to publish HII Package list with Strings packages. Part 2: String Packages data generation
- [Lesson 47](Lessons/Lesson_47): Use `NewPackageList` from the `EFI_HII_DATABASE_PROTOCOL` directly to publish HII Package list with Strings packages. Part 3: Combine everything together. Use `NewPackageList` and `GetString` protocol functions
+- [Lesson 48](Lessons/Lesson_48): Use `UNI` files and `HiiLib` to publish and work with HII String packages
+
_____
diff --git a/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c b/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c
new file mode 100644
index 0000000..160108b
--- /dev/null
+++ b/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.c
@@ -0,0 +1,32 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/HiiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HII_HANDLE Handle = HiiAddPackages(&gHIIStringsUNIGuid,
+ NULL,
+ HIIStringsUNIStrings,
+ NULL);
+
+ if (Handle == NULL)
+ {
+ Print(L"Error! Can't perform HiiAddPackages\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Print(L"en-US ID=1: %s\n", HiiGetString(Handle, 1, "en-US"));
+ Print(L"en-US ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "en-US"));
+ Print(L"en-US ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "en-US"));
+ Print(L"fr-FR ID=1: %s\n", HiiGetString(Handle, 1, "fr-FR"));
+ Print(L"fr-FR ID=2: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_HELLO), "fr-FR"));
+ Print(L"fr-FR ID=3: %s\n", HiiGetString(Handle, STRING_TOKEN(STR_BYE), "fr-FR"));
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf b/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
new file mode 100644
index 0000000..42b01a7
--- /dev/null
+++ b/UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HIIStringsUNI
+ FILE_GUID = d6c2599a-096f-4644-af1c-aee12e320fb0
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ HIIStringsUNI.c
+ Strings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ HiiLib
+
+[Guids]
+ gHIIStringsUNIGuid
diff --git a/UefiLessonsPkg/HIIStringsUNI/Strings.uni b/UefiLessonsPkg/HIIStringsUNI/Strings.uni
new file mode 100644
index 0000000..2bce7e3
--- /dev/null
+++ b/UefiLessonsPkg/HIIStringsUNI/Strings.uni
@@ -0,0 +1,8 @@
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_HELLO #language en-US "Hello!"
+ #language fr-FR "Bonjour!"
+
+#string STR_BYE #language en-US "Bye!"
+ #language fr-FR "Au revoir!"
diff --git a/UefiLessonsPkg/UefiLessonsPkg.dec b/UefiLessonsPkg/UefiLessonsPkg.dec
index 8a6ff4b..6d44885 100644
--- a/UefiLessonsPkg/UefiLessonsPkg.dec
+++ b/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -12,6 +12,7 @@
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 }}
[Protocols]
gSimpleClassProtocolGuid = { 0xb5510eea, 0x6f11, 0x4e4b, { 0xad, 0x0f, 0x35, 0xce, 0x17, 0xbd, 0x7a, 0x67 }}
diff --git a/UefiLessonsPkg/UefiLessonsPkg.dsc b/UefiLessonsPkg/UefiLessonsPkg.dsc
index 075cc8e..6a331f2 100644
--- a/UefiLessonsPkg/UefiLessonsPkg.dsc
+++ b/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -60,6 +60,7 @@
UefiLessonsPkg/HotKeyDriver/HotKeyDriver.inf
UefiLessonsPkg/ShowHII/ShowHII.inf
UefiLessonsPkg/HIIStringsC/HIIStringsC.inf
+ UefiLessonsPkg/HIIStringsUNI/HIIStringsUNI.inf
[PcdsFixedAtBuild]
gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44