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