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