Write for UEFI BIOS in Visual Studio. Part 3 - Front Page Localization

Introduction

This article is a continuation of previous Part 1 and Part 2. In this article we will create national font to localize UEFI BIOS pages. As soon as the author (me) is Russian, Russian localization will be implemented. However, no problem seems to be with adding any other national language - all you need is just to use your national alphabet instead, principles are the same. Except hieroglyphs, of course - they have double width, so it's required to use EFI_WIDE_GLYPH structure instead of EFI_NARROW_GLYPH at least. 

After we create local font (glyphs), we will localize with it the main settings page from the example available in edk2. Here is the example of result. Please note that French language is included in EDK2 by default.

Note
The flattened Russian font is a consequence of the fact that the author was looking for a bitmap font 8x19 for half a day from which it would be possible to take glyphs, but did not find it and took 8x16 from the Win7 terminal console. If someone is deeply immersed in this topic - give the name of the fixed font with an 8x19 bitmap, ideally free, I will correct the pictures and the article.

To display the Russian language on the main page, you must have access to the source code of the firmware used. Those. after passing the article, you can add the Russian locale to your UEFI BIOS build, on a virtual or real machine, but it’s impossible to add some brand to the existing hardware system in the manner described, since there is no access to the original firmware code. That is, it is theoretically possible, but it will take significantly more effort and knowledge than described in this article.

First, a little theory. To begin with, there is no True Type Fonts in UEFI. At least now, in the implementation of the UEFI Specification 2.6. Fixed only. Fonts consist of so-called glyphs - small bitmaps of fixed width and height, by default - 8x19, but there may be, of course, other sizes - for example, double width for hieroglyphs. Here is the glyph for the capital English letter “A” :

This bitmap is stored in text format in the format of the EFI_NARROW_GLYPH structure:

typedef struct { 
CHAR16 UnicodeWeight;
UINT8 Attributes;
UINT8 GlyphCol1[EFI_GLYPH_HEIGHT];
} EFI_NARROW_GLYPH;

Consider the fields of this structure in more detail:

UnicodeWeight - the character code in UCS-2. You can read about this, for example, here - or by typing UCS2 in Google

Attributes - indicates how large and wide the pixels should be in the font, whether there should be a space after the letters, single or double width. Currently this field is not analyzed in edk2, instead it is a zero value in the implementation of the system font. You can see the description of attributes in the UEFI 2.6 specification, clause 31.3.2.2 of EFI_NARROW_GLYPH.

Russian characters have code 04xx, where 04 is the encoding of the Russian language, and xx is the code of the corresponding Russian letter, from “A” (0410) to “I” (044F), these codes will be contained in the UnicodeWeight field.

As they say, it’s better to see once than read the description a hundred times. This is what the space glyph for English encoding 00xx looks like, as an element of the above described EFI_NARROW_GLYPH structure:

{ 0x0020, //0x20 - "space" symbol code, in both UCS-2 and ASCII 
0x00, //attributes, no need to analyze
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00}},//it's "space" bitmap, all zeroes

And so - the glyph of the capital English letter A :

{ 0x0041, // 0x41 - letter “A” code
0x00, //attributes
{0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,
0x00,0x00}},// bitmap fo “A” symbol, match this with the pictire above

All with the theory so far, go to the practice and experiments. At the same time, as promised earlier, it is necessary to reach a time of 10 seconds by pressing F5 before opening the UEFI Shell window - this is already quite comfortable for work.

Creating a project in the UEFI Driver Wizard

Specify the name Workspace as C:/FW/edk2. Make the first and second settings page, as in the previous article, and click Finish. Of course, the name of the project must be changed, put Matreshka - it reflects the subtleties of implementation, hidden from first sight, through which we will pass in the process.
It is better to bring relevant screenshots (of course, a completely different GUID will be generated in your case):

If you were cursed at the end, then most likely, the Workspace was incorrectly specified. We believe that everything turned out. Close the UEFI Driver Wizard.

Creating a project in Visual Studio

Open our Solution NT32 and create a new project in it, right-click on Solution, then Add-> New Project and select the project type Makefile Project. The project name, as you already guessed, is Matreshka :

We will continue without screenshots, since in the first article we should have explained this in detail, and in the third - perhaps, too much. If something is not clear in the process of project settings, it is better to go back to the first article and look at the pictures.

Now open the properties of our created project (right-click on the Matreshka project and select Properties.

NMake settings

In the line Build Command Line :

set NASM_PREFIX=C:\FW\NASM\ 
call C:\FW\edk2\edksetup.bat --nt32
build –p Nt32Pkg/Nt32Pkg.dsc -m EducationPkg\Matreshka\Matreshka.inf

And here, of course, an explanation is required, since the line with build differs from that in the first article. Let's sort this line:

–p Nt32Pkg/Nt32Pkg.dsc

This is an indication to edk2 that only the Nt32Pkg package should be recompiled. You do not need to recompile the rest, and the make utility (strictly speaking, not to it, but in the first approximation so be it) should not waste time checking all the packages in the edk2 tree for changes to the source files (and there are almost 200M of them there noticed when rocking with git).

-m EducationPkg\Matreshka\Matreshka.inf

Indication that only the Matreshka module is recompiled, without disturbing the others.

These two instructions save us time not only to view the changes of all the other files in the edk2 tree, in this case, the NVRAM image is not created anew, which, firstly, takes time, and secondly, it erases the information that we brought there last run. So far we do not need this, but in the next article - it will be required.

In the Rebuild All Command Line :
No change from the first article. View (and recompile if necessary) the entire edk2 tree, with the creation of a new image of NVRAM. We will also need this today, since editing the source code in the Matreshka project will not be limited to, we will have to go into other projects, and PCD will not work for this purpose. However, we will not run clean here for the whole tree, in order to save time, but rather we will move it to the next option. So:

set NASM_PREFIX=C:\FW\NASM\ call C:\FW\edk2\edksetup.bat --nt32 build

In the Clean Command Line, we clear the entire edk2 tree:

set NASM_PREFIX=C:\FW\NASM\ call C:\FW\edk2\edksetup.bat --nt32 build clean

All with NMake settings.

Debugging Settings

Command line:

C:\FW\edk2\Build\NT32IA32\DEBUG_VS2010x86\IA32\SecMain.exe


Line Working Directory :

C:\FW\edk2\Build\NT32IA32\DEBUG_VS2010x86\IA32\


Finished with the settings of Visual Studio.

Add our project to Nt32Pkg

Open the file

C:\FW\edk2\Nt32Pkg\Nt32Pkg.dsc

And we are looking for a line in it, which was added last time:

EducationPkg/MyFirstDriver/MyFirstDriver.inf

We comment on it with the # symbol, since we will quickly get tired of typing several characters each time so that our previous project MyFirstDriver will give us the opportunity to go on without entering any phrase. Then we add our line, as you probably guessed:

EducationPkg\Matreshka\Matreshka.inf

If you have not done the number 2 described in the last article, then you do not have the line with MyFirstDriver, then add a line with Matreshka after the comment

# Add new modules here

Edit startup.nsh for autostart of our driver

This time just open the startup.nsh file directly in Visual Studio, from the directory

C:\FW\edk2\Build\NT32IA32\DEBUG_VS2010x86\IA32

Commenting on the line

# load MyFirstdriver.efi

And add the line

load Matreshka.efi

All with settings. We compile the project on F5 and look at autoloading the driver, which so far does nothing. Compiled and loaded - go ahead, no - rule the error.

Examine the current situation at first

We right-click on the Matreshka project in Visual Studio, select Add-> Existing Item, go to our catalog

C:\FW\edk2\EducationPkg\MyFirstDriver

Select all the files with the mouse and click on Add, adding them to our project Matreshka in Visual Studio.

Open the file Matreshka.c and create at the very bottom, after all the functions, its function MyTestString ()

EFI_STATUS EFIAPI MyTestString(void){ 
EFI_STATUS Status;
EFI_HII_FONT_PROTOCOL *mHiiFontProtocol;
EFI_FONT_DISPLAY_INFO *FontInfo;
CHAR16 TestString[] = L"Тестовая строка, Test String\n\r";
// Send a test string to output for check if there any Russian letters
Status = gST->ConOut->OutputString(gST->ConOut, TestString);
// See the test string on output window to check if all is OK
DEBUG((EFI_D_INFO, "OutputString status = %r\n\r", Status));
// Check which font is installed in the system
// and get a handle to EFI_HII_FONT_PROTOCOL
Status = gBS->LocateProtocol (
// Protocol interface that already installed in the system we are looking for
&gEfiHiiFontProtocolGuid,
// We need only one interface, end of the list
NULL,
// Assign our handle the link on the protocol that we have found
(VOID **) &mHiiFontProtocol );
if (EFI_ERROR (Status)) {
// If required protocol is not installed in the system, there is nothing else to do
return EFI_UNSUPPORTED;
}
// Recieve a string that contains the name of font we have found
Status = mHiiFontProtocol->GetFontInfo (
mHiiFontProtocol,
NULL,
NULL,
// the structure contains a string with the name of the protocol
&FontInfo,
NULL );
DEBUG((EFI_D_INFO, "GetFontInfo status = %r, current font has '%s' name\n\r", Status, FontInfo->FontInfo.FontName));
return EFI_SUCCESS; }

We also add a call to our function at the end of the MatreshkaDriverEntryPoint () function, before the last return Status operator in this function:

MyTestString(); 
return Status;
}

And we add #include <Protocol/HiiFont.h> and the description of our function to the beginning of the Matreshka.c file, immediately after

#include "Matreshka.h"

It should turn out like this:

#include "Matreshka.h" 
#
include <Protocol/HiiFont.h>
EFI_STATUS
EFIAPI MyTestString(void);

Click F5. Pay attention to the driver launch speed - the long awaited 10 seconds. For the first time, the compilation went on for a long time, because of the change in Nt32Pkg.dsc, all Nt32Pkg was recompiled, and now we are finally in a normal rut. We look at the output in Shell :

Spaces and comma were derived correctly, because they are international, but with Russian letters - alas.

We look at the output of OVMF :

It can be seen that you can’t cook porridge with the OutputString () diagnostics - “But otherwise, beautiful marquise, everything is good, everything is good”, Success status, although Russian letters are not derived. It is necessary to diagnose something else (s).

Commenting out the string with DEBUG, which displays the status from OutputString (), it does not required any more:

//DEBUG((EFI_D_INFO, "OutputString() status = %r\n\r", Status));

Now let's add a couple of variables to our function:

UINTN Count = 0; 
EFI_IMAGE_OUTPUT *Blt = NULL;

And the search cycle for glyphs displayed in the character string in the font used:

// Until we meet "\0" 
while (TestString[Count]) {
// Look for an info about the symbol used in the currenr font
Status = mHiiFontProtocol->GetGlyph (
// Protocol used
mHiiFontProtocol,
// Checked symbol
TestString[Count],
// No need all other
NULL,
&Blt,
NULL );
if (Blt != NULL) {
FreePool (Blt);
Blt = NULL;
}
// Print out UCS-2 symblol code and move to the next symbol
DEBUG ((EFI_D_INFO,"Current symbol code is 0x%04x\t",TestString[Count++]));
// Print out the status indicated presence of the symbol in the font
DEBUG ((EFI_D_INFO,"Status: %r\r\n", Status));
}

This loop should be inserted into our MyTestString () function before the last string.

return EFI_SUCCESS;

And then we look at the output of DEBUG in the OVMF window:

Well, there is already a useful diagnosis. We analyze this conclusion DEBUG.

Wherever there is a Russian code page 04xx, we received a Warning Unknown Glyph, i.e. for the character with this code there is no corresponding glyph. And with the output of the English line and a space, including between Russian letters - no problem, they were brought to the UEFI Shell screen. At the end, the same error message, but here it should have a place: what kind of bitmap for special characters of a line feed and carriage return “\ n \ r” ?

The problem was uncovered - there are no Russian glyphs. Now we think how to solve it. That is, how to solve something is clear, from somewhere to take and add to the system, the question of where to get and how to add.

The problem is, in fact, quite large. We need fonts of the same size as English, 819 in the system, so that Russian and English letters can be put next to each other.

8x19 free and non-free fonts in the internet are clearly not a car (try searching for yourself), and we follow the usual path: take the existing one and adapt it to your needs.

Let's write the simplest program in a project of the Win32 Console type in Visual Studio, in which we will display all Russian letters of the 16th font alphabet in a cycle in cmd console (no 19th fixed, and fonts in the cmd of TTF console cannot be output). We will leave the implementation of the program at your discretion, and the result will be a string of Russian capital and ordinary letters 8x16 pixels. Then we take a screenshot of the output line and cut it to the size of 560x19 pixels with the addition of 3 empty lines in the bottom position, and writing it in bmp format (here it is ready)

Now we need to read this bmp file line by line into one large array and then successively output small two-dimensional arrays with the resulting glyphs using fprintf () into a text file, in the format of instances of the EFI_NARROW_GLYPH structure described at the beginning of the article. Codes of Russian characters in the Russian page UCS-2 - from 0x0410 (the letter “A” is Russian) to 0x0455 (some Greek letter, however, is present in the Russian page UCS-2 ).

We will not give the code of this program here, since parsing of bmp-files is not on the topic of the article, and the volume increases greatly, so just write the output to a file (you can search the Internet for the source code of bmp parsers, there are)

Result (no need to read it, just copy and use):
{ 0x0410, 0x00, {0x00,0x00,0x00,0x30,0x78,0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}, 
{ 0x0411, 0x00, {0x00,0x00,0x00,0xfe,0x62,0x60,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0412, 0x00, {0x00,0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0413, 0x00, {0x00,0x00,0x00,0xfe,0x62,0x62,0x60,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0414, 0x00, {0x00,0x00,0x00,0x3e,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0xff,0xc3,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0415, 0x00, {0x00,0x00,0x00,0xfe,0x62,0x60,0x64,0x7c,0x64,0x60,0x62,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0416, 0x00, {0x00,0x00,0x00,0x99,0xdb,0x5a,0x7e,0x3c,0x7e,0x5a,0xdb,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0417, 0x00, {0x00,0x00,0x00,0x3c,0x66,0x46,0x06,0x1c,0x06,0x46,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0418, 0x00, {0x00,0x00,0x00,0xc6,0xc6,0xce,0xde,0xfe,0xf6,0xe6,0xc6,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0419, 0x00, {0x00,0x00,0x18,0xd6,0xf6,0xce,0xde,0xfe,0xf6,0xe6,0xc6,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041a, 0x00, {0x00,0x00,0x00,0xe6,0x66,0x6c,0x6c,0x78,0x6c,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041b, 0x00, {0x00,0x00,0x00,0x1e,0x3e,0x66,0x66,0x66,0x66,0x66,0x66,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041c, 0x00, {0x00,0x00,0x00,0xc6,0xee,0xfe,0xfe,0xd6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041d, 0x00, {0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041e, 0x00, {0x00,0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x041f, 0x00, {0x00,0x00,0x00,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0420, 0x00, {0x00,0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0421, 0x00, {0x00,0x00,0x00,0x3c,0x66,0xc6,0xc0,0xc0,0xc0,0xc6,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0422, 0x00, {0x00,0x00,0x00,0x7e,0x5a,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0423, 0x00, {0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3e,0x06,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0424, 0x00, {0x00,0x00,0x00,0x18,0x7e,0xdb,0xdb,0xdb,0xdb,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0425, 0x00, {0x00,0x00,0x00,0xcc,0xcc,0xcc,0x78,0x30,0x78,0xcc,0xcc,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0426, 0x00, {0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfe,0x06,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0427, 0x00, {0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0428, 0x00, {0x00,0x00,0x00,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0429, 0x00, {0x00,0x00,0x00,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xd6,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042a, 0x00, {0x00,0x00,0x00,0xe0,0xe0,0x60,0x60,0x7c,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042b, 0x00, {0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xf6,0xde,0xde,0xde,0xf6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042c, 0x00, {0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042d, 0x00, {0x00,0x00,0x00,0x78,0xcc,0xc6,0x06,0x1e,0x06,0xc6,0xcc,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042e, 0x00, {0x00,0x00,0x00,0xce,0xdb,0xdb,0xfb,0xfb,0xdb,0xdb,0xdb,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x042f, 0x00, {0x00,0x00,0x00,0x3f,0x66,0x66,0x66,0x3e,0x36,0x66,0x66,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0430, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x06,0x3e,0x66,0x66,0x3b,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0431, 0x00, {0x00,0x00,0x00,0x00,0x00,0x02,0x3e,0x60,0x7c,0x66,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0432, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x66,0x7c,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0433, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0434, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x36,0x36,0x36,0x36,0x7f,0x63,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0435, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x7e,0x60,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0436, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x49,0x6b,0x3e,0x3e,0x6b,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0437, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x46,0x1c,0x06,0x46,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0438, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x6e,0x7e,0x76,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0439, 0x00, {0x00,0x00,0x00,0x04,0x0c,0x08,0x66,0x66,0x6e,0x7e,0x76,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x6c,0x78,0x6c,0x64,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x1e,0x16,0x36,0x26,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x77,0x6b,0x6b,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x7e,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x043f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0440, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0x00,0x00,0x00,0x00,0x00}},
{ 0x0441, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0442, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0443, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x33,0x33,0x33,0x1f,0x03,0x33,0x1e,0x00,0x00,0x00,0x00,0x00}},
{ 0x0444, 0x00, {0x00,0x00,0x00,0x00,0x00,0x08,0x3e,0x6b,0x6b,0x6b,0x3e,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0445, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x36,0x1c,0x1c,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0446, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7f,0x03,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0447, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x3e,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0448, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0x6b,0x6b,0x6b,0x6b,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0449, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0x6b,0x6b,0x6b,0x6b,0x7f,0x01,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044a, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x3e,0x33,0x33,0xbe,0x80,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044b, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x63,0x63,0x7b,0x6f,0x6f,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044c, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x7c,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044d, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x1e,0x06,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044e, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0x7b,0x7b,0x7b,0x7b,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x044f, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x66,0x66,0x3e,0x36,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0450, 0x00, {0x00,0x00,0x6c,0xfe,0x62,0x60,0x64,0x7c,0x64,0x60,0x62,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0451, 0x00, {0x00,0x00,0x00,0x48,0x48,0x00,0x78,0xcc,0xfc,0xc0,0xcc,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0452, 0x00, {0x00,0x00,0x00,0x3c,0x66,0xc6,0xc0,0xf0,0xc0,0xc6,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0453, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x78,0xcc,0xf0,0xc0,0xcc,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0454, 0x00, {0x00,0x00,0xcc,0xcc,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0455, 0x00, {0x00,0x00,0x00,0x66,0x66,0x00,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},

The font glyphs we received. Now, to add Russian font in the UEFI BIOS, we have two ways:

1. Do everything in the right way, i.e. create a font, create a font package for this font, and then every time in a new module that requires Russian-language output, connect this package. Useful knowledge for those who make graphic applications on UEFI, where you need different size fonts for headings, text, footnotes and others. The problem is that you need this knowledge only when working with IBV, where in most cases all the necessary fonts already exist. Those. 99.9% chance that you will not need the ability to create your font package and add it to the system in the future.

2. Add Russian letters, more precisely, glyphs with them, to the sysdefault font, the benefit is the Russian code page is empty there, and when you need output in Russian - just write a sentence in Russian. Or in Ukrainian, having performed the operations below for the Ukrainian font.

Guess which of the two approaches will be chosen. Right. Copy the resulting glyphs of our font to the file where the glyphs of the English font are stored:

C:\FW\edk2\MdeModulePkg\Universal\Console\GraphicsConsoleDxe\LaffStd.c

in the array of our format:

EFI_NARROW_GLYPH gUsStdNarrowGlyphData[] = {
// Unicode glyphs from 0x20 to 0x7e are the same as ASCII characters 0x20 to 0x7e
{ 0x0020, 0x00, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{ 0x0021, 0x00, {0x00,0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00}},
...

Add the generated glyphs to this array, after the string

{ 0x00ff, 0x00, {0x00,0x00,0x00,0xC6,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00}},

In order not to forget later, let us denote the beginning and end of our insertion with comments // Russian Symbols. Actually, this is all - the codes of the Russian letters in the UnicodeWeight field of this array, naturally, do not overlap with anything, and nothing needs to be changed anywhere else.

We added, launched Rebuild (if we press the F5 debug button in Visual Studio, only our Matreshka project will be recompiled, and GraphicsConsoleDxe, from which glyphs are taken, will remain un-recompiled). If there are no compilation errors, then we launch our module for debugging and look at the results: it is quite another thing!

Small, in comparison with English, Russian font size is due to the fact that we took to copy the 16x8 font, not 19x8 - this was not. Even 18 font has a size of 18x9, which would lead to the imposition of letters on each other on the sides.

We look at the diagnosis: here is the beauty also

All characters have their own glyphs, with the exception of the last two, returning the string and carriage return, which is logical. That is, everything is working fine, we now have a Russian font in edk2 and we can freely print lines in Russian. Than now use.

HII form localization

First, the theory, the story of what is the HII - Human Interface Infrastructure.

It is better to start with a picture from a standard that describes the components of the HII system :

Consider each of the components of the system in more detail.

HID Devices - Human Interface Devices, they can be a mouse, keyboard, touchpad, trackball and more. The goal is to enter into the system information from the person who uses the system, i.e. works in UEFI BIOS.

Display Devices - on the contrary, output information from the UEFI BIOS to the user. “Display” in this context is not a “monitor”, but a “display”. In daily work, they are not needed (remember, when was the last time you entered the BIOS?). But in case of reconfigurationor debug they became necessary, because a user needs to see a response of the system on its actions during setup/debug process. So the information is printed out online to Display Devices, which can be a display, COM port, remote network connection – in such a way, for example:

EFI Global Variable Store – the same NVRAM, flash chip that contains UEFI BIOS code and also some variables, for example the disk number and partition number we use for booting.

HII Database – the whole repository for all HII information. Database is a database. Interaction with it comes not directly through I/O devices, but using corresponding drivers for these devices, through protocols (remember previous article).

Related to browser it's better to use an analogy. Forms Browser, by its meaning, is similar to client-server concept, where client is VFR – Visual Form Representation that acts as a mediator for user communication, and IFR, Internal Form Representation, plays server role, having dense binary code.

There we stop educational part, let's move to concrete things. If someone needs more explanations can look at HII UEFI standard chapters 31-33. UEFI standard is written in plain language, with large explanatory inserts. This is the only problem: it is large (2525 pages in version 2.6).

Add localization (Russian language support) to a page

So, our goal is to add Russian language support to the Front Page, i.e. add code and data that will allow us to see the display of information in Russian. Since we did not create Front Page, we will have to adjust files from another project.

Accordingly, we are now interested in the part, which is designated as Strings. Work with strings occurs through the String ID as follows:

That is, one String ID corresponds to several strings in different languages, with different characters.

The list of languages ​​supported for this project, as well as the output lines, are stored in the *.uni file, where uni means Unicode ( UCS UniCode Strings ). It looks like this:

#langdef en "English" 
#langdef es
"Spanish"
#langdef cn
"Chinese"
#string STR_HELLO_WORLD #language en
"Hello World"
#language es
"Hola Mundo"
#language cn
"您好世界"

So, when we switch keyboard layout on the  Front Page, the system assigns String ID “STR_HELLO_WORLD” string on required laguage and the string printed out to the form. It's simple.

There is one unobvious problem. No problem for MS Word or a web page to show English, Russian and Chinese symbols in one document, however, Visual Studio requires to choose only one codepage, different from English one. To avoid that problem, it is required to create "*.uni" file containing the strings for output, in an editor that supports UCS-2 Little Endian layout, Notepad++ for example. It's not a big problem in our case, because we are adding only one locale - Russian, but we need to keep the problem in mind and use editors with UCS-2 support for *.uni files editing.

Apply the theory to the practice

So, we started. Our goal now is to add on existing Front Page our localization for Russian language support.

For the start, look at what we have ate the moment. After UEFI Shell load  type exit and see at Front Page :

There are all localizations we have before the start. We also don't need French, but as soon as we are going to change complicated system project, no need to change anything except required.

First, let's avoid exit typing each time and change startup.nsh file, adding exit in its last line.

fs0: 
load Matreshka.efi
exit


Let's change the Front Page to russify it. At first, we need to alter locales list, which UiApp prints out on the page, in file

C:\FW\edk2\MdePkg\MdePkg.dec

Add in the line containing PcdUefiVariableDefaultPlatformLangCode Russian locale(ru-RU) at the end:

## Default platform supported RFC 4646 languages: (American) English & French. 
# @Prompt Default Value of PlatformLangCodes Variable.
gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes|"en;fr;en-US;fr-FR;ru-RU"|VOID*|0x0000001e

Well, then edit file

C:\FW\edk2\MdeModulePkg\Application\UiApp\FrontPageStrings.uni

Open it in Notepad++ editor, set UCS-2 BE encoding ( Encoding->UCS-2 BE in menu), and then add Russian language support #langdef ru-RU «Русский»:

#langdef en-US "English" 
#langdef fr-FR
"Français"
#langdef en
"Standard English"
#langdef fr
"Standard Français"
#langdef ru-RU
"Русский"

We haven't finished yet. We need to russify captions Select Language, Continue, Reset. Add Russian strings for corresponding tags in FrontPageStrings.uni file:

#string STR_LANGUAGE_SELECT      #language en-US "Select Language" 
#language fr-FR
"Choisir la Langue"
#language ru-RU
"Выберите язык"

#string STR_LANGUAGE_SELECT_HELP #language en-US
"This is the option one adjusts to change the language for the current system"
#language fr-FR
"Ceci est l'option que celui ajuste changer la langue pour le système actuel"
#language ru-RU
"Здесь можно изменить текущий язык системы"

#string STR_CONTINUE_PROMPT #language en-US
"Continue"
#language fr-FR
"Continuer"
#language ru-RU
"Продолжить"


#string STR_RESET_STRING #language en-US
"Reset"
#language fr-FR
"Reset"
#language ru-RU
"Сброс"


And then we nedd to add three more strings, otherwise exclamation marks will be printed out instead. For both English and French locales these STRING_IDs were replaced by spaces, however, we place spaces for STR_NULL_STRING only. We add something funny for both CPU Model and CPU Speed to avoid wasting free space in the form:

#string STR_NULL_STRING             #language en-US " "
#language fr-FR " "
#language ru-RU " "

#string STR_FRONT_PAGE_CPU_MODEL #language en-US
""
#language fr-FR
""
#language ru-RU
"Процессор вроде Pentium"

#string STR_FRONT_PAGE_CPU_SPEED #language en-US
""
#language fr-FR ""
#language ru-RU
"Частота около 100 ГГц"


That way we got "Русский" ("Russian") option when we can select Russian language:

You probably already paid you attention that out driver Matreshka tests only local language possibilites, nothing more. It doesn't add the laguage itself, we use existing UIApp project from MdePkg package and GraphicsConsoleDxe from MdeModulePkg package. Hope now you understand why it is impossible to add Russian locale on hardware platform (that already exists) without access to source code - as it was pointed in the disclaimer.

 

My original article on Russian was published on: https://habr.com/ru/post/338634/

You can send me any questions to This email address is being protected from spambots. You need JavaScript enabled to view it.

 

©2020 Nikolay Bodunov. All Rights Reserved.