]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiHiiLib/HiiLib.c
Base on the type field to get the width of value field for option opcode.
[mirror_edk2.git] / MdeModulePkg / Library / UefiHiiLib / HiiLib.c
1 /** @file
2 HII Library implementation that uses DXE protocols and services.
3
4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "InternalHiiLib.h"
16
17 #define GUID_CONFIG_STRING_TYPE 0x00
18 #define NAME_CONFIG_STRING_TYPE 0x01
19 #define PATH_CONFIG_STRING_TYPE 0x02
20
21 #define ACTION_SET_DEFAUTL_VALUE 0x01
22 #define ACTION_VALIDATE_SETTING 0x02
23
24 #define HII_LIB_DEFAULT_VARSTORE_SIZE 0x200
25
26 typedef struct {
27 LIST_ENTRY Entry; // Link to Block array
28 UINT16 Offset;
29 UINT16 Width;
30 UINT8 OpCode;
31 UINT8 Scope;
32 } IFR_BLOCK_DATA;
33
34 //
35 // <ConfigHdr> Template
36 //
37 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR16 mConfigHdrTemplate[] = L"GUID=00000000000000000000000000000000&NAME=0000&PATH=00";
38
39 EFI_FORM_BROWSER2_PROTOCOL *mUefiFormBrowser2 = NULL;
40
41 //
42 // Template used to mark the end of a list of packages
43 //
44 GLOBAL_REMOVE_IF_UNREFERENCED CONST EFI_HII_PACKAGE_HEADER mEndOfPakageList = {
45 sizeof (EFI_HII_PACKAGE_HEADER),
46 EFI_HII_PACKAGE_END
47 };
48
49 /**
50 Extract Hii package list GUID for given HII handle.
51
52 If HiiHandle could not be found in the HII database, then ASSERT.
53 If Guid is NULL, then ASSERT.
54
55 @param Handle Hii handle
56 @param Guid Package list GUID
57
58 @retval EFI_SUCCESS Successfully extract GUID from Hii database.
59
60 **/
61 EFI_STATUS
62 EFIAPI
63 InternalHiiExtractGuidFromHiiHandle (
64 IN EFI_HII_HANDLE Handle,
65 OUT EFI_GUID *Guid
66 )
67 {
68 EFI_STATUS Status;
69 UINTN BufferSize;
70 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
71
72 ASSERT (Guid != NULL);
73 ASSERT (Handle != NULL);
74
75 //
76 // Get HII PackageList
77 //
78 BufferSize = 0;
79 HiiPackageList = NULL;
80
81 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
82 ASSERT (Status != EFI_NOT_FOUND);
83
84 if (Status == EFI_BUFFER_TOO_SMALL) {
85 HiiPackageList = AllocatePool (BufferSize);
86 ASSERT (HiiPackageList != NULL);
87
88 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
89 }
90 if (EFI_ERROR (Status)) {
91 FreePool (HiiPackageList);
92 return Status;
93 }
94
95 //
96 // Extract GUID
97 //
98 CopyGuid (Guid, &HiiPackageList->PackageListGuid);
99
100 FreePool (HiiPackageList);
101
102 return EFI_SUCCESS;
103 }
104
105 /**
106 Registers a list of packages in the HII Database and returns the HII Handle
107 associated with that registration. If an HII Handle has already been registered
108 with the same PackageListGuid and DeviceHandle, then NULL is returned. If there
109 are not enough resources to perform the registration, then NULL is returned.
110 If an empty list of packages is passed in, then NULL is returned. If the size of
111 the list of package is 0, then NULL is returned.
112
113 The variable arguments are pointers which point to package header that defined
114 by UEFI VFR compiler and StringGather tool.
115
116 #pragma pack (push, 1)
117 typedef struct {
118 UINT32 BinaryLength;
119 EFI_HII_PACKAGE_HEADER PackageHeader;
120 } EDKII_AUTOGEN_PACKAGES_HEADER;
121 #pragma pack (pop)
122
123 @param[in] PackageListGuid The GUID of the package list.
124 @param[in] DeviceHandle If not NULL, the Device Handle on which
125 an instance of DEVICE_PATH_PROTOCOL is installed.
126 This Device Handle uniquely defines the device that
127 the added packages are associated with.
128 @param[in] ... The variable argument list that contains pointers
129 to packages terminated by a NULL.
130
131 @retval NULL A HII Handle has already been registered in the HII Database with
132 the same PackageListGuid and DeviceHandle.
133 @retval NULL The HII Handle could not be created.
134 @retval NULL An empty list of packages was passed in.
135 @retval NULL All packages are empty.
136 @retval Other The HII Handle associated with the newly registered package list.
137
138 **/
139 EFI_HII_HANDLE
140 EFIAPI
141 HiiAddPackages (
142 IN CONST EFI_GUID *PackageListGuid,
143 IN EFI_HANDLE DeviceHandle OPTIONAL,
144 ...
145 )
146 {
147 EFI_STATUS Status;
148 VA_LIST Args;
149 UINT32 *Package;
150 EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
151 EFI_HII_HANDLE HiiHandle;
152 UINT32 Length;
153 UINT8 *Data;
154
155 ASSERT (PackageListGuid != NULL);
156
157 //
158 // Calculate the length of all the packages in the variable argument list
159 //
160 for (Length = 0, VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
161 Length += (ReadUnaligned32 (Package) - sizeof (UINT32));
162 }
163 VA_END (Args);
164
165 //
166 // If there are no packages in the variable argument list or all the packages
167 // are empty, then return a NULL HII Handle
168 //
169 if (Length == 0) {
170 return NULL;
171 }
172
173 //
174 // Add the length of the Package List Header and the terminating Package Header
175 //
176 Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
177
178 //
179 // Allocate the storage for the entire Package List
180 //
181 PackageListHeader = AllocateZeroPool (Length);
182
183 //
184 // If the Package List can not be allocated, then return a NULL HII Handle
185 //
186 if (PackageListHeader == NULL) {
187 return NULL;
188 }
189
190 //
191 // Fill in the GUID and Length of the Package List Header
192 //
193 CopyGuid (&PackageListHeader->PackageListGuid, PackageListGuid);
194 PackageListHeader->PackageLength = Length;
195
196 //
197 // Initialize a pointer to the beginning if the Package List data
198 //
199 Data = (UINT8 *)(PackageListHeader + 1);
200
201 //
202 // Copy the data from each package in the variable argument list
203 //
204 for (VA_START (Args, DeviceHandle); (Package = VA_ARG (Args, UINT32 *)) != NULL; ) {
205 Length = ReadUnaligned32 (Package) - sizeof (UINT32);
206 CopyMem (Data, Package + 1, Length);
207 Data += Length;
208 }
209 VA_END (Args);
210
211 //
212 // Append a package of type EFI_HII_PACKAGE_END to mark the end of the package list
213 //
214 CopyMem (Data, &mEndOfPakageList, sizeof (mEndOfPakageList));
215
216 //
217 // Register the package list with the HII Database
218 //
219 Status = gHiiDatabase->NewPackageList (
220 gHiiDatabase,
221 PackageListHeader,
222 DeviceHandle,
223 &HiiHandle
224 );
225 if (EFI_ERROR (Status)) {
226 HiiHandle = NULL;
227 }
228
229 //
230 // Free the allocated package list
231 //
232 FreePool (PackageListHeader);
233
234 //
235 // Return the new HII Handle
236 //
237 return HiiHandle;
238 }
239
240 /**
241 Removes a package list from the HII database.
242
243 If HiiHandle is NULL, then ASSERT.
244 If HiiHandle is not a valid EFI_HII_HANDLE in the HII database, then ASSERT.
245
246 @param[in] HiiHandle The handle that was previously registered in the HII database
247
248 **/
249 VOID
250 EFIAPI
251 HiiRemovePackages (
252 IN EFI_HII_HANDLE HiiHandle
253 )
254 {
255 EFI_STATUS Status;
256
257 ASSERT (HiiHandle != NULL);
258 Status = gHiiDatabase->RemovePackageList (gHiiDatabase, HiiHandle);
259 ASSERT_EFI_ERROR (Status);
260 }
261
262
263 /**
264 Retrieves the array of all the HII Handles or the HII handles of a specific
265 package list GUID in the HII Database.
266 This array is terminated with a NULL HII Handle.
267 This function allocates the returned array using AllocatePool().
268 The caller is responsible for freeing the array with FreePool().
269
270 @param[in] PackageListGuid An optional parameter that is used to request
271 HII Handles associated with a specific
272 Package List GUID. If this parameter is NULL,
273 then all the HII Handles in the HII Database
274 are returned. If this parameter is not NULL,
275 then zero or more HII Handles associated with
276 PackageListGuid are returned.
277
278 @retval NULL No HII handles were found in the HII database
279 @retval NULL The array of HII Handles could not be retrieved
280 @retval Other A pointer to the NULL terminated array of HII Handles
281
282 **/
283 EFI_HII_HANDLE *
284 EFIAPI
285 HiiGetHiiHandles (
286 IN CONST EFI_GUID *PackageListGuid OPTIONAL
287 )
288 {
289 EFI_STATUS Status;
290 UINTN HandleBufferLength;
291 EFI_HII_HANDLE TempHiiHandleBuffer;
292 EFI_HII_HANDLE *HiiHandleBuffer;
293 EFI_GUID Guid;
294 UINTN Index1;
295 UINTN Index2;
296
297 //
298 // Retrieve the size required for the buffer of all HII handles.
299 //
300 HandleBufferLength = 0;
301 Status = gHiiDatabase->ListPackageLists (
302 gHiiDatabase,
303 EFI_HII_PACKAGE_TYPE_ALL,
304 NULL,
305 &HandleBufferLength,
306 &TempHiiHandleBuffer
307 );
308
309 //
310 // If ListPackageLists() returns EFI_SUCCESS for a zero size,
311 // then there are no HII handles in the HII database. If ListPackageLists()
312 // returns an error other than EFI_BUFFER_TOO_SMALL, then there are no HII
313 // handles in the HII database.
314 //
315 if (Status != EFI_BUFFER_TOO_SMALL) {
316 //
317 // Return NULL if the size can not be retrieved, or if there are no HII
318 // handles in the HII Database
319 //
320 return NULL;
321 }
322
323 //
324 // Allocate the array of HII handles to hold all the HII Handles and a NULL terminator
325 //
326 HiiHandleBuffer = AllocateZeroPool (HandleBufferLength + sizeof (EFI_HII_HANDLE));
327 if (HiiHandleBuffer == NULL) {
328 //
329 // Return NULL if allocation fails.
330 //
331 return NULL;
332 }
333
334 //
335 // Retrieve the array of HII Handles in the HII Database
336 //
337 Status = gHiiDatabase->ListPackageLists (
338 gHiiDatabase,
339 EFI_HII_PACKAGE_TYPE_ALL,
340 NULL,
341 &HandleBufferLength,
342 HiiHandleBuffer
343 );
344 if (EFI_ERROR (Status)) {
345 //
346 // Free the buffer and return NULL if the HII handles can not be retrieved.
347 //
348 FreePool (HiiHandleBuffer);
349 return NULL;
350 }
351
352 if (PackageListGuid == NULL) {
353 //
354 // Return the NULL terminated array of HII handles in the HII Database
355 //
356 return HiiHandleBuffer;
357 } else {
358 for (Index1 = 0, Index2 = 0; HiiHandleBuffer[Index1] != NULL; Index1++) {
359 Status = InternalHiiExtractGuidFromHiiHandle (HiiHandleBuffer[Index1], &Guid);
360 ASSERT_EFI_ERROR (Status);
361 if (CompareGuid (&Guid, PackageListGuid)) {
362 HiiHandleBuffer[Index2++] = HiiHandleBuffer[Index1];
363 }
364 }
365 if (Index2 > 0) {
366 HiiHandleBuffer[Index2] = NULL;
367 return HiiHandleBuffer;
368 } else {
369 FreePool (HiiHandleBuffer);
370 return NULL;
371 }
372 }
373 }
374
375 /**
376 Converts all hex dtring characters in range ['A'..'F'] to ['a'..'f'] for
377 hex digits that appear between a '=' and a '&' in a config string.
378
379 If ConfigString is NULL, then ASSERT().
380
381 @param[in] ConfigString Pointer to a Null-terminated Unicode string.
382
383 @return Pointer to the Null-terminated Unicode result string.
384
385 **/
386 EFI_STRING
387 EFIAPI
388 InternalHiiLowerConfigString (
389 IN EFI_STRING ConfigString
390 )
391 {
392 EFI_STRING String;
393 BOOLEAN Lower;
394
395 ASSERT (ConfigString != NULL);
396
397 //
398 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
399 //
400 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
401 if (*String == L'=') {
402 Lower = TRUE;
403 } else if (*String == L'&') {
404 Lower = FALSE;
405 } else if (Lower && *String >= L'A' && *String <= L'F') {
406 *String = (CHAR16) (*String - L'A' + L'a');
407 }
408 }
409
410 return ConfigString;
411 }
412
413 /**
414 Uses the BlockToConfig() service of the Config Routing Protocol to
415 convert <ConfigRequest> and a buffer to a <ConfigResp>
416
417 If ConfigRequest is NULL, then ASSERT().
418 If Block is NULL, then ASSERT().
419
420 @param[in] ConfigRequest Pointer to a Null-terminated Unicode string.
421 @param[in] Block Pointer to a block of data.
422 @param[in] BlockSize The zie, in bytes, of Block.
423
424 @retval NULL The <ConfigResp> string could not be generated.
425 @retval Other Pointer to the Null-terminated Unicode <ConfigResp> string.
426
427 **/
428 EFI_STRING
429 EFIAPI
430 InternalHiiBlockToConfig (
431 IN CONST EFI_STRING ConfigRequest,
432 IN CONST UINT8 *Block,
433 IN UINTN BlockSize
434 )
435 {
436 EFI_STATUS Status;
437 EFI_STRING ConfigResp;
438 CHAR16 *Progress;
439
440 ASSERT (ConfigRequest != NULL);
441 ASSERT (Block != NULL);
442
443 //
444 // Convert <ConfigRequest> to <ConfigResp>
445 //
446 Status = gHiiConfigRouting->BlockToConfig (
447 gHiiConfigRouting,
448 ConfigRequest,
449 Block,
450 BlockSize,
451 &ConfigResp,
452 &Progress
453 );
454 if (EFI_ERROR (Status)) {
455 return NULL;
456 }
457 return ConfigResp;
458 }
459
460 /**
461 Uses the BrowserCallback() service of the Form Browser Protocol to retrieve
462 or set uncommitted data. If sata i being retrieved, then the buffer is
463 allocated using AllocatePool(). The caller is then responsible for freeing
464 the buffer using FreePool().
465
466 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
467 parameter that may be NULL.
468 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
469 is an optional parameter that may be NULL.
470 @param[in] SetResultsData If not NULL, then this parameter specified the buffer
471 of uncommited data to set. If this parameter is NULL,
472 then the caller is requesting to get the uncommited data
473 from the Form Browser.
474
475 @retval NULL The uncommitted data could not be retrieved.
476 @retval Other A pointer to a buffer containing the uncommitted data.
477
478 **/
479 EFI_STRING
480 EFIAPI
481 InternalHiiBrowserCallback (
482 IN CONST EFI_GUID *VariableGuid, OPTIONAL
483 IN CONST CHAR16 *VariableName, OPTIONAL
484 IN CONST EFI_STRING SetResultsData OPTIONAL
485 )
486 {
487 EFI_STATUS Status;
488 UINTN ResultsDataSize;
489 EFI_STRING ResultsData;
490 CHAR16 TempResultsData;
491
492 //
493 // Locate protocols
494 //
495 if (mUefiFormBrowser2 == NULL) {
496 Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mUefiFormBrowser2);
497 if (EFI_ERROR (Status) || mUefiFormBrowser2 == NULL) {
498 return NULL;
499 }
500 }
501
502 ResultsDataSize = 0;
503
504 if (SetResultsData != NULL) {
505 //
506 // Request to to set data in the uncommitted browser state information
507 //
508 ResultsData = SetResultsData;
509 } else {
510 //
511 // Retrieve the length of the buffer required ResultsData from the Browser Callback
512 //
513 Status = mUefiFormBrowser2->BrowserCallback (
514 mUefiFormBrowser2,
515 &ResultsDataSize,
516 &TempResultsData,
517 TRUE,
518 VariableGuid,
519 VariableName
520 );
521
522 if (!EFI_ERROR (Status)) {
523 //
524 // No Resluts Data, only allocate one char for '\0'
525 //
526 ResultsData = AllocateZeroPool (sizeof (CHAR16));
527 return ResultsData;
528 }
529
530 if (Status != EFI_BUFFER_TOO_SMALL) {
531 return NULL;
532 }
533
534 //
535 // Allocate the ResultsData buffer
536 //
537 ResultsData = AllocateZeroPool (ResultsDataSize);
538 if (ResultsData == NULL) {
539 return NULL;
540 }
541 }
542
543 //
544 // Retrieve or set the ResultsData from the Browser Callback
545 //
546 Status = mUefiFormBrowser2->BrowserCallback (
547 mUefiFormBrowser2,
548 &ResultsDataSize,
549 ResultsData,
550 (BOOLEAN)(SetResultsData == NULL),
551 VariableGuid,
552 VariableName
553 );
554 if (EFI_ERROR (Status)) {
555 return NULL;
556 }
557
558 return ResultsData;
559 }
560
561 /**
562 Allocates and returns a Null-terminated Unicode <ConfigHdr> string using routing
563 information that includes a GUID, an optional Unicode string name, and a device
564 path. The string returned is allocated with AllocatePool(). The caller is
565 responsible for freeing the allocated string with FreePool().
566
567 The format of a <ConfigHdr> is as follows:
568
569 GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize<Null>
570
571 @param[in] Guid Pointer to an EFI_GUID that is the routing information
572 GUID. Each of the 16 bytes in Guid is converted to
573 a 2 Unicode character hexidecimal string. This is
574 an optional parameter that may be NULL.
575 @param[in] Name Pointer to a Null-terminated Unicode string that is
576 the routing information NAME. This is an optional
577 parameter that may be NULL. Each 16-bit Unicode
578 character in Name is converted to a 4 character Unicode
579 hexidecimal string.
580 @param[in] DriverHandle The driver handle which supports a Device Path Protocol
581 that is the routing information PATH. Each byte of
582 the Device Path associated with DriverHandle is converted
583 to a 2 Unicode character hexidecimal string.
584
585 @retval NULL DriverHandle does not support the Device Path Protocol.
586 @retval Other A pointer to the Null-terminate Unicode <ConfigHdr> string
587
588 **/
589 EFI_STRING
590 EFIAPI
591 HiiConstructConfigHdr (
592 IN CONST EFI_GUID *Guid, OPTIONAL
593 IN CONST CHAR16 *Name, OPTIONAL
594 IN EFI_HANDLE DriverHandle
595 )
596 {
597 UINTN NameLength;
598 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
599 UINTN DevicePathSize;
600 CHAR16 *String;
601 CHAR16 *ReturnString;
602 UINTN Index;
603 UINT8 *Buffer;
604
605 //
606 // Compute the length of Name in Unicode characters.
607 // If Name is NULL, then the length is 0.
608 //
609 NameLength = 0;
610 if (Name != NULL) {
611 NameLength = StrLen (Name);
612 }
613
614 DevicePath = NULL;
615 DevicePathSize = 0;
616 //
617 // Retrieve DevicePath Protocol associated with DriverHandle
618 //
619 if (DriverHandle != NULL) {
620 DevicePath = DevicePathFromHandle (DriverHandle);
621 if (DevicePath == NULL) {
622 return NULL;
623 }
624 //
625 // Compute the size of the device path in bytes
626 //
627 DevicePathSize = GetDevicePathSize (DevicePath);
628 }
629
630 //
631 // GUID=<HexCh>32&NAME=<Char>NameLength&PATH=<HexChar>DevicePathSize <Null>
632 // | 5 | sizeof (EFI_GUID) * 2 | 6 | NameStrLen*4 | 6 | DevicePathSize * 2 | 1 |
633 //
634 String = AllocateZeroPool ((5 + sizeof (EFI_GUID) * 2 + 6 + NameLength * 4 + 6 + DevicePathSize * 2 + 1) * sizeof (CHAR16));
635 if (String == NULL) {
636 return NULL;
637 }
638
639 //
640 // Start with L"GUID="
641 //
642 ReturnString = StrCpy (String, L"GUID=");
643 String += StrLen (String);
644
645 if (Guid != NULL) {
646 //
647 // Append Guid converted to <HexCh>32
648 //
649 for (Index = 0, Buffer = (UINT8 *)Guid; Index < sizeof (EFI_GUID); Index++) {
650 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
651 }
652 }
653
654 //
655 // Append L"&NAME="
656 //
657 StrCpy (String, L"&NAME=");
658 String += StrLen (String);
659
660 if (Name != NULL) {
661 //
662 // Append Name converted to <Char>NameLength
663 //
664 for (; *Name != L'\0'; Name++) {
665 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *Name, 4);
666 }
667 }
668
669 //
670 // Append L"&PATH="
671 //
672 StrCpy (String, L"&PATH=");
673 String += StrLen (String);
674
675 //
676 // Append the device path associated with DriverHandle converted to <HexChar>DevicePathSize
677 //
678 for (Index = 0, Buffer = (UINT8 *)DevicePath; Index < DevicePathSize; Index++) {
679 String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(Buffer++), 2);
680 }
681
682 //
683 // Null terminate the Unicode string
684 //
685 *String = L'\0';
686
687 //
688 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
689 //
690 return InternalHiiLowerConfigString (ReturnString);
691 }
692
693 /**
694 Convert the hex UNICODE encoding string of UEFI GUID, NAME or device path
695 to binary buffer from <ConfigHdr>.
696
697 This is a internal function.
698
699 @param String UEFI configuration string.
700 @param Flag Flag specifies what type buffer will be retrieved.
701 @param Buffer Binary of Guid, Name or Device path.
702
703 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
704 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
705 @retval EFI_SUCCESS The buffer data is retrieved and translated to
706 binary format.
707
708 **/
709 EFI_STATUS
710 InternalHiiGetBufferFromString (
711 IN EFI_STRING String,
712 IN UINT8 Flag,
713 OUT UINT8 **Buffer
714 )
715 {
716 UINTN Length;
717 EFI_STRING ConfigHdr;
718 CHAR16 *StringPtr;
719 UINT8 *DataBuffer;
720 CHAR16 TemStr[5];
721 UINTN Index;
722 UINT8 DigitUint8;
723
724 if (String == NULL || Buffer == NULL) {
725 return EFI_INVALID_PARAMETER;
726 }
727
728 DataBuffer = NULL;
729 StringPtr = NULL;
730 ConfigHdr = String;
731 //
732 // The content between 'GUID', 'NAME', 'PATH' of <ConfigHdr> and '&' of next element
733 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding string.
734 //
735 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
736
737 switch (Flag) {
738 case GUID_CONFIG_STRING_TYPE:
739 case PATH_CONFIG_STRING_TYPE:
740 //
741 // The data in <ConfigHdr> is encoded as hex UNICODE %02x bytes in the same order
742 // as the device path and Guid resides in RAM memory.
743 // Translate the data into binary.
744 //
745 DataBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
746 if (DataBuffer == NULL) {
747 return EFI_OUT_OF_RESOURCES;
748 }
749 //
750 // Convert binary byte one by one
751 //
752 ZeroMem (TemStr, sizeof (TemStr));
753 for (Index = 0; Index < Length; Index ++) {
754 TemStr[0] = ConfigHdr[Index];
755 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
756 if ((Index & 1) == 0) {
757 DataBuffer [Index/2] = DigitUint8;
758 } else {
759 DataBuffer [Index/2] = (UINT8) ((DataBuffer [Index/2] << 4) + DigitUint8);
760 }
761 }
762
763 *Buffer = DataBuffer;
764 break;
765
766 case NAME_CONFIG_STRING_TYPE:
767 //
768 // Convert Config String to Unicode String, e.g. "0041004200430044" => "ABCD"
769 //
770
771 //
772 // Add the tailling char L'\0'
773 //
774 DataBuffer = (UINT8 *) AllocateZeroPool ((Length/4 + 1) * sizeof (CHAR16));
775 if (DataBuffer == NULL) {
776 return EFI_OUT_OF_RESOURCES;
777 }
778 //
779 // Convert character one by one
780 //
781 StringPtr = (CHAR16 *) DataBuffer;
782 ZeroMem (TemStr, sizeof (TemStr));
783 for (Index = 0; Index < Length; Index += 4) {
784 StrnCpy (TemStr, ConfigHdr + Index, 4);
785 StringPtr[Index/4] = (CHAR16) StrHexToUint64 (TemStr);
786 }
787 //
788 // Add tailing L'\0' character
789 //
790 StringPtr[Index/4] = L'\0';
791
792 *Buffer = DataBuffer;
793 break;
794
795 default:
796 return EFI_INVALID_PARAMETER;
797 }
798
799 return EFI_SUCCESS;
800 }
801
802 /**
803 This function checks VarOffset and VarWidth is in the block range.
804
805 @param BlockArray The block array is to be checked.
806 @param VarOffset Offset of var to the structure
807 @param VarWidth Width of var.
808
809 @retval TRUE This Var is in the block range.
810 @retval FALSE This Var is not in the block range.
811 **/
812 BOOLEAN
813 BlockArrayCheck (
814 IN IFR_BLOCK_DATA *BlockArray,
815 IN UINT16 VarOffset,
816 IN UINT16 VarWidth
817 )
818 {
819 LIST_ENTRY *Link;
820 IFR_BLOCK_DATA *BlockData;
821
822 //
823 // No Request Block array, all vars are got.
824 //
825 if (BlockArray == NULL) {
826 return TRUE;
827 }
828
829 //
830 // Check the input var is in the request block range.
831 //
832 for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
833 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
834 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
835 return TRUE;
836 }
837 }
838
839 return FALSE;
840 }
841
842 /**
843 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
844 or WIDTH or VALUE.
845 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
846
847 @param ValueString String in <BlockConfig> format and points to the
848 first character of <Number>.
849 @param ValueData The output value. Caller takes the responsibility
850 to free memory.
851 @param ValueLength Length of the <Number>, in characters.
852
853 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
854 structures.
855 @retval EFI_SUCCESS Value of <Number> is outputted in Number
856 successfully.
857
858 **/
859 EFI_STATUS
860 EFIAPI
861 InternalHiiGetValueOfNumber (
862 IN EFI_STRING ValueString,
863 OUT UINT8 **ValueData,
864 OUT UINTN *ValueLength
865 )
866 {
867 EFI_STRING StringPtr;
868 UINTN Length;
869 UINT8 *Buf;
870 UINT8 DigitUint8;
871 UINTN Index;
872 CHAR16 TemStr[2];
873
874 ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
875 ASSERT (*ValueString != L'\0');
876
877 //
878 // Get the length of value string
879 //
880 StringPtr = ValueString;
881 while (*StringPtr != L'\0' && *StringPtr != L'&') {
882 StringPtr++;
883 }
884 Length = StringPtr - ValueString;
885
886 //
887 // Allocate buffer to store the value
888 //
889 Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
890 if (Buf == NULL) {
891 return EFI_OUT_OF_RESOURCES;
892 }
893
894 //
895 // Convert character one by one to the value buffer
896 //
897 ZeroMem (TemStr, sizeof (TemStr));
898 for (Index = 0; Index < Length; Index ++) {
899 TemStr[0] = ValueString[Length - Index - 1];
900 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
901 if ((Index & 1) == 0) {
902 Buf [Index/2] = DigitUint8;
903 } else {
904 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
905 }
906 }
907
908 //
909 // Set the converted value and string length.
910 //
911 *ValueData = Buf;
912 *ValueLength = Length;
913 return EFI_SUCCESS;
914 }
915
916 /**
917 This internal function parses IFR data to validate current setting.
918
919 @param ConfigResp ConfigResp string contains the current setting.
920 @param HiiPackageList Point to Hii package list.
921 @param PackageListLength The length of the pacakge.
922 @param VarGuid Guid of the buffer storage.
923 @param VarName Name of the buffer storage.
924
925 @retval EFI_SUCCESS The current setting is valid.
926 @retval EFI_OUT_OF_RESOURCES The memory is not enough.
927 @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
928 **/
929 EFI_STATUS
930 EFIAPI
931 InternalHiiValidateCurrentSetting (
932 IN EFI_STRING ConfigResp,
933 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
934 IN UINTN PackageListLength,
935 IN EFI_GUID *VarGuid,
936 IN CHAR16 *VarName
937 )
938 {
939 IFR_BLOCK_DATA *CurrentBlockArray;
940 IFR_BLOCK_DATA *BlockData;
941 IFR_BLOCK_DATA *NewBlockData;
942 IFR_BLOCK_DATA VarBlockData;
943 EFI_STRING StringPtr;
944 UINTN Length;
945 UINT8 *TmpBuffer;
946 UINT16 Offset;
947 UINT16 Width;
948 UINT64 VarValue;
949 UINT64 TmpValue;
950 LIST_ENTRY *Link;
951 UINT8 *VarBuffer;
952 UINTN MaxBufferSize;
953 EFI_STATUS Status;
954 EFI_HII_PACKAGE_HEADER PacakgeHeader;
955 UINT32 PackageOffset;
956 UINT8 *PackageData;
957 UINTN IfrOffset;
958 EFI_IFR_OP_HEADER *IfrOpHdr;
959 EFI_IFR_VARSTORE *IfrVarStore;
960 EFI_IFR_ONE_OF *IfrOneOf;
961 EFI_IFR_NUMERIC *IfrNumeric;
962 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
963 EFI_IFR_CHECKBOX *IfrCheckBox;
964 EFI_IFR_STRING *IfrString;
965 CHAR8 *VarStoreName;
966 UINTN Index;
967
968 //
969 // 1. Get the current setting to current block data array and Convert them into VarBuffer
970 //
971
972 //
973 // Skip ConfigHdr string
974 //
975 StringPtr = ConfigResp;
976 StringPtr = StrStr (ConfigResp, L"&OFFSET");
977 if (StringPtr == NULL) {
978 //
979 // No ConfigBlock value is required to be validated.
980 // EFI_SUCCESS directly return.
981 //
982 return EFI_SUCCESS;
983 }
984
985 //
986 // Initialize the local variables.
987 //
988 Index = 0;
989 VarStoreName = NULL;
990 Status = EFI_SUCCESS;
991 BlockData = NULL;
992 NewBlockData = NULL;
993 TmpBuffer = NULL;
994 MaxBufferSize = HII_LIB_DEFAULT_VARSTORE_SIZE;
995 VarBuffer = AllocateZeroPool (MaxBufferSize);
996 if (VarBuffer == NULL) {
997 return EFI_OUT_OF_RESOURCES;
998 }
999
1000 //
1001 // Init CurrentBlockArray
1002 //
1003 CurrentBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1004 if (CurrentBlockArray == NULL) {
1005 Status = EFI_OUT_OF_RESOURCES;
1006 goto Done;
1007 }
1008 InitializeListHead (&CurrentBlockArray->Entry);
1009
1010 //
1011 // Parse each <RequestElement> if exists
1012 // Only <BlockName> format is supported by this help function.
1013 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
1014 //
1015 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
1016 //
1017 // Skip the &OFFSET= string
1018 //
1019 StringPtr += StrLen (L"&OFFSET=");
1020
1021 //
1022 // Get Offset
1023 //
1024 Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1025 if (EFI_ERROR (Status)) {
1026 goto Done;
1027 }
1028 Offset = 0;
1029 CopyMem (
1030 &Offset,
1031 TmpBuffer,
1032 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1033 );
1034 FreePool (TmpBuffer);
1035 TmpBuffer = NULL;
1036
1037 StringPtr += Length;
1038 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1039 Status = EFI_INVALID_PARAMETER;
1040 goto Done;
1041 }
1042 StringPtr += StrLen (L"&WIDTH=");
1043
1044 //
1045 // Get Width
1046 //
1047 Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1048 if (EFI_ERROR (Status)) {
1049 goto Done;
1050 }
1051 Width = 0;
1052 CopyMem (
1053 &Width,
1054 TmpBuffer,
1055 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1056 );
1057 FreePool (TmpBuffer);
1058 TmpBuffer = NULL;
1059
1060 StringPtr += Length;
1061 if (*StringPtr != 0 && *StringPtr != L'&') {
1062 Status = EFI_INVALID_PARAMETER;
1063 goto Done;
1064 }
1065
1066 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1067 Status = EFI_INVALID_PARAMETER;
1068 goto Done;
1069 }
1070 StringPtr += StrLen (L"&VALUE=");
1071
1072 //
1073 // Get Value
1074 //
1075 Status = InternalHiiGetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1076 if (EFI_ERROR (Status)) {
1077 goto Done;
1078 }
1079
1080 StringPtr += Length;
1081 if (*StringPtr != 0 && *StringPtr != L'&') {
1082 Status = EFI_INVALID_PARAMETER;
1083 goto Done;
1084 }
1085
1086 //
1087 // Check whether VarBuffer is enough
1088 //
1089 if ((UINTN) (Offset + Width) > MaxBufferSize) {
1090 VarBuffer = ReallocatePool (
1091 MaxBufferSize,
1092 Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE,
1093 VarBuffer
1094 );
1095 if (VarBuffer == NULL) {
1096 Status = EFI_OUT_OF_RESOURCES;
1097 goto Done;
1098 }
1099 MaxBufferSize = Offset + Width + HII_LIB_DEFAULT_VARSTORE_SIZE;
1100 }
1101
1102 //
1103 // Update the Block with configuration info
1104 //
1105 CopyMem (VarBuffer + Offset, TmpBuffer, Width);
1106 FreePool (TmpBuffer);
1107 TmpBuffer = NULL;
1108
1109 //
1110 // Set new Block Data
1111 //
1112 NewBlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1113 if (NewBlockData == NULL) {
1114 Status = EFI_OUT_OF_RESOURCES;
1115 goto Done;
1116 }
1117 NewBlockData->Offset = Offset;
1118 NewBlockData->Width = Width;
1119
1120 //
1121 // Insert the new block data into the block data array.
1122 //
1123 for (Link = CurrentBlockArray->Entry.ForwardLink; Link != &CurrentBlockArray->Entry; Link = Link->ForwardLink) {
1124 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1125 if (NewBlockData->Offset == BlockData->Offset) {
1126 if (NewBlockData->Width > BlockData->Width) {
1127 BlockData->Width = NewBlockData->Width;
1128 }
1129 FreePool (NewBlockData);
1130 break;
1131 } else if (NewBlockData->Offset < BlockData->Offset) {
1132 //
1133 // Insert new block data as the previous one of this link.
1134 //
1135 InsertTailList (Link, &NewBlockData->Entry);
1136 break;
1137 }
1138 }
1139
1140 //
1141 // Insert new block data into the array tail.
1142 //
1143 if (Link == &CurrentBlockArray->Entry) {
1144 InsertTailList (Link, &NewBlockData->Entry);
1145 }
1146
1147 //
1148 // If '\0', parsing is finished.
1149 //
1150 if (*StringPtr == 0) {
1151 break;
1152 }
1153 //
1154 // Go to next ConfigBlock
1155 //
1156 }
1157
1158 //
1159 // Merge the aligned block data into the single block data.
1160 //
1161 Link = CurrentBlockArray->Entry.ForwardLink;
1162 while ((Link != &CurrentBlockArray->Entry) && (Link->ForwardLink != &CurrentBlockArray->Entry)) {
1163 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1164 NewBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
1165 if ((NewBlockData->Offset >= BlockData->Offset) && (NewBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
1166 if ((NewBlockData->Offset + NewBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
1167 BlockData->Width = (UINT16) (NewBlockData->Offset + NewBlockData->Width - BlockData->Offset);
1168 }
1169 RemoveEntryList (Link->ForwardLink);
1170 FreePool (NewBlockData);
1171 continue;
1172 }
1173 Link = Link->ForwardLink;
1174 }
1175
1176 if (IsListEmpty (&CurrentBlockArray->Entry)) {
1177 Status = EFI_SUCCESS;
1178 goto Done;
1179 }
1180
1181 //
1182 // 2. Check IFR value is in block data, then Validate Value
1183 //
1184 ZeroMem (&VarBlockData, sizeof (VarBlockData));
1185 VarValue = 0;
1186 IfrVarStore = NULL;
1187 PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1188 while (PackageOffset < PackageListLength) {
1189 CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader));
1190
1191 //
1192 // Parse IFR opcode from the form package.
1193 //
1194 if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) {
1195 IfrOffset = sizeof (PacakgeHeader);
1196 PackageData = (UINT8 *) HiiPackageList + PackageOffset;
1197 while (IfrOffset < PacakgeHeader.Length) {
1198 IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
1199 //
1200 // Validate current setting to the value built in IFR opcode
1201 //
1202 switch (IfrOpHdr->OpCode) {
1203 case EFI_IFR_VARSTORE_OP:
1204 //
1205 // VarStoreId has been found. No further found.
1206 //
1207 if (IfrVarStore != NULL) {
1208 break;
1209 }
1210 //
1211 // Find the matched VarStoreId to the input VarGuid and VarName
1212 //
1213 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
1214 if (CompareGuid ((EFI_GUID *) (VOID *) &IfrVarStore->Guid, VarGuid)) {
1215 VarStoreName = (CHAR8 *) IfrVarStore->Name;
1216 for (Index = 0; VarStoreName[Index] != 0; Index ++) {
1217 if ((CHAR16) VarStoreName[Index] != VarName[Index]) {
1218 break;
1219 }
1220 }
1221 //
1222 // The matched VarStore is found.
1223 //
1224 if ((VarStoreName[Index] != 0) || (VarName[Index] != 0)) {
1225 IfrVarStore = NULL;
1226 }
1227 } else {
1228 IfrVarStore = NULL;
1229 }
1230 break;
1231 case EFI_IFR_FORM_OP:
1232 case EFI_IFR_FORM_MAP_OP:
1233 //
1234 // Check the matched VarStoreId is found.
1235 //
1236 if (IfrVarStore == NULL) {
1237 Status = EFI_SUCCESS;
1238 goto Done;
1239 }
1240 break;
1241 case EFI_IFR_ONE_OF_OP:
1242 //
1243 // Check whether current value is the one of option.
1244 //
1245
1246 //
1247 // OneOf question is not in IFR Form. This IFR form is not valid.
1248 //
1249 if (IfrVarStore == NULL) {
1250 Status = EFI_INVALID_PARAMETER;
1251 goto Done;
1252 }
1253 //
1254 // Check whether this question is for the requested varstore.
1255 //
1256 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
1257 if (IfrOneOf->Question.VarStoreId != IfrVarStore->VarStoreId) {
1258 break;
1259 }
1260
1261 //
1262 // Get Offset by Question header and Width by DataType Flags
1263 //
1264 Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
1265 Width = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
1266 //
1267 // Check whether this question is in current block array.
1268 //
1269 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1270 //
1271 // This question is not in the current configuration string. Skip it.
1272 //
1273 break;
1274 }
1275 //
1276 // Check this var question is in the var storage
1277 //
1278 if ((Offset + Width) > IfrVarStore->Size) {
1279 //
1280 // This question exceeds the var store size.
1281 //
1282 Status = EFI_INVALID_PARAMETER;
1283 goto Done;
1284 }
1285
1286 //
1287 // Get the current value for oneof opcode
1288 //
1289 VarValue = 0;
1290 CopyMem (&VarValue, VarBuffer + Offset, Width);
1291 //
1292 // Set Block Data, to be checked in the following Oneof option opcode.
1293 //
1294 VarBlockData.Offset = Offset;
1295 VarBlockData.Width = Width;
1296 VarBlockData.OpCode = IfrOpHdr->OpCode;
1297 VarBlockData.Scope = IfrOpHdr->Scope;
1298 break;
1299 case EFI_IFR_NUMERIC_OP:
1300 //
1301 // Check the current value is in the numeric range.
1302 //
1303
1304 //
1305 // Numeric question is not in IFR Form. This IFR form is not valid.
1306 //
1307 if (IfrVarStore == NULL) {
1308 Status = EFI_INVALID_PARAMETER;
1309 goto Done;
1310 }
1311 //
1312 // Check whether this question is for the requested varstore.
1313 //
1314 IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
1315 if (IfrNumeric->Question.VarStoreId != IfrVarStore->VarStoreId) {
1316 break;
1317 }
1318
1319 //
1320 // Get Offset by Question header and Width by DataType Flags
1321 //
1322 Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
1323 Width = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
1324 //
1325 // Check whether this question is in current block array.
1326 //
1327 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1328 //
1329 // This question is not in the current configuration string. Skip it.
1330 //
1331 break;
1332 }
1333 //
1334 // Check this var question is in the var storage
1335 //
1336 if ((Offset + Width) > IfrVarStore->Size) {
1337 //
1338 // This question exceeds the var store size.
1339 //
1340 Status = EFI_INVALID_PARAMETER;
1341 goto Done;
1342 }
1343
1344 //
1345 // Check the current value is in the numeric range.
1346 //
1347 VarValue = 0;
1348 CopyMem (&VarValue, VarBuffer + Offset, Width);
1349 switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
1350 case EFI_IFR_NUMERIC_SIZE_1:
1351 if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
1352 //
1353 // Not in the valid range.
1354 //
1355 Status = EFI_INVALID_PARAMETER;
1356 goto Done;
1357 }
1358 break;
1359 case EFI_IFR_NUMERIC_SIZE_2:
1360 if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
1361 //
1362 // Not in the valid range.
1363 //
1364 Status = EFI_INVALID_PARAMETER;
1365 goto Done;
1366 }
1367 break;
1368 case EFI_IFR_NUMERIC_SIZE_4:
1369 if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
1370 //
1371 // Not in the valid range.
1372 //
1373 Status = EFI_INVALID_PARAMETER;
1374 goto Done;
1375 }
1376 break;
1377 case EFI_IFR_NUMERIC_SIZE_8:
1378 if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
1379 //
1380 // Not in the valid range.
1381 //
1382 Status = EFI_INVALID_PARAMETER;
1383 goto Done;
1384 }
1385 break;
1386 }
1387
1388 break;
1389 case EFI_IFR_CHECKBOX_OP:
1390 //
1391 // Check value is BOOLEAN type, only 0 and 1 is valid.
1392 //
1393
1394 //
1395 // CheckBox question is not in IFR Form. This IFR form is not valid.
1396 //
1397 if (IfrVarStore == NULL) {
1398 Status = EFI_INVALID_PARAMETER;
1399 goto Done;
1400 }
1401
1402 //
1403 // Check whether this question is for the requested varstore.
1404 //
1405 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1406 if (IfrCheckBox->Question.VarStoreId != IfrVarStore->VarStoreId) {
1407 break;
1408 }
1409
1410 //
1411 // Get Offset by Question header
1412 //
1413 Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1414 Width = (UINT16) sizeof (BOOLEAN);
1415 //
1416 // Check whether this question is in current block array.
1417 //
1418 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1419 //
1420 // This question is not in the current configuration string. Skip it.
1421 //
1422 break;
1423 }
1424 //
1425 // Check this var question is in the var storage
1426 //
1427 if ((Offset + Width) > IfrVarStore->Size) {
1428 //
1429 // This question exceeds the var store size.
1430 //
1431 Status = EFI_INVALID_PARAMETER;
1432 goto Done;
1433 }
1434
1435 //
1436 // Boolean type, only 1 and 0 is valid.
1437 //
1438 if (*(VarBuffer + Offset) > 1) {
1439 Status = EFI_INVALID_PARAMETER;
1440 goto Done;
1441 }
1442
1443 break;
1444 case EFI_IFR_STRING_OP:
1445 //
1446 // Check current string length is less than maxsize
1447 //
1448
1449 //
1450 // CheckBox question is not in IFR Form. This IFR form is not valid.
1451 //
1452 if (IfrVarStore == NULL) {
1453 Status = EFI_INVALID_PARAMETER;
1454 goto Done;
1455 }
1456
1457 //
1458 // Check whether this question is for the requested varstore.
1459 //
1460 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1461 if (IfrString->Question.VarStoreId != IfrVarStore->VarStoreId) {
1462 break;
1463 }
1464
1465 //
1466 // Get Offset/Width by Question header and OneOf Flags
1467 //
1468 Offset = IfrString->Question.VarStoreInfo.VarOffset;
1469 Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1470 //
1471 // Check whether this question is in current block array.
1472 //
1473 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1474 //
1475 // This question is not in the current configuration string. Skip it.
1476 //
1477 break;
1478 }
1479 //
1480 // Check this var question is in the var storage
1481 //
1482 if ((Offset + Width) > IfrVarStore->Size) {
1483 //
1484 // This question exceeds the var store size.
1485 //
1486 Status = EFI_INVALID_PARAMETER;
1487 goto Done;
1488 }
1489
1490 //
1491 // Check current string length is less than maxsize
1492 //
1493 if (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) {
1494 Status = EFI_INVALID_PARAMETER;
1495 goto Done;
1496 }
1497 break;
1498 case EFI_IFR_ONE_OF_OPTION_OP:
1499 //
1500 // Opcode Scope is zero. This one of option is not to be checked.
1501 //
1502 if (VarBlockData.Scope == 0) {
1503 break;
1504 }
1505
1506 //
1507 // Only check for OneOf and OrderList opcode
1508 //
1509 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1510 if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
1511 //
1512 // Check current value is the value of one of option.
1513 //
1514 TmpValue = 0;
1515 CopyMem (&TmpValue, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
1516 if (VarValue == TmpValue) {
1517 //
1518 // The value is one of option value.
1519 // Set OpCode to Zero, don't need check again.
1520 //
1521 VarBlockData.OpCode = 0;
1522 }
1523 }
1524
1525 break;
1526 case EFI_IFR_END_OP:
1527 //
1528 // Decrease opcode scope for the validated opcode
1529 //
1530 if (VarBlockData.Scope > 0) {
1531 VarBlockData.Scope --;
1532 }
1533
1534 //
1535 // OneOf value doesn't belong to one of option value.
1536 //
1537 if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
1538 Status = EFI_INVALID_PARAMETER;
1539 goto Done;
1540 }
1541 break;
1542 default:
1543 //
1544 // Increase Scope for the validated opcode
1545 //
1546 if (VarBlockData.Scope > 0) {
1547 VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
1548 }
1549 break;
1550 }
1551 //
1552 // Go to the next opcode
1553 //
1554 IfrOffset += IfrOpHdr->Length;
1555 }
1556 //
1557 // Only one form is in a package list.
1558 //
1559 break;
1560 }
1561
1562 //
1563 // Go to next package.
1564 //
1565 PackageOffset += PacakgeHeader.Length;
1566 }
1567
1568 Done:
1569 if (VarBuffer != NULL) {
1570 FreePool (VarBuffer);
1571 }
1572
1573 if (CurrentBlockArray != NULL) {
1574 //
1575 // Free Link Array CurrentBlockArray
1576 //
1577 while (!IsListEmpty (&CurrentBlockArray->Entry)) {
1578 BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
1579 RemoveEntryList (&BlockData->Entry);
1580 FreePool (BlockData);
1581 }
1582 FreePool (CurrentBlockArray);
1583 }
1584
1585 return Status;
1586 }
1587
1588 /**
1589 This function parses the input ConfigRequest string and its matched IFR code
1590 string for setting default value and validating current setting.
1591
1592 1. For setting default action, Reset the default value specified by DefaultId
1593 to the driver configuration got by Request string.
1594 2. For validating current setting, Validate the current configuration
1595 by parsing HII form IFR opcode.
1596
1597 NULL request string support depends on the ExportConfig interface of
1598 HiiConfigRouting protocol in UEFI specification.
1599
1600 @param Request A null-terminated Unicode string in
1601 <MultiConfigRequest> format. It can be NULL.
1602 If it is NULL, all current configuration for the
1603 entirety of the current HII database will be validated.
1604 If it is NULL, all configuration for the
1605 entirety of the current HII database will be reset.
1606 @param DefaultId Specifies the type of defaults to retrieve only for setting default action.
1607 @param ActionType Action supports setting defaults and validate current setting.
1608
1609 @retval TURE Action runs successfully.
1610 @retval FALSE Action is not valid or Action can't be executed successfully..
1611 **/
1612 BOOLEAN
1613 EFIAPI
1614 InternalHiiIfrValueAction (
1615 IN CONST EFI_STRING Request, OPTIONAL
1616 IN UINT16 DefaultId,
1617 IN UINT8 ActionType
1618 )
1619 {
1620 EFI_STRING ConfigAltResp;
1621 EFI_STRING ConfigAltHdr;
1622 EFI_STRING ConfigResp;
1623 EFI_STRING Progress;
1624 EFI_STRING StringPtr;
1625 EFI_STRING StringHdr;
1626 EFI_STATUS Status;
1627 EFI_HANDLE DriverHandle;
1628 EFI_HANDLE TempDriverHandle;
1629 EFI_HII_HANDLE *HiiHandleBuffer;
1630 EFI_HII_HANDLE HiiHandle;
1631 UINT32 Index;
1632 EFI_GUID *VarGuid;
1633 EFI_STRING VarName;
1634
1635 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
1636 UINTN PackageListLength;
1637 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1638 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1639
1640 ConfigAltResp = NULL;
1641 ConfigResp = NULL;
1642 VarGuid = NULL;
1643 VarName = NULL;
1644 DevicePath = NULL;
1645 ConfigAltHdr = NULL;
1646 HiiHandleBuffer = NULL;
1647 Index = 0;
1648 TempDriverHandle = NULL;
1649 HiiHandle = NULL;
1650 HiiPackageList = NULL;
1651
1652 //
1653 // Only support set default and validate setting action.
1654 //
1655 if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
1656 return FALSE;
1657 }
1658
1659 //
1660 // Get the full requested value and deault value string.
1661 //
1662 if (Request != NULL) {
1663 Status = gHiiConfigRouting->ExtractConfig (
1664 gHiiConfigRouting,
1665 Request,
1666 &Progress,
1667 &ConfigAltResp
1668 );
1669 } else {
1670 Status = gHiiConfigRouting->ExportConfig (
1671 gHiiConfigRouting,
1672 &ConfigAltResp
1673 );
1674 }
1675
1676 if (EFI_ERROR (Status)) {
1677 return FALSE;
1678 }
1679
1680 StringPtr = ConfigAltResp;
1681
1682 while (StringPtr != L'\0') {
1683 //
1684 // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
1685 //
1686 StringHdr = StringPtr;
1687
1688 //
1689 // Get Guid value
1690 //
1691 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1692 Status = EFI_INVALID_PARAMETER;
1693 goto Done;
1694 }
1695 StringPtr += StrLen (L"GUID=");
1696 Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
1697 if (EFI_ERROR (Status)) {
1698 goto Done;
1699 }
1700
1701 //
1702 // Get Name value VarName
1703 //
1704 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1705 StringPtr++;
1706 }
1707 if (*StringPtr == L'\0') {
1708 Status = EFI_INVALID_PARAMETER;
1709 goto Done;
1710 }
1711 StringPtr += StrLen (L"&NAME=");
1712 Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
1713 if (EFI_ERROR (Status)) {
1714 goto Done;
1715 }
1716
1717 //
1718 // Get Path value DevicePath
1719 //
1720 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1721 StringPtr++;
1722 }
1723 if (*StringPtr == L'\0') {
1724 Status = EFI_INVALID_PARAMETER;
1725 goto Done;
1726 }
1727 StringPtr += StrLen (L"&PATH=");
1728 Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
1729 if (EFI_ERROR (Status)) {
1730 goto Done;
1731 }
1732
1733 //
1734 // Get the Driver handle by the got device path.
1735 //
1736 TempDevicePath = DevicePath;
1737 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
1738 if (EFI_ERROR (Status)) {
1739 goto Done;
1740 }
1741
1742 //
1743 // Find the matched Hii Handle for the found Driver handle
1744 //
1745 HiiHandleBuffer = HiiGetHiiHandles (NULL);
1746 if (HiiHandleBuffer == NULL) {
1747 Status = EFI_NOT_FOUND;
1748 goto Done;
1749 }
1750
1751 for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
1752 gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
1753 if (TempDriverHandle == DriverHandle) {
1754 break;
1755 }
1756 }
1757
1758 HiiHandle = HiiHandleBuffer[Index];
1759 FreePool (HiiHandleBuffer);
1760
1761 if (HiiHandle == NULL) {
1762 //
1763 // This request string has no its Hii package.
1764 // Its default value and validating can't execute by parsing IFR data.
1765 // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
1766 //
1767 Status = EFI_SUCCESS;
1768 goto NextConfigAltResp;
1769 }
1770
1771 //
1772 // 2. Get HiiPackage by HiiHandle
1773 //
1774 PackageListLength = 0;
1775 HiiPackageList = NULL;
1776 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
1777
1778 //
1779 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
1780 //
1781 if (Status != EFI_BUFFER_TOO_SMALL) {
1782 Status = EFI_INVALID_PARAMETER;
1783 goto Done;
1784 }
1785
1786 HiiPackageList = AllocatePool (PackageListLength);
1787 if (HiiPackageList == NULL) {
1788 Status = EFI_OUT_OF_RESOURCES;
1789 goto Done;
1790 }
1791
1792 //
1793 // Get PackageList on HiiHandle
1794 //
1795 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
1796 if (EFI_ERROR (Status)) {
1797 goto Done;
1798 }
1799
1800 //
1801 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
1802 // Get the default configuration string according to the default ID.
1803 //
1804 Status = gHiiConfigRouting->GetAltConfig (
1805 gHiiConfigRouting,
1806 ConfigAltResp,
1807 VarGuid,
1808 VarName,
1809 DevicePath,
1810 (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL, // it can be NULL to get the current setting.
1811 &ConfigResp
1812 );
1813
1814 //
1815 // The required setting can't be found. So, it is not required to be validated and set.
1816 //
1817 if (EFI_ERROR (Status)) {
1818 Status = EFI_SUCCESS;
1819 goto NextConfigAltResp;
1820 }
1821 //
1822 // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
1823 //
1824 if (StrStr (ConfigResp, L"&OFFSET=") == NULL) {
1825 goto NextConfigAltResp;
1826 }
1827
1828 //
1829 // 4. Set the default configuration information or Validate current setting by parse IFR code.
1830 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
1831 //
1832 if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
1833 //
1834 // Set the default configuration information.
1835 //
1836 Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
1837 } else {
1838 //
1839 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
1840 //
1841 Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName);
1842 }
1843
1844 if (EFI_ERROR (Status)) {
1845 goto Done;
1846 }
1847
1848 NextConfigAltResp:
1849 //
1850 // Free the allocated pacakge buffer and the got ConfigResp string.
1851 //
1852 if (HiiPackageList != NULL) {
1853 FreePool (HiiPackageList);
1854 HiiPackageList = NULL;
1855 }
1856
1857 if (ConfigResp != NULL) {
1858 FreePool (ConfigResp);
1859 ConfigResp = NULL;
1860 }
1861
1862 //
1863 // Free the allocated buffer.
1864 //
1865 FreePool (VarGuid);
1866 VarGuid = NULL;
1867
1868 FreePool (VarName);
1869 VarName = NULL;
1870
1871 FreePool (DevicePath);
1872 DevicePath = NULL;
1873
1874 //
1875 // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
1876 //
1877
1878 //
1879 // Get and Skip ConfigHdr
1880 //
1881 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1882 StringPtr++;
1883 }
1884 if (*StringPtr == L'\0') {
1885 break;
1886 }
1887
1888 //
1889 // Construct ConfigAltHdr string "&<ConfigHdr>&ALTCFG=\0"
1890 // | 1 | StrLen (ConfigHdr) | 8 | 1 |
1891 //
1892 ConfigAltHdr = AllocateZeroPool ((1 + StringPtr - StringHdr + 8 + 1) * sizeof (CHAR16));
1893 if (ConfigAltHdr == NULL) {
1894 Status = EFI_OUT_OF_RESOURCES;
1895 goto Done;
1896 }
1897 StrCpy (ConfigAltHdr, L"&");
1898 StrnCat (ConfigAltHdr, StringHdr, StringPtr - StringHdr);
1899 StrCat (ConfigAltHdr, L"&ALTCFG=");
1900
1901 //
1902 // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
1903 //
1904 while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
1905 StringPtr = StringHdr + StrLen (ConfigAltHdr);
1906 if (*StringPtr == L'\0') {
1907 break;
1908 }
1909 }
1910
1911 //
1912 // Free the allocated ConfigAltHdr string
1913 //
1914 FreePool (ConfigAltHdr);
1915 if (*StringPtr == L'\0') {
1916 break;
1917 }
1918
1919 //
1920 // Find &GUID as the next ConfigHdr
1921 //
1922 StringPtr = StrStr (StringPtr, L"&GUID");
1923 if (StringPtr == NULL) {
1924 break;
1925 }
1926
1927 //
1928 // Skip char '&'
1929 //
1930 StringPtr ++;
1931 }
1932
1933 Done:
1934 if (VarGuid != NULL) {
1935 FreePool (VarGuid);
1936 }
1937
1938 if (VarName != NULL) {
1939 FreePool (VarName);
1940 }
1941
1942 if (DevicePath != NULL) {
1943 FreePool (DevicePath);
1944 }
1945
1946 if (ConfigResp != NULL) {
1947 FreePool (ConfigResp);
1948 }
1949
1950 if (ConfigAltResp != NULL) {
1951 FreePool (ConfigAltResp);
1952 }
1953
1954 if (HiiPackageList != NULL) {
1955 FreePool (HiiPackageList);
1956 }
1957
1958 if (EFI_ERROR (Status)) {
1959 return FALSE;
1960 }
1961
1962 return TRUE;
1963 }
1964
1965 /**
1966 Validate the current configuration by parsing HII form IFR opcode.
1967
1968 NULL request string support depends on the ExportConfig interface of
1969 HiiConfigRouting protocol in UEFI specification.
1970
1971 @param Request A null-terminated Unicode string in
1972 <MultiConfigRequest> format. It can be NULL.
1973 If it is NULL, all current configuration for the
1974 entirety of the current HII database will be validated.
1975
1976 @retval TRUE Current configuration is valid.
1977 @retval FALSE Current configuration is invalid.
1978 **/
1979 BOOLEAN
1980 EFIAPI
1981 HiiValidateSettings (
1982 IN CONST EFI_STRING Request OPTIONAL
1983 )
1984 {
1985 return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
1986 }
1987
1988 /**
1989 Reset the default value specified by DefaultId to the driver
1990 configuration got by Request string.
1991
1992 NULL request string support depends on the ExportConfig interface of
1993 HiiConfigRouting protocol in UEFI specification.
1994
1995 @param Request A null-terminated Unicode string in
1996 <MultiConfigRequest> format. It can be NULL.
1997 If it is NULL, all configuration for the
1998 entirety of the current HII database will be reset.
1999 @param DefaultId Specifies the type of defaults to retrieve.
2000
2001 @retval TURE The default value is set successfully.
2002 @retval FALSE The default value can't be found and set.
2003 **/
2004 BOOLEAN
2005 EFIAPI
2006 HiiSetToDefaults (
2007 IN CONST EFI_STRING Request, OPTIONAL
2008 IN UINT16 DefaultId
2009 )
2010 {
2011 return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
2012 }
2013
2014 /**
2015 Determines if two values in config strings match.
2016
2017 Compares the substring between StartSearchString and StopSearchString in
2018 FirstString to the substring between StartSearchString and StopSearchString
2019 in SecondString. If the two substrings match, then TRUE is returned. If the
2020 two substrings do not match, then FALSE is returned.
2021
2022 If FirstString is NULL, then ASSERT().
2023 If SecondString is NULL, then ASSERT().
2024 If StartSearchString is NULL, then ASSERT().
2025 If StopSearchString is NULL, then ASSERT().
2026
2027 @param FirstString Pointer to the first Null-terminated Unicode string.
2028 @param SecondString Pointer to the second Null-terminated Unicode string.
2029 @param StartSearchString Pointer to the Null-terminated Unicode string that
2030 marks the start of the value string to compare.
2031 @param StopSearchString Pointer to the Null-terminated Unicode string that
2032 marks the end of the value string to compare.
2033
2034 @retval FALSE StartSearchString is not present in FirstString.
2035 @retval FALSE StartSearchString is not present in SecondString.
2036 @retval FALSE StopSearchString is not present in FirstString.
2037 @retval FALSE StopSearchString is not present in SecondString.
2038 @retval FALSE The length of the substring in FirstString is not the
2039 same length as the substring in SecondString.
2040 @retval FALSE The value string in FirstString does not matche the
2041 value string in SecondString.
2042 @retval TRUE The value string in FirstString matches the value
2043 string in SecondString.
2044
2045 **/
2046 BOOLEAN
2047 EFIAPI
2048 InternalHiiCompareSubString (
2049 IN CHAR16 *FirstString,
2050 IN CHAR16 *SecondString,
2051 IN CHAR16 *StartSearchString,
2052 IN CHAR16 *StopSearchString
2053 )
2054 {
2055 CHAR16 *EndFirstString;
2056 CHAR16 *EndSecondString;
2057
2058 ASSERT (FirstString != NULL);
2059 ASSERT (SecondString != NULL);
2060 ASSERT (StartSearchString != NULL);
2061 ASSERT (StopSearchString != NULL);
2062
2063 FirstString = StrStr (FirstString, StartSearchString);
2064 if (FirstString == NULL) {
2065 return FALSE;
2066 }
2067
2068 SecondString = StrStr (SecondString, StartSearchString);
2069 if (SecondString == NULL) {
2070 return FALSE;
2071 }
2072
2073 EndFirstString = StrStr (FirstString, StopSearchString);
2074 if (EndFirstString == NULL) {
2075 return FALSE;
2076 }
2077
2078 EndSecondString = StrStr (SecondString, StopSearchString);
2079 if (EndSecondString == NULL) {
2080 return FALSE;
2081 }
2082
2083 if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
2084 return FALSE;
2085 }
2086
2087 return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
2088 }
2089
2090 /**
2091 Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
2092
2093 If ConfigHdr is NULL, then ASSERT().
2094
2095 @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
2096 @param[in] Guid GUID of the storage.
2097 @param[in] Name NAME of the storage.
2098
2099 @retval TRUE Routing information matches <ConfigHdr>.
2100 @retval FALSE Routing information does not match <ConfigHdr>.
2101
2102 **/
2103 BOOLEAN
2104 EFIAPI
2105 HiiIsConfigHdrMatch (
2106 IN CONST EFI_STRING ConfigHdr,
2107 IN CONST EFI_GUID *Guid, OPTIONAL
2108 IN CONST CHAR16 *Name OPTIONAL
2109 )
2110 {
2111 EFI_STRING CompareConfigHdr;
2112 BOOLEAN Result;
2113
2114 ASSERT (ConfigHdr != NULL);
2115
2116 //
2117 // Use Guid and Name to generate a <ConfigHdr> string
2118 //
2119 CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
2120 if (CompareConfigHdr == NULL) {
2121 return FALSE;
2122 }
2123
2124 Result = TRUE;
2125 if (Guid != NULL) {
2126 //
2127 // Compare GUID value strings
2128 //
2129 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
2130 }
2131
2132 if (Result && Name != NULL) {
2133 //
2134 // Compare NAME value strings
2135 //
2136 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
2137 }
2138
2139 //
2140 // Free the <ConfigHdr> string
2141 //
2142 FreePool (CompareConfigHdr);
2143
2144 return Result;
2145 }
2146
2147 /**
2148 Retrieves uncommitted data from the Form Browser and converts it to a binary
2149 buffer.
2150
2151 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2152 parameter that may be NULL.
2153 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2154 is an optional parameter that may be NULL.
2155 @param[in] BufferSize Length in bytes of buffer to hold retrieved data.
2156 @param[out] Buffer Buffer of data to be updated.
2157
2158 @retval FALSE The uncommitted data could not be retrieved.
2159 @retval TRUE The uncommitted data was retrieved.
2160
2161 **/
2162 BOOLEAN
2163 EFIAPI
2164 HiiGetBrowserData (
2165 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2166 IN CONST CHAR16 *VariableName, OPTIONAL
2167 IN UINTN BufferSize,
2168 OUT UINT8 *Buffer
2169 )
2170 {
2171 EFI_STRING ResultsData;
2172 UINTN Size;
2173 EFI_STRING ConfigResp;
2174 EFI_STATUS Status;
2175 CHAR16 *Progress;
2176
2177 //
2178 // Retrieve the results data from the Browser Callback
2179 //
2180 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
2181 if (ResultsData == NULL) {
2182 return FALSE;
2183 }
2184
2185 //
2186 // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
2187 //
2188 Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
2189 Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
2190 ConfigResp = AllocateZeroPool (Size);
2191 UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
2192
2193 //
2194 // Free the allocated buffer
2195 //
2196 FreePool (ResultsData);
2197 if (ConfigResp == NULL) {
2198 return FALSE;
2199 }
2200
2201 //
2202 // Convert <ConfigResp> to a buffer
2203 //
2204 Status = gHiiConfigRouting->ConfigToBlock (
2205 gHiiConfigRouting,
2206 ConfigResp,
2207 Buffer,
2208 &BufferSize,
2209 &Progress
2210 );
2211 //
2212 // Free the allocated buffer
2213 //
2214 FreePool (ConfigResp);
2215
2216 if (EFI_ERROR (Status)) {
2217 return FALSE;
2218 }
2219
2220 return TRUE;
2221 }
2222
2223 /**
2224 Updates uncommitted data in the Form Browser.
2225
2226 If Buffer is NULL, then ASSERT().
2227
2228 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2229 parameter that may be NULL.
2230 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2231 is an optional parameter that may be NULL.
2232 @param[in] BufferSize Length, in bytes, of Buffer.
2233 @param[in] Buffer Buffer of data to commit.
2234 @param[in] RequestElement An optional field to specify which part of the
2235 buffer data will be send back to Browser. If NULL,
2236 the whole buffer of data will be committed to
2237 Browser.
2238 <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
2239
2240 @retval FALSE The uncommitted data could not be updated.
2241 @retval TRUE The uncommitted data was updated.
2242
2243 **/
2244 BOOLEAN
2245 EFIAPI
2246 HiiSetBrowserData (
2247 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2248 IN CONST CHAR16 *VariableName, OPTIONAL
2249 IN UINTN BufferSize,
2250 IN CONST UINT8 *Buffer,
2251 IN CONST CHAR16 *RequestElement OPTIONAL
2252 )
2253 {
2254 UINTN Size;
2255 EFI_STRING ConfigRequest;
2256 EFI_STRING ConfigResp;
2257 EFI_STRING ResultsData;
2258
2259 ASSERT (Buffer != NULL);
2260
2261 //
2262 // Construct <ConfigRequest>
2263 //
2264 if (RequestElement == NULL) {
2265 //
2266 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2267 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
2268 //
2269 Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
2270 ConfigRequest = AllocateZeroPool (Size);
2271 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
2272 } else {
2273 //
2274 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2275 // followed by <RequestElement> followed by a Null-terminator
2276 //
2277 Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
2278 Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
2279 ConfigRequest = AllocateZeroPool (Size);
2280 UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
2281 }
2282 if (ConfigRequest == NULL) {
2283 return FALSE;
2284 }
2285
2286 //
2287 // Convert <ConfigRequest> to <ConfigResp>
2288 //
2289 ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
2290 FreePool (ConfigRequest);
2291 if (ConfigResp == NULL) {
2292 return FALSE;
2293 }
2294
2295 //
2296 // Set data in the uncommitted browser state information
2297 //
2298 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
2299 FreePool (ConfigResp);
2300
2301 return (BOOLEAN)(ResultsData != NULL);
2302 }
2303
2304 /////////////////////////////////////////
2305 /////////////////////////////////////////
2306 /// IFR Functions
2307 /////////////////////////////////////////
2308 /////////////////////////////////////////
2309
2310 #define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200
2311
2312 typedef struct {
2313 UINT8 *Buffer;
2314 UINTN BufferSize;
2315 UINTN Position;
2316 } HII_LIB_OPCODE_BUFFER;
2317
2318 ///
2319 /// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
2320 ///
2321 GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
2322 1, // EFI_IFR_TYPE_NUM_SIZE_8
2323 2, // EFI_IFR_TYPE_NUM_SIZE_16
2324 4, // EFI_IFR_TYPE_NUM_SIZE_32
2325 8, // EFI_IFR_TYPE_NUM_SIZE_64
2326 1, // EFI_IFR_TYPE_BOOLEAN
2327 3, // EFI_IFR_TYPE_TIME
2328 4, // EFI_IFR_TYPE_DATE
2329 2 // EFI_IFR_TYPE_STRING
2330 };
2331
2332 /**
2333 Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
2334 HiiFreeOpCodeHandle().
2335
2336 @retval NULL There are not enough resources to allocate a new OpCode Handle.
2337 @retval Other A new OpCode handle.
2338
2339 **/
2340 VOID *
2341 EFIAPI
2342 HiiAllocateOpCodeHandle (
2343 VOID
2344 )
2345 {
2346 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2347
2348 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
2349 if (OpCodeBuffer == NULL) {
2350 return NULL;
2351 }
2352 OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
2353 if (OpCodeBuffer->Buffer == NULL) {
2354 FreePool (OpCodeBuffer);
2355 return NULL;
2356 }
2357 OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
2358 OpCodeBuffer->Position = 0;
2359 return (VOID *)OpCodeBuffer;
2360 }
2361
2362 /**
2363 Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
2364 When an OpCode Handle is freed, all of the opcodes associated with the OpCode
2365 Handle are also freed.
2366
2367 If OpCodeHandle is NULL, then ASSERT().
2368
2369 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2370
2371 **/
2372 VOID
2373 EFIAPI
2374 HiiFreeOpCodeHandle (
2375 VOID *OpCodeHandle
2376 )
2377 {
2378 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2379
2380 ASSERT (OpCodeHandle != NULL);
2381
2382 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2383 if (OpCodeBuffer->Buffer != NULL) {
2384 FreePool (OpCodeBuffer->Buffer);
2385 }
2386 FreePool (OpCodeBuffer);
2387 }
2388
2389 /**
2390 Internal function gets the current position of opcode buffer.
2391
2392 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2393
2394 @return Current position of opcode buffer.
2395 **/
2396 UINTN
2397 EFIAPI
2398 InternalHiiOpCodeHandlePosition (
2399 IN VOID *OpCodeHandle
2400 )
2401 {
2402 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position;
2403 }
2404
2405 /**
2406 Internal function gets the start pointer of opcode buffer.
2407
2408 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2409
2410 @return Pointer to the opcode buffer base.
2411 **/
2412 UINT8 *
2413 EFIAPI
2414 InternalHiiOpCodeHandleBuffer (
2415 IN VOID *OpCodeHandle
2416 )
2417 {
2418 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer;
2419 }
2420
2421 /**
2422 Internal function reserves the enough buffer for current opcode.
2423 When the buffer is not enough, Opcode buffer will be extended.
2424
2425 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2426 @param[in] Size Size of current opcode.
2427
2428 @return Pointer to the current opcode.
2429 **/
2430 UINT8 *
2431 EFIAPI
2432 InternalHiiGrowOpCodeHandle (
2433 IN VOID *OpCodeHandle,
2434 IN UINTN Size
2435 )
2436 {
2437 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2438 UINT8 *Buffer;
2439
2440 ASSERT (OpCodeHandle != NULL);
2441
2442 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2443 if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
2444 Buffer = ReallocatePool (
2445 OpCodeBuffer->BufferSize,
2446 OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
2447 OpCodeBuffer->Buffer
2448 );
2449 ASSERT (Buffer != NULL);
2450 OpCodeBuffer->Buffer = Buffer;
2451 OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
2452 }
2453 Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
2454 OpCodeBuffer->Position += Size;
2455 return Buffer;
2456 }
2457
2458 /**
2459 Internal function creates opcode based on the template opcode.
2460
2461 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2462 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
2463 @param[in] OpCode OpCode IFR value.
2464 @param[in] OpCodeSize Size of opcode.
2465 @param[in] ExtensionSize Size of extended opcode.
2466 @param[in] Scope Scope bit of opcode.
2467
2468 @return Pointer to the current opcode with opcode data.
2469 **/
2470 UINT8 *
2471 EFIAPI
2472 InternalHiiCreateOpCodeExtended (
2473 IN VOID *OpCodeHandle,
2474 IN VOID *OpCodeTemplate,
2475 IN UINT8 OpCode,
2476 IN UINTN OpCodeSize,
2477 IN UINTN ExtensionSize,
2478 IN UINT8 Scope
2479 )
2480 {
2481 EFI_IFR_OP_HEADER *Header;
2482 UINT8 *Buffer;
2483
2484 ASSERT (OpCodeTemplate != NULL);
2485 ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
2486
2487 Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
2488 Header->OpCode = OpCode;
2489 Header->Scope = Scope;
2490 Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
2491 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
2492 return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
2493 }
2494
2495 /**
2496 Internal function creates opcode based on the template opcode for the normal opcode.
2497
2498 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2499 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
2500 @param[in] OpCode OpCode IFR value.
2501 @param[in] OpCodeSize Size of opcode.
2502
2503 @return Pointer to the current opcode with opcode data.
2504 **/
2505 UINT8 *
2506 EFIAPI
2507 InternalHiiCreateOpCode (
2508 IN VOID *OpCodeHandle,
2509 IN VOID *OpCodeTemplate,
2510 IN UINT8 OpCode,
2511 IN UINTN OpCodeSize
2512 )
2513 {
2514 return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
2515 }
2516
2517 /**
2518 Append raw opcodes to an OpCodeHandle.
2519
2520 If OpCodeHandle is NULL, then ASSERT().
2521 If RawBuffer is NULL, then ASSERT();
2522
2523 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2524 @param[in] RawBuffer Buffer of opcodes to append.
2525 @param[in] RawBufferSize The size, in bytes, of Buffer.
2526
2527 @retval NULL There is not enough space left in Buffer to add the opcode.
2528 @retval Other A pointer to the appended opcodes.
2529
2530 **/
2531 UINT8 *
2532 EFIAPI
2533 HiiCreateRawOpCodes (
2534 IN VOID *OpCodeHandle,
2535 IN UINT8 *RawBuffer,
2536 IN UINTN RawBufferSize
2537 )
2538 {
2539 UINT8 *Buffer;
2540
2541 ASSERT (RawBuffer != NULL);
2542
2543 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
2544 return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
2545 }
2546
2547 /**
2548 Append opcodes from one OpCode Handle to another OpCode handle.
2549
2550 If OpCodeHandle is NULL, then ASSERT().
2551 If RawOpCodeHandle is NULL, then ASSERT();
2552
2553 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2554 @param[in] RawOpCodeHandle Handle to the buffer of opcodes.
2555
2556 @retval NULL There is not enough space left in Buffer to add the opcode.
2557 @retval Other A pointer to the appended opcodes.
2558
2559 **/
2560 UINT8 *
2561 EFIAPI
2562 InternalHiiAppendOpCodes (
2563 IN VOID *OpCodeHandle,
2564 IN VOID *RawOpCodeHandle
2565 )
2566 {
2567 HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer;
2568
2569 ASSERT (RawOpCodeHandle != NULL);
2570
2571 RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
2572 return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
2573 }
2574
2575 /**
2576 Create EFI_IFR_END_OP opcode.
2577
2578 If OpCodeHandle is NULL, then ASSERT().
2579
2580 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2581
2582 @retval NULL There is not enough space left in Buffer to add the opcode.
2583 @retval Other A pointer to the created opcode.
2584
2585 **/
2586 UINT8 *
2587 EFIAPI
2588 HiiCreateEndOpCode (
2589 IN VOID *OpCodeHandle
2590 )
2591 {
2592 EFI_IFR_END OpCode;
2593
2594 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
2595 }
2596
2597 /**
2598 Create EFI_IFR_ONE_OF_OPTION_OP opcode.
2599
2600 If OpCodeHandle is NULL, then ASSERT().
2601 If Type is invalid, then ASSERT().
2602 If Flags is invalid, then ASSERT().
2603
2604 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2605 @param[in] StringId StringId for the option
2606 @param[in] Flags Flags for the option
2607 @param[in] Type Type for the option
2608 @param[in] Value Value for the option
2609
2610 @retval NULL There is not enough space left in Buffer to add the opcode.
2611 @retval Other A pointer to the created opcode.
2612
2613 **/
2614 UINT8 *
2615 EFIAPI
2616 HiiCreateOneOfOptionOpCode (
2617 IN VOID *OpCodeHandle,
2618 IN UINT16 StringId,
2619 IN UINT8 Flags,
2620 IN UINT8 Type,
2621 IN UINT64 Value
2622 )
2623 {
2624 EFI_IFR_ONE_OF_OPTION OpCode;
2625
2626 ASSERT (Type < EFI_IFR_TYPE_OTHER);
2627
2628 ZeroMem (&OpCode, sizeof (OpCode));
2629 OpCode.Option = StringId;
2630 OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
2631 OpCode.Type = Type;
2632 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
2633
2634 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
2635 }
2636
2637 /**
2638 Create EFI_IFR_DEFAULT_OP opcode.
2639
2640 If OpCodeHandle is NULL, then ASSERT().
2641 If Type is invalid, then ASSERT().
2642
2643 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2644 @param[in] DefaultId DefaultId for the default
2645 @param[in] Type Type for the default
2646 @param[in] Value Value for the default
2647
2648 @retval NULL There is not enough space left in Buffer to add the opcode.
2649 @retval Other A pointer to the created opcode.
2650
2651 **/
2652 UINT8 *
2653 EFIAPI
2654 HiiCreateDefaultOpCode (
2655 IN VOID *OpCodeHandle,
2656 IN UINT16 DefaultId,
2657 IN UINT8 Type,
2658 IN UINT64 Value
2659 )
2660 {
2661 EFI_IFR_DEFAULT OpCode;
2662
2663 ASSERT (Type < EFI_IFR_TYPE_OTHER);
2664
2665 ZeroMem (&OpCode, sizeof (OpCode));
2666 OpCode.Type = Type;
2667 OpCode.DefaultId = DefaultId;
2668 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
2669
2670 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
2671 }
2672
2673 /**
2674 Create EFI_IFR_GUID opcode.
2675
2676 If OpCodeHandle is NULL, then ASSERT().
2677 If Guid is NULL, then ASSERT().
2678 If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
2679
2680 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2681 @param[in] Guid Pointer to EFI_GUID of this guided opcode.
2682 @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an
2683 optional parameter that may be NULL. If this
2684 parameter is NULL, then the GUID extension
2685 region of the created opcode is filled with zeros.
2686 If this parameter is not NULL, then the GUID
2687 extension region of GuidData will be copied to
2688 the GUID extension region of the created opcode.
2689 @param[in] OpCodeSize The size, in bytes, of created opcode. This value
2690 must be >= sizeof(EFI_IFR_GUID).
2691
2692 @retval NULL There is not enough space left in Buffer to add the opcode.
2693 @retval Other A pointer to the created opcode.
2694
2695 **/
2696 UINT8 *
2697 EFIAPI
2698 HiiCreateGuidOpCode (
2699 IN VOID *OpCodeHandle,
2700 IN CONST EFI_GUID *Guid,
2701 IN CONST VOID *GuidOpCode, OPTIONAL
2702 IN UINTN OpCodeSize
2703 )
2704 {
2705 EFI_IFR_GUID OpCode;
2706 EFI_IFR_GUID *OpCodePointer;
2707
2708 ASSERT (Guid != NULL);
2709 ASSERT (OpCodeSize >= sizeof (OpCode));
2710
2711 ZeroMem (&OpCode, sizeof (OpCode));
2712 CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
2713
2714 OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
2715 OpCodeHandle,
2716 &OpCode,
2717 EFI_IFR_GUID_OP,
2718 sizeof (OpCode),
2719 OpCodeSize - sizeof (OpCode),
2720 0
2721 );
2722 if (OpCodePointer != NULL && GuidOpCode != NULL) {
2723 CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
2724 }
2725 return (UINT8 *)OpCodePointer;
2726 }
2727
2728 /**
2729 Create EFI_IFR_ACTION_OP opcode.
2730
2731 If OpCodeHandle is NULL, then ASSERT().
2732 If any reserved bits are set in QuestionFlags, then ASSERT().
2733
2734 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2735 @param[in] QuestionId Question ID
2736 @param[in] Prompt String ID for Prompt
2737 @param[in] Help String ID for Help
2738 @param[in] QuestionFlags Flags in Question Header
2739 @param[in] QuestionConfig String ID for configuration
2740
2741 @retval NULL There is not enough space left in Buffer to add the opcode.
2742 @retval Other A pointer to the created opcode.
2743
2744 **/
2745 UINT8 *
2746 EFIAPI
2747 HiiCreateActionOpCode (
2748 IN VOID *OpCodeHandle,
2749 IN EFI_QUESTION_ID QuestionId,
2750 IN EFI_STRING_ID Prompt,
2751 IN EFI_STRING_ID Help,
2752 IN UINT8 QuestionFlags,
2753 IN EFI_STRING_ID QuestionConfig
2754 )
2755 {
2756 EFI_IFR_ACTION OpCode;
2757
2758 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
2759
2760 ZeroMem (&OpCode, sizeof (OpCode));
2761 OpCode.Question.QuestionId = QuestionId;
2762 OpCode.Question.Header.Prompt = Prompt;
2763 OpCode.Question.Header.Help = Help;
2764 OpCode.Question.Flags = QuestionFlags;
2765 OpCode.QuestionConfig = QuestionConfig;
2766
2767 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
2768 }
2769
2770 /**
2771 Create EFI_IFR_SUBTITLE_OP opcode.
2772
2773 If OpCodeHandle is NULL, then ASSERT().
2774 If any reserved bits are set in Flags, then ASSERT().
2775 If Scope > 1, then ASSERT().
2776
2777 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2778 @param[in] Prompt String ID for Prompt
2779 @param[in] Help String ID for Help
2780 @param[in] Flags Subtitle opcode flags
2781 @param[in] Scope 1 if this opcpde is the beginning of a new scope.
2782 0 if this opcode is within the current scope.
2783
2784 @retval NULL There is not enough space left in Buffer to add the opcode.
2785 @retval Other A pointer to the created opcode.
2786
2787 **/
2788 UINT8 *
2789 EFIAPI
2790 HiiCreateSubTitleOpCode (
2791 IN VOID *OpCodeHandle,
2792 IN EFI_STRING_ID Prompt,
2793 IN EFI_STRING_ID Help,
2794 IN UINT8 Flags,
2795 IN UINT8 Scope
2796 )
2797 {
2798 EFI_IFR_SUBTITLE OpCode;
2799
2800 ASSERT (Scope <= 1);
2801 ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
2802
2803 ZeroMem (&OpCode, sizeof (OpCode));
2804 OpCode.Statement.Prompt = Prompt;
2805 OpCode.Statement.Help = Help;
2806 OpCode.Flags = Flags;
2807
2808 return InternalHiiCreateOpCodeExtended (
2809 OpCodeHandle,
2810 &OpCode,
2811 EFI_IFR_SUBTITLE_OP,
2812 sizeof (OpCode),
2813 0,
2814 Scope
2815 );
2816 }
2817
2818 /**
2819 Create EFI_IFR_REF_OP opcode.
2820
2821 If OpCodeHandle is NULL, then ASSERT().
2822 If any reserved bits are set in QuestionFlags, then ASSERT().
2823
2824 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2825 @param[in] FormId Destination Form ID
2826 @param[in] Prompt String ID for Prompt
2827 @param[in] Help String ID for Help
2828 @param[in] QuestionFlags Flags in Question Header
2829 @param[in] QuestionId Question ID
2830
2831 @retval NULL There is not enough space left in Buffer to add the opcode.
2832 @retval Other A pointer to the created opcode.
2833
2834 **/
2835 UINT8 *
2836 EFIAPI
2837 HiiCreateGotoOpCode (
2838 IN VOID *OpCodeHandle,
2839 IN EFI_FORM_ID FormId,
2840 IN EFI_STRING_ID Prompt,
2841 IN EFI_STRING_ID Help,
2842 IN UINT8 QuestionFlags,
2843 IN EFI_QUESTION_ID QuestionId
2844 )
2845 {
2846 EFI_IFR_REF OpCode;
2847
2848 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
2849
2850 ZeroMem (&OpCode, sizeof (OpCode));
2851 OpCode.Question.Header.Prompt = Prompt;
2852 OpCode.Question.Header.Help = Help;
2853 OpCode.Question.QuestionId = QuestionId;
2854 OpCode.Question.Flags = QuestionFlags;
2855 OpCode.FormId = FormId;
2856
2857 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
2858 }
2859
2860 /**
2861 Create EFI_IFR_CHECKBOX_OP opcode.
2862
2863 If OpCodeHandle is NULL, then ASSERT().
2864 If any reserved bits are set in QuestionFlags, then ASSERT().
2865 If any reserved bits are set in CheckBoxFlags, then ASSERT().
2866
2867 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2868 @param[in] QuestionId Question ID
2869 @param[in] VarStoreId Storage ID
2870 @param[in] VarOffset Offset in Storage
2871 @param[in] Prompt String ID for Prompt
2872 @param[in] Help String ID for Help
2873 @param[in] QuestionFlags Flags in Question Header
2874 @param[in] CheckBoxFlags Flags for checkbox opcode
2875 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
2876 is an optional parameter that may be NULL.
2877
2878 @retval NULL There is not enough space left in Buffer to add the opcode.
2879 @retval Other A pointer to the created opcode.
2880
2881 **/
2882 UINT8 *
2883 EFIAPI
2884 HiiCreateCheckBoxOpCode (
2885 IN VOID *OpCodeHandle,
2886 IN EFI_QUESTION_ID QuestionId,
2887 IN EFI_VARSTORE_ID VarStoreId,
2888 IN UINT16 VarOffset,
2889 IN EFI_STRING_ID Prompt,
2890 IN EFI_STRING_ID Help,
2891 IN UINT8 QuestionFlags,
2892 IN UINT8 CheckBoxFlags,
2893 IN VOID *DefaultsOpCodeHandle OPTIONAL
2894 )
2895 {
2896 EFI_IFR_CHECKBOX OpCode;
2897 UINTN Position;
2898
2899 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
2900
2901 ZeroMem (&OpCode, sizeof (OpCode));
2902 OpCode.Question.QuestionId = QuestionId;
2903 OpCode.Question.VarStoreId = VarStoreId;
2904 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
2905 OpCode.Question.Header.Prompt = Prompt;
2906 OpCode.Question.Header.Help = Help;
2907 OpCode.Question.Flags = QuestionFlags;
2908 OpCode.Flags = CheckBoxFlags;
2909
2910 if (DefaultsOpCodeHandle == NULL) {
2911 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
2912 }
2913
2914 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
2915 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
2916 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
2917 HiiCreateEndOpCode (OpCodeHandle);
2918 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
2919 }
2920
2921 /**
2922 Create EFI_IFR_NUMERIC_OP opcode.
2923
2924 If OpCodeHandle is NULL, then ASSERT().
2925 If any reserved bits are set in QuestionFlags, then ASSERT().
2926 If any reserved bits are set in NumericFlags, then ASSERT().
2927
2928 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2929 @param[in] QuestionId Question ID
2930 @param[in] VarStoreId Storage ID
2931 @param[in] VarOffset Offset in Storage
2932 @param[in] Prompt String ID for Prompt
2933 @param[in] Help String ID for Help
2934 @param[in] QuestionFlags Flags in Question Header
2935 @param[in] NumericFlags Flags for numeric opcode
2936 @param[in] Minimum Numeric minimum value
2937 @param[in] Maximum Numeric maximum value
2938 @param[in] Step Numeric step for edit
2939 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
2940 is an optional parameter that may be NULL.
2941
2942 @retval NULL There is not enough space left in Buffer to add the opcode.
2943 @retval Other A pointer to the created opcode.
2944
2945 **/
2946 UINT8 *
2947 EFIAPI
2948 HiiCreateNumericOpCode (
2949 IN VOID *OpCodeHandle,
2950 IN EFI_QUESTION_ID QuestionId,
2951 IN EFI_VARSTORE_ID VarStoreId,
2952 IN UINT16 VarOffset,
2953 IN EFI_STRING_ID Prompt,
2954 IN EFI_STRING_ID Help,
2955 IN UINT8 QuestionFlags,
2956 IN UINT8 NumericFlags,
2957 IN UINT64 Minimum,
2958 IN UINT64 Maximum,
2959 IN UINT64 Step,
2960 IN VOID *DefaultsOpCodeHandle OPTIONAL
2961 )
2962 {
2963 EFI_IFR_NUMERIC OpCode;
2964 UINTN Position;
2965 UINTN Length;
2966
2967 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
2968
2969 Length = 0;
2970 ZeroMem (&OpCode, sizeof (OpCode));
2971 OpCode.Question.QuestionId = QuestionId;
2972 OpCode.Question.VarStoreId = VarStoreId;
2973 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
2974 OpCode.Question.Header.Prompt = Prompt;
2975 OpCode.Question.Header.Help = Help;
2976 OpCode.Question.Flags = QuestionFlags;
2977 OpCode.Flags = NumericFlags;
2978
2979 switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
2980 case EFI_IFR_NUMERIC_SIZE_1:
2981 OpCode.data.u8.MinValue = (UINT8)Minimum;
2982 OpCode.data.u8.MaxValue = (UINT8)Maximum;
2983 OpCode.data.u8.Step = (UINT8)Step;
2984 Length = 3;
2985 break;
2986
2987 case EFI_IFR_NUMERIC_SIZE_2:
2988 OpCode.data.u16.MinValue = (UINT16)Minimum;
2989 OpCode.data.u16.MaxValue = (UINT16)Maximum;
2990 OpCode.data.u16.Step = (UINT16)Step;
2991 Length = 6;
2992 break;
2993
2994 case EFI_IFR_NUMERIC_SIZE_4:
2995 OpCode.data.u32.MinValue = (UINT32)Minimum;
2996 OpCode.data.u32.MaxValue = (UINT32)Maximum;
2997 OpCode.data.u32.Step = (UINT32)Step;
2998 Length = 12;
2999 break;
3000
3001 case EFI_IFR_NUMERIC_SIZE_8:
3002 OpCode.data.u64.MinValue = Minimum;
3003 OpCode.data.u64.MaxValue = Maximum;
3004 OpCode.data.u64.Step = Step;
3005 Length = 24;
3006 break;
3007 }
3008
3009 Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
3010
3011 if (DefaultsOpCodeHandle == NULL) {
3012 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
3013 }
3014
3015 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3016 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
3017 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3018 HiiCreateEndOpCode (OpCodeHandle);
3019 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3020 }
3021
3022 /**
3023 Create EFI_IFR_STRING_OP opcode.
3024
3025 If OpCodeHandle is NULL, then ASSERT().
3026 If any reserved bits are set in QuestionFlags, then ASSERT().
3027 If any reserved bits are set in StringFlags, then ASSERT().
3028
3029 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3030 @param[in] QuestionId Question ID
3031 @param[in] VarStoreId Storage ID
3032 @param[in] VarOffset Offset in Storage
3033 @param[in] Prompt String ID for Prompt
3034 @param[in] Help String ID for Help
3035 @param[in] QuestionFlags Flags in Question Header
3036 @param[in] StringFlags Flags for string opcode
3037 @param[in] MinSize String minimum length
3038 @param[in] MaxSize String maximum length
3039 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3040 is an optional parameter that may be NULL.
3041
3042 @retval NULL There is not enough space left in Buffer to add the opcode.
3043 @retval Other A pointer to the created opcode.
3044
3045 **/
3046 UINT8 *
3047 EFIAPI
3048 HiiCreateStringOpCode (
3049 IN VOID *OpCodeHandle,
3050 IN EFI_QUESTION_ID QuestionId,
3051 IN EFI_VARSTORE_ID VarStoreId,
3052 IN UINT16 VarOffset,
3053 IN EFI_STRING_ID Prompt,
3054 IN EFI_STRING_ID Help,
3055 IN UINT8 QuestionFlags,
3056 IN UINT8 StringFlags,
3057 IN UINT8 MinSize,
3058 IN UINT8 MaxSize,
3059 IN VOID *DefaultsOpCodeHandle OPTIONAL
3060 )
3061 {
3062 EFI_IFR_STRING OpCode;
3063 UINTN Position;
3064
3065 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3066
3067 ZeroMem (&OpCode, sizeof (OpCode));
3068 OpCode.Question.Header.Prompt = Prompt;
3069 OpCode.Question.Header.Help = Help;
3070 OpCode.Question.QuestionId = QuestionId;
3071 OpCode.Question.VarStoreId = VarStoreId;
3072 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3073 OpCode.Question.Flags = QuestionFlags;
3074 OpCode.MinSize = MinSize;
3075 OpCode.MaxSize = MaxSize;
3076 OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
3077
3078 if (DefaultsOpCodeHandle == NULL) {
3079 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
3080 }
3081
3082 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3083 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
3084 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3085 HiiCreateEndOpCode (OpCodeHandle);
3086 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3087 }
3088
3089 /**
3090 Create EFI_IFR_ONE_OF_OP opcode.
3091
3092 If OpCodeHandle is NULL, then ASSERT().
3093 If any reserved bits are set in QuestionFlags, then ASSERT().
3094 If any reserved bits are set in OneOfFlags, then ASSERT().
3095
3096 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3097 @param[in] QuestionId Question ID
3098 @param[in] VarStoreId Storage ID
3099 @param[in] VarOffset Offset in Storage
3100 @param[in] Prompt String ID for Prompt
3101 @param[in] Help String ID for Help
3102 @param[in] QuestionFlags Flags in Question Header
3103 @param[in] OneOfFlags Flags for oneof opcode
3104 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3105 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3106 is an optional parameter that may be NULL.
3107
3108 @retval NULL There is not enough space left in Buffer to add the opcode.
3109 @retval Other A pointer to the created opcode.
3110
3111 **/
3112 UINT8 *
3113 EFIAPI
3114 HiiCreateOneOfOpCode (
3115 IN VOID *OpCodeHandle,
3116 IN EFI_QUESTION_ID QuestionId,
3117 IN EFI_VARSTORE_ID VarStoreId,
3118 IN UINT16 VarOffset,
3119 IN EFI_STRING_ID Prompt,
3120 IN EFI_STRING_ID Help,
3121 IN UINT8 QuestionFlags,
3122 IN UINT8 OneOfFlags,
3123 IN VOID *OptionsOpCodeHandle,
3124 IN VOID *DefaultsOpCodeHandle OPTIONAL
3125 )
3126 {
3127 EFI_IFR_ONE_OF OpCode;
3128 UINTN Position;
3129 UINTN Length;
3130
3131 ASSERT (OptionsOpCodeHandle != NULL);
3132 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3133
3134 ZeroMem (&OpCode, sizeof (OpCode));
3135 OpCode.Question.Header.Prompt = Prompt;
3136 OpCode.Question.Header.Help = Help;
3137 OpCode.Question.QuestionId = QuestionId;
3138 OpCode.Question.VarStoreId = VarStoreId;
3139 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3140 OpCode.Question.Flags = QuestionFlags;
3141 OpCode.Flags = OneOfFlags;
3142
3143 Length = OFFSET_OF (EFI_IFR_ONE_OF, data);
3144 Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
3145
3146 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3147 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
3148 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3149 if (DefaultsOpCodeHandle != NULL) {
3150 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3151 }
3152 HiiCreateEndOpCode (OpCodeHandle);
3153 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3154 }
3155
3156 /**
3157 Create EFI_IFR_ORDERED_LIST_OP opcode.
3158
3159 If OpCodeHandle is NULL, then ASSERT().
3160 If any reserved bits are set in QuestionFlags, then ASSERT().
3161 If any reserved bits are set in OrderedListFlags, then ASSERT().
3162
3163 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3164 @param[in] QuestionId Question ID
3165 @param[in] VarStoreId Storage ID
3166 @param[in] VarOffset Offset in Storage
3167 @param[in] Prompt String ID for Prompt
3168 @param[in] Help String ID for Help
3169 @param[in] QuestionFlags Flags in Question Header
3170 @param[in] OrderedListFlags Flags for ordered list opcode
3171 @param[in] DataType Type for option value
3172 @param[in] MaxContainers Maximum count for options in this ordered list
3173 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3174 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3175 is an optional parameter that may be NULL.
3176
3177 @retval NULL There is not enough space left in Buffer to add the opcode.
3178 @retval Other A pointer to the created opcode.
3179
3180 **/
3181 UINT8 *
3182 EFIAPI
3183 HiiCreateOrderedListOpCode (
3184 IN VOID *OpCodeHandle,
3185 IN EFI_QUESTION_ID QuestionId,
3186 IN EFI_VARSTORE_ID VarStoreId,
3187 IN UINT16 VarOffset,
3188 IN EFI_STRING_ID Prompt,
3189 IN EFI_STRING_ID Help,
3190 IN UINT8 QuestionFlags,
3191 IN UINT8 OrderedListFlags,
3192 IN UINT8 DataType,
3193 IN UINT8 MaxContainers,
3194 IN VOID *OptionsOpCodeHandle,
3195 IN VOID *DefaultsOpCodeHandle OPTIONAL
3196 )
3197 {
3198 EFI_IFR_ORDERED_LIST OpCode;
3199 UINTN Position;
3200
3201 ASSERT (OptionsOpCodeHandle != NULL);
3202 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3203
3204 ZeroMem (&OpCode, sizeof (OpCode));
3205 OpCode.Question.Header.Prompt = Prompt;
3206 OpCode.Question.Header.Help = Help;
3207 OpCode.Question.QuestionId = QuestionId;
3208 OpCode.Question.VarStoreId = VarStoreId;
3209 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3210 OpCode.Question.Flags = QuestionFlags;
3211 OpCode.MaxContainers = MaxContainers;
3212 OpCode.Flags = OrderedListFlags;
3213
3214 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3215 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
3216 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3217 if (DefaultsOpCodeHandle != NULL) {
3218 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3219 }
3220 HiiCreateEndOpCode (OpCodeHandle);
3221 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3222 }
3223
3224 /**
3225 Create EFI_IFR_TEXT_OP opcode.
3226
3227 If OpCodeHandle is NULL, then ASSERT().
3228
3229 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3230 @param[in] Prompt String ID for Prompt.
3231 @param[in] Help String ID for Help.
3232 @param[in] TextTwo String ID for TextTwo.
3233
3234 @retval NULL There is not enough space left in Buffer to add the opcode.
3235 @retval Other A pointer to the created opcode.
3236
3237 **/
3238 UINT8 *
3239 EFIAPI
3240 HiiCreateTextOpCode (
3241 IN VOID *OpCodeHandle,
3242 IN EFI_STRING_ID Prompt,
3243 IN EFI_STRING_ID Help,
3244 IN EFI_STRING_ID TextTwo
3245 )
3246 {
3247 EFI_IFR_TEXT OpCode;
3248
3249 ZeroMem (&OpCode, sizeof (OpCode));
3250 OpCode.Statement.Prompt = Prompt;
3251 OpCode.Statement.Help = Help;
3252 OpCode.TextTwo = TextTwo;
3253
3254 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
3255 }
3256
3257 /**
3258 Create EFI_IFR_DATE_OP opcode.
3259
3260 If OpCodeHandle is NULL, then ASSERT().
3261 If any reserved bits are set in QuestionFlags, then ASSERT().
3262 If any reserved bits are set in DateFlags, then ASSERT().
3263
3264 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3265 @param[in] QuestionId Question ID
3266 @param[in] VarStoreId Storage ID, optional. If DateFlags is not
3267 QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3268 @param[in] VarOffset Offset in Storage, optional. If DateFlags is not
3269 QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3270 @param[in] Prompt String ID for Prompt
3271 @param[in] Help String ID for Help
3272 @param[in] QuestionFlags Flags in Question Header
3273 @param[in] DateFlags Flags for date opcode
3274 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3275 is an optional parameter that may be NULL.
3276
3277 @retval NULL There is not enough space left in Buffer to add the opcode.
3278 @retval Other A pointer to the created opcode.
3279
3280 **/
3281 UINT8 *
3282 EFIAPI
3283 HiiCreateDateOpCode (
3284 IN VOID *OpCodeHandle,
3285 IN EFI_QUESTION_ID QuestionId,
3286 IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
3287 IN UINT16 VarOffset, OPTIONAL
3288 IN EFI_STRING_ID Prompt,
3289 IN EFI_STRING_ID Help,
3290 IN UINT8 QuestionFlags,
3291 IN UINT8 DateFlags,
3292 IN VOID *DefaultsOpCodeHandle OPTIONAL
3293 )
3294 {
3295 EFI_IFR_DATE OpCode;
3296 UINTN Position;
3297
3298 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3299 ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
3300
3301 ZeroMem (&OpCode, sizeof (OpCode));
3302 OpCode.Question.Header.Prompt = Prompt;
3303 OpCode.Question.Header.Help = Help;
3304 OpCode.Question.QuestionId = QuestionId;
3305 OpCode.Question.VarStoreId = VarStoreId;
3306 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3307 OpCode.Question.Flags = QuestionFlags;
3308 OpCode.Flags = DateFlags;
3309
3310 if (DefaultsOpCodeHandle == NULL) {
3311 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
3312 }
3313
3314 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3315 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
3316 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3317 HiiCreateEndOpCode (OpCodeHandle);
3318 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3319 }
3320
3321 /**
3322 Create EFI_IFR_TIME_OP opcode.
3323
3324 If OpCodeHandle is NULL, then ASSERT().
3325 If any reserved bits are set in QuestionFlags, then ASSERT().
3326 If any reserved bits are set in TimeFlags, then ASSERT().
3327
3328 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3329 @param[in] QuestionId Question ID
3330 @param[in] VarStoreId Storage ID, optional. If TimeFlags is not
3331 QF_TIME_STORAGE_NORMAL, this parameter is ignored.
3332 @param[in] VarOffset Offset in Storage, optional. If TimeFlags is not
3333 QF_TIME_STORAGE_NORMAL, this parameter is ignored.
3334 @param[in] Prompt String ID for Prompt
3335 @param[in] Help String ID for Help
3336 @param[in] QuestionFlags Flags in Question Header
3337 @param[in] TimeFlags Flags for time opcode
3338 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3339 is an optional parameter that may be NULL.
3340
3341 @retval NULL There is not enough space left in Buffer to add the opcode.
3342 @retval Other A pointer to the created opcode.
3343
3344 **/
3345 UINT8 *
3346 EFIAPI
3347 HiiCreateTimeOpCode (
3348 IN VOID *OpCodeHandle,
3349 IN EFI_QUESTION_ID QuestionId,
3350 IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
3351 IN UINT16 VarOffset, OPTIONAL
3352 IN EFI_STRING_ID Prompt,
3353 IN EFI_STRING_ID Help,
3354 IN UINT8 QuestionFlags,
3355 IN UINT8 TimeFlags,
3356 IN VOID *DefaultsOpCodeHandle OPTIONAL
3357 )
3358 {
3359 EFI_IFR_TIME OpCode;
3360 UINTN Position;
3361
3362 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3363 ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
3364
3365 ZeroMem (&OpCode, sizeof (OpCode));
3366 OpCode.Question.Header.Prompt = Prompt;
3367 OpCode.Question.Header.Help = Help;
3368 OpCode.Question.QuestionId = QuestionId;
3369 OpCode.Question.VarStoreId = VarStoreId;
3370 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3371 OpCode.Question.Flags = QuestionFlags;
3372 OpCode.Flags = TimeFlags;
3373
3374 if (DefaultsOpCodeHandle == NULL) {
3375 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
3376 }
3377
3378 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3379 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
3380 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3381 HiiCreateEndOpCode (OpCodeHandle);
3382 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3383 }
3384
3385 /**
3386 This is the internal worker function to update the data in
3387 a form specified by FormSetGuid, FormId and Label.
3388
3389 @param[in] FormSetGuid The optional Formset GUID.
3390 @param[in] FormId The Form ID.
3391 @param[in] Package The package header.
3392 @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
3393 opcodes to be inserted or replaced in the form.
3394 @param[in] OpCodeBufferEnd An OpCcode buffer that contains the IFR opcode
3395 that marks the end of a replace operation in the form.
3396 @param[out] TempPackage The resultant package.
3397
3398 @retval EFI_SUCCESS The function completes successfully.
3399 @retval EFI_NOT_FOUND The updated opcode or endopcode is not found.
3400
3401 **/
3402 EFI_STATUS
3403 EFIAPI
3404 InternalHiiUpdateFormPackageData (
3405 IN EFI_GUID *FormSetGuid, OPTIONAL
3406 IN EFI_FORM_ID FormId,
3407 IN EFI_HII_PACKAGE_HEADER *Package,
3408 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart,
3409 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL
3410 OUT EFI_HII_PACKAGE_HEADER *TempPackage
3411 )
3412 {
3413 UINTN AddSize;
3414 UINT8 *BufferPos;
3415 EFI_HII_PACKAGE_HEADER PackageHeader;
3416 UINTN Offset;
3417 EFI_IFR_OP_HEADER *IfrOpHdr;
3418 EFI_IFR_OP_HEADER *UpdateIfrOpHdr;
3419 BOOLEAN GetFormSet;
3420 BOOLEAN GetForm;
3421 BOOLEAN Updated;
3422 UINTN UpdatePackageLength;
3423
3424 CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3425 UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
3426 BufferPos = (UINT8 *) (TempPackage + 1);
3427
3428 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3429 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
3430 Offset = sizeof (EFI_HII_PACKAGE_HEADER);
3431 GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
3432 GetForm = FALSE;
3433 Updated = FALSE;
3434
3435 while (Offset < PackageHeader.Length) {
3436 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
3437 BufferPos += IfrOpHdr->Length;
3438 UpdatePackageLength += IfrOpHdr->Length;
3439
3440 //
3441 // Find the matched FormSet and Form
3442 //
3443 if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
3444 if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
3445 GetFormSet = TRUE;
3446 } else {
3447 GetFormSet = FALSE;
3448 }
3449 } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
3450 if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
3451 GetForm = TRUE;
3452 } else {
3453 GetForm = FALSE;
3454 }
3455 }
3456
3457 //
3458 // The matched Form is found, and Update data in this form
3459 //
3460 if (GetFormSet && GetForm) {
3461 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
3462 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
3463 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
3464 //
3465 // Remove the original data when End OpCode buffer exist.
3466 //
3467 if (OpCodeBufferEnd != NULL) {
3468 Offset += IfrOpHdr->Length;
3469 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
3470 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
3471 while (Offset < PackageHeader.Length) {
3472 //
3473 // Search the matched end opcode
3474 //
3475 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
3476 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
3477 break;
3478 }
3479 //
3480 // Go to the next Op-Code
3481 //
3482 Offset += IfrOpHdr->Length;
3483 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
3484 }
3485
3486 if (Offset >= PackageHeader.Length) {
3487 //
3488 // The end opcode is not found.
3489 //
3490 return EFI_NOT_FOUND;
3491 }
3492 }
3493
3494 //
3495 // Insert the updated data
3496 //
3497 AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
3498 CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
3499 BufferPos += OpCodeBufferStart->Position - AddSize;
3500 UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
3501
3502 if (OpCodeBufferEnd != NULL) {
3503 //
3504 // Add the end opcode
3505 //
3506 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
3507 BufferPos += IfrOpHdr->Length;
3508 UpdatePackageLength += IfrOpHdr->Length;
3509 }
3510
3511 //
3512 // Copy the left package data.
3513 //
3514 Offset += IfrOpHdr->Length;
3515 CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
3516 UpdatePackageLength += PackageHeader.Length - Offset;
3517
3518 //
3519 // Set update flag
3520 //
3521 Updated = TRUE;
3522 break;
3523 }
3524 }
3525
3526 //
3527 // Go to the next Op-Code
3528 //
3529 Offset += IfrOpHdr->Length;
3530 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
3531 }
3532
3533 if (!Updated) {
3534 //
3535 // The updated opcode buffer is not found.
3536 //
3537 return EFI_NOT_FOUND;
3538 }
3539 //
3540 // Update the package length.
3541 //
3542 PackageHeader.Length = (UINT32) UpdatePackageLength;
3543 CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
3544
3545 return EFI_SUCCESS;
3546 }
3547
3548 /**
3549 This function updates a form that has previously been registered with the HII
3550 Database. This function will perform at most one update operation.
3551
3552 The form to update is specified by Handle, FormSetGuid, and FormId. Binary
3553 comparisons of IFR opcodes are performed from the beginning of the form being
3554 updated until an IFR opcode is found that exactly matches the first IFR opcode
3555 specified by StartOpCodeHandle. The following rules are used to determine if
3556 an insert, replace, or delete operation is performed.
3557
3558 1) If no matches are found, then NULL is returned.
3559 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
3560 from StartOpCodeHandle except the first opcode are inserted immediately after
3561 the matching IFR opcode in the form to be updated.
3562 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
3563 from the matching IFR opcode until an IFR opcode exactly matches the first
3564 IFR opcode specified by EndOpCodeHandle. If no match is found for the first
3565 IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
3566 is found, then all of the IFR opcodes between the start match and the end
3567 match are deleted from the form being updated and all of the IFR opcodes
3568 from StartOpCodeHandle except the first opcode are inserted immediately after
3569 the matching start IFR opcode. If StartOpCcodeHandle only contains one
3570 IFR instruction, then the result of this operation will delete all of the IFR
3571 opcodes between the start end matches.
3572
3573 If HiiHandle is NULL, then ASSERT().
3574 If StartOpCodeHandle is NULL, then ASSERT().
3575
3576 @param[in] HiiHandle The HII Handle of the form to update.
3577 @param[in] FormSetGuid The Formset GUID of the form to update. This
3578 is an optional parameter that may be NULL.
3579 If it is NULL, all FormSet will be updated.
3580 @param[in] FormId The ID of the form to update.
3581 @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
3582 opcodes to be inserted or replaced in the form.
3583 The first IFR instruction in StartOpCodeHandle
3584 is used to find matching IFR opcode in the
3585 form.
3586 @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
3587 that marks the end of a replace operation in
3588 the form. This is an optional parameter that
3589 may be NULL. If it is NULL, then an the IFR
3590 opcodes specified by StartOpCodeHandle are
3591 inserted into the form.
3592
3593 @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
3594 @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND.
3595 1) The form specified by HiiHandle, FormSetGuid,
3596 and FormId could not be found in the HII Database.
3597 2) No IFR opcodes in the target form match the first
3598 IFR opcode in StartOpCodeHandle.
3599 3) EndOpCOde is not NULL, and no IFR opcodes in the
3600 target form following a matching start opcode match
3601 the first IFR opcode in EndOpCodeHandle.
3602 @retval EFI_SUCCESS The matched form is updated by StartOpcode.
3603
3604 **/
3605 EFI_STATUS
3606 EFIAPI
3607 HiiUpdateForm (
3608 IN EFI_HII_HANDLE HiiHandle,
3609 IN EFI_GUID *FormSetGuid, OPTIONAL
3610 IN EFI_FORM_ID FormId,
3611 IN VOID *StartOpCodeHandle,
3612 IN VOID *EndOpCodeHandle OPTIONAL
3613 )
3614 {
3615 EFI_STATUS Status;
3616 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
3617 UINT32 PackageListLength;
3618 UINT32 Offset;
3619 EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList;
3620 UINTN BufferSize;
3621 UINT8 *UpdateBufferPos;
3622 EFI_HII_PACKAGE_HEADER *Package;
3623 EFI_HII_PACKAGE_HEADER *TempPacakge;
3624 EFI_HII_PACKAGE_HEADER PackageHeader;
3625 BOOLEAN Updated;
3626 HII_LIB_OPCODE_BUFFER *OpCodeBufferStart;
3627 HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd;
3628
3629 //
3630 // Input update data can't be NULL.
3631 //
3632 ASSERT (HiiHandle != NULL);
3633 ASSERT (StartOpCodeHandle != NULL);
3634 UpdatePackageList = NULL;
3635 TempPacakge = NULL;
3636 HiiPackageList = NULL;
3637
3638 //
3639 // Retrieve buffer data from Opcode Handle
3640 //
3641 OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
3642 OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
3643
3644 //
3645 // Get the original package list
3646 //
3647 BufferSize = 0;
3648 HiiPackageList = NULL;
3649 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
3650 //
3651 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
3652 //
3653 if (Status != EFI_BUFFER_TOO_SMALL) {
3654 return Status;
3655 }
3656
3657 HiiPackageList = AllocatePool (BufferSize);
3658 if (HiiPackageList == NULL) {
3659 Status = EFI_OUT_OF_RESOURCES;
3660 goto Finish;
3661 }
3662
3663 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
3664 if (EFI_ERROR (Status)) {
3665 goto Finish;
3666 }
3667
3668 //
3669 // Calculate and allocate space for retrieval of IFR data
3670 //
3671 BufferSize += OpCodeBufferStart->Position;
3672 UpdatePackageList = AllocateZeroPool (BufferSize);
3673 if (UpdatePackageList == NULL) {
3674 Status = EFI_OUT_OF_RESOURCES;
3675 goto Finish;
3676 }
3677
3678 //
3679 // Allocate temp buffer to store the temp updated package buffer
3680 //
3681 TempPacakge = AllocateZeroPool (BufferSize);
3682 if (TempPacakge == NULL) {
3683 Status = EFI_OUT_OF_RESOURCES;
3684 goto Finish;
3685 }
3686
3687 UpdateBufferPos = (UINT8 *) UpdatePackageList;
3688
3689 //
3690 // Copy the package list header
3691 //
3692 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
3693 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3694
3695 //
3696 // Go through each package to find the matched package and update one by one
3697 //
3698 Updated = FALSE;
3699 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3700 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
3701 while (Offset < PackageListLength) {
3702 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
3703 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3704 Offset += Package->Length;
3705
3706 if (Package->Type == EFI_HII_PACKAGE_FORMS) {
3707 //
3708 // Check this package is the matched package.
3709 //
3710 Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPacakge);
3711 //
3712 // The matched package is found. Its package buffer will be updated by the input new data.
3713 //
3714 if (!EFI_ERROR(Status)) {
3715 //
3716 // Set Update Flag
3717 //
3718 Updated = TRUE;
3719 //
3720 // Add updated package buffer
3721 //
3722 Package = TempPacakge;
3723 }
3724 }
3725
3726 //
3727 // Add pacakge buffer
3728 //
3729 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3730 CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
3731 UpdateBufferPos += PackageHeader.Length;
3732 }
3733
3734 if (Updated) {
3735 //
3736 // Update package list length
3737 //
3738 BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
3739 WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
3740
3741 //
3742 // Update Package to show form
3743 //
3744 Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
3745 } else {
3746 //
3747 // Not matched form is found and updated.
3748 //
3749 Status = EFI_NOT_FOUND;
3750 }
3751
3752 Finish:
3753 if (HiiPackageList != NULL) {
3754 FreePool (HiiPackageList);
3755 }
3756
3757 if (UpdatePackageList != NULL) {
3758 FreePool (UpdatePackageList);
3759 }
3760
3761 if (TempPacakge != NULL) {
3762 FreePool (TempPacakge);
3763 }
3764
3765 return Status;
3766 }