3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This file contains the package processing code to the HII database.
23 #include "HiiDatabase.h"
29 OUT UINT32
*NumberOfTokens
34 Determines the passed in Pack's size and returns the value.
42 EFI_HII_STRING_PACK
*StringPack
;
49 if (!CompareMem (&((EFI_HII_PACK_HEADER
*) Pack
)->Type
, &Type
, sizeof (UINT16
))) {
51 // The header contains the full IFR length
53 CopyMem (&Length
, &((EFI_HII_PACK_HEADER
*) Pack
)->Length
, sizeof (Length
));
54 *PackSize
= (UINTN
) Length
;
58 Type
= EFI_HII_STRING
;
59 if (!CompareMem (&((EFI_HII_PACK_HEADER
*) Pack
)->Type
, &Type
, sizeof (UINT16
))) {
61 // The header contains the STRING package length
62 // The assumption is that the strings for all languages
63 // are a contiguous block of data and there is a series of
64 // these package instances which will terminate with a NULL package
67 StringPack
= (EFI_HII_STRING_PACK
*) Pack
;
70 // There may be multiple instances packed together of strings
71 // so we must walk the self describing structures until we encounter
72 // the NULL structure to determine the full size.
74 CopyMem (&Length
, &StringPack
->Header
.Length
, sizeof (Length
));
75 if (NumberOfTokens
!= NULL
) {
76 CopyMem (NumberOfTokens
, &StringPack
->NumStringPointers
, sizeof (UINT32
));
80 *PackSize
= *PackSize
+ Length
;
81 StringPack
= (EFI_HII_STRING_PACK
*) ((CHAR8
*) StringPack
+ Length
);
82 CopyMem (&Length
, &StringPack
->Header
.Length
, sizeof (Length
));
85 // Encountered a length of 0, so let's add the space for the NULL terminator
86 // pack's length and call it done.
88 *PackSize
= *PackSize
+ sizeof (EFI_HII_STRING_PACK
);
92 // We only determine the size of the non-global Package types.
93 // If neither IFR or STRING data were found, return an error
100 IN EFI_HII_PROTOCOL
*This
,
101 IN EFI_HII_PACKAGE_INSTANCE
*PackageInstance
,
102 OUT EFI_HII_PACKAGE_INSTANCE
**StringPackageInstance
,
103 OUT UINT32
*TotalStringCount
108 Verifies that the package instance is using the correct handle for string operations.
116 EFI_HII_DATA
*HiiData
;
117 EFI_HII_HANDLE_DATABASE
*HandleDatabase
;
118 EFI_HII_PACKAGE_INSTANCE
*HandlePackageInstance
;
121 EFI_HII_IFR_PACK
*FormPack
;
125 return EFI_INVALID_PARAMETER
;
128 HiiData
= EFI_HII_DATA_FROM_THIS (This
);
130 HandleDatabase
= HiiData
->DatabaseHead
;
131 ZeroMem (&Guid
, sizeof (EFI_GUID
));
133 *StringPackageInstance
= PackageInstance
;
136 // Based on if there is IFR data in this package instance, determine
137 // what the location is of the beginning of the string data.
139 if (PackageInstance
->IfrSize
> 0) {
140 FormPack
= (EFI_HII_IFR_PACK
*) ((CHAR8
*) (&PackageInstance
->IfrData
) + sizeof (EFI_HII_PACK_HEADER
));
143 // If there is no IFR data assume the caller knows what they are doing.
148 RawData
= (UINT8
*) FormPack
;
150 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
151 if (RawData
[Index
] == EFI_IFR_FORM_SET_OP
) {
153 // Cache the guid for this formset
155 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) &RawData
[Index
])->Guid
, sizeof (EFI_GUID
));
159 Index
= RawData
[Index
+ 1] + Index
;
162 // If there is no string package, and the PackageInstance->IfrPack.Guid and PackageInstance->Guid are
163 // different, we should return the correct handle for the caller to use for strings.
165 if ((PackageInstance
->StringSize
== 0) && (!CompareGuid (&Guid
, &PackageInstance
->Guid
))) {
167 // Search the database for a handle that matches the PackageInstance->Guid
169 for (; HandleDatabase
!= NULL
; HandleDatabase
= HandleDatabase
->NextHandleDatabase
) {
171 // Get Ifrdata and extract the Guid for it
173 HandlePackageInstance
= HandleDatabase
->Buffer
;
175 ASSERT (HandlePackageInstance
->IfrSize
!= 0);
177 FormPack
= (EFI_HII_IFR_PACK
*) ((CHAR8
*) (&HandlePackageInstance
->IfrData
) + sizeof (EFI_HII_PACK_HEADER
));
178 RawData
= (UINT8
*) FormPack
;
180 for (Index
= 0; RawData
[Index
] != EFI_IFR_END_FORM_SET_OP
;) {
181 if (RawData
[Index
] == EFI_IFR_FORM_SET_OP
) {
183 // Cache the guid for this formset
185 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) &RawData
[Index
])->Guid
, sizeof (EFI_GUID
));
189 Index
= RawData
[Index
+ 1] + Index
;
192 // If the Guid from the new handle matches the original Guid referenced in the original package data
193 // return the appropriate package instance data to use.
195 if (CompareGuid (&Guid
, &PackageInstance
->Guid
)) {
196 if (TotalStringCount
!= NULL
) {
197 *TotalStringCount
= HandleDatabase
->NumberOfTokens
;
200 *StringPackageInstance
= HandlePackageInstance
;
216 IN EFI_HII_PROTOCOL
*This
,
217 IN EFI_HII_PACKAGES
*Packages
,
218 OUT EFI_HII_HANDLE
*Handle
224 Extracts the various packs from a package list.
228 This - Pointer of HII protocol.
229 Packages - Pointer of HII packages.
230 Handle - Handle value to be returned.
234 EFI_SUCCESS - Pacakges has added to HII database successfully.
235 EFI_INVALID_PARAMETER - Invalid parameter.
239 EFI_HII_PACKAGE_INSTANCE
*PackageInstance
;
240 EFI_HII_DATA
*HiiData
;
241 EFI_HII_HANDLE_DATABASE
*HandleDatabase
;
242 EFI_HII_HANDLE_DATABASE
*Database
;
243 EFI_HII_PACK_HEADER
*PackageHeader
;
244 EFI_HII_GLOBAL_DATA
*GlobalData
;
245 EFI_HII_IFR_PACK
*IfrPack
;
246 EFI_HII_STRING_PACK
*StringPack
;
247 EFI_HII_FONT_PACK
*FontPack
;
248 EFI_HII_KEYBOARD_PACK
*KeyboardPack
;
252 UINTN TotalStringSize
;
258 EFI_FORM_SET_STUB FormSetStub
;
261 UINT16 NumWideGlyphs
;
262 UINT16 NumNarrowGlyphs
;
263 UINT32 NumberOfTokens
;
264 UINT32 TotalTokenNumber
;
266 EFI_NARROW_GLYPH
*NarrowGlyph
;
267 EFI_WIDE_GLYPH
*WideGlyph
;
269 if (Packages
->NumberOfPackages
== 0 || This
== NULL
) {
270 return EFI_INVALID_PARAMETER
;
273 HiiData
= EFI_HII_DATA_FROM_THIS (This
);
275 GlobalData
= HiiData
->GlobalData
;
277 Database
= HiiData
->DatabaseHead
;
279 PackageInstance
= NULL
;
287 TotalTokenNumber
= 0;
290 // Search through the passed in Packages for the IfrPack and any StringPack.
292 for (Index
= 0; Index
< Packages
->NumberOfPackages
; Index
++) {
294 PackageHeader
= *(EFI_HII_PACK_HEADER
**) (((UINT8
*) Packages
) + sizeof (EFI_HII_PACKAGES
) + Index
* sizeof (VOID
*));
296 switch (PackageHeader
->Type
) {
299 // There shoule be only one Ifr package.
301 ASSERT (IfrPack
== NULL
);
302 IfrPack
= (EFI_HII_IFR_PACK
*) PackageHeader
;
306 StringPack
= (EFI_HII_STRING_PACK
*) PackageHeader
;
308 // Sending me a String Package. Get its size.
310 Status
= GetPackSize ((VOID
*) StringPack
, &StringSize
, &NumberOfTokens
);
311 ASSERT (!EFI_ERROR (Status
));
314 // The size which GetPackSize() returns include the null terminator. So if multiple
315 // string packages are passed in, merge all these packages, and only pad one null terminator.
317 if (TotalStringSize
> 0) {
318 TotalStringSize
-= sizeof (EFI_HII_STRING_PACK
);
321 TotalStringSize
+= StringSize
;
322 TotalTokenNumber
+= NumberOfTokens
;
327 // If sending a StringPack without an IfrPack, you must include a GuidId
329 if ((StringPack
!= NULL
) && (IfrPack
== NULL
)) {
330 if (Packages
->GuidId
== NULL
) {
331 return EFI_INVALID_PARAMETER
;
335 // If passing in an IfrPack and a GuidId is provided, ensure they are the same value.
337 if ((IfrPack
!= NULL
) && (Packages
->GuidId
!= NULL
)) {
338 Location
= ((UINT8
*) IfrPack
);
339 Location
= (UINT8
*) (((UINTN
) Location
) + sizeof (EFI_HII_PACK_HEADER
));
342 // Advance to the Form Set Op-code
344 for (Count
= 0; ((EFI_IFR_OP_HEADER
*) &Location
[Count
])->OpCode
!= EFI_IFR_FORM_SET_OP
;) {
345 Count
= Count
+ ((EFI_IFR_OP_HEADER
*) &Location
[Count
])->Length
;
348 // Copy to local variable
350 CopyMem (&Guid
, &((EFI_IFR_FORM_SET
*) &Location
[Count
])->Guid
, sizeof (EFI_GUID
));
353 // Check to see if IfrPack->Guid != GuidId
355 if (!CompareGuid (&Guid
, Packages
->GuidId
)) {
357 // If a string package is present, the GUIDs should have agreed. Return an error
359 if (StringPack
!= NULL
) {
360 return EFI_INVALID_PARAMETER
;
365 // If someone is passing in a string only, create a dummy IfrPack with a Guid
366 // to enable future searching of this data.
368 if ((IfrPack
== NULL
) && (StringPack
!= NULL
)) {
369 ZeroMem (&FormSetStub
, sizeof (FormSetStub
));
371 FormSetStub
.Header
.Type
= EFI_HII_IFR
;
372 FormSetStub
.Header
.Length
= sizeof (EFI_FORM_SET_STUB
);
374 FormSetStub
.FormSet
.Header
.OpCode
= EFI_IFR_FORM_SET_OP
;
375 FormSetStub
.FormSet
.Header
.Length
= (UINT8
) sizeof (EFI_IFR_FORM_SET
);
379 FormSetStub
.FormSet
.FormSetTitle
= 0x02;
380 CopyMem (&FormSetStub
.FormSet
.Guid
, Packages
->GuidId
, sizeof (EFI_GUID
));
382 FormSetStub
.EndFormSet
.Header
.OpCode
= EFI_IFR_END_FORM_SET_OP
;
383 FormSetStub
.EndFormSet
.Header
.Length
= (UINT8
) sizeof (EFI_IFR_END_FORM_SET
);
384 IfrPack
= (EFI_HII_IFR_PACK
*) &FormSetStub
;
387 if (IfrPack
!= NULL
) {
389 // Sending me an IFR Package. Get its size.
391 Status
= GetPackSize ((VOID
*) IfrPack
, &IfrSize
, NULL
);
392 ASSERT (!EFI_ERROR (Status
));
395 // Prepare the internal package instace buffer to store package data.
397 InstanceSize
= IfrSize
+ TotalStringSize
;
399 if (InstanceSize
!= 0) {
400 PackageInstance
= AllocateZeroPool (InstanceSize
+ sizeof (EFI_HII_PACKAGE_INSTANCE
));
402 ASSERT (PackageInstance
);
405 // If there is no DatabaseHead allocated - allocate one
407 if (HiiData
->DatabaseHead
== NULL
) {
408 HiiData
->DatabaseHead
= AllocateZeroPool (sizeof (EFI_HII_HANDLE_DATABASE
));
409 ASSERT (HiiData
->DatabaseHead
);
412 // If the head is being used (Handle is non-zero), allocate next Database and
413 // add it to the linked-list
415 if (HiiData
->DatabaseHead
->Handle
!= 0) {
416 HandleDatabase
= AllocateZeroPool (sizeof (EFI_HII_HANDLE_DATABASE
));
418 ASSERT (HandleDatabase
);
420 for (; Database
->NextHandleDatabase
!= NULL
; Database
= Database
->NextHandleDatabase
)
424 // We are sitting on the Database entry which contains the null Next pointer. Fix it.
426 Database
->NextHandleDatabase
= HandleDatabase
;
430 Database
= HiiData
->DatabaseHead
;
433 // Initialize this instance data
435 for (*Handle
= 1; Database
->NextHandleDatabase
!= NULL
; Database
= Database
->NextHandleDatabase
) {
437 // Since the first Database instance will have a passed back handle of 1, we will continue
438 // down the linked list of entries until we encounter the end of the linked list. Each time
439 // we go down one level deeper, increment the handle value that will be passed back.
441 if (Database
->Handle
>= *Handle
) {
442 *Handle
= Database
->Handle
+ 1;
446 PackageInstance
->Handle
= *Handle
;
447 PackageInstance
->IfrSize
= IfrSize
;
448 PackageInstance
->StringSize
= TotalStringSize
;
449 if (Packages
->GuidId
!= NULL
) {
450 CopyMem (&PackageInstance
->Guid
, Packages
->GuidId
, sizeof (EFI_GUID
));
453 Database
->Buffer
= PackageInstance
;
454 Database
->Handle
= PackageInstance
->Handle
;
455 Database
->NumberOfTokens
= TotalTokenNumber
;
456 Database
->NextHandleDatabase
= NULL
;
459 // Copy the Ifr package data into package instance.
462 CopyMem (&PackageInstance
->IfrData
, IfrPack
, IfrSize
);
465 // Main loop to store package data into HII database.
470 for (Index
= 0; Index
< Packages
->NumberOfPackages
; Index
++) {
472 PackageHeader
= *(EFI_HII_PACK_HEADER
**) (((UINT8
*) Packages
) + sizeof (EFI_HII_PACKAGES
) + Index
* sizeof (VOID
*));
474 switch (PackageHeader
->Type
) {
476 StringPack
= (EFI_HII_STRING_PACK
*) PackageHeader
;
478 // The size which GetPackSize() returns include the null terminator. So if multiple
479 // string packages are passed in, merge all these packages, and only pad one null terminator.
481 if (TotalStringSize
> 0) {
482 TotalStringSize
-= sizeof (EFI_HII_STRING_PACK
);
485 GetPackSize ((VOID
*) StringPack
, &StringSize
, &NumberOfTokens
);
486 CopyMem ((CHAR8
*) (&PackageInstance
->IfrData
) + IfrSize
+ TotalStringSize
, StringPack
, StringSize
);
488 TotalStringSize
+= StringSize
;
491 case EFI_HII_HANDLES
:
492 CopyMem (&PackageInstance
->HandlePack
, PackageHeader
, sizeof (EFI_HII_HANDLE_PACK
));
496 FontPack
= (EFI_HII_FONT_PACK
*) PackageHeader
;
498 // Add whatever narrow glyphs were passed to us if undefined
500 CopyMem (&NumNarrowGlyphs
, &FontPack
->NumberOfNarrowGlyphs
, sizeof (UINT16
));
501 for (Count
= 0; Count
<= NumNarrowGlyphs
; Count
++) {
502 Local
= (UINT8
*) (&FontPack
->NumberOfWideGlyphs
+ sizeof (UINT8
)) + (sizeof (EFI_NARROW_GLYPH
)) * Count
;
503 NarrowGlyph
= (EFI_NARROW_GLYPH
*) Local
;
504 CopyMem (&Member
, &NarrowGlyph
->UnicodeWeight
, sizeof (UINT16
));
506 // If the glyph is already defined, do not overwrite it. It is what it is.
508 CopyMem (&Unicode
, &GlobalData
->NarrowGlyphs
[Member
].UnicodeWeight
, sizeof (UINT16
));
510 CopyMem (&GlobalData
->NarrowGlyphs
[Member
], Local
, sizeof (EFI_NARROW_GLYPH
));
514 // Add whatever wide glyphs were passed to us if undefined
516 CopyMem (&NumWideGlyphs
, &FontPack
->NumberOfWideGlyphs
, sizeof (UINT16
));
517 for (Count
= 0; Count
<= NumWideGlyphs
; Count
++) {
518 Local
= (UINT8
*) (&FontPack
->NumberOfWideGlyphs
+ sizeof (UINT8
)) +
519 (sizeof (EFI_NARROW_GLYPH
)) *
521 WideGlyph
= (EFI_WIDE_GLYPH
*) Local
;
524 (UINTN
*) (Local
+ sizeof (EFI_WIDE_GLYPH
) * Count
),
528 // If the glyph is already defined, do not overwrite it. It is what it is.
530 CopyMem (&Unicode
, &GlobalData
->WideGlyphs
[Member
].UnicodeWeight
, sizeof (UINT16
));
532 Local
= (UINT8
*)(&FontPack
->NumberOfWideGlyphs
+ sizeof(UINT8
)) + (sizeof(EFI_NARROW_GLYPH
)) * NumNarrowGlyphs
;
533 WideGlyph
= (EFI_WIDE_GLYPH
*) Local
;
535 &GlobalData
->WideGlyphs
[Member
],
536 (UINTN
*) (Local
+ sizeof (EFI_WIDE_GLYPH
) * Count
),
537 sizeof (EFI_WIDE_GLYPH
)
543 case EFI_HII_KEYBOARD
:
544 KeyboardPack
= (EFI_HII_KEYBOARD_PACK
*) PackageHeader
;
546 // Sending me a Keyboard Package
548 if (KeyboardPack
->DescriptorCount
> 105) {
549 return EFI_INVALID_PARAMETER
;
552 // If someone updates the Descriptors with a count of 0, blow aware the overrides.
554 if (KeyboardPack
->DescriptorCount
== 0) {
555 ZeroMem (GlobalData
->OverrideKeyboardLayout
, sizeof (EFI_KEY_DESCRIPTOR
) * 106);
558 if (KeyboardPack
->DescriptorCount
< 106 && KeyboardPack
->DescriptorCount
> 0) {
560 // If SystemKeyboard was updated already, then steer changes to the override database
562 if (GlobalData
->SystemKeyboardUpdate
) {
563 ZeroMem (GlobalData
->OverrideKeyboardLayout
, sizeof (EFI_KEY_DESCRIPTOR
) * 106);
564 for (Count
= 0; Count
< KeyboardPack
->DescriptorCount
; Count
++) {
565 CopyMem (&Member
, &KeyboardPack
->Descriptor
[Count
].Key
, sizeof (UINT16
));
567 &GlobalData
->OverrideKeyboardLayout
[Member
],
568 &KeyboardPack
->Descriptor
[Count
],
569 sizeof (EFI_KEY_DESCRIPTOR
)
574 // SystemKeyboard was never updated, so this is likely the keyboard driver setting the System database.
576 ZeroMem (GlobalData
->SystemKeyboardLayout
, sizeof (EFI_KEY_DESCRIPTOR
) * 106);
577 for (Count
= 0; Count
< KeyboardPack
->DescriptorCount
; Count
++) {
578 CopyMem (&Member
, &KeyboardPack
->Descriptor
->Key
, sizeof (UINT16
));
580 &GlobalData
->SystemKeyboardLayout
[Member
],
581 &KeyboardPack
->Descriptor
[Count
],
582 sizeof (EFI_KEY_DESCRIPTOR
)
586 // Just updated the system keyboard database, reflect that in the global flag.
588 GlobalData
->SystemKeyboardUpdate
= TRUE
;
604 IN EFI_HII_PROTOCOL
*This
,
605 IN EFI_HII_HANDLE Handle
610 Removes the various packs from a Handle
618 EFI_HII_PACKAGE_INSTANCE
*PackageInstance
;
619 EFI_HII_DATA
*HiiData
;
620 EFI_HII_HANDLE_DATABASE
*HandleDatabase
;
621 EFI_HII_HANDLE_DATABASE
*PreviousHandleDatabase
;
624 if (This
== NULL
|| Handle
== 0) {
625 return EFI_INVALID_PARAMETER
;
628 HiiData
= EFI_HII_DATA_FROM_THIS (This
);
630 HandleDatabase
= HiiData
->DatabaseHead
;
631 PackageInstance
= NULL
;
634 // Initialize the Previous with the Head of the Database
636 PreviousHandleDatabase
= HandleDatabase
;
638 for (Count
= 0; HandleDatabase
!= NULL
; HandleDatabase
= HandleDatabase
->NextHandleDatabase
) {
640 // Match the numeric value with the database entry - if matched,
641 // free the package instance and apply fix-up to database linked list
643 if (Handle
== HandleDatabase
->Handle
) {
644 PackageInstance
= HandleDatabase
->Buffer
;
647 // Free the Package Instance
649 gBS
->FreePool (PackageInstance
);
652 // If this was the only Handle in the database
654 if (HiiData
->DatabaseHead
== HandleDatabase
) {
655 HiiData
->DatabaseHead
= NULL
;
658 // Make the parent->Next point to the current->Next
660 PreviousHandleDatabase
->NextHandleDatabase
= HandleDatabase
->NextHandleDatabase
;
661 gBS
->FreePool (HandleDatabase
);
665 // If this was not the HandleDatabase entry we were looking for, cache it just in case the next one is
667 PreviousHandleDatabase
= HandleDatabase
;
670 // No handle was found - error condition
672 if (PackageInstance
== NULL
) {
673 return EFI_INVALID_PARAMETER
;