]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/UefiHiiLib/HiiLib.c
3d7a4e5f5f2d1acf519481e5954e18422790d521
[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 - 2010, Intel Corporation<BR>
5 All rights reserved. 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.
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 break;
798 }
799
800 return EFI_SUCCESS;
801 }
802
803 /**
804 This function checks VarOffset and VarWidth is in the block range.
805
806 @param BlockArray The block array is to be checked.
807 @param VarOffset Offset of var to the structure
808 @param VarWidth Width of var.
809
810 @retval TRUE This Var is in the block range.
811 @retval FALSE This Var is not in the block range.
812 **/
813 BOOLEAN
814 BlockArrayCheck (
815 IN IFR_BLOCK_DATA *BlockArray,
816 IN UINT16 VarOffset,
817 IN UINT16 VarWidth
818 )
819 {
820 LIST_ENTRY *Link;
821 IFR_BLOCK_DATA *BlockData;
822
823 //
824 // No Request Block array, all vars are got.
825 //
826 if (BlockArray == NULL) {
827 return TRUE;
828 }
829
830 //
831 // Check the input var is in the request block range.
832 //
833 for (Link = BlockArray->Entry.ForwardLink; Link != &BlockArray->Entry; Link = Link->ForwardLink) {
834 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
835 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
836 return TRUE;
837 }
838 }
839
840 return FALSE;
841 }
842
843 /**
844 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
845 or WIDTH or VALUE.
846 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
847
848 @param ValueString String in <BlockConfig> format and points to the
849 first character of <Number>.
850 @param ValueData The output value. Caller takes the responsibility
851 to free memory.
852 @param ValueLength Length of the <Number>, in characters.
853
854 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
855 structures.
856 @retval EFI_SUCCESS Value of <Number> is outputted in Number
857 successfully.
858
859 **/
860 EFI_STATUS
861 EFIAPI
862 InternalHiiGetValueOfNumber (
863 IN EFI_STRING ValueString,
864 OUT UINT8 **ValueData,
865 OUT UINTN *ValueLength
866 )
867 {
868 EFI_STRING StringPtr;
869 UINTN Length;
870 UINT8 *Buf;
871 UINT8 DigitUint8;
872 UINTN Index;
873 CHAR16 TemStr[2];
874
875 ASSERT (ValueString != NULL && ValueData != NULL && ValueLength != NULL);
876 ASSERT (*ValueString != L'\0');
877
878 //
879 // Get the length of value string
880 //
881 StringPtr = ValueString;
882 while (*StringPtr != L'\0' && *StringPtr != L'&') {
883 StringPtr++;
884 }
885 Length = StringPtr - ValueString;
886
887 //
888 // Allocate buffer to store the value
889 //
890 Buf = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
891 if (Buf == NULL) {
892 return EFI_OUT_OF_RESOURCES;
893 }
894
895 //
896 // Convert character one by one to the value buffer
897 //
898 ZeroMem (TemStr, sizeof (TemStr));
899 for (Index = 0; Index < Length; Index ++) {
900 TemStr[0] = ValueString[Length - Index - 1];
901 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
902 if ((Index & 1) == 0) {
903 Buf [Index/2] = DigitUint8;
904 } else {
905 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
906 }
907 }
908
909 //
910 // Set the converted value and string length.
911 //
912 *ValueData = Buf;
913 *ValueLength = Length;
914 return EFI_SUCCESS;
915 }
916
917 /**
918 This internal function parses IFR data to validate current setting.
919
920 @param ConfigResp ConfigResp string contains the current setting.
921 @param HiiPackageList Point to Hii package list.
922 @param PackageListLength The length of the pacakge.
923 @param VarGuid Guid of the buffer storage.
924 @param VarName Name of the buffer storage.
925
926 @retval EFI_SUCCESS The current setting is valid.
927 @retval EFI_OUT_OF_RESOURCES The memory is not enough.
928 @retval EFI_INVALID_PARAMETER The config string or the Hii package is invalid.
929 **/
930 EFI_STATUS
931 EFIAPI
932 InternalHiiValidateCurrentSetting (
933 IN EFI_STRING ConfigResp,
934 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,
935 IN UINTN PackageListLength,
936 IN EFI_GUID *VarGuid,
937 IN CHAR16 *VarName
938 )
939 {
940 IFR_BLOCK_DATA *CurrentBlockArray;
941 IFR_BLOCK_DATA *BlockData;
942 IFR_BLOCK_DATA *NewBlockData;
943 IFR_BLOCK_DATA VarBlockData;
944 EFI_STRING StringPtr;
945 UINTN Length;
946 UINT8 *TmpBuffer;
947 UINT16 Offset;
948 UINT16 Width;
949 UINT64 VarValue;
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 //
1233 // Check the matched VarStoreId is found.
1234 //
1235 if (IfrVarStore == NULL) {
1236 Status = EFI_SUCCESS;
1237 goto Done;
1238 }
1239 break;
1240 case EFI_IFR_ONE_OF_OP:
1241 //
1242 // Check whether current value is the one of option.
1243 //
1244
1245 //
1246 // OneOf question is not in IFR Form. This IFR form is not valid.
1247 //
1248 if (IfrVarStore == NULL) {
1249 Status = EFI_INVALID_PARAMETER;
1250 goto Done;
1251 }
1252 //
1253 // Check whether this question is for the requested varstore.
1254 //
1255 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
1256 if (IfrOneOf->Question.VarStoreId != IfrVarStore->VarStoreId) {
1257 break;
1258 }
1259
1260 //
1261 // Get Offset by Question header and Width by DataType Flags
1262 //
1263 Offset = IfrOneOf->Question.VarStoreInfo.VarOffset;
1264 Width = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
1265 //
1266 // Check whether this question is in current block array.
1267 //
1268 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1269 //
1270 // This question is not in the current configuration string. Skip it.
1271 //
1272 break;
1273 }
1274 //
1275 // Check this var question is in the var storage
1276 //
1277 if ((Offset + Width) > IfrVarStore->Size) {
1278 //
1279 // This question exceeds the var store size.
1280 //
1281 Status = EFI_INVALID_PARAMETER;
1282 goto Done;
1283 }
1284
1285 //
1286 // Get the current value for oneof opcode
1287 //
1288 VarValue = 0;
1289 CopyMem (&VarValue, VarBuffer + Offset, Width);
1290 //
1291 // Set Block Data, to be checked in the following Oneof option opcode.
1292 //
1293 VarBlockData.Offset = Offset;
1294 VarBlockData.Width = Width;
1295 VarBlockData.OpCode = IfrOpHdr->OpCode;
1296 VarBlockData.Scope = IfrOpHdr->Scope;
1297 break;
1298 case EFI_IFR_NUMERIC_OP:
1299 //
1300 // Check the current value is in the numeric range.
1301 //
1302
1303 //
1304 // Numeric question is not in IFR Form. This IFR form is not valid.
1305 //
1306 if (IfrVarStore == NULL) {
1307 Status = EFI_INVALID_PARAMETER;
1308 goto Done;
1309 }
1310 //
1311 // Check whether this question is for the requested varstore.
1312 //
1313 IfrNumeric = (EFI_IFR_NUMERIC *) IfrOpHdr;
1314 if (IfrNumeric->Question.VarStoreId != IfrVarStore->VarStoreId) {
1315 break;
1316 }
1317
1318 //
1319 // Get Offset by Question header and Width by DataType Flags
1320 //
1321 Offset = IfrNumeric->Question.VarStoreInfo.VarOffset;
1322 Width = (UINT16) (1 << (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE));
1323 //
1324 // Check whether this question is in current block array.
1325 //
1326 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1327 //
1328 // This question is not in the current configuration string. Skip it.
1329 //
1330 break;
1331 }
1332 //
1333 // Check this var question is in the var storage
1334 //
1335 if ((Offset + Width) > IfrVarStore->Size) {
1336 //
1337 // This question exceeds the var store size.
1338 //
1339 Status = EFI_INVALID_PARAMETER;
1340 goto Done;
1341 }
1342
1343 //
1344 // Check the current value is in the numeric range.
1345 //
1346 VarValue = 0;
1347 CopyMem (&VarValue, VarBuffer + Offset, Width);
1348 switch (IfrNumeric->Flags & EFI_IFR_NUMERIC_SIZE) {
1349 case EFI_IFR_NUMERIC_SIZE_1:
1350 if ((UINT8) VarValue < IfrNumeric->data.u8.MinValue || (UINT8) VarValue > IfrNumeric->data.u8.MaxValue) {
1351 //
1352 // Not in the valid range.
1353 //
1354 Status = EFI_INVALID_PARAMETER;
1355 goto Done;
1356 }
1357 break;
1358 case EFI_IFR_NUMERIC_SIZE_2:
1359 if ((UINT16) VarValue < IfrNumeric->data.u16.MinValue || (UINT16) VarValue > IfrNumeric->data.u16.MaxValue) {
1360 //
1361 // Not in the valid range.
1362 //
1363 Status = EFI_INVALID_PARAMETER;
1364 goto Done;
1365 }
1366 break;
1367 case EFI_IFR_NUMERIC_SIZE_4:
1368 if ((UINT32) VarValue < IfrNumeric->data.u32.MinValue || (UINT32) VarValue > IfrNumeric->data.u32.MaxValue) {
1369 //
1370 // Not in the valid range.
1371 //
1372 Status = EFI_INVALID_PARAMETER;
1373 goto Done;
1374 }
1375 break;
1376 case EFI_IFR_NUMERIC_SIZE_8:
1377 if ((UINT64) VarValue < IfrNumeric->data.u64.MinValue || (UINT64) VarValue > IfrNumeric->data.u64.MaxValue) {
1378 //
1379 // Not in the valid range.
1380 //
1381 Status = EFI_INVALID_PARAMETER;
1382 goto Done;
1383 }
1384 break;
1385 }
1386
1387 break;
1388 case EFI_IFR_CHECKBOX_OP:
1389 //
1390 // Check value is BOOLEAN type, only 0 and 1 is valid.
1391 //
1392
1393 //
1394 // CheckBox question is not in IFR Form. This IFR form is not valid.
1395 //
1396 if (IfrVarStore == NULL) {
1397 Status = EFI_INVALID_PARAMETER;
1398 goto Done;
1399 }
1400
1401 //
1402 // Check whether this question is for the requested varstore.
1403 //
1404 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1405 if (IfrCheckBox->Question.VarStoreId != IfrVarStore->VarStoreId) {
1406 break;
1407 }
1408
1409 //
1410 // Get Offset by Question header
1411 //
1412 Offset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1413 Width = sizeof (BOOLEAN);
1414 //
1415 // Check whether this question is in current block array.
1416 //
1417 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1418 //
1419 // This question is not in the current configuration string. Skip it.
1420 //
1421 break;
1422 }
1423 //
1424 // Check this var question is in the var storage
1425 //
1426 if ((Offset + Width) > IfrVarStore->Size) {
1427 //
1428 // This question exceeds the var store size.
1429 //
1430 Status = EFI_INVALID_PARAMETER;
1431 goto Done;
1432 }
1433
1434 //
1435 // Boolean type, only 1 and 0 is valid.
1436 //
1437 if (*(VarBuffer + Offset) > 1) {
1438 Status = EFI_INVALID_PARAMETER;
1439 goto Done;
1440 }
1441
1442 break;
1443 case EFI_IFR_STRING_OP:
1444 //
1445 // Check current string length is less than maxsize
1446 //
1447
1448 //
1449 // CheckBox question is not in IFR Form. This IFR form is not valid.
1450 //
1451 if (IfrVarStore == NULL) {
1452 Status = EFI_INVALID_PARAMETER;
1453 goto Done;
1454 }
1455
1456 //
1457 // Check whether this question is for the requested varstore.
1458 //
1459 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1460 if (IfrString->Question.VarStoreId != IfrVarStore->VarStoreId) {
1461 break;
1462 }
1463
1464 //
1465 // Get Offset/Width by Question header and OneOf Flags
1466 //
1467 Offset = IfrString->Question.VarStoreInfo.VarOffset;
1468 Width = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1469 //
1470 // Check whether this question is in current block array.
1471 //
1472 if (!BlockArrayCheck (CurrentBlockArray, Offset, Width)) {
1473 //
1474 // This question is not in the current configuration string. Skip it.
1475 //
1476 break;
1477 }
1478 //
1479 // Check this var question is in the var storage
1480 //
1481 if ((Offset + Width) > IfrVarStore->Size) {
1482 //
1483 // This question exceeds the var store size.
1484 //
1485 Status = EFI_INVALID_PARAMETER;
1486 goto Done;
1487 }
1488
1489 //
1490 // Check current string length is less than maxsize
1491 //
1492 if (StrSize ((CHAR16 *) (VarBuffer + Offset)) > Width) {
1493 Status = EFI_INVALID_PARAMETER;
1494 goto Done;
1495 }
1496 break;
1497 case EFI_IFR_ONE_OF_OPTION_OP:
1498 //
1499 // Opcode Scope is zero. This one of option is not to be checked.
1500 //
1501 if (VarBlockData.Scope == 0) {
1502 break;
1503 }
1504
1505 //
1506 // Only check for OneOf and OrderList opcode
1507 //
1508 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1509 if (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP) {
1510 //
1511 // Check current value is the value of one of option.
1512 //
1513 if (VarValue == IfrOneOfOption->Value.u64) {
1514 //
1515 // The value is one of option value.
1516 // Set OpCode to Zero, don't need check again.
1517 //
1518 VarBlockData.OpCode = 0;
1519 }
1520 }
1521
1522 break;
1523 case EFI_IFR_END_OP:
1524 //
1525 // Decrease opcode scope for the validated opcode
1526 //
1527 if (VarBlockData.Scope > 0) {
1528 VarBlockData.Scope --;
1529 }
1530
1531 //
1532 // OneOf value doesn't belong to one of option value.
1533 //
1534 if ((VarBlockData.Scope == 0) && (VarBlockData.OpCode == EFI_IFR_ONE_OF_OP)) {
1535 Status = EFI_INVALID_PARAMETER;
1536 goto Done;
1537 }
1538 break;
1539 default:
1540 //
1541 // Increase Scope for the validated opcode
1542 //
1543 if (VarBlockData.Scope > 0) {
1544 VarBlockData.Scope = (UINT8) (VarBlockData.Scope + IfrOpHdr->Scope);
1545 }
1546 break;
1547 }
1548 //
1549 // Go to the next opcode
1550 //
1551 IfrOffset += IfrOpHdr->Length;
1552 }
1553 //
1554 // Only one form is in a package list.
1555 //
1556 break;
1557 }
1558
1559 //
1560 // Go to next package.
1561 //
1562 PackageOffset += PacakgeHeader.Length;
1563 }
1564
1565 Done:
1566 if (VarBuffer != NULL) {
1567 FreePool (VarBuffer);
1568 }
1569
1570 if (CurrentBlockArray != NULL) {
1571 //
1572 // Free Link Array CurrentBlockArray
1573 //
1574 while (!IsListEmpty (&CurrentBlockArray->Entry)) {
1575 BlockData = BASE_CR (CurrentBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
1576 RemoveEntryList (&BlockData->Entry);
1577 FreePool (BlockData);
1578 }
1579 FreePool (CurrentBlockArray);
1580 }
1581
1582 return Status;
1583 }
1584
1585 /**
1586 This function parses the input ConfigRequest string and its matched IFR code
1587 string for setting default value and validating current setting.
1588
1589 1. For setting default action, Reset the default value specified by DefaultId
1590 to the driver configuration got by Request string.
1591 2. For validating current setting, Validate the current configuration
1592 by parsing HII form IFR opcode.
1593
1594 NULL request string support depends on the ExportConfig interface of
1595 HiiConfigRouting protocol in UEFI specification.
1596
1597 @param Request A null-terminated Unicode string in
1598 <MultiConfigRequest> format. It can be NULL.
1599 If it is NULL, all current configuration for the
1600 entirety of the current HII database will be validated.
1601 If it is NULL, all configuration for the
1602 entirety of the current HII database will be reset.
1603 @param DefaultId Specifies the type of defaults to retrieve only for setting default action.
1604 @param ActionType Action supports setting defaults and validate current setting.
1605
1606 @retval TURE Action runs successfully.
1607 @retval FALSE Action is not valid or Action can't be executed successfully..
1608 **/
1609 BOOLEAN
1610 EFIAPI
1611 InternalHiiIfrValueAction (
1612 IN CONST EFI_STRING Request, OPTIONAL
1613 IN UINT16 DefaultId,
1614 IN UINT8 ActionType
1615 )
1616 {
1617 EFI_STRING ConfigAltResp;
1618 EFI_STRING ConfigAltHdr;
1619 EFI_STRING ConfigResp;
1620 EFI_STRING Progress;
1621 EFI_STRING StringPtr;
1622 EFI_STRING StringHdr;
1623 EFI_STATUS Status;
1624 EFI_HANDLE DriverHandle;
1625 EFI_HANDLE TempDriverHandle;
1626 EFI_HII_HANDLE *HiiHandleBuffer;
1627 EFI_HII_HANDLE HiiHandle;
1628 UINT32 Index;
1629 EFI_GUID *VarGuid;
1630 EFI_STRING VarName;
1631 EFI_STRING_ID DefaultName;
1632
1633 UINT8 *PackageData;
1634 UINTN IfrOffset;
1635 EFI_IFR_OP_HEADER *IfrOpHdr;
1636 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
1637 UINT32 PackageOffset;
1638 UINTN PackageListLength;
1639 EFI_HII_PACKAGE_HEADER PacakgeHeader;
1640 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1641 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
1642
1643 ConfigAltResp = NULL;
1644 ConfigResp = NULL;
1645 VarGuid = NULL;
1646 VarName = NULL;
1647 DevicePath = NULL;
1648 ConfigAltHdr = NULL;
1649 HiiHandleBuffer = NULL;
1650 Index = 0;
1651 TempDriverHandle = NULL;
1652 HiiHandle = NULL;
1653 PackageData = NULL;
1654 HiiPackageList = NULL;
1655
1656 //
1657 // Only support set default and validate setting action.
1658 //
1659 if ((ActionType != ACTION_SET_DEFAUTL_VALUE) && (ActionType != ACTION_VALIDATE_SETTING)) {
1660 return FALSE;
1661 }
1662
1663 //
1664 // Get the full requested value and deault value string.
1665 //
1666 if (Request != NULL) {
1667 Status = gHiiConfigRouting->ExtractConfig (
1668 gHiiConfigRouting,
1669 Request,
1670 &Progress,
1671 &ConfigAltResp
1672 );
1673 } else {
1674 Status = gHiiConfigRouting->ExportConfig (
1675 gHiiConfigRouting,
1676 &ConfigAltResp
1677 );
1678 }
1679
1680 if (EFI_ERROR (Status)) {
1681 return FALSE;
1682 }
1683
1684 StringPtr = ConfigAltResp;
1685
1686 while (StringPtr != L'\0') {
1687 //
1688 // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
1689 //
1690 StringHdr = StringPtr;
1691
1692 //
1693 // Get Guid value
1694 //
1695 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1696 Status = EFI_INVALID_PARAMETER;
1697 goto Done;
1698 }
1699 StringPtr += StrLen (L"GUID=");
1700 Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
1701 if (EFI_ERROR (Status)) {
1702 goto Done;
1703 }
1704
1705 //
1706 // Get Name value VarName
1707 //
1708 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1709 StringPtr++;
1710 }
1711 if (*StringPtr == L'\0') {
1712 Status = EFI_INVALID_PARAMETER;
1713 goto Done;
1714 }
1715 StringPtr += StrLen (L"&NAME=");
1716 Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
1717 if (EFI_ERROR (Status)) {
1718 goto Done;
1719 }
1720
1721 //
1722 // Get Path value DevicePath
1723 //
1724 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1725 StringPtr++;
1726 }
1727 if (*StringPtr == L'\0') {
1728 Status = EFI_INVALID_PARAMETER;
1729 goto Done;
1730 }
1731 StringPtr += StrLen (L"&PATH=");
1732 Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
1733 if (EFI_ERROR (Status)) {
1734 goto Done;
1735 }
1736
1737 //
1738 // Get the Driver handle by the got device path.
1739 //
1740 TempDevicePath = DevicePath;
1741 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
1742 if (EFI_ERROR (Status)) {
1743 goto Done;
1744 }
1745
1746 //
1747 // Find the matched Hii Handle for the found Driver handle
1748 //
1749 HiiHandleBuffer = HiiGetHiiHandles (NULL);
1750 if (HiiHandleBuffer == NULL) {
1751 Status = EFI_NOT_FOUND;
1752 goto Done;
1753 }
1754
1755 for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
1756 gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
1757 if (TempDriverHandle == DriverHandle) {
1758 break;
1759 }
1760 }
1761
1762 HiiHandle = HiiHandleBuffer[Index];
1763 FreePool (HiiHandleBuffer);
1764
1765 if (HiiHandle == NULL) {
1766 //
1767 // This request string has no its Hii package.
1768 // Its default value and validating can't execute by parsing IFR data.
1769 // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
1770 //
1771 Status = EFI_SUCCESS;
1772 goto NextConfigAltResp;
1773 }
1774
1775 //
1776 // 2. Get DefaultName string ID by parsing the PacakgeList
1777 //
1778
1779 //
1780 // Get HiiPackage by HiiHandle
1781 //
1782 PackageListLength = 0;
1783 HiiPackageList = NULL;
1784 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
1785
1786 //
1787 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
1788 //
1789 if (Status != EFI_BUFFER_TOO_SMALL) {
1790 Status = EFI_INVALID_PARAMETER;
1791 goto Done;
1792 }
1793
1794 HiiPackageList = AllocatePool (PackageListLength);
1795 if (HiiPackageList == NULL) {
1796 Status = EFI_OUT_OF_RESOURCES;
1797 goto Done;
1798 }
1799
1800 //
1801 // Get PackageList on HiiHandle
1802 //
1803 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
1804 if (EFI_ERROR (Status)) {
1805 goto Done;
1806 }
1807
1808 //
1809 // Parse the form package and get the default name string ID.
1810 //
1811 if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
1812 PackageOffset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
1813 Status = EFI_NOT_FOUND;
1814 while (PackageOffset < PackageListLength) {
1815 CopyMem (&PacakgeHeader, (UINT8 *) HiiPackageList + PackageOffset, sizeof (PacakgeHeader));
1816
1817 //
1818 // Parse IFR opcode to get default store opcode
1819 //
1820 if (PacakgeHeader.Type == EFI_HII_PACKAGE_FORMS) {
1821 IfrOffset = sizeof (PacakgeHeader);
1822 PackageData = (UINT8 *) HiiPackageList + PackageOffset;
1823 while (IfrOffset < PacakgeHeader.Length) {
1824 IfrOpHdr = (EFI_IFR_OP_HEADER *) (PackageData + IfrOffset);
1825 //
1826 // Match DefaultId to find its DefaultName
1827 //
1828 if (IfrOpHdr->OpCode == EFI_IFR_DEFAULTSTORE_OP) {
1829 if (((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId == DefaultId) {
1830 DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName;
1831 Status = EFI_SUCCESS;
1832 break;
1833 }
1834 }
1835 IfrOffset += IfrOpHdr->Length;
1836 }
1837 //
1838 // Only one form is in a package list.
1839 //
1840 break;
1841 }
1842
1843 //
1844 // Go to next package.
1845 //
1846 PackageOffset += PacakgeHeader.Length;
1847 }
1848
1849 //
1850 // Not found the matched default string ID
1851 //
1852 if (EFI_ERROR (Status)) {
1853 Status = EFI_SUCCESS;
1854 goto NextConfigAltResp;
1855 }
1856 }
1857
1858 //
1859 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
1860 // Get the default configuration string according to the found default name string ID.
1861 //
1862 Status = gHiiConfigRouting->GetAltConfig (
1863 gHiiConfigRouting,
1864 ConfigAltResp,
1865 VarGuid,
1866 VarName,
1867 DevicePath,
1868 (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultName:NULL, // it can be NULL to get the current setting.
1869 &ConfigResp
1870 );
1871
1872 //
1873 // The required setting can't be found. So, it is not required to be validated and set.
1874 //
1875 if (EFI_ERROR (Status)) {
1876 Status = EFI_SUCCESS;
1877 goto NextConfigAltResp;
1878 }
1879 //
1880 // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
1881 //
1882 if (StrStr (ConfigResp, L"&OFFSET=") == NULL) {
1883 goto NextConfigAltResp;
1884 }
1885
1886 //
1887 // 4. Set the default configuration information or Validate current setting by parse IFR code.
1888 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
1889 //
1890 if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
1891 //
1892 // Set the default configuration information.
1893 //
1894 Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
1895 } else {
1896 //
1897 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
1898 //
1899 Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName);
1900 }
1901
1902 if (EFI_ERROR (Status)) {
1903 goto Done;
1904 }
1905
1906 NextConfigAltResp:
1907 //
1908 // Free the allocated pacakge buffer and the got ConfigResp string.
1909 //
1910 if (HiiPackageList != NULL) {
1911 FreePool (HiiPackageList);
1912 HiiPackageList = NULL;
1913 }
1914
1915 if (ConfigResp != NULL) {
1916 FreePool (ConfigResp);
1917 ConfigResp = NULL;
1918 }
1919
1920 //
1921 // Free the allocated buffer.
1922 //
1923 FreePool (VarGuid);
1924 VarGuid = NULL;
1925
1926 FreePool (VarName);
1927 VarName = NULL;
1928
1929 FreePool (DevicePath);
1930 DevicePath = NULL;
1931
1932 //
1933 // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
1934 //
1935
1936 //
1937 // Get and Skip ConfigHdr
1938 //
1939 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1940 StringPtr++;
1941 }
1942 if (*StringPtr == L'\0') {
1943 break;
1944 }
1945
1946 //
1947 // Construct ConfigAltHdr string "&<ConfigHdr>&ALTCFG=\0"
1948 // | 1 | StrLen (ConfigHdr) | 8 | 1 |
1949 //
1950 ConfigAltHdr = AllocateZeroPool ((1 + StringPtr - StringHdr + 8 + 1) * sizeof (CHAR16));
1951 if (ConfigAltHdr == NULL) {
1952 Status = EFI_OUT_OF_RESOURCES;
1953 goto Done;
1954 }
1955 StrCpy (ConfigAltHdr, L"&");
1956 StrnCat (ConfigAltHdr, StringHdr, StringPtr - StringHdr);
1957 StrCat (ConfigAltHdr, L"&ALTCFG=");
1958
1959 //
1960 // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
1961 //
1962 while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
1963 StringPtr = StringHdr + StrLen (ConfigAltHdr);
1964 if (*StringPtr == L'\0') {
1965 break;
1966 }
1967 }
1968
1969 //
1970 // Free the allocated ConfigAltHdr string
1971 //
1972 FreePool (ConfigAltHdr);
1973 if (*StringPtr == L'\0') {
1974 break;
1975 }
1976
1977 //
1978 // Find &GUID as the next ConfigHdr
1979 //
1980 StringPtr = StrStr (StringPtr, L"&GUID");
1981 if (StringPtr == NULL) {
1982 break;
1983 }
1984
1985 //
1986 // Skip char '&'
1987 //
1988 StringPtr ++;
1989 }
1990
1991 Done:
1992 if (VarGuid != NULL) {
1993 FreePool (VarGuid);
1994 }
1995
1996 if (VarName != NULL) {
1997 FreePool (VarName);
1998 }
1999
2000 if (DevicePath != NULL) {
2001 FreePool (DevicePath);
2002 }
2003
2004 if (ConfigResp != NULL) {
2005 FreePool (ConfigResp);
2006 }
2007
2008 if (ConfigAltResp != NULL) {
2009 FreePool (ConfigAltResp);
2010 }
2011
2012 if (HiiPackageList != NULL) {
2013 FreePool (HiiPackageList);
2014 }
2015
2016 if (EFI_ERROR (Status)) {
2017 return FALSE;
2018 }
2019
2020 return TRUE;
2021 }
2022
2023 /**
2024 Validate the current configuration by parsing HII form IFR opcode.
2025
2026 NULL request string support depends on the ExportConfig interface of
2027 HiiConfigRouting protocol in UEFI specification.
2028
2029 @param Request A null-terminated Unicode string in
2030 <MultiConfigRequest> format. It can be NULL.
2031 If it is NULL, all current configuration for the
2032 entirety of the current HII database will be validated.
2033
2034 @retval TURE Current configuration is valid.
2035 @retval FALSE Current configuration is invalid.
2036 **/
2037 BOOLEAN
2038 EFIAPI
2039 HiiValidateSettings (
2040 IN CONST EFI_STRING Request OPTIONAL
2041 )
2042 {
2043 return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
2044 }
2045
2046 /**
2047 Reset the default value specified by DefaultId to the driver
2048 configuration got by Request string.
2049
2050 NULL request string support depends on the ExportConfig interface of
2051 HiiConfigRouting protocol in UEFI specification.
2052
2053 @param Request A null-terminated Unicode string in
2054 <MultiConfigRequest> format. It can be NULL.
2055 If it is NULL, all configuration for the
2056 entirety of the current HII database will be reset.
2057 @param DefaultId Specifies the type of defaults to retrieve.
2058
2059 @retval TURE The default value is set successfully.
2060 @retval FALSE The default value can't be found and set.
2061 **/
2062 BOOLEAN
2063 EFIAPI
2064 HiiSetToDefaults (
2065 IN CONST EFI_STRING Request, OPTIONAL
2066 IN UINT16 DefaultId
2067 )
2068 {
2069 return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
2070 }
2071
2072 /**
2073 Determines if two values in config strings match.
2074
2075 Compares the substring between StartSearchString and StopSearchString in
2076 FirstString to the substring between StartSearchString and StopSearchString
2077 in SecondString. If the two substrings match, then TRUE is returned. If the
2078 two substrings do not match, then FALSE is returned.
2079
2080 If FirstString is NULL, then ASSERT().
2081 If SecondString is NULL, then ASSERT().
2082 If StartSearchString is NULL, then ASSERT().
2083 If StopSearchString is NULL, then ASSERT().
2084
2085 @param FirstString Pointer to the first Null-terminated Unicode string.
2086 @param SecondString Pointer to the second Null-terminated Unicode string.
2087 @param StartSearchString Pointer to the Null-terminated Unicode string that
2088 marks the start of the value string to compare.
2089 @param StopSearchString Pointer to the Null-terminated Unicode string that
2090 marks the end of the value string to compare.
2091
2092 @retval FALSE StartSearchString is not present in FirstString.
2093 @retval FALSE StartSearchString is not present in SecondString.
2094 @retval FALSE StopSearchString is not present in FirstString.
2095 @retval FALSE StopSearchString is not present in SecondString.
2096 @retval FALSE The length of the substring in FirstString is not the
2097 same length as the substring in SecondString.
2098 @retval FALSE The value string in FirstString does not matche the
2099 value string in SecondString.
2100 @retval TRUE The value string in FirstString matches the value
2101 string in SecondString.
2102
2103 **/
2104 BOOLEAN
2105 EFIAPI
2106 InternalHiiCompareSubString (
2107 IN CHAR16 *FirstString,
2108 IN CHAR16 *SecondString,
2109 IN CHAR16 *StartSearchString,
2110 IN CHAR16 *StopSearchString
2111 )
2112 {
2113 CHAR16 *EndFirstString;
2114 CHAR16 *EndSecondString;
2115
2116 ASSERT (FirstString != NULL);
2117 ASSERT (SecondString != NULL);
2118 ASSERT (StartSearchString != NULL);
2119 ASSERT (StopSearchString != NULL);
2120
2121 FirstString = StrStr (FirstString, StartSearchString);
2122 if (FirstString == NULL) {
2123 return FALSE;
2124 }
2125
2126 SecondString = StrStr (SecondString, StartSearchString);
2127 if (SecondString == NULL) {
2128 return FALSE;
2129 }
2130
2131 EndFirstString = StrStr (FirstString, StopSearchString);
2132 if (EndFirstString == NULL) {
2133 return FALSE;
2134 }
2135
2136 EndSecondString = StrStr (SecondString, StopSearchString);
2137 if (EndSecondString == NULL) {
2138 return FALSE;
2139 }
2140
2141 if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
2142 return FALSE;
2143 }
2144
2145 return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
2146 }
2147
2148 /**
2149 Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
2150
2151 If ConfigHdr is NULL, then ASSERT().
2152
2153 @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
2154 @param[in] Guid GUID of the storage.
2155 @param[in] Name NAME of the storage.
2156
2157 @retval TRUE Routing information matches <ConfigHdr>.
2158 @retval FALSE Routing information does not match <ConfigHdr>.
2159
2160 **/
2161 BOOLEAN
2162 EFIAPI
2163 HiiIsConfigHdrMatch (
2164 IN CONST EFI_STRING ConfigHdr,
2165 IN CONST EFI_GUID *Guid, OPTIONAL
2166 IN CONST CHAR16 *Name OPTIONAL
2167 )
2168 {
2169 EFI_STRING CompareConfigHdr;
2170 BOOLEAN Result;
2171
2172 ASSERT (ConfigHdr != NULL);
2173
2174 //
2175 // Use Guid and Name to generate a <ConfigHdr> string
2176 //
2177 CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
2178 if (CompareConfigHdr == NULL) {
2179 return FALSE;
2180 }
2181
2182 Result = TRUE;
2183 if (Guid != NULL) {
2184 //
2185 // Compare GUID value strings
2186 //
2187 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
2188 }
2189
2190 if (Result && Name != NULL) {
2191 //
2192 // Compare NAME value strings
2193 //
2194 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
2195 }
2196
2197 //
2198 // Free the <ConfigHdr> string
2199 //
2200 FreePool (CompareConfigHdr);
2201
2202 return Result;
2203 }
2204
2205 /**
2206 Retrieves uncommitted data from the Form Browser and converts it to a binary
2207 buffer.
2208
2209 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2210 parameter that may be NULL.
2211 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2212 is an optional parameter that may be NULL.
2213 @param[in] BufferSize Length in bytes of buffer to hold retrieved data.
2214 @param[out] Buffer Buffer of data to be updated.
2215
2216 @retval FALSE The uncommitted data could not be retrieved.
2217 @retval TRUE The uncommitted data was retrieved.
2218
2219 **/
2220 BOOLEAN
2221 EFIAPI
2222 HiiGetBrowserData (
2223 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2224 IN CONST CHAR16 *VariableName, OPTIONAL
2225 IN UINTN BufferSize,
2226 OUT UINT8 *Buffer
2227 )
2228 {
2229 EFI_STRING ResultsData;
2230 UINTN Size;
2231 EFI_STRING ConfigResp;
2232 EFI_STATUS Status;
2233 CHAR16 *Progress;
2234
2235 //
2236 // Retrieve the results data from the Browser Callback
2237 //
2238 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
2239 if (ResultsData == NULL) {
2240 return FALSE;
2241 }
2242
2243 //
2244 // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
2245 //
2246 Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
2247 Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
2248 ConfigResp = AllocateZeroPool (Size);
2249 UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
2250
2251 //
2252 // Free the allocated buffer
2253 //
2254 FreePool (ResultsData);
2255 if (ConfigResp == NULL) {
2256 return FALSE;
2257 }
2258
2259 //
2260 // Convert <ConfigResp> to a buffer
2261 //
2262 Status = gHiiConfigRouting->ConfigToBlock (
2263 gHiiConfigRouting,
2264 ConfigResp,
2265 Buffer,
2266 &BufferSize,
2267 &Progress
2268 );
2269 //
2270 // Free the allocated buffer
2271 //
2272 FreePool (ConfigResp);
2273
2274 if (EFI_ERROR (Status)) {
2275 return FALSE;
2276 }
2277
2278 return TRUE;
2279 }
2280
2281 /**
2282 Updates uncommitted data in the Form Browser.
2283
2284 If Buffer is NULL, then ASSERT().
2285
2286 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2287 parameter that may be NULL.
2288 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2289 is an optional parameter that may be NULL.
2290 @param[in] BufferSize Length, in bytes, of Buffer.
2291 @param[in] Buffer Buffer of data to commit.
2292 @param[in] RequestElement An optional field to specify which part of the
2293 buffer data will be send back to Browser. If NULL,
2294 the whole buffer of data will be committed to
2295 Browser.
2296 <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
2297
2298 @retval FALSE The uncommitted data could not be updated.
2299 @retval TRUE The uncommitted data was updated.
2300
2301 **/
2302 BOOLEAN
2303 EFIAPI
2304 HiiSetBrowserData (
2305 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2306 IN CONST CHAR16 *VariableName, OPTIONAL
2307 IN UINTN BufferSize,
2308 IN CONST UINT8 *Buffer,
2309 IN CONST CHAR16 *RequestElement OPTIONAL
2310 )
2311 {
2312 UINTN Size;
2313 EFI_STRING ConfigRequest;
2314 EFI_STRING ConfigResp;
2315 EFI_STRING ResultsData;
2316
2317 ASSERT (Buffer != NULL);
2318
2319 //
2320 // Construct <ConfigRequest>
2321 //
2322 if (RequestElement == NULL) {
2323 //
2324 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2325 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
2326 //
2327 Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
2328 ConfigRequest = AllocateZeroPool (Size);
2329 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
2330 } else {
2331 //
2332 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2333 // followed by <RequestElement> followed by a Null-terminator
2334 //
2335 Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
2336 Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
2337 ConfigRequest = AllocateZeroPool (Size);
2338 UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
2339 }
2340 if (ConfigRequest == NULL) {
2341 return FALSE;
2342 }
2343
2344 //
2345 // Convert <ConfigRequest> to <ConfigResp>
2346 //
2347 ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
2348 FreePool (ConfigRequest);
2349 if (ConfigResp == NULL) {
2350 return FALSE;
2351 }
2352
2353 //
2354 // Set data in the uncommitted browser state information
2355 //
2356 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
2357 FreePool (ConfigResp);
2358
2359 return (BOOLEAN)(ResultsData != NULL);
2360 }
2361
2362 /////////////////////////////////////////
2363 /////////////////////////////////////////
2364 /// IFR Functions
2365 /////////////////////////////////////////
2366 /////////////////////////////////////////
2367
2368 #define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200
2369
2370 typedef struct {
2371 UINT8 *Buffer;
2372 UINTN BufferSize;
2373 UINTN Position;
2374 } HII_LIB_OPCODE_BUFFER;
2375
2376 ///
2377 /// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
2378 ///
2379 GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
2380 1, // EFI_IFR_TYPE_NUM_SIZE_8
2381 2, // EFI_IFR_TYPE_NUM_SIZE_16
2382 4, // EFI_IFR_TYPE_NUM_SIZE_32
2383 8, // EFI_IFR_TYPE_NUM_SIZE_64
2384 1, // EFI_IFR_TYPE_BOOLEAN
2385 3, // EFI_IFR_TYPE_TIME
2386 4, // EFI_IFR_TYPE_DATE
2387 2 // EFI_IFR_TYPE_STRING
2388 };
2389
2390 /**
2391 Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
2392 HiiFreeOpCodeHandle().
2393
2394 @retval NULL There are not enough resources to allocate a new OpCode Handle.
2395 @retval Other A new OpCode handle.
2396
2397 **/
2398 VOID *
2399 EFIAPI
2400 HiiAllocateOpCodeHandle (
2401 VOID
2402 )
2403 {
2404 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2405
2406 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
2407 if (OpCodeBuffer == NULL) {
2408 return NULL;
2409 }
2410 OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
2411 if (OpCodeBuffer->Buffer == NULL) {
2412 FreePool (OpCodeBuffer);
2413 return NULL;
2414 }
2415 OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
2416 OpCodeBuffer->Position = 0;
2417 return (VOID *)OpCodeBuffer;
2418 }
2419
2420 /**
2421 Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
2422 When an OpCode Handle is freed, all of the opcodes associated with the OpCode
2423 Handle are also freed.
2424
2425 If OpCodeHandle is NULL, then ASSERT().
2426
2427 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2428
2429 **/
2430 VOID
2431 EFIAPI
2432 HiiFreeOpCodeHandle (
2433 VOID *OpCodeHandle
2434 )
2435 {
2436 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2437
2438 ASSERT (OpCodeHandle != NULL);
2439
2440 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2441 if (OpCodeBuffer->Buffer != NULL) {
2442 FreePool (OpCodeBuffer->Buffer);
2443 }
2444 FreePool (OpCodeBuffer);
2445 }
2446
2447 /**
2448 Internal function gets the current position of opcode buffer.
2449
2450 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2451
2452 @return Current position of opcode buffer.
2453 **/
2454 UINTN
2455 EFIAPI
2456 InternalHiiOpCodeHandlePosition (
2457 IN VOID *OpCodeHandle
2458 )
2459 {
2460 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position;
2461 }
2462
2463 /**
2464 Internal function gets the start pointer of opcode buffer.
2465
2466 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2467
2468 @return Pointer to the opcode buffer base.
2469 **/
2470 UINT8 *
2471 EFIAPI
2472 InternalHiiOpCodeHandleBuffer (
2473 IN VOID *OpCodeHandle
2474 )
2475 {
2476 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer;
2477 }
2478
2479 /**
2480 Internal function reserves the enough buffer for current opcode.
2481 When the buffer is not enough, Opcode buffer will be extended.
2482
2483 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2484 @param[in] Size Size of current opcode.
2485
2486 @return Pointer to the current opcode.
2487 **/
2488 UINT8 *
2489 EFIAPI
2490 InternalHiiGrowOpCodeHandle (
2491 IN VOID *OpCodeHandle,
2492 IN UINTN Size
2493 )
2494 {
2495 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2496 UINT8 *Buffer;
2497
2498 ASSERT (OpCodeHandle != NULL);
2499
2500 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2501 if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
2502 Buffer = ReallocatePool (
2503 OpCodeBuffer->BufferSize,
2504 OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
2505 OpCodeBuffer->Buffer
2506 );
2507 if (Buffer == NULL) {
2508 return NULL;
2509 }
2510 OpCodeBuffer->Buffer = Buffer;
2511 OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
2512 }
2513 Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
2514 OpCodeBuffer->Position += Size;
2515 return Buffer;
2516 }
2517
2518 /**
2519 Internal function creates opcode based on the template opcode.
2520
2521 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2522 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
2523 @param[in] OpCode OpCode IFR value.
2524 @param[in] OpCodeSize Size of opcode.
2525 @param[in] ExtensionSize Size of extended opcode.
2526 @param[in] Scope Scope bit of opcode.
2527
2528 @return Pointer to the current opcode with opcode data.
2529 **/
2530 UINT8 *
2531 EFIAPI
2532 InternalHiiCreateOpCodeExtended (
2533 IN VOID *OpCodeHandle,
2534 IN VOID *OpCodeTemplate,
2535 IN UINT8 OpCode,
2536 IN UINTN OpCodeSize,
2537 IN UINTN ExtensionSize,
2538 IN UINT8 Scope
2539 )
2540 {
2541 EFI_IFR_OP_HEADER *Header;
2542 UINT8 *Buffer;
2543
2544 ASSERT (OpCodeTemplate != NULL);
2545 ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
2546
2547 Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
2548 Header->OpCode = OpCode;
2549 Header->Scope = Scope;
2550 Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
2551 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
2552 return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
2553 }
2554
2555 /**
2556 Internal function creates opcode based on the template opcode for the normal opcode.
2557
2558 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2559 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
2560 @param[in] OpCode OpCode IFR value.
2561 @param[in] OpCodeSize Size of opcode.
2562
2563 @return Pointer to the current opcode with opcode data.
2564 **/
2565 UINT8 *
2566 EFIAPI
2567 InternalHiiCreateOpCode (
2568 IN VOID *OpCodeHandle,
2569 IN VOID *OpCodeTemplate,
2570 IN UINT8 OpCode,
2571 IN UINTN OpCodeSize
2572 )
2573 {
2574 return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
2575 }
2576
2577 /**
2578 Append raw opcodes to an OpCodeHandle.
2579
2580 If OpCodeHandle is NULL, then ASSERT().
2581 If RawBuffer is NULL, then ASSERT();
2582
2583 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2584 @param[in] RawBuffer Buffer of opcodes to append.
2585 @param[in] RawBufferSize The size, in bytes, of Buffer.
2586
2587 @retval NULL There is not enough space left in Buffer to add the opcode.
2588 @retval Other A pointer to the appended opcodes.
2589
2590 **/
2591 UINT8 *
2592 EFIAPI
2593 HiiCreateRawOpCodes (
2594 IN VOID *OpCodeHandle,
2595 IN UINT8 *RawBuffer,
2596 IN UINTN RawBufferSize
2597 )
2598 {
2599 UINT8 *Buffer;
2600
2601 ASSERT (RawBuffer != NULL);
2602
2603 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
2604 return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
2605 }
2606
2607 /**
2608 Append opcodes from one OpCode Handle to another OpCode handle.
2609
2610 If OpCodeHandle is NULL, then ASSERT().
2611 If RawOpCodeHandle is NULL, then ASSERT();
2612
2613 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2614 @param[in] RawOpCodeHandle Handle to the buffer of opcodes.
2615
2616 @retval NULL There is not enough space left in Buffer to add the opcode.
2617 @retval Other A pointer to the appended opcodes.
2618
2619 **/
2620 UINT8 *
2621 EFIAPI
2622 InternalHiiAppendOpCodes (
2623 IN VOID *OpCodeHandle,
2624 IN VOID *RawOpCodeHandle
2625 )
2626 {
2627 HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer;
2628
2629 ASSERT (RawOpCodeHandle != NULL);
2630
2631 RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
2632 return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
2633 }
2634
2635 /**
2636 Create EFI_IFR_END_OP opcode.
2637
2638 If OpCodeHandle is NULL, then ASSERT().
2639
2640 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2641
2642 @retval NULL There is not enough space left in Buffer to add the opcode.
2643 @retval Other A pointer to the created opcode.
2644
2645 **/
2646 UINT8 *
2647 EFIAPI
2648 HiiCreateEndOpCode (
2649 IN VOID *OpCodeHandle
2650 )
2651 {
2652 EFI_IFR_END OpCode;
2653
2654 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
2655 }
2656
2657 /**
2658 Create EFI_IFR_ONE_OF_OPTION_OP opcode.
2659
2660 If OpCodeHandle is NULL, then ASSERT().
2661 If Type is invalid, then ASSERT().
2662 If Flags is invalid, then ASSERT().
2663
2664 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2665 @param[in] StringId StringId for the option
2666 @param[in] Flags Flags for the option
2667 @param[in] Type Type for the option
2668 @param[in] Value Value for the option
2669
2670 @retval NULL There is not enough space left in Buffer to add the opcode.
2671 @retval Other A pointer to the created opcode.
2672
2673 **/
2674 UINT8 *
2675 EFIAPI
2676 HiiCreateOneOfOptionOpCode (
2677 IN VOID *OpCodeHandle,
2678 IN UINT16 StringId,
2679 IN UINT8 Flags,
2680 IN UINT8 Type,
2681 IN UINT64 Value
2682 )
2683 {
2684 EFI_IFR_ONE_OF_OPTION OpCode;
2685
2686 ASSERT (Type < EFI_IFR_TYPE_OTHER);
2687
2688 ZeroMem (&OpCode, sizeof (OpCode));
2689 OpCode.Option = StringId;
2690 OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
2691 OpCode.Type = Type;
2692 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
2693
2694 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, sizeof (OpCode));
2695 }
2696
2697 /**
2698 Create EFI_IFR_DEFAULT_OP opcode.
2699
2700 If OpCodeHandle is NULL, then ASSERT().
2701 If Type is invalid, then ASSERT().
2702
2703 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2704 @param[in] DefaultId DefaultId for the default
2705 @param[in] Type Type for the default
2706 @param[in] Value Value for the default
2707
2708 @retval NULL There is not enough space left in Buffer to add the opcode.
2709 @retval Other A pointer to the created opcode.
2710
2711 **/
2712 UINT8 *
2713 EFIAPI
2714 HiiCreateDefaultOpCode (
2715 IN VOID *OpCodeHandle,
2716 IN UINT16 DefaultId,
2717 IN UINT8 Type,
2718 IN UINT64 Value
2719 )
2720 {
2721 EFI_IFR_DEFAULT OpCode;
2722
2723 ASSERT (Type < EFI_IFR_TYPE_OTHER);
2724
2725 ZeroMem (&OpCode, sizeof (OpCode));
2726 OpCode.Type = Type;
2727 OpCode.DefaultId = DefaultId;
2728 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
2729
2730 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, sizeof (OpCode));
2731 }
2732
2733 /**
2734 Create EFI_IFR_GUID opcode.
2735
2736 If OpCodeHandle is NULL, then ASSERT().
2737 If Guid is NULL, then ASSERT().
2738 If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
2739
2740 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2741 @param[in] Guid Pointer to EFI_GUID of this guided opcode.
2742 @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an
2743 optional parameter that may be NULL. If this
2744 parameter is NULL, then the GUID extension
2745 region of the created opcode is filled with zeros.
2746 If this parameter is not NULL, then the GUID
2747 extension region of GuidData will be copied to
2748 the GUID extension region of the created opcode.
2749 @param[in] OpCodeSize The size, in bytes, of created opcode. This value
2750 must be >= sizeof(EFI_IFR_GUID).
2751
2752 @retval NULL There is not enough space left in Buffer to add the opcode.
2753 @retval Other A pointer to the created opcode.
2754
2755 **/
2756 UINT8 *
2757 EFIAPI
2758 HiiCreateGuidOpCode (
2759 IN VOID *OpCodeHandle,
2760 IN CONST EFI_GUID *Guid,
2761 IN CONST VOID *GuidOpCode, OPTIONAL
2762 IN UINTN OpCodeSize
2763 )
2764 {
2765 EFI_IFR_GUID OpCode;
2766 EFI_IFR_GUID *OpCodePointer;
2767
2768 ASSERT (Guid != NULL);
2769 ASSERT (OpCodeSize >= sizeof (OpCode));
2770
2771 ZeroMem (&OpCode, sizeof (OpCode));
2772 CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
2773
2774 OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
2775 OpCodeHandle,
2776 &OpCode,
2777 EFI_IFR_GUID_OP,
2778 sizeof (OpCode),
2779 OpCodeSize - sizeof (OpCode),
2780 0
2781 );
2782 if (OpCodePointer != NULL && GuidOpCode != NULL) {
2783 CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
2784 }
2785 return (UINT8 *)OpCodePointer;
2786 }
2787
2788 /**
2789 Create EFI_IFR_ACTION_OP opcode.
2790
2791 If OpCodeHandle is NULL, then ASSERT().
2792 If any reserved bits are set in QuestionFlags, then ASSERT().
2793
2794 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2795 @param[in] QuestionId Question ID
2796 @param[in] Prompt String ID for Prompt
2797 @param[in] Help String ID for Help
2798 @param[in] QuestionFlags Flags in Question Header
2799 @param[in] QuestionConfig String ID for configuration
2800
2801 @retval NULL There is not enough space left in Buffer to add the opcode.
2802 @retval Other A pointer to the created opcode.
2803
2804 **/
2805 UINT8 *
2806 EFIAPI
2807 HiiCreateActionOpCode (
2808 IN VOID *OpCodeHandle,
2809 IN EFI_QUESTION_ID QuestionId,
2810 IN EFI_STRING_ID Prompt,
2811 IN EFI_STRING_ID Help,
2812 IN UINT8 QuestionFlags,
2813 IN EFI_STRING_ID QuestionConfig
2814 )
2815 {
2816 EFI_IFR_ACTION OpCode;
2817
2818 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
2819
2820 ZeroMem (&OpCode, sizeof (OpCode));
2821 OpCode.Question.QuestionId = QuestionId;
2822 OpCode.Question.Header.Prompt = Prompt;
2823 OpCode.Question.Header.Help = Help;
2824 OpCode.Question.Flags = QuestionFlags;
2825 OpCode.QuestionConfig = QuestionConfig;
2826
2827 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
2828 }
2829
2830 /**
2831 Create EFI_IFR_SUBTITLE_OP opcode.
2832
2833 If OpCodeHandle is NULL, then ASSERT().
2834 If any reserved bits are set in Flags, then ASSERT().
2835 If Scope > 1, then ASSERT().
2836
2837 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2838 @param[in] Prompt String ID for Prompt
2839 @param[in] Help String ID for Help
2840 @param[in] Flags Subtitle opcode flags
2841 @param[in] Scope 1 if this opcpde is the beginning of a new scope.
2842 0 if this opcode is within the current scope.
2843
2844 @retval NULL There is not enough space left in Buffer to add the opcode.
2845 @retval Other A pointer to the created opcode.
2846
2847 **/
2848 UINT8 *
2849 EFIAPI
2850 HiiCreateSubTitleOpCode (
2851 IN VOID *OpCodeHandle,
2852 IN EFI_STRING_ID Prompt,
2853 IN EFI_STRING_ID Help,
2854 IN UINT8 Flags,
2855 IN UINT8 Scope
2856 )
2857 {
2858 EFI_IFR_SUBTITLE OpCode;
2859
2860 ASSERT (Scope <= 1);
2861 ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
2862
2863 ZeroMem (&OpCode, sizeof (OpCode));
2864 OpCode.Statement.Prompt = Prompt;
2865 OpCode.Statement.Help = Help;
2866 OpCode.Flags = Flags;
2867
2868 return InternalHiiCreateOpCodeExtended (
2869 OpCodeHandle,
2870 &OpCode,
2871 EFI_IFR_SUBTITLE_OP,
2872 sizeof (OpCode),
2873 0,
2874 Scope
2875 );
2876 }
2877
2878 /**
2879 Create EFI_IFR_REF_OP opcode.
2880
2881 If OpCodeHandle is NULL, then ASSERT().
2882 If any reserved bits are set in QuestionFlags, then ASSERT().
2883
2884 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2885 @param[in] FormId Destination Form ID
2886 @param[in] Prompt String ID for Prompt
2887 @param[in] Help String ID for Help
2888 @param[in] QuestionFlags Flags in Question Header
2889 @param[in] QuestionId Question ID
2890
2891 @retval NULL There is not enough space left in Buffer to add the opcode.
2892 @retval Other A pointer to the created opcode.
2893
2894 **/
2895 UINT8 *
2896 EFIAPI
2897 HiiCreateGotoOpCode (
2898 IN VOID *OpCodeHandle,
2899 IN EFI_FORM_ID FormId,
2900 IN EFI_STRING_ID Prompt,
2901 IN EFI_STRING_ID Help,
2902 IN UINT8 QuestionFlags,
2903 IN EFI_QUESTION_ID QuestionId
2904 )
2905 {
2906 EFI_IFR_REF OpCode;
2907
2908 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
2909
2910 ZeroMem (&OpCode, sizeof (OpCode));
2911 OpCode.Question.Header.Prompt = Prompt;
2912 OpCode.Question.Header.Help = Help;
2913 OpCode.Question.QuestionId = QuestionId;
2914 OpCode.Question.Flags = QuestionFlags;
2915 OpCode.FormId = FormId;
2916
2917 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
2918 }
2919
2920 /**
2921 Create EFI_IFR_CHECKBOX_OP opcode.
2922
2923 If OpCodeHandle is NULL, then ASSERT().
2924 If any reserved bits are set in QuestionFlags, then ASSERT().
2925 If any reserved bits are set in CheckBoxFlags, then ASSERT().
2926
2927 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2928 @param[in] QuestionId Question ID
2929 @param[in] VarStoreId Storage ID
2930 @param[in] VarOffset Offset in Storage
2931 @param[in] Prompt String ID for Prompt
2932 @param[in] Help String ID for Help
2933 @param[in] QuestionFlags Flags in Question Header
2934 @param[in] CheckBoxFlags Flags for checkbox opcode
2935 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
2936 is an optional parameter that may be NULL.
2937
2938 @retval NULL There is not enough space left in Buffer to add the opcode.
2939 @retval Other A pointer to the created opcode.
2940
2941 **/
2942 UINT8 *
2943 EFIAPI
2944 HiiCreateCheckBoxOpCode (
2945 IN VOID *OpCodeHandle,
2946 IN EFI_QUESTION_ID QuestionId,
2947 IN EFI_VARSTORE_ID VarStoreId,
2948 IN UINT16 VarOffset,
2949 IN EFI_STRING_ID Prompt,
2950 IN EFI_STRING_ID Help,
2951 IN UINT8 QuestionFlags,
2952 IN UINT8 CheckBoxFlags,
2953 IN VOID *DefaultsOpCodeHandle OPTIONAL
2954 )
2955 {
2956 EFI_IFR_CHECKBOX OpCode;
2957 UINTN Position;
2958
2959 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
2960
2961 ZeroMem (&OpCode, sizeof (OpCode));
2962 OpCode.Question.QuestionId = QuestionId;
2963 OpCode.Question.VarStoreId = VarStoreId;
2964 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
2965 OpCode.Question.Header.Prompt = Prompt;
2966 OpCode.Question.Header.Help = Help;
2967 OpCode.Question.Flags = QuestionFlags;
2968 OpCode.Flags = CheckBoxFlags;
2969
2970 if (DefaultsOpCodeHandle == NULL) {
2971 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
2972 }
2973
2974 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
2975 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
2976 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
2977 HiiCreateEndOpCode (OpCodeHandle);
2978 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
2979 }
2980
2981 /**
2982 Create EFI_IFR_NUMERIC_OP opcode.
2983
2984 If OpCodeHandle is NULL, then ASSERT().
2985 If any reserved bits are set in QuestionFlags, then ASSERT().
2986 If any reserved bits are set in NumericFlags, then ASSERT().
2987
2988 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2989 @param[in] QuestionId Question ID
2990 @param[in] VarStoreId Storage ID
2991 @param[in] VarOffset Offset in Storage
2992 @param[in] Prompt String ID for Prompt
2993 @param[in] Help String ID for Help
2994 @param[in] QuestionFlags Flags in Question Header
2995 @param[in] NumericFlags Flags for numeric opcode
2996 @param[in] Minimum Numeric minimum value
2997 @param[in] Maximum Numeric maximum value
2998 @param[in] Step Numeric step for edit
2999 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3000 is an optional parameter that may be NULL.
3001
3002 @retval NULL There is not enough space left in Buffer to add the opcode.
3003 @retval Other A pointer to the created opcode.
3004
3005 **/
3006 UINT8 *
3007 EFIAPI
3008 HiiCreateNumericOpCode (
3009 IN VOID *OpCodeHandle,
3010 IN EFI_QUESTION_ID QuestionId,
3011 IN EFI_VARSTORE_ID VarStoreId,
3012 IN UINT16 VarOffset,
3013 IN EFI_STRING_ID Prompt,
3014 IN EFI_STRING_ID Help,
3015 IN UINT8 QuestionFlags,
3016 IN UINT8 NumericFlags,
3017 IN UINT64 Minimum,
3018 IN UINT64 Maximum,
3019 IN UINT64 Step,
3020 IN VOID *DefaultsOpCodeHandle OPTIONAL
3021 )
3022 {
3023 EFI_IFR_NUMERIC OpCode;
3024 UINTN Position;
3025
3026 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3027
3028 ZeroMem (&OpCode, sizeof (OpCode));
3029 OpCode.Question.QuestionId = QuestionId;
3030 OpCode.Question.VarStoreId = VarStoreId;
3031 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3032 OpCode.Question.Header.Prompt = Prompt;
3033 OpCode.Question.Header.Help = Help;
3034 OpCode.Question.Flags = QuestionFlags;
3035 OpCode.Flags = NumericFlags;
3036
3037 switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
3038 case EFI_IFR_NUMERIC_SIZE_1:
3039 OpCode.data.u8.MinValue = (UINT8)Minimum;
3040 OpCode.data.u8.MaxValue = (UINT8)Maximum;
3041 OpCode.data.u8.Step = (UINT8)Step;
3042 break;
3043
3044 case EFI_IFR_NUMERIC_SIZE_2:
3045 OpCode.data.u16.MinValue = (UINT16)Minimum;
3046 OpCode.data.u16.MaxValue = (UINT16)Maximum;
3047 OpCode.data.u16.Step = (UINT16)Step;
3048 break;
3049
3050 case EFI_IFR_NUMERIC_SIZE_4:
3051 OpCode.data.u32.MinValue = (UINT32)Minimum;
3052 OpCode.data.u32.MaxValue = (UINT32)Maximum;
3053 OpCode.data.u32.Step = (UINT32)Step;
3054 break;
3055
3056 case EFI_IFR_NUMERIC_SIZE_8:
3057 OpCode.data.u64.MinValue = Minimum;
3058 OpCode.data.u64.MaxValue = Maximum;
3059 OpCode.data.u64.Step = Step;
3060 break;
3061 }
3062
3063 if (DefaultsOpCodeHandle == NULL) {
3064 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode));
3065 }
3066
3067 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3068 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, sizeof (OpCode), 0, 1);
3069 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3070 HiiCreateEndOpCode (OpCodeHandle);
3071 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3072 }
3073
3074 /**
3075 Create EFI_IFR_STRING_OP opcode.
3076
3077 If OpCodeHandle is NULL, then ASSERT().
3078 If any reserved bits are set in QuestionFlags, then ASSERT().
3079 If any reserved bits are set in StringFlags, then ASSERT().
3080
3081 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3082 @param[in] QuestionId Question ID
3083 @param[in] VarStoreId Storage ID
3084 @param[in] VarOffset Offset in Storage
3085 @param[in] Prompt String ID for Prompt
3086 @param[in] Help String ID for Help
3087 @param[in] QuestionFlags Flags in Question Header
3088 @param[in] StringFlags Flags for string opcode
3089 @param[in] MinSize String minimum length
3090 @param[in] MaxSize String maximum length
3091 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3092 is an optional parameter that may be NULL.
3093
3094 @retval NULL There is not enough space left in Buffer to add the opcode.
3095 @retval Other A pointer to the created opcode.
3096
3097 **/
3098 UINT8 *
3099 EFIAPI
3100 HiiCreateStringOpCode (
3101 IN VOID *OpCodeHandle,
3102 IN EFI_QUESTION_ID QuestionId,
3103 IN EFI_VARSTORE_ID VarStoreId,
3104 IN UINT16 VarOffset,
3105 IN EFI_STRING_ID Prompt,
3106 IN EFI_STRING_ID Help,
3107 IN UINT8 QuestionFlags,
3108 IN UINT8 StringFlags,
3109 IN UINT8 MinSize,
3110 IN UINT8 MaxSize,
3111 IN VOID *DefaultsOpCodeHandle OPTIONAL
3112 )
3113 {
3114 EFI_IFR_STRING OpCode;
3115 UINTN Position;
3116
3117 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3118
3119 ZeroMem (&OpCode, sizeof (OpCode));
3120 OpCode.Question.Header.Prompt = Prompt;
3121 OpCode.Question.Header.Help = Help;
3122 OpCode.Question.QuestionId = QuestionId;
3123 OpCode.Question.VarStoreId = VarStoreId;
3124 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3125 OpCode.Question.Flags = QuestionFlags;
3126 OpCode.MinSize = MinSize;
3127 OpCode.MaxSize = MaxSize;
3128 OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
3129
3130 if (DefaultsOpCodeHandle == NULL) {
3131 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
3132 }
3133
3134 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3135 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
3136 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3137 HiiCreateEndOpCode (OpCodeHandle);
3138 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3139 }
3140
3141 /**
3142 Create EFI_IFR_ONE_OF_OP opcode.
3143
3144 If OpCodeHandle is NULL, then ASSERT().
3145 If any reserved bits are set in QuestionFlags, then ASSERT().
3146 If any reserved bits are set in OneOfFlags, then ASSERT().
3147
3148 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3149 @param[in] QuestionId Question ID
3150 @param[in] VarStoreId Storage ID
3151 @param[in] VarOffset Offset in Storage
3152 @param[in] Prompt String ID for Prompt
3153 @param[in] Help String ID for Help
3154 @param[in] QuestionFlags Flags in Question Header
3155 @param[in] OneOfFlags Flags for oneof opcode
3156 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3157 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3158 is an optional parameter that may be NULL.
3159
3160 @retval NULL There is not enough space left in Buffer to add the opcode.
3161 @retval Other A pointer to the created opcode.
3162
3163 **/
3164 UINT8 *
3165 EFIAPI
3166 HiiCreateOneOfOpCode (
3167 IN VOID *OpCodeHandle,
3168 IN EFI_QUESTION_ID QuestionId,
3169 IN EFI_VARSTORE_ID VarStoreId,
3170 IN UINT16 VarOffset,
3171 IN EFI_STRING_ID Prompt,
3172 IN EFI_STRING_ID Help,
3173 IN UINT8 QuestionFlags,
3174 IN UINT8 OneOfFlags,
3175 IN VOID *OptionsOpCodeHandle,
3176 IN VOID *DefaultsOpCodeHandle OPTIONAL
3177 )
3178 {
3179 EFI_IFR_ONE_OF OpCode;
3180 UINTN Position;
3181
3182 ASSERT (OptionsOpCodeHandle != NULL);
3183 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3184
3185 ZeroMem (&OpCode, sizeof (OpCode));
3186 OpCode.Question.Header.Prompt = Prompt;
3187 OpCode.Question.Header.Help = Help;
3188 OpCode.Question.QuestionId = QuestionId;
3189 OpCode.Question.VarStoreId = VarStoreId;
3190 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3191 OpCode.Question.Flags = QuestionFlags;
3192 OpCode.Flags = OneOfFlags;
3193
3194 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3195 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, sizeof (OpCode), 0, 1);
3196 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3197 if (DefaultsOpCodeHandle != NULL) {
3198 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3199 }
3200 HiiCreateEndOpCode (OpCodeHandle);
3201 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3202 }
3203
3204 /**
3205 Create EFI_IFR_ORDERED_LIST_OP opcode.
3206
3207 If OpCodeHandle is NULL, then ASSERT().
3208 If any reserved bits are set in QuestionFlags, then ASSERT().
3209 If any reserved bits are set in OrderedListFlags, then ASSERT().
3210
3211 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3212 @param[in] QuestionId Question ID
3213 @param[in] VarStoreId Storage ID
3214 @param[in] VarOffset Offset in Storage
3215 @param[in] Prompt String ID for Prompt
3216 @param[in] Help String ID for Help
3217 @param[in] QuestionFlags Flags in Question Header
3218 @param[in] OrderedListFlags Flags for ordered list opcode
3219 @param[in] DataType Type for option value
3220 @param[in] MaxContainers Maximum count for options in this ordered list
3221 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3222 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3223 is an optional parameter that may be NULL.
3224
3225 @retval NULL There is not enough space left in Buffer to add the opcode.
3226 @retval Other A pointer to the created opcode.
3227
3228 **/
3229 UINT8 *
3230 EFIAPI
3231 HiiCreateOrderedListOpCode (
3232 IN VOID *OpCodeHandle,
3233 IN EFI_QUESTION_ID QuestionId,
3234 IN EFI_VARSTORE_ID VarStoreId,
3235 IN UINT16 VarOffset,
3236 IN EFI_STRING_ID Prompt,
3237 IN EFI_STRING_ID Help,
3238 IN UINT8 QuestionFlags,
3239 IN UINT8 OrderedListFlags,
3240 IN UINT8 DataType,
3241 IN UINT8 MaxContainers,
3242 IN VOID *OptionsOpCodeHandle,
3243 IN VOID *DefaultsOpCodeHandle OPTIONAL
3244 )
3245 {
3246 EFI_IFR_ORDERED_LIST OpCode;
3247 UINTN Position;
3248
3249 ASSERT (OptionsOpCodeHandle != NULL);
3250 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3251
3252 ZeroMem (&OpCode, sizeof (OpCode));
3253 OpCode.Question.Header.Prompt = Prompt;
3254 OpCode.Question.Header.Help = Help;
3255 OpCode.Question.QuestionId = QuestionId;
3256 OpCode.Question.VarStoreId = VarStoreId;
3257 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3258 OpCode.Question.Flags = QuestionFlags;
3259 OpCode.MaxContainers = MaxContainers;
3260 OpCode.Flags = OrderedListFlags;
3261
3262 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3263 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
3264 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3265 if (DefaultsOpCodeHandle != NULL) {
3266 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3267 }
3268 HiiCreateEndOpCode (OpCodeHandle);
3269 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3270 }
3271
3272 /**
3273 This is the internal worker function to update the data in
3274 a form specified by FormSetGuid, FormId and Label.
3275
3276 @param[in] FormSetGuid The optional Formset GUID.
3277 @param[in] FormId The Form ID.
3278 @param[in] Package The package header.
3279 @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
3280 opcodes to be inserted or replaced in the form.
3281 @param[in] OpCodeBufferEnd An OpCcode buffer that contains the IFR opcode
3282 that marks the end of a replace operation in the form.
3283 @param[out] TempPackage The resultant package.
3284
3285 @retval EFI_SUCCESS The function completes successfully.
3286 @retval EFI_NOT_FOUND The updated opcode or endopcode is not found.
3287
3288 **/
3289 EFI_STATUS
3290 EFIAPI
3291 InternalHiiUpdateFormPackageData (
3292 IN EFI_GUID *FormSetGuid, OPTIONAL
3293 IN EFI_FORM_ID FormId,
3294 IN EFI_HII_PACKAGE_HEADER *Package,
3295 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart,
3296 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL
3297 OUT EFI_HII_PACKAGE_HEADER *TempPackage
3298 )
3299 {
3300 UINTN AddSize;
3301 UINT8 *BufferPos;
3302 EFI_HII_PACKAGE_HEADER PackageHeader;
3303 UINTN Offset;
3304 EFI_IFR_OP_HEADER *IfrOpHdr;
3305 EFI_IFR_OP_HEADER *UpdateIfrOpHdr;
3306 BOOLEAN GetFormSet;
3307 BOOLEAN GetForm;
3308 BOOLEAN Updated;
3309 UINTN UpdatePackageLength;
3310
3311 CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3312 UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
3313 BufferPos = (UINT8 *) (TempPackage + 1);
3314
3315 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3316 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
3317 Offset = sizeof (EFI_HII_PACKAGE_HEADER);
3318 GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
3319 GetForm = FALSE;
3320 Updated = FALSE;
3321
3322 while (Offset < PackageHeader.Length) {
3323 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
3324 BufferPos += IfrOpHdr->Length;
3325 UpdatePackageLength += IfrOpHdr->Length;
3326
3327 //
3328 // Find the matched FormSet and Form
3329 //
3330 if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
3331 if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
3332 GetFormSet = TRUE;
3333 } else {
3334 GetFormSet = FALSE;
3335 }
3336 } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP) {
3337 if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
3338 GetForm = TRUE;
3339 } else {
3340 GetForm = FALSE;
3341 }
3342 }
3343
3344 //
3345 // The matched Form is found, and Update data in this form
3346 //
3347 if (GetFormSet && GetForm) {
3348 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
3349 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
3350 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
3351 //
3352 // Remove the original data when End OpCode buffer exist.
3353 //
3354 if (OpCodeBufferEnd != NULL) {
3355 Offset += IfrOpHdr->Length;
3356 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
3357 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
3358 while (Offset < PackageHeader.Length) {
3359 //
3360 // Search the matched end opcode
3361 //
3362 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
3363 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
3364 break;
3365 }
3366 //
3367 // Go to the next Op-Code
3368 //
3369 Offset += IfrOpHdr->Length;
3370 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
3371 }
3372
3373 if (Offset >= PackageHeader.Length) {
3374 //
3375 // The end opcode is not found.
3376 //
3377 return EFI_NOT_FOUND;
3378 }
3379 }
3380
3381 //
3382 // Insert the updated data
3383 //
3384 AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
3385 CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
3386 BufferPos += OpCodeBufferStart->Position - AddSize;
3387 UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
3388
3389 if (OpCodeBufferEnd != NULL) {
3390 //
3391 // Add the end opcode
3392 //
3393 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
3394 BufferPos += IfrOpHdr->Length;
3395 UpdatePackageLength += IfrOpHdr->Length;
3396 }
3397
3398 //
3399 // Copy the left package data.
3400 //
3401 Offset += IfrOpHdr->Length;
3402 CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
3403 UpdatePackageLength += PackageHeader.Length - Offset;
3404
3405 //
3406 // Set update flag
3407 //
3408 Updated = TRUE;
3409 break;
3410 }
3411 }
3412
3413 //
3414 // Go to the next Op-Code
3415 //
3416 Offset += IfrOpHdr->Length;
3417 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
3418 }
3419
3420 if (!Updated) {
3421 //
3422 // The updated opcode buffer is not found.
3423 //
3424 return EFI_NOT_FOUND;
3425 }
3426 //
3427 // Update the package length.
3428 //
3429 PackageHeader.Length = (UINT32) UpdatePackageLength;
3430 CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
3431
3432 return EFI_SUCCESS;
3433 }
3434
3435 /**
3436 This function updates a form that has previously been registered with the HII
3437 Database. This function will perform at most one update operation.
3438
3439 The form to update is specified by Handle, FormSetGuid, and FormId. Binary
3440 comparisons of IFR opcodes are performed from the beginning of the form being
3441 updated until an IFR opcode is found that exactly matches the first IFR opcode
3442 specified by StartOpCodeHandle. The following rules are used to determine if
3443 an insert, replace, or delete operation is performed.
3444
3445 1) If no matches are found, then NULL is returned.
3446 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
3447 from StartOpCodeHandle except the first opcode are inserted immediately after
3448 the matching IFR opcode in the form to be updated.
3449 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
3450 from the matching IFR opcode until an IFR opcode exactly matches the first
3451 IFR opcode specified by EndOpCodeHandle. If no match is found for the first
3452 IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
3453 is found, then all of the IFR opcodes between the start match and the end
3454 match are deleted from the form being updated and all of the IFR opcodes
3455 from StartOpCodeHandle except the first opcode are inserted immediately after
3456 the matching start IFR opcode. If StartOpCcodeHandle only contains one
3457 IFR instruction, then the result of this operation will delete all of the IFR
3458 opcodes between the start end matches.
3459
3460 If HiiHandle is NULL, then ASSERT().
3461 If StartOpCodeHandle is NULL, then ASSERT().
3462
3463 @param[in] HiiHandle The HII Handle of the form to update.
3464 @param[in] FormSetGuid The Formset GUID of the form to update. This
3465 is an optional parameter that may be NULL.
3466 If it is NULL, all FormSet will be updated.
3467 @param[in] FormId The ID of the form to update.
3468 @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
3469 opcodes to be inserted or replaced in the form.
3470 The first IFR instruction in StartOpCodeHandle
3471 is used to find matching IFR opcode in the
3472 form.
3473 @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
3474 that marks the end of a replace operation in
3475 the form. This is an optional parameter that
3476 may be NULL. If it is NULL, then an the IFR
3477 opcodes specified by StartOpCodeHandle are
3478 inserted into the form.
3479
3480 @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
3481 @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND.
3482 1) The form specified by HiiHandle, FormSetGuid,
3483 and FormId could not be found in the HII Database.
3484 2) No IFR opcodes in the target form match the first
3485 IFR opcode in StartOpCodeHandle.
3486 3) EndOpCOde is not NULL, and no IFR opcodes in the
3487 target form following a matching start opcode match
3488 the first IFR opcode in EndOpCodeHandle.
3489 @retval EFI_SUCCESS The matched form is updated by StartOpcode.
3490
3491 **/
3492 EFI_STATUS
3493 EFIAPI
3494 HiiUpdateForm (
3495 IN EFI_HII_HANDLE HiiHandle,
3496 IN EFI_GUID *FormSetGuid, OPTIONAL
3497 IN EFI_FORM_ID FormId,
3498 IN VOID *StartOpCodeHandle,
3499 IN VOID *EndOpCodeHandle OPTIONAL
3500 )
3501 {
3502 EFI_STATUS Status;
3503 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
3504 UINT32 PackageListLength;
3505 UINT32 Offset;
3506 EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList;
3507 UINTN BufferSize;
3508 UINT8 *UpdateBufferPos;
3509 EFI_HII_PACKAGE_HEADER *Package;
3510 EFI_HII_PACKAGE_HEADER *TempPacakge;
3511 EFI_HII_PACKAGE_HEADER PackageHeader;
3512 BOOLEAN Updated;
3513 HII_LIB_OPCODE_BUFFER *OpCodeBufferStart;
3514 HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd;
3515
3516 //
3517 // Input update data can't be NULL.
3518 //
3519 ASSERT (HiiHandle != NULL);
3520 ASSERT (StartOpCodeHandle != NULL);
3521 UpdatePackageList = NULL;
3522 TempPacakge = NULL;
3523 HiiPackageList = NULL;
3524
3525 //
3526 // Retrieve buffer data from Opcode Handle
3527 //
3528 OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
3529 OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
3530
3531 //
3532 // Get the original package list
3533 //
3534 BufferSize = 0;
3535 HiiPackageList = NULL;
3536 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
3537 //
3538 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
3539 //
3540 if (Status != EFI_BUFFER_TOO_SMALL) {
3541 return Status;
3542 }
3543
3544 HiiPackageList = AllocatePool (BufferSize);
3545 if (HiiPackageList == NULL) {
3546 Status = EFI_OUT_OF_RESOURCES;
3547 goto Finish;
3548 }
3549
3550 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
3551 if (EFI_ERROR (Status)) {
3552 goto Finish;
3553 }
3554
3555 //
3556 // Calculate and allocate space for retrieval of IFR data
3557 //
3558 BufferSize += OpCodeBufferStart->Position;
3559 UpdatePackageList = AllocateZeroPool (BufferSize);
3560 if (UpdatePackageList == NULL) {
3561 Status = EFI_OUT_OF_RESOURCES;
3562 goto Finish;
3563 }
3564
3565 //
3566 // Allocate temp buffer to store the temp updated package buffer
3567 //
3568 TempPacakge = AllocateZeroPool (BufferSize);
3569 if (TempPacakge == NULL) {
3570 Status = EFI_OUT_OF_RESOURCES;
3571 goto Finish;
3572 }
3573
3574 UpdateBufferPos = (UINT8 *) UpdatePackageList;
3575
3576 //
3577 // Copy the package list header
3578 //
3579 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
3580 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3581
3582 //
3583 // Go through each package to find the matched package and update one by one
3584 //
3585 Updated = FALSE;
3586 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
3587 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
3588 while (Offset < PackageListLength) {
3589 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
3590 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3591 Offset += Package->Length;
3592
3593 if (Package->Type == EFI_HII_PACKAGE_FORMS) {
3594 //
3595 // Check this package is the matched package.
3596 //
3597 Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPacakge);
3598 //
3599 // The matched package is found. Its package buffer will be updated by the input new data.
3600 //
3601 if (!EFI_ERROR(Status)) {
3602 //
3603 // Set Update Flag
3604 //
3605 Updated = TRUE;
3606 //
3607 // Add updated package buffer
3608 //
3609 Package = TempPacakge;
3610 }
3611 }
3612
3613 //
3614 // Add pacakge buffer
3615 //
3616 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
3617 CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
3618 UpdateBufferPos += PackageHeader.Length;
3619 }
3620
3621 if (Updated) {
3622 //
3623 // Update package list length
3624 //
3625 BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
3626 WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
3627
3628 //
3629 // Update Package to show form
3630 //
3631 Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
3632 } else {
3633 //
3634 // Not matched form is found and updated.
3635 //
3636 Status = EFI_NOT_FOUND;
3637 }
3638
3639 Finish:
3640 if (HiiPackageList != NULL) {
3641 FreePool (HiiPackageList);
3642 }
3643
3644 if (UpdatePackageList != NULL) {
3645 FreePool (UpdatePackageList);
3646 }
3647
3648 if (TempPacakge != NULL) {
3649 FreePool (TempPacakge);
3650 }
3651
3652 return Status;
3653 }