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