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