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