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