aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_44/README.md
blob: c62d099539139d6aaaad02509f847ba0cf5aa83d (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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
In this lesson we would explore some internals behind the HII database.

First of all let's look at the main structure of the HII database:

https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h
```
typedef struct _HII_DATABASE_PRIVATE_DATA {
  UINTN                                 Signature;
  LIST_ENTRY                            DatabaseList;
  LIST_ENTRY                            DatabaseNotifyList;
  EFI_HII_FONT_PROTOCOL                 HiiFont;
  EFI_HII_IMAGE_PROTOCOL                HiiImage;
  EFI_HII_IMAGE_EX_PROTOCOL             HiiImageEx;
  EFI_HII_STRING_PROTOCOL               HiiString;
  EFI_HII_DATABASE_PROTOCOL             HiiDatabase;
  EFI_HII_CONFIG_ROUTING_PROTOCOL       ConfigRouting;
  EFI_CONFIG_KEYWORD_HANDLER_PROTOCOL   ConfigKeywordHandler;
  LIST_ENTRY                            HiiHandleList;
  INTN                                  HiiHandleCount;
  LIST_ENTRY                            FontInfoList;
  UINTN                                 Attribute;
  EFI_GUID                              CurrentLayoutGuid;
  EFI_HII_KEYBOARD_LAYOUT               *CurrentLayout;
} HII_DATABASE_PRIVATE_DATA;
```

This structure contains pointers to the main HII protocols. Each of these protocols is responsible for interactons with different parts of HII. For example one is responsible for interaction with fonts in the HII database (`EFI_HII_FONT_PROTOCOL`), another one for interaction with images (`EFI_HII_IMAGE_PROTOCOL`/`EFI_HII_IMAGE_EX_PROTOCOL`) and another one for interaction with strings (`EFI_HII_STRING_PROTOCOL`).
We've already glimpsed at the `EFI_HII_DATABASE_PROTOCOL` that is responsible for adding/removing HII packages to/from the databse.
We will investigate possibilities of this protocols more as we would go through different HII elements.

Besides the protocols this structure maintains a set of double linked list to different elements.
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h:
```
///
/// LIST_ENTRY structure definition.
///
typedef struct _LIST_ENTRY LIST_ENTRY;

///
/// _LIST_ENTRY structure definition.
///
struct _LIST_ENTRY {
  LIST_ENTRY  *ForwardLink;
  LIST_ENTRY  *BackLink;
};
```
Among these lists there is a double linked list to database records ```LIST_ENTRY DatabaseList```.
You can look at the definition of a database record at the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h:
```
#define HII_DATABASE_RECORD_SIGNATURE   SIGNATURE_32 ('h','i','d','r')

typedef struct _HII_DATABASE_RECORD {
  UINTN                                 Signature;
  HII_DATABASE_PACKAGE_LIST_INSTANCE    *PackageList;
  EFI_HANDLE                            DriverHandle;
  EFI_HII_HANDLE                        Handle;
  LIST_ENTRY                            DatabaseEntry;
} HII_DATABASE_RECORD;
```
`LIST_ENTRY DatabaseList` points to the `DatabaseEntry` field in the first `HII_DATABASE_RECORD`. `DatabaseEntry` in this structure in turn points to the `DatabaseEntry` field in the next `HII_DATABASE_RECORD` and so on.

Each database record have a `HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList` field, let's look at this definition (https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h):
```
typedef struct _HII_DATABASE_PACKAGE_LIST_INSTANCE {
  EFI_HII_PACKAGE_LIST_HEADER           PackageListHdr;
  LIST_ENTRY                            GuidPkgHdr;
  LIST_ENTRY                            FormPkgHdr;
  LIST_ENTRY                            KeyboardLayoutHdr;
  LIST_ENTRY                            StringPkgHdr;
  LIST_ENTRY                            FontPkgHdr;
  HII_IMAGE_PACKAGE_INSTANCE            *ImagePkg;
  LIST_ENTRY                            SimpleFontPkgHdr;
  UINT8                                 *DevicePathPkg;
} HII_DATABASE_PACKAGE_LIST_INSTANCE;
```
Each of these double linked list contains pointers to packages of corresponding type present in this package list.
In the previous lesson we've recieved all the package lists and its packages as a continious data array, but this was only a handy feature of the `ExportPackageLists` function from the `EFI_HII_DATABASE_PROTOCOL`. As you can see now in a reality HII data is represented in a double linked lists that could be sparsed all over the platform memory.

Another important field that is present in the `HII_DATABASE_RECORD` is a `EFI_HII_HANDLE Handle`. Each `HII_DATABASE_RECORD` defines a package list and is identified by this `EFI_HII_HANDLE`. According to the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiInternalFormRepresentation.h it is:
```
typedef VOID*   EFI_HII_HANDLE;
```
But if you look to the implementation of the `GenerateHiiDatabaseRecord` function in the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/Database.c you could see the actual implementation of the HII handle:
```
EFI_STATUS
GenerateHiiDatabaseRecord (
  IN  HII_DATABASE_PRIVATE_DATA *Private,
  OUT HII_DATABASE_RECORD       **DatabaseNode
  )
{
 ...
 HII_HANDLE                         *HiiHandle;
 HII_DATABASE_RECORD                *DatabaseRecord;
 ...
 DatabaseRecord->Handle = (EFI_HII_HANDLE) HiiHandle;
 ...
} 
```
The type `HII_HANDLE` is defined in the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabase.h:
```
#define HII_HANDLE_SIGNATURE            SIGNATURE_32 ('h','i','h','l')

typedef struct {
  UINTN               Signature;
  LIST_ENTRY          Handle;
  UINTN               Key;
} HII_HANDLE;
```

The `Key` field here corresponds to the current value of the `HiiHandleCount` field in the main `HII_DATABASE_PRIVATE_DATA`.

And the `LIST_ENTRY Handle` helps to connect all the `HII_HANDLEs` in the system together. The important point to note that the `LIST_ENTRY HiiHandleList` field in the main `HII_DATABASE_PRIVATE_DATA` is the same handle list.


# HII database initialization

This HII database structure has static initializiation in the `HiiDatabaseDxe` (https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseEntry.c):
```
HII_DATABASE_PRIVATE_DATA mPrivate = {
  HII_DATABASE_PRIVATE_DATA_SIGNATURE,
  {
    (LIST_ENTRY *) NULL,
    (LIST_ENTRY *) NULL
  },
  {
    (LIST_ENTRY *) NULL,
    (LIST_ENTRY *) NULL
  },
  {
    HiiStringToImage,
    HiiStringIdToImage,
    HiiGetGlyph,
    HiiGetFontInfo
  },
  {
    HiiNewImage,
    HiiGetImage,
    HiiSetImage,
    HiiDrawImage,
    HiiDrawImageId
  },
  {
    HiiNewImageEx,
    HiiGetImageEx,
    HiiSetImageEx,
    HiiDrawImageEx,
    HiiDrawImageIdEx,
    HiiGetImageInfo
  },
  {
    HiiNewString,
    HiiGetString,
    HiiSetString,
    HiiGetLanguages,
    HiiGetSecondaryLanguages
  },
  {
    HiiNewPackageList,
    HiiRemovePackageList,
    HiiUpdatePackageList,
    HiiListPackageLists,
    HiiExportPackageLists,
    HiiRegisterPackageNotify,
    HiiUnregisterPackageNotify,
    HiiFindKeyboardLayouts,
    HiiGetKeyboardLayout,
    HiiSetKeyboardLayout,
    HiiGetPackageListHandle
  },
  {
    HiiConfigRoutingExtractConfig,
    HiiConfigRoutingExportConfig,
    HiiConfigRoutingRouteConfig,
    HiiBlockToConfig,
    HiiConfigToBlock,
    HiiGetAltCfg
  },
  {
    EfiConfigKeywordHandlerSetData,
    EfiConfigKeywordHandlerGetData
  },
  {
    (LIST_ENTRY *) NULL,
    (LIST_ENTRY *) NULL
  },
  0,
  {
    (LIST_ENTRY *) NULL,
    (LIST_ENTRY *) NULL
  },
  EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK),
  {
    0x00000000,
    0x0000,
    0x0000,
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  },
  NULL
};
```

In the `HiiDatabaseDxe` driver entry point it initializes linked lists (`LIST_ENTRY`) and installs all the protocols from the HII database to the system:

```
EFI_STATUS
EFIAPI
InitializeHiiDatabase (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS                             Status;
  EFI_HANDLE                             Handle;
  ...
  InitializeListHead (&mPrivate.DatabaseList);
  InitializeListHead (&mPrivate.DatabaseNotifyList);
  InitializeListHead (&mPrivate.HiiHandleList);
  InitializeListHead (&mPrivate.FontInfoList);
  ...
  Handle = NULL;
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &Handle,
                  &gEfiHiiFontProtocolGuid,
                  &mPrivate.HiiFont,
                  &gEfiHiiStringProtocolGuid,
                  &mPrivate.HiiString,
                  &gEfiHiiDatabaseProtocolGuid,
                  &mPrivate.HiiDatabase,
                  &gEfiHiiConfigRoutingProtocolGuid,
                  &mPrivate.ConfigRouting,
                  &gEfiConfigKeywordHandlerProtocolGuid,
                  &mPrivate.ConfigKeywordHandler,
                  NULL
                  );
  ...
  if (FeaturePcdGet (PcdSupportHiiImageProtocol)) {
    Status = gBS->InstallMultipleProtocolInterfaces (
                    &Handle,
                    &gEfiHiiImageProtocolGuid, &mPrivate.HiiImage,
                    &gEfiHiiImageExProtocolGuid, &mPrivate.HiiImageEx,
                    NULL
                    );

  }
  ...
}
```
_____________________________________

# Linked lists pointers

Just in case here is some preprocessor magic that helps to get pointer to a structure by a pointer to its field.

It is easy to get pointer to `HII_DATABASE_RECORD` by the pointer to its field `DatabaseEntry` with a help of `CR` macro:
```
LIST_ENTRY* Link;
HII_DATABASE_RECORD* DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
```
In case you wonder definition for the CR macro can be found
https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DebugLib.h
```
  @param  Record         The pointer to the field specified by Field within a data
                         structure of type TYPE.

  @param  TYPE           The name of the data structure type to return  This
                         data structure must contain the field specified by Field.

  @param  Field          The name of the field in the data structure specified
                         by TYPE to which Record points.

  @param  TestSignature  The 32-bit signature value to match.

**/
#if !defined(MDEPKG_NDEBUG)
  #define CR(Record, TYPE, Field, TestSignature)                                              \
    (DebugAssertEnabled () && (BASE_CR (Record, TYPE, Field)->Signature != TestSignature)) ?  \
    (TYPE *) (_ASSERT (CR has Bad Signature), Record) :                                       \
    BASE_CR (Record, TYPE, Field)
#else
  #define CR(Record, TYPE, Field, TestSignature)                                              \
    BASE_CR (Record, TYPE, Field)
#endif
```
And the definition for `BASE_CR` is placed under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h:
```
/**
  Macro that returns a pointer to the data structure that contains a specified field of
  that data structure.  This is a lightweight method to hide information by placing a
  public data structure inside a larger private data structure and using a pointer to
  the public data structure to retrieve a pointer to the private data structure.
  This function computes the offset, in bytes, of field specified by Field from the beginning
  of the  data structure specified by TYPE.  This offset is subtracted from Record, and is
  used to return a pointer to a data structure of the type specified by TYPE. If the data type
  specified by TYPE does not contain the field specified by Field, then the module will not compile.
  @param   Record   Pointer to the field specified by Field within a data structure of type TYPE.
  @param   TYPE     The name of the data structure type to return.  This data structure must
                    contain the field specified by Field.
  @param   Field    The name of the field in the data structure specified by TYPE to which Record points.
  @return  A pointer to the structure from one of it's elements.
**/
#define BASE_CR(Record, TYPE, Field)  ((TYPE *) ((CHAR8 *) (Record) - OFFSET_OF (TYPE, Field)))
```
```
/**
  The macro that returns the byte offset of a field in a data structure.
  This function returns the offset, in bytes, of field specified by Field from the
  beginning of the  data structure specified by TYPE. If TYPE does not contain Field,
  the module will not compile.
  @param   TYPE     The name of the data structure that contains the field specified by Field.
  @param   Field    The name of the field in the data structure.
  @return  Offset, in bytes, of field.
**/
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
#define OFFSET_OF(TYPE, Field) ((UINTN) __builtin_offsetof(TYPE, Field))
#endif

#ifndef OFFSET_OF
#define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field))
#endif
```