aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_50/README.md
blob: 686a528ddcd22738151cca345897ab45037d325a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
In this lesson we would look at another method how your application can publish HII String packages. This time we would talk about embedding HII data in the resulting EFI file PE/COFF resources.

# Create application

As usual create new application:
```
./createNewApp.sh HIIStringsUNIRC
```

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]
  ...
  gHIIStringsUNIRCGuid = { 0x785693b4, 0x623e, 0x40fa, { 0x9a, 0x45, 0x68, 0xda, 0x38, 0x30, 0x89, 0xdd }}
```

Now modify application files to be similar to the `HIIStringsUNI` app. You'll need to create `Strings.uni` file and modify application INF and *.c file:
- `UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf`
- `UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.c`
- `UefiLessonsPkg/HIIStringsUNIRC/Strings.uni`

In the end you should have the same result as the `HIIStringsUNI` app:
```
FS0:\> HIIStringsUNIRC.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!
Best language ID=1: English
Best language ID=2: Hello!
Best language ID=3: Bye!
fr ID=3: Au revoir!
```

Now we'are ready for modifications.

# UEFI_HII_RESOURCE_SECTION

Add this to the `UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf`:
```
[Defines]
  ...
  UEFI_HII_RESOURCE_SECTION      = TRUE
```

`UEFI_HII_RESOURCE_SECTION` flag specifies whether HII resource section is generated into PE image.

Now you wouldn't be able to build our application because of the error:
```
UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.c:15:42: error: ‘HIIStringsUNIRCStrings’ undeclared (first use in this function);
```

If you'll look at the `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC/DEBUG/HIIStringsUNIRCStrDefs.h` you'll see that this file still contains string tokens, but the `HIIStringsUNIRCStrings` is no longer here:

And `AutoGen.c` file no longer contains `HIIStringsUNIRCStrings` array initialization code (`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC/DEBUG/AutoGen.c`).

Now our strings directly encoded into the special section of the resulting *.efi image.

To get them we need to search for a protocol `EFI_HII_PACKAGE_LIST_PROTOCOL` in the application `EFI_HANDLE ImageHandle`. 

Here is relevant content from UEFI specification for the `EFI_BOOT_SERVICES.LoadImage()` function which shell uses to load every program:
```
Once the image is loaded, LoadImage() installs EFI_HII_PACKAGE_LIST_PROTOCOL on the handle if
the image contains a custom PE/COFF resource with the type 'HII'. The protocol's interface pointer points
to the HII package list which is contained in the resource's data
```

The `EFI_HII_PACKAGE_LIST_PROTOCOL` is identified by the `gEfiHiiPackageListProtocolGuid` from the https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec:
```
[Protocols]
  ...
  ## Include/Protocol/HiiPackageList.h
  gEfiHiiPackageListProtocolGuid  = { 0x6a1ee763, 0xd47a, 0x43b4, {0xaa, 0xbe, 0xef, 0x1d, 0xe2, 0xab, 0x56, 0xfc}}
```

As we already have `MdeModulePkg/MdeModulePkg.dec` in the `[Packages]` section of our INF file, all we need to do is add this GUID to the `[Protocols]` section:
```
[Protocols]
  gEfiHiiPackageListProtocolGuid
```

In the code we could aquire `PackageList` protocol from the application `ImageHandle` with a help of `OpenProtocol` UEFI boot service:
```
...

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS Status;
  EFI_HII_PACKAGE_LIST_HEADER *PackageList;
  //
  // Retrieve HII package list from ImageHandle.
  //
  Status = gBS->OpenProtocol (
                  ImageHandle,
                  &gEfiHiiPackageListProtocolGuid,
                  (VOID **)&PackageList,
                  ImageHandle,
                  NULL,
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
                  );
  if (EFI_ERROR (Status)) {
    Print(L"Error! Can't open EFI_HII_PACKAGE_LIST_PROTOCOL\n");
    return Status;
  }
  ...
```

The resulting `PackageList` is not only String packages with some size header from the `StrGather` script like in was in the case of `HIIStringsUNI` application. It is an ordinary Package list like the one that we've manually constructed in our `HIIStringsC` application.
So instead of using `HiiAddPackages` library function we need to use `EFI_HII_DATABASE_PROTOCOL.NewPackageList()` directly:
```
EFI_HII_HANDLE Handle;
Status = gHiiDatabase->NewPackageList(gHiiDatabase, PackageList, NULL, &Handle);
if (EFI_ERROR(Status))
{
  Print(L"Can't register HII Package list %g, status = %r\n", gHIIStringsUNIRCGuid, Status);
  return Status;
}
```

Here I've used `gHiiDatabase`, so don't forget to add necessary header ```#include <Library/UefiHiiServicesLib.h>```and add `UefiHiiServicesLib` to the Library classes in the application INF file:
```
[LibraryClasses]
  ...
  UefiHiiServicesLib
```

Now you can build and verify that everything is ok:
```
FS0:\> HIIStringsUNIRC.efi
Status = Success
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!
Best language ID=1: English
Best language ID=2: Hello!
Best language ID=3: Bye!
fr ID=3: Au revoir!
```

# PE/COFF resource with the type 'HII'

Let's use `objdump` utility to look at the application headers. You can output content of all headers with the `-x` option:
```
objdump -x  Build/UefiLessonsPkg/RELEASE_GCC5/X64/HIIStringsUNIRC.efi
```

Pay attention to these things:
```
...

The Data Directory
Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 0000000000000000 00000000 Import Directory [parts of .idata]
Entry 2 00000000000023c0 00000180 Resource Directory [.rsrc]                <---------- Resource Directory has data
Entry 3 0000000000000000 00000000 Exception Directory [.pdata]
Entry 4 0000000000000000 00000000 Security Directory
Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000000022cc 0000001c Debug Directory
Entry 7 0000000000000000 00000000 Description Directory
Entry 8 0000000000000000 00000000 Special Directory
Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls]
Entry a 0000000000000000 00000000 Load Configuration Directory
Entry b 0000000000000000 00000000 Bound Import Directory
Entry c 0000000000000000 00000000 Import Address Table Directory
Entry d 0000000000000000 00000000 Delay Import Directory
Entry e 0000000000000000 00000000 CLR Runtime Header
Entry f 0000000000000000 00000000 Reserved

...

The .rsrc Resource Directory section:
000  Type Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
010   Entry: name: [val: 80000048 len 3]: HII, Value: 0x80000018           <--------- Data has type HII
018    Name Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
028     Entry: name: [val: 80000050 len 3]: EFI, Value: 0x80000030
030      Language Table: Char: 0, Time: 00000000, Ver: 0/0, Num Names: 1, IDs: 0
040       Entry: name: [val: 80000058 len 3]: BIN, Value: 0x000060
060        Leaf: Addr: 0x002430, Size: 0x0000ea, Codepage: 0
 String table starts at offset: 0x48
 Resources start at offset: 0x70

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00001fc0  0000000000000240  0000000000000240  00000240  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         000001c0  0000000000002200  0000000000002200  00002200  2**4
                  CONTENTS, ALLOC, LOAD, DATA
  2 .rsrc         00000180  00000000000023c0  00000000000023c0  000023c0  2**2       <----- .rsrc is displayed here as well
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
SYMBOL TABLE:
no symbols
```

Now comment `UEFI_HII_RESOURCE_SECTION` in the `UefiLessonsPkg/HIIStringsUNIRC/HIIStringsUNIRC.inf`:
```
[Defines]
  ...
  #UEFI_HII_RESOURCE_SECTION      = TRUE
```
Build application and execute `objdump` once again:
```
...

The Data Directory
Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
Entry 1 0000000000000000 00000000 Import Directory [parts of .idata]
Entry 2 0000000000000000 00000000 Resource Directory [.rsrc]                 <----- Resource directory is empty
Entry 3 0000000000000000 00000000 Exception Directory [.pdata]
Entry 4 0000000000000000 00000000 Security Directory
Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc]
Entry 6 00000000000022cc 0000001c Debug Directory
Entry 7 0000000000000000 00000000 Description Directory
Entry 8 0000000000000000 00000000 Special Directory
Entry 9 0000000000000000 00000000 Thread Storage Directory [.tls]
Entry a 0000000000000000 00000000 Load Configuration Directory
Entry b 0000000000000000 00000000 Bound Import Directory
Entry c 0000000000000000 00000000 Import Address Table Directory
Entry d 0000000000000000 00000000 Delay Import Directory
Entry e 0000000000000000 00000000 CLR Runtime Header
Entry f 0000000000000000 00000000 Reserved

...                                                                          <----- No .rsrc Resource Directory section

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00001fc0  0000000000000240  0000000000000240  00000240  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         000001c0  0000000000002200  0000000000002200  00002200  2**4   <---- No .rsrc section here as well
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
no symbols
```

If you try to execute this version of our application you would get:
```
FS0:\> HIIStringsUNIRC.efi
Error! Can't open EFI_HII_PACKAGE_LIST_PROTOCOL
```