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
InternalHiiExtractGuidFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_GUID * Guid)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
HiiAddPackages(IN CONST EFI_GUID * PackageListGuid,IN EFI_HANDLE DeviceHandle OPTIONAL,...)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
HiiRemovePackages(IN EFI_HII_HANDLE HiiHandle)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
HiiGetHiiHandles(IN CONST EFI_GUID * PackageListGuid OPTIONAL)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
HiiGetFormSetFromHiiHandle(IN EFI_HII_HANDLE Handle,OUT EFI_IFR_FORM_SET ** Buffer,OUT UINTN * BufferSize)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
InternalHiiLowerConfigString(IN EFI_STRING ConfigString)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
InternalHiiBlockToConfig(IN CONST EFI_STRING ConfigRequest,IN CONST UINT8 * Block,IN UINTN BlockSize)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
InternalHiiBrowserCallback(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN CONST EFI_STRING SetResultsData OPTIONAL)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
HiiConstructConfigHdr(IN CONST EFI_GUID * Guid,OPTIONAL IN CONST CHAR16 * Name,OPTIONAL IN EFI_HANDLE DriverHandle)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
InternalHiiGetBufferFromString(IN EFI_STRING String,IN UINT8 Flag,OUT UINT8 ** Buffer)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
BlockArrayCheck(IN IFR_BLOCK_DATA * BlockArray,IN UINT16 VarOffset,IN UINT16 VarWidth)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
InternalHiiGetValueOfNumber(IN EFI_STRING ValueString,OUT UINT8 ** ValueData,OUT UINTN * ValueLength)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
GetValueFromRequest(IN CHAR16 * ConfigElement,IN CHAR16 * VarName,OUT UINT64 * VarValue)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
ValidateQuestionFromVfr(IN EFI_HII_PACKAGE_LIST_HEADER * HiiPackageList,IN UINTN PackageListLength,IN EFI_GUID * VarGuid,IN CHAR16 * VarName,IN UINT8 * VarBuffer,IN IFR_BLOCK_DATA * CurrentBlockArray,IN CHAR16 * RequestElement,IN EFI_HII_HANDLE HiiHandle,IN BOOLEAN NameValueType)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
GetBlockDataInfo(IN CHAR16 * ConfigElement,OUT IFR_BLOCK_DATA ** CurrentBlockArray,OUT UINT8 ** VarBuffer)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
InternalHiiValidateCurrentSetting(IN EFI_STRING ConfigResp,IN EFI_HII_PACKAGE_LIST_HEADER * HiiPackageList,IN UINTN PackageListLength,IN EFI_GUID * VarGuid,IN CHAR16 * VarName,IN EFI_HII_HANDLE HiiHandle)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
GetElementsFromRequest(IN EFI_STRING ConfigRequest)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
InternalHiiIfrValueAction(IN CONST EFI_STRING Request,OPTIONAL IN UINT16 DefaultId,IN UINT8 ActionType)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 ASSERT (StringPtr != NULL);
2184
2185 while (*StringPtr != L'\0') {
2186 //
2187 // 1. Find <ConfigHdr> GUID=...&NAME=...&PATH=...
2188 //
2189 StringHdr = StringPtr;
2190
2191 //
2192 // Get Guid value
2193 //
2194 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2195 Status = EFI_INVALID_PARAMETER;
2196 goto Done;
2197 }
2198 StringPtr += StrLen (L"GUID=");
2199 Status = InternalHiiGetBufferFromString (StringPtr, GUID_CONFIG_STRING_TYPE, (UINT8 **) &VarGuid);
2200 if (EFI_ERROR (Status)) {
2201 goto Done;
2202 }
2203
2204 //
2205 // Get Name value VarName
2206 //
2207 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
2208 StringPtr++;
2209 }
2210 if (*StringPtr == L'\0') {
2211 Status = EFI_INVALID_PARAMETER;
2212 goto Done;
2213 }
2214 StringPtr += StrLen (L"&NAME=");
2215 Status = InternalHiiGetBufferFromString (StringPtr, NAME_CONFIG_STRING_TYPE, (UINT8 **) &VarName);
2216 if (EFI_ERROR (Status)) {
2217 goto Done;
2218 }
2219
2220 //
2221 // Get Path value DevicePath
2222 //
2223 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
2224 StringPtr++;
2225 }
2226 if (*StringPtr == L'\0') {
2227 Status = EFI_INVALID_PARAMETER;
2228 goto Done;
2229 }
2230 StringPtr += StrLen (L"&PATH=");
2231 Status = InternalHiiGetBufferFromString (StringPtr, PATH_CONFIG_STRING_TYPE, (UINT8 **) &DevicePath);
2232 if (EFI_ERROR (Status)) {
2233 goto Done;
2234 }
2235
2236 //
2237 // Get the Driver handle by the got device path.
2238 //
2239 TempDevicePath = DevicePath;
2240 Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDevicePath, &DriverHandle);
2241 if (EFI_ERROR (Status)) {
2242 goto Done;
2243 }
2244
2245 //
2246 // Find the matched Hii Handle for the found Driver handle
2247 //
2248 HiiHandleBuffer = HiiGetHiiHandles (NULL);
2249 if (HiiHandleBuffer == NULL) {
2250 Status = EFI_NOT_FOUND;
2251 goto Done;
2252 }
2253
2254 for (Index = 0; HiiHandleBuffer[Index] != NULL; Index ++) {
2255 gHiiDatabase->GetPackageListHandle (gHiiDatabase, HiiHandleBuffer[Index], &TempDriverHandle);
2256 if (TempDriverHandle == DriverHandle) {
2257 break;
2258 }
2259 }
2260
2261 HiiHandle = HiiHandleBuffer[Index];
2262 FreePool (HiiHandleBuffer);
2263
2264 if (HiiHandle == NULL) {
2265 //
2266 // This request string has no its Hii package.
2267 // Its default value and validating can't execute by parsing IFR data.
2268 // Directly jump into the next ConfigAltResp string for another pair Guid, Name, and Path.
2269 //
2270 Status = EFI_SUCCESS;
2271 goto NextConfigAltResp;
2272 }
2273
2274 //
2275 // 2. Get HiiPackage by HiiHandle
2276 //
2277 PackageListLength = 0;
2278 HiiPackageList = NULL;
2279 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
2280
2281 //
2282 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
2283 //
2284 if (Status != EFI_BUFFER_TOO_SMALL) {
2285 Status = EFI_INVALID_PARAMETER;
2286 goto Done;
2287 }
2288
2289 HiiPackageList = AllocatePool (PackageListLength);
2290 if (HiiPackageList == NULL) {
2291 Status = EFI_OUT_OF_RESOURCES;
2292 goto Done;
2293 }
2294
2295 //
2296 // Get PackageList on HiiHandle
2297 //
2298 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &PackageListLength, HiiPackageList);
2299 if (EFI_ERROR (Status)) {
2300 goto Done;
2301 }
2302
2303 //
2304 // 3. Call ConfigRouting GetAltCfg(ConfigRoute, <ConfigResponse>, Guid, Name, DevicePath, AltCfgId, AltCfgResp)
2305 // Get the default configuration string according to the default ID.
2306 //
2307 Status = gHiiConfigRouting->GetAltConfig (
2308 gHiiConfigRouting,
2309 ConfigAltResp,
2310 VarGuid,
2311 VarName,
2312 DevicePath,
2313 (ActionType == ACTION_SET_DEFAUTL_VALUE) ? &DefaultId:NULL, // it can be NULL to get the current setting.
2314 &ConfigResp
2315 );
2316
2317 //
2318 // The required setting can't be found. So, it is not required to be validated and set.
2319 //
2320 if (EFI_ERROR (Status)) {
2321 Status = EFI_SUCCESS;
2322 goto NextConfigAltResp;
2323 }
2324 //
2325 // Only the ConfigHdr is found. Not any block data is found. No data is required to be validated and set.
2326 //
2327 if (!GetElementsFromRequest (ConfigResp)) {
2328 goto NextConfigAltResp;
2329 }
2330
2331 //
2332 // 4. Set the default configuration information or Validate current setting by parse IFR code.
2333 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
2334 //
2335 if (ActionType == ACTION_SET_DEFAUTL_VALUE) {
2336 //
2337 // Set the default configuration information.
2338 //
2339 Status = gHiiConfigRouting->RouteConfig (gHiiConfigRouting, ConfigResp, &Progress);
2340 } else {
2341 //
2342 // Current Setting is in ConfigResp, will be set into buffer, then check it again.
2343 //
2344 Status = InternalHiiValidateCurrentSetting (ConfigResp, HiiPackageList, PackageListLength, VarGuid, VarName, HiiHandle);
2345 }
2346
2347 if (EFI_ERROR (Status)) {
2348 goto Done;
2349 }
2350
2351 NextConfigAltResp:
2352 //
2353 // Free the allocated pacakge buffer and the got ConfigResp string.
2354 //
2355 if (HiiPackageList != NULL) {
2356 FreePool (HiiPackageList);
2357 HiiPackageList = NULL;
2358 }
2359
2360 if (ConfigResp != NULL) {
2361 FreePool (ConfigResp);
2362 ConfigResp = NULL;
2363 }
2364
2365 //
2366 // Free the allocated buffer.
2367 //
2368 FreePool (VarGuid);
2369 VarGuid = NULL;
2370
2371 FreePool (VarName);
2372 VarName = NULL;
2373
2374 FreePool (DevicePath);
2375 DevicePath = NULL;
2376
2377 //
2378 // 5. Jump to next ConfigAltResp for another Guid, Name, Path.
2379 //
2380
2381 //
2382 // Get and Skip ConfigHdr
2383 //
2384 while (*StringPtr != L'\0' && *StringPtr != L'&') {
2385 StringPtr++;
2386 }
2387 if (*StringPtr == L'\0') {
2388 break;
2389 }
2390
2391 //
2392 // Construct ConfigAltHdr string "&<ConfigHdr>&ALTCFG=\0"
2393 // | 1 | StrLen (ConfigHdr) | 8 | 1 |
2394 //
2395 MaxLen = 1 + StringPtr - StringHdr + 8 + 1;
2396 ConfigAltHdr = AllocateZeroPool ( MaxLen * sizeof (CHAR16));
2397 if (ConfigAltHdr == NULL) {
2398 Status = EFI_OUT_OF_RESOURCES;
2399 goto Done;
2400 }
2401 StrCpyS (ConfigAltHdr, MaxLen, L"&");
2402 StrnCatS (ConfigAltHdr, MaxLen, StringHdr, StringPtr - StringHdr);
2403 StrCatS (ConfigAltHdr, MaxLen, L"&ALTCFG=");
2404
2405 //
2406 // Skip all AltResp (AltConfigHdr ConfigBody) for the same ConfigHdr
2407 //
2408 while ((StringHdr = StrStr (StringPtr, ConfigAltHdr)) != NULL) {
2409 StringPtr = StringHdr + StrLen (ConfigAltHdr);
2410 if (*StringPtr == L'\0') {
2411 break;
2412 }
2413 }
2414
2415 //
2416 // Free the allocated ConfigAltHdr string
2417 //
2418 FreePool (ConfigAltHdr);
2419 if (*StringPtr == L'\0') {
2420 break;
2421 }
2422
2423 //
2424 // Find &GUID as the next ConfigHdr
2425 //
2426 StringPtr = StrStr (StringPtr, L"&GUID");
2427 if (StringPtr == NULL) {
2428 break;
2429 }
2430
2431 //
2432 // Skip char '&'
2433 //
2434 StringPtr ++;
2435 }
2436
2437 Done:
2438 if (VarGuid != NULL) {
2439 FreePool (VarGuid);
2440 }
2441
2442 if (VarName != NULL) {
2443 FreePool (VarName);
2444 }
2445
2446 if (DevicePath != NULL) {
2447 FreePool (DevicePath);
2448 }
2449
2450 if (ConfigResp != NULL) {
2451 FreePool (ConfigResp);
2452 }
2453
2454 if (ConfigAltResp != NULL) {
2455 FreePool (ConfigAltResp);
2456 }
2457
2458 if (HiiPackageList != NULL) {
2459 FreePool (HiiPackageList);
2460 }
2461
2462 if (EFI_ERROR (Status)) {
2463 return FALSE;
2464 }
2465
2466 return TRUE;
2467 }
2468
2469 /**
2470 Validate the current configuration by parsing HII form IFR opcode.
2471
2472 NULL request string support depends on the ExportConfig interface of
2473 HiiConfigRouting protocol in UEFI specification.
2474
2475 @param Request A null-terminated Unicode string in
2476 <MultiConfigRequest> format. It can be NULL.
2477 If it is NULL, all current configuration for the
2478 entirety of the current HII database will be validated.
2479
2480 @retval TRUE Current configuration is valid.
2481 @retval FALSE Current configuration is invalid.
2482 **/
2483 BOOLEAN
2484 EFIAPI
HiiValidateSettings(IN CONST EFI_STRING Request OPTIONAL)2485 HiiValidateSettings (
2486 IN CONST EFI_STRING Request OPTIONAL
2487 )
2488 {
2489 return InternalHiiIfrValueAction (Request, 0, ACTION_VALIDATE_SETTING);
2490 }
2491
2492 /**
2493 Reset the default value specified by DefaultId to the driver
2494 configuration got by Request string.
2495
2496 NULL request string support depends on the ExportConfig interface of
2497 HiiConfigRouting protocol in UEFI specification.
2498
2499 @param Request A null-terminated Unicode string in
2500 <MultiConfigRequest> format. It can be NULL.
2501 If it is NULL, all configuration for the
2502 entirety of the current HII database will be reset.
2503 @param DefaultId Specifies the type of defaults to retrieve.
2504
2505 @retval TRUE The default value is set successfully.
2506 @retval FALSE The default value can't be found and set.
2507 **/
2508 BOOLEAN
2509 EFIAPI
HiiSetToDefaults(IN CONST EFI_STRING Request,OPTIONAL IN UINT16 DefaultId)2510 HiiSetToDefaults (
2511 IN CONST EFI_STRING Request, OPTIONAL
2512 IN UINT16 DefaultId
2513 )
2514 {
2515 return InternalHiiIfrValueAction (Request, DefaultId, ACTION_SET_DEFAUTL_VALUE);
2516 }
2517
2518 /**
2519 Determines if two values in config strings match.
2520
2521 Compares the substring between StartSearchString and StopSearchString in
2522 FirstString to the substring between StartSearchString and StopSearchString
2523 in SecondString. If the two substrings match, then TRUE is returned. If the
2524 two substrings do not match, then FALSE is returned.
2525
2526 If FirstString is NULL, then ASSERT().
2527 If SecondString is NULL, then ASSERT().
2528 If StartSearchString is NULL, then ASSERT().
2529 If StopSearchString is NULL, then ASSERT().
2530
2531 @param FirstString Pointer to the first Null-terminated Unicode string.
2532 @param SecondString Pointer to the second Null-terminated Unicode string.
2533 @param StartSearchString Pointer to the Null-terminated Unicode string that
2534 marks the start of the value string to compare.
2535 @param StopSearchString Pointer to the Null-terminated Unicode string that
2536 marks the end of the value string to compare.
2537
2538 @retval FALSE StartSearchString is not present in FirstString.
2539 @retval FALSE StartSearchString is not present in SecondString.
2540 @retval FALSE StopSearchString is not present in FirstString.
2541 @retval FALSE StopSearchString is not present in SecondString.
2542 @retval FALSE The length of the substring in FirstString is not the
2543 same length as the substring in SecondString.
2544 @retval FALSE The value string in FirstString does not matche the
2545 value string in SecondString.
2546 @retval TRUE The value string in FirstString matches the value
2547 string in SecondString.
2548
2549 **/
2550 BOOLEAN
2551 EFIAPI
InternalHiiCompareSubString(IN CHAR16 * FirstString,IN CHAR16 * SecondString,IN CHAR16 * StartSearchString,IN CHAR16 * StopSearchString)2552 InternalHiiCompareSubString (
2553 IN CHAR16 *FirstString,
2554 IN CHAR16 *SecondString,
2555 IN CHAR16 *StartSearchString,
2556 IN CHAR16 *StopSearchString
2557 )
2558 {
2559 CHAR16 *EndFirstString;
2560 CHAR16 *EndSecondString;
2561
2562 ASSERT (FirstString != NULL);
2563 ASSERT (SecondString != NULL);
2564 ASSERT (StartSearchString != NULL);
2565 ASSERT (StopSearchString != NULL);
2566
2567 FirstString = StrStr (FirstString, StartSearchString);
2568 if (FirstString == NULL) {
2569 return FALSE;
2570 }
2571
2572 SecondString = StrStr (SecondString, StartSearchString);
2573 if (SecondString == NULL) {
2574 return FALSE;
2575 }
2576
2577 EndFirstString = StrStr (FirstString, StopSearchString);
2578 if (EndFirstString == NULL) {
2579 return FALSE;
2580 }
2581
2582 EndSecondString = StrStr (SecondString, StopSearchString);
2583 if (EndSecondString == NULL) {
2584 return FALSE;
2585 }
2586
2587 if ((EndFirstString - FirstString) != (EndSecondString - SecondString)) {
2588 return FALSE;
2589 }
2590
2591 return (BOOLEAN)(StrnCmp (FirstString, SecondString, EndFirstString - FirstString) == 0);
2592 }
2593
2594 /**
2595 Determines if the routing data specified by GUID and NAME match a <ConfigHdr>.
2596
2597 If ConfigHdr is NULL, then ASSERT().
2598
2599 @param[in] ConfigHdr Either <ConfigRequest> or <ConfigResp>.
2600 @param[in] Guid GUID of the storage.
2601 @param[in] Name NAME of the storage.
2602
2603 @retval TRUE Routing information matches <ConfigHdr>.
2604 @retval FALSE Routing information does not match <ConfigHdr>.
2605
2606 **/
2607 BOOLEAN
2608 EFIAPI
HiiIsConfigHdrMatch(IN CONST EFI_STRING ConfigHdr,IN CONST EFI_GUID * Guid,OPTIONAL IN CONST CHAR16 * Name OPTIONAL)2609 HiiIsConfigHdrMatch (
2610 IN CONST EFI_STRING ConfigHdr,
2611 IN CONST EFI_GUID *Guid, OPTIONAL
2612 IN CONST CHAR16 *Name OPTIONAL
2613 )
2614 {
2615 EFI_STRING CompareConfigHdr;
2616 BOOLEAN Result;
2617
2618 ASSERT (ConfigHdr != NULL);
2619
2620 //
2621 // Use Guid and Name to generate a <ConfigHdr> string
2622 //
2623 CompareConfigHdr = HiiConstructConfigHdr (Guid, Name, NULL);
2624 if (CompareConfigHdr == NULL) {
2625 return FALSE;
2626 }
2627
2628 Result = TRUE;
2629 if (Guid != NULL) {
2630 //
2631 // Compare GUID value strings
2632 //
2633 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"GUID=", L"&NAME=");
2634 }
2635
2636 if (Result && Name != NULL) {
2637 //
2638 // Compare NAME value strings
2639 //
2640 Result = InternalHiiCompareSubString (ConfigHdr, CompareConfigHdr, L"&NAME=", L"&PATH=");
2641 }
2642
2643 //
2644 // Free the <ConfigHdr> string
2645 //
2646 FreePool (CompareConfigHdr);
2647
2648 return Result;
2649 }
2650
2651 /**
2652 Retrieves uncommitted data from the Form Browser and converts it to a binary
2653 buffer.
2654
2655 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2656 parameter that may be NULL.
2657 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2658 is an optional parameter that may be NULL.
2659 @param[in] BufferSize Length in bytes of buffer to hold retrieved data.
2660 @param[out] Buffer Buffer of data to be updated.
2661
2662 @retval FALSE The uncommitted data could not be retrieved.
2663 @retval TRUE The uncommitted data was retrieved.
2664
2665 **/
2666 BOOLEAN
2667 EFIAPI
HiiGetBrowserData(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN UINTN BufferSize,OUT UINT8 * Buffer)2668 HiiGetBrowserData (
2669 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2670 IN CONST CHAR16 *VariableName, OPTIONAL
2671 IN UINTN BufferSize,
2672 OUT UINT8 *Buffer
2673 )
2674 {
2675 EFI_STRING ResultsData;
2676 UINTN Size;
2677 EFI_STRING ConfigResp;
2678 EFI_STATUS Status;
2679 CHAR16 *Progress;
2680
2681 //
2682 // Retrieve the results data from the Browser Callback
2683 //
2684 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, NULL);
2685 if (ResultsData == NULL) {
2686 return FALSE;
2687 }
2688
2689 //
2690 // Construct <ConfigResp> mConfigHdrTemplate L'&' ResultsData L'\0'
2691 //
2692 Size = (StrLen (mConfigHdrTemplate) + 1) * sizeof (CHAR16);
2693 Size = Size + (StrLen (ResultsData) + 1) * sizeof (CHAR16);
2694 ConfigResp = AllocateZeroPool (Size);
2695 UnicodeSPrint (ConfigResp, Size, L"%s&%s", mConfigHdrTemplate, ResultsData);
2696
2697 //
2698 // Free the allocated buffer
2699 //
2700 FreePool (ResultsData);
2701 if (ConfigResp == NULL) {
2702 return FALSE;
2703 }
2704
2705 //
2706 // Convert <ConfigResp> to a buffer
2707 //
2708 Status = gHiiConfigRouting->ConfigToBlock (
2709 gHiiConfigRouting,
2710 ConfigResp,
2711 Buffer,
2712 &BufferSize,
2713 &Progress
2714 );
2715 //
2716 // Free the allocated buffer
2717 //
2718 FreePool (ConfigResp);
2719
2720 if (EFI_ERROR (Status)) {
2721 return FALSE;
2722 }
2723
2724 return TRUE;
2725 }
2726
2727 /**
2728 Updates uncommitted data in the Form Browser.
2729
2730 If Buffer is NULL, then ASSERT().
2731
2732 @param[in] VariableGuid Pointer to an EFI_GUID structure. This is an optional
2733 parameter that may be NULL.
2734 @param[in] VariableName Pointer to a Null-terminated Unicode string. This
2735 is an optional parameter that may be NULL.
2736 @param[in] BufferSize Length, in bytes, of Buffer.
2737 @param[in] Buffer Buffer of data to commit.
2738 @param[in] RequestElement An optional field to specify which part of the
2739 buffer data will be send back to Browser. If NULL,
2740 the whole buffer of data will be committed to
2741 Browser.
2742 <RequestElement> ::= &OFFSET=<Number>&WIDTH=<Number>*
2743
2744 @retval FALSE The uncommitted data could not be updated.
2745 @retval TRUE The uncommitted data was updated.
2746
2747 **/
2748 BOOLEAN
2749 EFIAPI
HiiSetBrowserData(IN CONST EFI_GUID * VariableGuid,OPTIONAL IN CONST CHAR16 * VariableName,OPTIONAL IN UINTN BufferSize,IN CONST UINT8 * Buffer,IN CONST CHAR16 * RequestElement OPTIONAL)2750 HiiSetBrowserData (
2751 IN CONST EFI_GUID *VariableGuid, OPTIONAL
2752 IN CONST CHAR16 *VariableName, OPTIONAL
2753 IN UINTN BufferSize,
2754 IN CONST UINT8 *Buffer,
2755 IN CONST CHAR16 *RequestElement OPTIONAL
2756 )
2757 {
2758 UINTN Size;
2759 EFI_STRING ConfigRequest;
2760 EFI_STRING ConfigResp;
2761 EFI_STRING ResultsData;
2762
2763 ASSERT (Buffer != NULL);
2764
2765 //
2766 // Construct <ConfigRequest>
2767 //
2768 if (RequestElement == NULL) {
2769 //
2770 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2771 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
2772 //
2773 Size = (StrLen (mConfigHdrTemplate) + 32 + 1) * sizeof (CHAR16);
2774 ConfigRequest = AllocateZeroPool (Size);
2775 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", mConfigHdrTemplate, (UINT64)BufferSize);
2776 } else {
2777 //
2778 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
2779 // followed by <RequestElement> followed by a Null-terminator
2780 //
2781 Size = StrLen (mConfigHdrTemplate) * sizeof (CHAR16);
2782 Size = Size + (StrLen (RequestElement) + 1) * sizeof (CHAR16);
2783 ConfigRequest = AllocateZeroPool (Size);
2784 UnicodeSPrint (ConfigRequest, Size, L"%s%s", mConfigHdrTemplate, RequestElement);
2785 }
2786 if (ConfigRequest == NULL) {
2787 return FALSE;
2788 }
2789
2790 //
2791 // Convert <ConfigRequest> to <ConfigResp>
2792 //
2793 ConfigResp = InternalHiiBlockToConfig (ConfigRequest, Buffer, BufferSize);
2794 FreePool (ConfigRequest);
2795 if (ConfigResp == NULL) {
2796 return FALSE;
2797 }
2798
2799 //
2800 // Set data in the uncommitted browser state information
2801 //
2802 ResultsData = InternalHiiBrowserCallback (VariableGuid, VariableName, ConfigResp + StrLen(mConfigHdrTemplate) + 1);
2803 FreePool (ConfigResp);
2804
2805 return (BOOLEAN)(ResultsData != NULL);
2806 }
2807
2808 /////////////////////////////////////////
2809 /////////////////////////////////////////
2810 /// IFR Functions
2811 /////////////////////////////////////////
2812 /////////////////////////////////////////
2813
2814 #define HII_LIB_OPCODE_ALLOCATION_SIZE 0x200
2815
2816 typedef struct {
2817 UINT8 *Buffer;
2818 UINTN BufferSize;
2819 UINTN Position;
2820 } HII_LIB_OPCODE_BUFFER;
2821
2822 ///
2823 /// Lookup table that converts EFI_IFR_TYPE_X enum values to a width in bytes
2824 ///
2825 GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 mHiiDefaultTypeToWidth[] = {
2826 1, // EFI_IFR_TYPE_NUM_SIZE_8
2827 2, // EFI_IFR_TYPE_NUM_SIZE_16
2828 4, // EFI_IFR_TYPE_NUM_SIZE_32
2829 8, // EFI_IFR_TYPE_NUM_SIZE_64
2830 1, // EFI_IFR_TYPE_BOOLEAN
2831 3, // EFI_IFR_TYPE_TIME
2832 4, // EFI_IFR_TYPE_DATE
2833 2 // EFI_IFR_TYPE_STRING
2834 };
2835
2836 /**
2837 Allocates and returns a new OpCode Handle. OpCode Handles must be freed with
2838 HiiFreeOpCodeHandle().
2839
2840 @retval NULL There are not enough resources to allocate a new OpCode Handle.
2841 @retval Other A new OpCode handle.
2842
2843 **/
2844 VOID *
2845 EFIAPI
HiiAllocateOpCodeHandle(VOID)2846 HiiAllocateOpCodeHandle (
2847 VOID
2848 )
2849 {
2850 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2851
2852 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)AllocatePool (sizeof (HII_LIB_OPCODE_BUFFER));
2853 if (OpCodeBuffer == NULL) {
2854 return NULL;
2855 }
2856 OpCodeBuffer->Buffer = (UINT8 *)AllocatePool (HII_LIB_OPCODE_ALLOCATION_SIZE);
2857 if (OpCodeBuffer->Buffer == NULL) {
2858 FreePool (OpCodeBuffer);
2859 return NULL;
2860 }
2861 OpCodeBuffer->BufferSize = HII_LIB_OPCODE_ALLOCATION_SIZE;
2862 OpCodeBuffer->Position = 0;
2863 return (VOID *)OpCodeBuffer;
2864 }
2865
2866 /**
2867 Frees an OpCode Handle that was previously allocated with HiiAllocateOpCodeHandle().
2868 When an OpCode Handle is freed, all of the opcodes associated with the OpCode
2869 Handle are also freed.
2870
2871 If OpCodeHandle is NULL, then ASSERT().
2872
2873 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2874
2875 **/
2876 VOID
2877 EFIAPI
HiiFreeOpCodeHandle(VOID * OpCodeHandle)2878 HiiFreeOpCodeHandle (
2879 VOID *OpCodeHandle
2880 )
2881 {
2882 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2883
2884 ASSERT (OpCodeHandle != NULL);
2885
2886 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2887 if (OpCodeBuffer->Buffer != NULL) {
2888 FreePool (OpCodeBuffer->Buffer);
2889 }
2890 FreePool (OpCodeBuffer);
2891 }
2892
2893 /**
2894 Internal function gets the current position of opcode buffer.
2895
2896 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2897
2898 @return Current position of opcode buffer.
2899 **/
2900 UINTN
2901 EFIAPI
InternalHiiOpCodeHandlePosition(IN VOID * OpCodeHandle)2902 InternalHiiOpCodeHandlePosition (
2903 IN VOID *OpCodeHandle
2904 )
2905 {
2906 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Position;
2907 }
2908
2909 /**
2910 Internal function gets the start pointer of opcode buffer.
2911
2912 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2913
2914 @return Pointer to the opcode buffer base.
2915 **/
2916 UINT8 *
2917 EFIAPI
InternalHiiOpCodeHandleBuffer(IN VOID * OpCodeHandle)2918 InternalHiiOpCodeHandleBuffer (
2919 IN VOID *OpCodeHandle
2920 )
2921 {
2922 return ((HII_LIB_OPCODE_BUFFER *)OpCodeHandle)->Buffer;
2923 }
2924
2925 /**
2926 Internal function reserves the enough buffer for current opcode.
2927 When the buffer is not enough, Opcode buffer will be extended.
2928
2929 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2930 @param[in] Size Size of current opcode.
2931
2932 @return Pointer to the current opcode.
2933 **/
2934 UINT8 *
2935 EFIAPI
InternalHiiGrowOpCodeHandle(IN VOID * OpCodeHandle,IN UINTN Size)2936 InternalHiiGrowOpCodeHandle (
2937 IN VOID *OpCodeHandle,
2938 IN UINTN Size
2939 )
2940 {
2941 HII_LIB_OPCODE_BUFFER *OpCodeBuffer;
2942 UINT8 *Buffer;
2943
2944 ASSERT (OpCodeHandle != NULL);
2945
2946 OpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)OpCodeHandle;
2947 if (OpCodeBuffer->Position + Size > OpCodeBuffer->BufferSize) {
2948 Buffer = ReallocatePool (
2949 OpCodeBuffer->BufferSize,
2950 OpCodeBuffer->BufferSize + (Size + HII_LIB_OPCODE_ALLOCATION_SIZE),
2951 OpCodeBuffer->Buffer
2952 );
2953 ASSERT (Buffer != NULL);
2954 OpCodeBuffer->Buffer = Buffer;
2955 OpCodeBuffer->BufferSize += (Size + HII_LIB_OPCODE_ALLOCATION_SIZE);
2956 }
2957 Buffer = OpCodeBuffer->Buffer + OpCodeBuffer->Position;
2958 OpCodeBuffer->Position += Size;
2959 return Buffer;
2960 }
2961
2962 /**
2963 Internal function creates opcode based on the template opcode.
2964
2965 @param[in] OpCodeHandle Handle to the buffer of opcodes.
2966 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
2967 @param[in] OpCode OpCode IFR value.
2968 @param[in] OpCodeSize Size of opcode.
2969 @param[in] ExtensionSize Size of extended opcode.
2970 @param[in] Scope Scope bit of opcode.
2971
2972 @return Pointer to the current opcode with opcode data.
2973 **/
2974 UINT8 *
2975 EFIAPI
InternalHiiCreateOpCodeExtended(IN VOID * OpCodeHandle,IN VOID * OpCodeTemplate,IN UINT8 OpCode,IN UINTN OpCodeSize,IN UINTN ExtensionSize,IN UINT8 Scope)2976 InternalHiiCreateOpCodeExtended (
2977 IN VOID *OpCodeHandle,
2978 IN VOID *OpCodeTemplate,
2979 IN UINT8 OpCode,
2980 IN UINTN OpCodeSize,
2981 IN UINTN ExtensionSize,
2982 IN UINT8 Scope
2983 )
2984 {
2985 EFI_IFR_OP_HEADER *Header;
2986 UINT8 *Buffer;
2987
2988 ASSERT (OpCodeTemplate != NULL);
2989 ASSERT ((OpCodeSize + ExtensionSize) <= 0x7F);
2990
2991 Header = (EFI_IFR_OP_HEADER *)OpCodeTemplate;
2992 Header->OpCode = OpCode;
2993 Header->Scope = Scope;
2994 Header->Length = (UINT8)(OpCodeSize + ExtensionSize);
2995 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, Header->Length);
2996 return (UINT8 *)CopyMem (Buffer, Header, OpCodeSize);
2997 }
2998
2999 /**
3000 Internal function creates opcode based on the template opcode for the normal opcode.
3001
3002 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3003 @param[in] OpCodeTemplate Pointer to the template buffer of opcode.
3004 @param[in] OpCode OpCode IFR value.
3005 @param[in] OpCodeSize Size of opcode.
3006
3007 @return Pointer to the current opcode with opcode data.
3008 **/
3009 UINT8 *
3010 EFIAPI
InternalHiiCreateOpCode(IN VOID * OpCodeHandle,IN VOID * OpCodeTemplate,IN UINT8 OpCode,IN UINTN OpCodeSize)3011 InternalHiiCreateOpCode (
3012 IN VOID *OpCodeHandle,
3013 IN VOID *OpCodeTemplate,
3014 IN UINT8 OpCode,
3015 IN UINTN OpCodeSize
3016 )
3017 {
3018 return InternalHiiCreateOpCodeExtended (OpCodeHandle, OpCodeTemplate, OpCode, OpCodeSize, 0, 0);
3019 }
3020
3021 /**
3022 Append raw opcodes to an OpCodeHandle.
3023
3024 If OpCodeHandle is NULL, then ASSERT().
3025 If RawBuffer is NULL, then ASSERT();
3026
3027 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3028 @param[in] RawBuffer Buffer of opcodes to append.
3029 @param[in] RawBufferSize The size, in bytes, of Buffer.
3030
3031 @retval NULL There is not enough space left in Buffer to add the opcode.
3032 @retval Other A pointer to the appended opcodes.
3033
3034 **/
3035 UINT8 *
3036 EFIAPI
HiiCreateRawOpCodes(IN VOID * OpCodeHandle,IN UINT8 * RawBuffer,IN UINTN RawBufferSize)3037 HiiCreateRawOpCodes (
3038 IN VOID *OpCodeHandle,
3039 IN UINT8 *RawBuffer,
3040 IN UINTN RawBufferSize
3041 )
3042 {
3043 UINT8 *Buffer;
3044
3045 ASSERT (RawBuffer != NULL);
3046
3047 Buffer = InternalHiiGrowOpCodeHandle (OpCodeHandle, RawBufferSize);
3048 return (UINT8 *)CopyMem (Buffer, RawBuffer, RawBufferSize);
3049 }
3050
3051 /**
3052 Append opcodes from one OpCode Handle to another OpCode handle.
3053
3054 If OpCodeHandle is NULL, then ASSERT().
3055 If RawOpCodeHandle is NULL, then ASSERT();
3056
3057 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3058 @param[in] RawOpCodeHandle Handle to the buffer of opcodes.
3059
3060 @retval NULL There is not enough space left in Buffer to add the opcode.
3061 @retval Other A pointer to the appended opcodes.
3062
3063 **/
3064 UINT8 *
3065 EFIAPI
InternalHiiAppendOpCodes(IN VOID * OpCodeHandle,IN VOID * RawOpCodeHandle)3066 InternalHiiAppendOpCodes (
3067 IN VOID *OpCodeHandle,
3068 IN VOID *RawOpCodeHandle
3069 )
3070 {
3071 HII_LIB_OPCODE_BUFFER *RawOpCodeBuffer;
3072
3073 ASSERT (RawOpCodeHandle != NULL);
3074
3075 RawOpCodeBuffer = (HII_LIB_OPCODE_BUFFER *)RawOpCodeHandle;
3076 return HiiCreateRawOpCodes (OpCodeHandle, RawOpCodeBuffer->Buffer, RawOpCodeBuffer->Position);
3077 }
3078
3079 /**
3080 Create EFI_IFR_END_OP opcode.
3081
3082 If OpCodeHandle is NULL, then ASSERT().
3083
3084 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3085
3086 @retval NULL There is not enough space left in Buffer to add the opcode.
3087 @retval Other A pointer to the created opcode.
3088
3089 **/
3090 UINT8 *
3091 EFIAPI
HiiCreateEndOpCode(IN VOID * OpCodeHandle)3092 HiiCreateEndOpCode (
3093 IN VOID *OpCodeHandle
3094 )
3095 {
3096 EFI_IFR_END OpCode;
3097
3098 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_END_OP, sizeof (OpCode));
3099 }
3100
3101 /**
3102 Create EFI_IFR_ONE_OF_OPTION_OP opcode.
3103
3104 If OpCodeHandle is NULL, then ASSERT().
3105 If Type is invalid, then ASSERT().
3106 If Flags is invalid, then ASSERT().
3107
3108 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3109 @param[in] StringId StringId for the option
3110 @param[in] Flags Flags for the option
3111 @param[in] Type Type for the option
3112 @param[in] Value Value for the option
3113
3114 @retval NULL There is not enough space left in Buffer to add the opcode.
3115 @retval Other A pointer to the created opcode.
3116
3117 **/
3118 UINT8 *
3119 EFIAPI
HiiCreateOneOfOptionOpCode(IN VOID * OpCodeHandle,IN UINT16 StringId,IN UINT8 Flags,IN UINT8 Type,IN UINT64 Value)3120 HiiCreateOneOfOptionOpCode (
3121 IN VOID *OpCodeHandle,
3122 IN UINT16 StringId,
3123 IN UINT8 Flags,
3124 IN UINT8 Type,
3125 IN UINT64 Value
3126 )
3127 {
3128 EFI_IFR_ONE_OF_OPTION OpCode;
3129
3130 ASSERT (Type < EFI_IFR_TYPE_OTHER);
3131
3132 ZeroMem (&OpCode, sizeof (OpCode));
3133 OpCode.Option = StringId;
3134 OpCode.Flags = (UINT8) (Flags & (EFI_IFR_OPTION_DEFAULT | EFI_IFR_OPTION_DEFAULT_MFG));
3135 OpCode.Type = Type;
3136 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
3137
3138 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OPTION_OP, OFFSET_OF(EFI_IFR_ONE_OF_OPTION, Value) + mHiiDefaultTypeToWidth[Type]);
3139 }
3140
3141 /**
3142 Create EFI_IFR_DEFAULT_OP opcode.
3143
3144 If OpCodeHandle is NULL, then ASSERT().
3145 If Type is invalid, then ASSERT().
3146
3147 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3148 @param[in] DefaultId DefaultId for the default
3149 @param[in] Type Type for the default
3150 @param[in] Value Value for the default
3151
3152 @retval NULL There is not enough space left in Buffer to add the opcode.
3153 @retval Other A pointer to the created opcode.
3154
3155 **/
3156 UINT8 *
3157 EFIAPI
HiiCreateDefaultOpCode(IN VOID * OpCodeHandle,IN UINT16 DefaultId,IN UINT8 Type,IN UINT64 Value)3158 HiiCreateDefaultOpCode (
3159 IN VOID *OpCodeHandle,
3160 IN UINT16 DefaultId,
3161 IN UINT8 Type,
3162 IN UINT64 Value
3163 )
3164 {
3165 EFI_IFR_DEFAULT OpCode;
3166
3167 ASSERT (Type < EFI_IFR_TYPE_OTHER);
3168
3169 ZeroMem (&OpCode, sizeof (OpCode));
3170 OpCode.Type = Type;
3171 OpCode.DefaultId = DefaultId;
3172 CopyMem (&OpCode.Value, &Value, mHiiDefaultTypeToWidth[Type]);
3173
3174 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DEFAULT_OP, OFFSET_OF(EFI_IFR_DEFAULT, Value) + mHiiDefaultTypeToWidth[Type]);
3175 }
3176
3177 /**
3178 Create EFI_IFR_GUID opcode.
3179
3180 If OpCodeHandle is NULL, then ASSERT().
3181 If Guid is NULL, then ASSERT().
3182 If OpCodeSize < sizeof (EFI_IFR_GUID), then ASSERT().
3183
3184 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3185 @param[in] Guid Pointer to EFI_GUID of this guided opcode.
3186 @param[in] GuidOpCode Pointer to an EFI_IFR_GUID opcode. This is an
3187 optional parameter that may be NULL. If this
3188 parameter is NULL, then the GUID extension
3189 region of the created opcode is filled with zeros.
3190 If this parameter is not NULL, then the GUID
3191 extension region of GuidData will be copied to
3192 the GUID extension region of the created opcode.
3193 @param[in] OpCodeSize The size, in bytes, of created opcode. This value
3194 must be >= sizeof(EFI_IFR_GUID).
3195
3196 @retval NULL There is not enough space left in Buffer to add the opcode.
3197 @retval Other A pointer to the created opcode.
3198
3199 **/
3200 UINT8 *
3201 EFIAPI
HiiCreateGuidOpCode(IN VOID * OpCodeHandle,IN CONST EFI_GUID * Guid,IN CONST VOID * GuidOpCode,OPTIONAL IN UINTN OpCodeSize)3202 HiiCreateGuidOpCode (
3203 IN VOID *OpCodeHandle,
3204 IN CONST EFI_GUID *Guid,
3205 IN CONST VOID *GuidOpCode, OPTIONAL
3206 IN UINTN OpCodeSize
3207 )
3208 {
3209 EFI_IFR_GUID OpCode;
3210 EFI_IFR_GUID *OpCodePointer;
3211
3212 ASSERT (Guid != NULL);
3213 ASSERT (OpCodeSize >= sizeof (OpCode));
3214
3215 ZeroMem (&OpCode, sizeof (OpCode));
3216 CopyGuid ((EFI_GUID *)(VOID *)&OpCode.Guid, Guid);
3217
3218 OpCodePointer = (EFI_IFR_GUID *)InternalHiiCreateOpCodeExtended (
3219 OpCodeHandle,
3220 &OpCode,
3221 EFI_IFR_GUID_OP,
3222 sizeof (OpCode),
3223 OpCodeSize - sizeof (OpCode),
3224 0
3225 );
3226 if (OpCodePointer != NULL && GuidOpCode != NULL) {
3227 CopyMem (OpCodePointer + 1, (EFI_IFR_GUID *)GuidOpCode + 1, OpCodeSize - sizeof (OpCode));
3228 }
3229 return (UINT8 *)OpCodePointer;
3230 }
3231
3232 /**
3233 Create EFI_IFR_ACTION_OP opcode.
3234
3235 If OpCodeHandle is NULL, then ASSERT().
3236 If any reserved bits are set in QuestionFlags, then ASSERT().
3237
3238 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3239 @param[in] QuestionId Question ID
3240 @param[in] Prompt String ID for Prompt
3241 @param[in] Help String ID for Help
3242 @param[in] QuestionFlags Flags in Question Header
3243 @param[in] QuestionConfig String ID for configuration
3244
3245 @retval NULL There is not enough space left in Buffer to add the opcode.
3246 @retval Other A pointer to the created opcode.
3247
3248 **/
3249 UINT8 *
3250 EFIAPI
HiiCreateActionOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_STRING_ID QuestionConfig)3251 HiiCreateActionOpCode (
3252 IN VOID *OpCodeHandle,
3253 IN EFI_QUESTION_ID QuestionId,
3254 IN EFI_STRING_ID Prompt,
3255 IN EFI_STRING_ID Help,
3256 IN UINT8 QuestionFlags,
3257 IN EFI_STRING_ID QuestionConfig
3258 )
3259 {
3260 EFI_IFR_ACTION OpCode;
3261
3262 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3263
3264 ZeroMem (&OpCode, sizeof (OpCode));
3265 OpCode.Question.QuestionId = QuestionId;
3266 OpCode.Question.Header.Prompt = Prompt;
3267 OpCode.Question.Header.Help = Help;
3268 OpCode.Question.Flags = QuestionFlags;
3269 OpCode.QuestionConfig = QuestionConfig;
3270
3271 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_ACTION_OP, sizeof (OpCode));
3272 }
3273
3274 /**
3275 Create EFI_IFR_SUBTITLE_OP opcode.
3276
3277 If OpCodeHandle is NULL, then ASSERT().
3278 If any reserved bits are set in Flags, then ASSERT().
3279 If Scope > 1, then ASSERT().
3280
3281 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3282 @param[in] Prompt String ID for Prompt
3283 @param[in] Help String ID for Help
3284 @param[in] Flags Subtitle opcode flags
3285 @param[in] Scope 1 if this opcpde is the beginning of a new scope.
3286 0 if this opcode is within the current scope.
3287
3288 @retval NULL There is not enough space left in Buffer to add the opcode.
3289 @retval Other A pointer to the created opcode.
3290
3291 **/
3292 UINT8 *
3293 EFIAPI
HiiCreateSubTitleOpCode(IN VOID * OpCodeHandle,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 Flags,IN UINT8 Scope)3294 HiiCreateSubTitleOpCode (
3295 IN VOID *OpCodeHandle,
3296 IN EFI_STRING_ID Prompt,
3297 IN EFI_STRING_ID Help,
3298 IN UINT8 Flags,
3299 IN UINT8 Scope
3300 )
3301 {
3302 EFI_IFR_SUBTITLE OpCode;
3303
3304 ASSERT (Scope <= 1);
3305 ASSERT ((Flags & (~(EFI_IFR_FLAGS_HORIZONTAL))) == 0);
3306
3307 ZeroMem (&OpCode, sizeof (OpCode));
3308 OpCode.Statement.Prompt = Prompt;
3309 OpCode.Statement.Help = Help;
3310 OpCode.Flags = Flags;
3311
3312 return InternalHiiCreateOpCodeExtended (
3313 OpCodeHandle,
3314 &OpCode,
3315 EFI_IFR_SUBTITLE_OP,
3316 sizeof (OpCode),
3317 0,
3318 Scope
3319 );
3320 }
3321
3322 /**
3323 Create EFI_IFR_REF_OP opcode.
3324
3325 If OpCodeHandle is NULL, then ASSERT().
3326 If any reserved bits are set in QuestionFlags, then ASSERT().
3327
3328 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3329 @param[in] FormId Destination Form ID
3330 @param[in] Prompt String ID for Prompt
3331 @param[in] Help String ID for Help
3332 @param[in] QuestionFlags Flags in Question Header
3333 @param[in] QuestionId Question ID
3334
3335 @retval NULL There is not enough space left in Buffer to add the opcode.
3336 @retval Other A pointer to the created opcode.
3337
3338 **/
3339 UINT8 *
3340 EFIAPI
HiiCreateGotoOpCode(IN VOID * OpCodeHandle,IN EFI_FORM_ID FormId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_QUESTION_ID QuestionId)3341 HiiCreateGotoOpCode (
3342 IN VOID *OpCodeHandle,
3343 IN EFI_FORM_ID FormId,
3344 IN EFI_STRING_ID Prompt,
3345 IN EFI_STRING_ID Help,
3346 IN UINT8 QuestionFlags,
3347 IN EFI_QUESTION_ID QuestionId
3348 )
3349 {
3350 EFI_IFR_REF OpCode;
3351
3352 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3353
3354 ZeroMem (&OpCode, sizeof (OpCode));
3355 OpCode.Question.Header.Prompt = Prompt;
3356 OpCode.Question.Header.Help = Help;
3357 OpCode.Question.QuestionId = QuestionId;
3358 OpCode.Question.Flags = QuestionFlags;
3359 OpCode.FormId = FormId;
3360
3361 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, sizeof (OpCode));
3362 }
3363
3364 /**
3365 Create EFI_IFR_REF_OP, EFI_IFR_REF2_OP, EFI_IFR_REF3_OP and EFI_IFR_REF4_OP opcode.
3366
3367 When RefDevicePath is not zero, EFI_IFR_REF4 opcode will be created.
3368 When RefDevicePath is zero and RefFormSetId is not NULL, EFI_IFR_REF3 opcode will be created.
3369 When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is not zero, EFI_IFR_REF2 opcode will be created.
3370 When RefDevicePath is zero, RefFormSetId is NULL and RefQuestionId is zero, EFI_IFR_REF opcode will be created.
3371
3372 If OpCodeHandle is NULL, then ASSERT().
3373 If any reserved bits are set in QuestionFlags, then ASSERT().
3374
3375 @param[in] OpCodeHandle The handle to the buffer of opcodes.
3376 @param[in] RefFormId The Destination Form ID.
3377 @param[in] Prompt The string ID for Prompt.
3378 @param[in] Help The string ID for Help.
3379 @param[in] QuestionFlags The flags in Question Header
3380 @param[in] QuestionId Question ID.
3381 @param[in] RefQuestionId The question on the form to which this link is referring.
3382 If its value is zero, then the link refers to the top of the form.
3383 @param[in] RefFormSetId The form set to which this link is referring. If its value is NULL, and RefDevicePath is
3384 zero, then the link is to the current form set.
3385 @param[in] RefDevicePath The string identifier that specifies the string containing the text representation of
3386 the device path to which the form set containing the form specified by FormId.
3387 If its value is zero, then the link refers to the current page.
3388
3389 @retval NULL There is not enough space left in Buffer to add the opcode.
3390 @retval Other A pointer to the created opcode.
3391
3392 **/
3393 UINT8 *
3394 EFIAPI
HiiCreateGotoExOpCode(IN VOID * OpCodeHandle,IN EFI_FORM_ID RefFormId,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN EFI_QUESTION_ID QuestionId,IN EFI_QUESTION_ID RefQuestionId,IN EFI_GUID * RefFormSetId,OPTIONAL IN EFI_STRING_ID RefDevicePath)3395 HiiCreateGotoExOpCode (
3396 IN VOID *OpCodeHandle,
3397 IN EFI_FORM_ID RefFormId,
3398 IN EFI_STRING_ID Prompt,
3399 IN EFI_STRING_ID Help,
3400 IN UINT8 QuestionFlags,
3401 IN EFI_QUESTION_ID QuestionId,
3402 IN EFI_QUESTION_ID RefQuestionId,
3403 IN EFI_GUID *RefFormSetId, OPTIONAL
3404 IN EFI_STRING_ID RefDevicePath
3405 )
3406 {
3407 EFI_IFR_REF4 OpCode;
3408 UINTN OpCodeSize;
3409
3410 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3411
3412 ZeroMem (&OpCode, sizeof (OpCode));
3413 OpCode.Question.Header.Prompt = Prompt;
3414 OpCode.Question.Header.Help = Help;
3415 OpCode.Question.QuestionId = QuestionId;
3416 OpCode.Question.Flags = QuestionFlags;
3417 OpCode.FormId = RefFormId;
3418 OpCode.QuestionId = RefQuestionId;
3419 OpCode.DevicePath = RefDevicePath;
3420 if (RefFormSetId != NULL) {
3421 CopyMem (&OpCode.FormSetId, RefFormSetId, sizeof (OpCode.FormSetId));
3422 }
3423
3424 //
3425 // Cacluate OpCodeSize based on the input Ref value.
3426 // Try to use the small OpCode to save size.
3427 //
3428 OpCodeSize = sizeof (EFI_IFR_REF);
3429 if (RefDevicePath != 0) {
3430 OpCodeSize = sizeof (EFI_IFR_REF4);
3431 } else if (RefFormSetId != NULL) {
3432 OpCodeSize = sizeof (EFI_IFR_REF3);
3433 } else if (RefQuestionId != 0) {
3434 OpCodeSize = sizeof (EFI_IFR_REF2);
3435 }
3436
3437 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_REF_OP, OpCodeSize);
3438 }
3439
3440 /**
3441 Create EFI_IFR_CHECKBOX_OP opcode.
3442
3443 If OpCodeHandle is NULL, then ASSERT().
3444 If any reserved bits are set in QuestionFlags, then ASSERT().
3445 If any reserved bits are set in CheckBoxFlags, then ASSERT().
3446
3447 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3448 @param[in] QuestionId Question ID
3449 @param[in] VarStoreId Storage ID
3450 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3451 for this name/value pair.
3452 @param[in] Prompt String ID for Prompt
3453 @param[in] Help String ID for Help
3454 @param[in] QuestionFlags Flags in Question Header
3455 @param[in] CheckBoxFlags Flags for checkbox opcode
3456 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3457 is an optional parameter that may be NULL.
3458
3459 @retval NULL There is not enough space left in Buffer to add the opcode.
3460 @retval Other A pointer to the created opcode.
3461
3462 **/
3463 UINT8 *
3464 EFIAPI
HiiCreateCheckBoxOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 CheckBoxFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)3465 HiiCreateCheckBoxOpCode (
3466 IN VOID *OpCodeHandle,
3467 IN EFI_QUESTION_ID QuestionId,
3468 IN EFI_VARSTORE_ID VarStoreId,
3469 IN UINT16 VarOffset,
3470 IN EFI_STRING_ID Prompt,
3471 IN EFI_STRING_ID Help,
3472 IN UINT8 QuestionFlags,
3473 IN UINT8 CheckBoxFlags,
3474 IN VOID *DefaultsOpCodeHandle OPTIONAL
3475 )
3476 {
3477 EFI_IFR_CHECKBOX OpCode;
3478 UINTN Position;
3479
3480 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3481
3482 ZeroMem (&OpCode, sizeof (OpCode));
3483 OpCode.Question.QuestionId = QuestionId;
3484 OpCode.Question.VarStoreId = VarStoreId;
3485 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3486 OpCode.Question.Header.Prompt = Prompt;
3487 OpCode.Question.Header.Help = Help;
3488 OpCode.Question.Flags = QuestionFlags;
3489 OpCode.Flags = CheckBoxFlags;
3490
3491 if (DefaultsOpCodeHandle == NULL) {
3492 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode));
3493 }
3494
3495 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3496 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_CHECKBOX_OP, sizeof (OpCode), 0, 1);
3497 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3498 HiiCreateEndOpCode (OpCodeHandle);
3499 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3500 }
3501
3502 /**
3503 Create EFI_IFR_NUMERIC_OP opcode.
3504
3505 If OpCodeHandle is NULL, then ASSERT().
3506 If any reserved bits are set in QuestionFlags, then ASSERT().
3507 If any reserved bits are set in NumericFlags, then ASSERT().
3508
3509 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3510 @param[in] QuestionId Question ID
3511 @param[in] VarStoreId Storage ID
3512 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3513 for this name/value pair.
3514 @param[in] Prompt String ID for Prompt
3515 @param[in] Help String ID for Help
3516 @param[in] QuestionFlags Flags in Question Header
3517 @param[in] NumericFlags Flags for numeric opcode
3518 @param[in] Minimum Numeric minimum value
3519 @param[in] Maximum Numeric maximum value
3520 @param[in] Step Numeric step for edit
3521 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3522 is an optional parameter that may be NULL.
3523
3524 @retval NULL There is not enough space left in Buffer to add the opcode.
3525 @retval Other A pointer to the created opcode.
3526
3527 **/
3528 UINT8 *
3529 EFIAPI
HiiCreateNumericOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 NumericFlags,IN UINT64 Minimum,IN UINT64 Maximum,IN UINT64 Step,IN VOID * DefaultsOpCodeHandle OPTIONAL)3530 HiiCreateNumericOpCode (
3531 IN VOID *OpCodeHandle,
3532 IN EFI_QUESTION_ID QuestionId,
3533 IN EFI_VARSTORE_ID VarStoreId,
3534 IN UINT16 VarOffset,
3535 IN EFI_STRING_ID Prompt,
3536 IN EFI_STRING_ID Help,
3537 IN UINT8 QuestionFlags,
3538 IN UINT8 NumericFlags,
3539 IN UINT64 Minimum,
3540 IN UINT64 Maximum,
3541 IN UINT64 Step,
3542 IN VOID *DefaultsOpCodeHandle OPTIONAL
3543 )
3544 {
3545 EFI_IFR_NUMERIC OpCode;
3546 UINTN Position;
3547 UINTN Length;
3548
3549 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3550
3551 Length = 0;
3552 ZeroMem (&OpCode, sizeof (OpCode));
3553 OpCode.Question.QuestionId = QuestionId;
3554 OpCode.Question.VarStoreId = VarStoreId;
3555 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3556 OpCode.Question.Header.Prompt = Prompt;
3557 OpCode.Question.Header.Help = Help;
3558 OpCode.Question.Flags = QuestionFlags;
3559 OpCode.Flags = NumericFlags;
3560
3561 switch (NumericFlags & EFI_IFR_NUMERIC_SIZE) {
3562 case EFI_IFR_NUMERIC_SIZE_1:
3563 OpCode.data.u8.MinValue = (UINT8)Minimum;
3564 OpCode.data.u8.MaxValue = (UINT8)Maximum;
3565 OpCode.data.u8.Step = (UINT8)Step;
3566 Length = 3;
3567 break;
3568
3569 case EFI_IFR_NUMERIC_SIZE_2:
3570 OpCode.data.u16.MinValue = (UINT16)Minimum;
3571 OpCode.data.u16.MaxValue = (UINT16)Maximum;
3572 OpCode.data.u16.Step = (UINT16)Step;
3573 Length = 6;
3574 break;
3575
3576 case EFI_IFR_NUMERIC_SIZE_4:
3577 OpCode.data.u32.MinValue = (UINT32)Minimum;
3578 OpCode.data.u32.MaxValue = (UINT32)Maximum;
3579 OpCode.data.u32.Step = (UINT32)Step;
3580 Length = 12;
3581 break;
3582
3583 case EFI_IFR_NUMERIC_SIZE_8:
3584 OpCode.data.u64.MinValue = Minimum;
3585 OpCode.data.u64.MaxValue = Maximum;
3586 OpCode.data.u64.Step = Step;
3587 Length = 24;
3588 break;
3589 }
3590
3591 Length += OFFSET_OF (EFI_IFR_NUMERIC, data);
3592
3593 if (DefaultsOpCodeHandle == NULL) {
3594 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length);
3595 }
3596
3597 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3598 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_NUMERIC_OP, Length, 0, 1);
3599 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3600 HiiCreateEndOpCode (OpCodeHandle);
3601 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3602 }
3603
3604 /**
3605 Create EFI_IFR_STRING_OP opcode.
3606
3607 If OpCodeHandle is NULL, then ASSERT().
3608 If any reserved bits are set in QuestionFlags, then ASSERT().
3609 If any reserved bits are set in StringFlags, then ASSERT().
3610
3611 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3612 @param[in] QuestionId Question ID
3613 @param[in] VarStoreId Storage ID
3614 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3615 for this name/value pair.
3616 @param[in] Prompt String ID for Prompt
3617 @param[in] Help String ID for Help
3618 @param[in] QuestionFlags Flags in Question Header
3619 @param[in] StringFlags Flags for string opcode
3620 @param[in] MinSize String minimum length
3621 @param[in] MaxSize String maximum length
3622 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3623 is an optional parameter that may be NULL.
3624
3625 @retval NULL There is not enough space left in Buffer to add the opcode.
3626 @retval Other A pointer to the created opcode.
3627
3628 **/
3629 UINT8 *
3630 EFIAPI
HiiCreateStringOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 StringFlags,IN UINT8 MinSize,IN UINT8 MaxSize,IN VOID * DefaultsOpCodeHandle OPTIONAL)3631 HiiCreateStringOpCode (
3632 IN VOID *OpCodeHandle,
3633 IN EFI_QUESTION_ID QuestionId,
3634 IN EFI_VARSTORE_ID VarStoreId,
3635 IN UINT16 VarOffset,
3636 IN EFI_STRING_ID Prompt,
3637 IN EFI_STRING_ID Help,
3638 IN UINT8 QuestionFlags,
3639 IN UINT8 StringFlags,
3640 IN UINT8 MinSize,
3641 IN UINT8 MaxSize,
3642 IN VOID *DefaultsOpCodeHandle OPTIONAL
3643 )
3644 {
3645 EFI_IFR_STRING OpCode;
3646 UINTN Position;
3647
3648 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3649
3650 ZeroMem (&OpCode, sizeof (OpCode));
3651 OpCode.Question.Header.Prompt = Prompt;
3652 OpCode.Question.Header.Help = Help;
3653 OpCode.Question.QuestionId = QuestionId;
3654 OpCode.Question.VarStoreId = VarStoreId;
3655 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3656 OpCode.Question.Flags = QuestionFlags;
3657 OpCode.MinSize = MinSize;
3658 OpCode.MaxSize = MaxSize;
3659 OpCode.Flags = (UINT8) (StringFlags & EFI_IFR_STRING_MULTI_LINE);
3660
3661 if (DefaultsOpCodeHandle == NULL) {
3662 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode));
3663 }
3664
3665 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3666 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_STRING_OP, sizeof (OpCode), 0, 1);
3667 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3668 HiiCreateEndOpCode (OpCodeHandle);
3669 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3670 }
3671
3672 /**
3673 Create EFI_IFR_ONE_OF_OP opcode.
3674
3675 If OpCodeHandle is NULL, then ASSERT().
3676 If any reserved bits are set in QuestionFlags, then ASSERT().
3677 If any reserved bits are set in OneOfFlags, then ASSERT().
3678
3679 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3680 @param[in] QuestionId Question ID
3681 @param[in] VarStoreId Storage ID
3682 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3683 for this name/value pair.
3684 @param[in] Prompt String ID for Prompt
3685 @param[in] Help String ID for Help
3686 @param[in] QuestionFlags Flags in Question Header
3687 @param[in] OneOfFlags Flags for oneof opcode
3688 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3689 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3690 is an optional parameter that may be NULL.
3691
3692 @retval NULL There is not enough space left in Buffer to add the opcode.
3693 @retval Other A pointer to the created opcode.
3694
3695 **/
3696 UINT8 *
3697 EFIAPI
HiiCreateOneOfOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 OneOfFlags,IN VOID * OptionsOpCodeHandle,IN VOID * DefaultsOpCodeHandle OPTIONAL)3698 HiiCreateOneOfOpCode (
3699 IN VOID *OpCodeHandle,
3700 IN EFI_QUESTION_ID QuestionId,
3701 IN EFI_VARSTORE_ID VarStoreId,
3702 IN UINT16 VarOffset,
3703 IN EFI_STRING_ID Prompt,
3704 IN EFI_STRING_ID Help,
3705 IN UINT8 QuestionFlags,
3706 IN UINT8 OneOfFlags,
3707 IN VOID *OptionsOpCodeHandle,
3708 IN VOID *DefaultsOpCodeHandle OPTIONAL
3709 )
3710 {
3711 EFI_IFR_ONE_OF OpCode;
3712 UINTN Position;
3713 UINTN Length;
3714
3715 ASSERT (OptionsOpCodeHandle != NULL);
3716 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3717
3718 ZeroMem (&OpCode, sizeof (OpCode));
3719 OpCode.Question.Header.Prompt = Prompt;
3720 OpCode.Question.Header.Help = Help;
3721 OpCode.Question.QuestionId = QuestionId;
3722 OpCode.Question.VarStoreId = VarStoreId;
3723 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3724 OpCode.Question.Flags = QuestionFlags;
3725 OpCode.Flags = OneOfFlags;
3726
3727 Length = OFFSET_OF (EFI_IFR_ONE_OF, data);
3728 Length += (1 << (OneOfFlags & EFI_IFR_NUMERIC_SIZE)) * 3;
3729
3730 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3731 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ONE_OF_OP, Length, 0, 1);
3732 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3733 if (DefaultsOpCodeHandle != NULL) {
3734 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3735 }
3736 HiiCreateEndOpCode (OpCodeHandle);
3737 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3738 }
3739
3740 /**
3741 Create EFI_IFR_ORDERED_LIST_OP opcode.
3742
3743 If OpCodeHandle is NULL, then ASSERT().
3744 If any reserved bits are set in QuestionFlags, then ASSERT().
3745 If any reserved bits are set in OrderedListFlags, then ASSERT().
3746
3747 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3748 @param[in] QuestionId Question ID
3749 @param[in] VarStoreId Storage ID
3750 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3751 for this name/value pair.
3752 @param[in] Prompt String ID for Prompt
3753 @param[in] Help String ID for Help
3754 @param[in] QuestionFlags Flags in Question Header
3755 @param[in] OrderedListFlags Flags for ordered list opcode
3756 @param[in] DataType Type for option value
3757 @param[in] MaxContainers Maximum count for options in this ordered list
3758 @param[in] OptionsOpCodeHandle Handle for a buffer of ONE_OF_OPTION opcodes.
3759 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3760 is an optional parameter that may be NULL.
3761
3762 @retval NULL There is not enough space left in Buffer to add the opcode.
3763 @retval Other A pointer to the created opcode.
3764
3765 **/
3766 UINT8 *
3767 EFIAPI
HiiCreateOrderedListOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,IN UINT16 VarOffset,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 OrderedListFlags,IN UINT8 DataType,IN UINT8 MaxContainers,IN VOID * OptionsOpCodeHandle,IN VOID * DefaultsOpCodeHandle OPTIONAL)3768 HiiCreateOrderedListOpCode (
3769 IN VOID *OpCodeHandle,
3770 IN EFI_QUESTION_ID QuestionId,
3771 IN EFI_VARSTORE_ID VarStoreId,
3772 IN UINT16 VarOffset,
3773 IN EFI_STRING_ID Prompt,
3774 IN EFI_STRING_ID Help,
3775 IN UINT8 QuestionFlags,
3776 IN UINT8 OrderedListFlags,
3777 IN UINT8 DataType,
3778 IN UINT8 MaxContainers,
3779 IN VOID *OptionsOpCodeHandle,
3780 IN VOID *DefaultsOpCodeHandle OPTIONAL
3781 )
3782 {
3783 EFI_IFR_ORDERED_LIST OpCode;
3784 UINTN Position;
3785
3786 ASSERT (OptionsOpCodeHandle != NULL);
3787 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED | EFI_IFR_FLAG_OPTIONS_ONLY))) == 0);
3788
3789 ZeroMem (&OpCode, sizeof (OpCode));
3790 OpCode.Question.Header.Prompt = Prompt;
3791 OpCode.Question.Header.Help = Help;
3792 OpCode.Question.QuestionId = QuestionId;
3793 OpCode.Question.VarStoreId = VarStoreId;
3794 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3795 OpCode.Question.Flags = QuestionFlags;
3796 OpCode.MaxContainers = MaxContainers;
3797 OpCode.Flags = OrderedListFlags;
3798
3799 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3800 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_ORDERED_LIST_OP, sizeof (OpCode), 0, 1);
3801 InternalHiiAppendOpCodes (OpCodeHandle, OptionsOpCodeHandle);
3802 if (DefaultsOpCodeHandle != NULL) {
3803 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3804 }
3805 HiiCreateEndOpCode (OpCodeHandle);
3806 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3807 }
3808
3809 /**
3810 Create EFI_IFR_TEXT_OP opcode.
3811
3812 If OpCodeHandle is NULL, then ASSERT().
3813
3814 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3815 @param[in] Prompt String ID for Prompt.
3816 @param[in] Help String ID for Help.
3817 @param[in] TextTwo String ID for TextTwo.
3818
3819 @retval NULL There is not enough space left in Buffer to add the opcode.
3820 @retval Other A pointer to the created opcode.
3821
3822 **/
3823 UINT8 *
3824 EFIAPI
HiiCreateTextOpCode(IN VOID * OpCodeHandle,IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN EFI_STRING_ID TextTwo)3825 HiiCreateTextOpCode (
3826 IN VOID *OpCodeHandle,
3827 IN EFI_STRING_ID Prompt,
3828 IN EFI_STRING_ID Help,
3829 IN EFI_STRING_ID TextTwo
3830 )
3831 {
3832 EFI_IFR_TEXT OpCode;
3833
3834 ZeroMem (&OpCode, sizeof (OpCode));
3835 OpCode.Statement.Prompt = Prompt;
3836 OpCode.Statement.Help = Help;
3837 OpCode.TextTwo = TextTwo;
3838
3839 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TEXT_OP, sizeof (OpCode));
3840 }
3841
3842 /**
3843 Create EFI_IFR_DATE_OP opcode.
3844
3845 If OpCodeHandle is NULL, then ASSERT().
3846 If any reserved bits are set in QuestionFlags, then ASSERT().
3847 If any reserved bits are set in DateFlags, then ASSERT().
3848
3849 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3850 @param[in] QuestionId Question ID
3851 @param[in] VarStoreId Storage ID, optional. If DateFlags is not
3852 QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3853 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3854 for this name/value pair, optional. If DateFlags is not
3855 QF_DATE_STORAGE_NORMAL, this parameter is ignored.
3856 @param[in] Prompt String ID for Prompt
3857 @param[in] Help String ID for Help
3858 @param[in] QuestionFlags Flags in Question Header
3859 @param[in] DateFlags Flags for date opcode
3860 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3861 is an optional parameter that may be NULL.
3862
3863 @retval NULL There is not enough space left in Buffer to add the opcode.
3864 @retval Other A pointer to the created opcode.
3865
3866 **/
3867 UINT8 *
3868 EFIAPI
HiiCreateDateOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,OPTIONAL IN UINT16 VarOffset,OPTIONAL IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 DateFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)3869 HiiCreateDateOpCode (
3870 IN VOID *OpCodeHandle,
3871 IN EFI_QUESTION_ID QuestionId,
3872 IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
3873 IN UINT16 VarOffset, OPTIONAL
3874 IN EFI_STRING_ID Prompt,
3875 IN EFI_STRING_ID Help,
3876 IN UINT8 QuestionFlags,
3877 IN UINT8 DateFlags,
3878 IN VOID *DefaultsOpCodeHandle OPTIONAL
3879 )
3880 {
3881 EFI_IFR_DATE OpCode;
3882 UINTN Position;
3883
3884 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3885 ASSERT ((DateFlags & (~(EFI_QF_DATE_YEAR_SUPPRESS | EFI_QF_DATE_MONTH_SUPPRESS | EFI_QF_DATE_DAY_SUPPRESS | EFI_QF_DATE_STORAGE))) == 0);
3886
3887 ZeroMem (&OpCode, sizeof (OpCode));
3888 OpCode.Question.Header.Prompt = Prompt;
3889 OpCode.Question.Header.Help = Help;
3890 OpCode.Question.QuestionId = QuestionId;
3891 OpCode.Question.VarStoreId = VarStoreId;
3892 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3893 OpCode.Question.Flags = QuestionFlags;
3894 OpCode.Flags = DateFlags;
3895
3896 if (DefaultsOpCodeHandle == NULL) {
3897 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode));
3898 }
3899
3900 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3901 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_DATE_OP, sizeof (OpCode), 0, 1);
3902 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3903 HiiCreateEndOpCode (OpCodeHandle);
3904 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3905 }
3906
3907 /**
3908 Create EFI_IFR_TIME_OP opcode.
3909
3910 If OpCodeHandle is NULL, then ASSERT().
3911 If any reserved bits are set in QuestionFlags, then ASSERT().
3912 If any reserved bits are set in TimeFlags, then ASSERT().
3913
3914 @param[in] OpCodeHandle Handle to the buffer of opcodes.
3915 @param[in] QuestionId Question ID
3916 @param[in] VarStoreId Storage ID, optional. If TimeFlags is not
3917 QF_TIME_STORAGE_NORMAL, this parameter is ignored.
3918 @param[in] VarOffset Offset in Storage or String ID of the name (VarName)
3919 for this name/value pair, optional. If TimeFlags is not
3920 QF_TIME_STORAGE_NORMAL, this parameter is ignored.
3921 @param[in] Prompt String ID for Prompt
3922 @param[in] Help String ID for Help
3923 @param[in] QuestionFlags Flags in Question Header
3924 @param[in] TimeFlags Flags for time opcode
3925 @param[in] DefaultsOpCodeHandle Handle for a buffer of DEFAULT opcodes. This
3926 is an optional parameter that may be NULL.
3927
3928 @retval NULL There is not enough space left in Buffer to add the opcode.
3929 @retval Other A pointer to the created opcode.
3930
3931 **/
3932 UINT8 *
3933 EFIAPI
HiiCreateTimeOpCode(IN VOID * OpCodeHandle,IN EFI_QUESTION_ID QuestionId,IN EFI_VARSTORE_ID VarStoreId,OPTIONAL IN UINT16 VarOffset,OPTIONAL IN EFI_STRING_ID Prompt,IN EFI_STRING_ID Help,IN UINT8 QuestionFlags,IN UINT8 TimeFlags,IN VOID * DefaultsOpCodeHandle OPTIONAL)3934 HiiCreateTimeOpCode (
3935 IN VOID *OpCodeHandle,
3936 IN EFI_QUESTION_ID QuestionId,
3937 IN EFI_VARSTORE_ID VarStoreId, OPTIONAL
3938 IN UINT16 VarOffset, OPTIONAL
3939 IN EFI_STRING_ID Prompt,
3940 IN EFI_STRING_ID Help,
3941 IN UINT8 QuestionFlags,
3942 IN UINT8 TimeFlags,
3943 IN VOID *DefaultsOpCodeHandle OPTIONAL
3944 )
3945 {
3946 EFI_IFR_TIME OpCode;
3947 UINTN Position;
3948
3949 ASSERT ((QuestionFlags & (~(EFI_IFR_FLAG_READ_ONLY | EFI_IFR_FLAG_CALLBACK | EFI_IFR_FLAG_RESET_REQUIRED))) == 0);
3950 ASSERT ((TimeFlags & (~(QF_TIME_HOUR_SUPPRESS | QF_TIME_MINUTE_SUPPRESS | QF_TIME_SECOND_SUPPRESS | QF_TIME_STORAGE))) == 0);
3951
3952 ZeroMem (&OpCode, sizeof (OpCode));
3953 OpCode.Question.Header.Prompt = Prompt;
3954 OpCode.Question.Header.Help = Help;
3955 OpCode.Question.QuestionId = QuestionId;
3956 OpCode.Question.VarStoreId = VarStoreId;
3957 OpCode.Question.VarStoreInfo.VarOffset = VarOffset;
3958 OpCode.Question.Flags = QuestionFlags;
3959 OpCode.Flags = TimeFlags;
3960
3961 if (DefaultsOpCodeHandle == NULL) {
3962 return InternalHiiCreateOpCode (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode));
3963 }
3964
3965 Position = InternalHiiOpCodeHandlePosition (OpCodeHandle);
3966 InternalHiiCreateOpCodeExtended (OpCodeHandle, &OpCode, EFI_IFR_TIME_OP, sizeof (OpCode), 0, 1);
3967 InternalHiiAppendOpCodes (OpCodeHandle, DefaultsOpCodeHandle);
3968 HiiCreateEndOpCode (OpCodeHandle);
3969 return InternalHiiOpCodeHandleBuffer (OpCodeHandle) + Position;
3970 }
3971
3972 /**
3973 This is the internal worker function to update the data in
3974 a form specified by FormSetGuid, FormId and Label.
3975
3976 @param[in] FormSetGuid The optional Formset GUID.
3977 @param[in] FormId The Form ID.
3978 @param[in] Package The package header.
3979 @param[in] OpCodeBufferStart An OpCode buffer that contains the set of IFR
3980 opcodes to be inserted or replaced in the form.
3981 @param[in] OpCodeBufferEnd An OpCcode buffer that contains the IFR opcode
3982 that marks the end of a replace operation in the form.
3983 @param[out] TempPackage The resultant package.
3984
3985 @retval EFI_SUCCESS The function completes successfully.
3986 @retval EFI_NOT_FOUND The updated opcode or endopcode is not found.
3987
3988 **/
3989 EFI_STATUS
3990 EFIAPI
InternalHiiUpdateFormPackageData(IN EFI_GUID * FormSetGuid,OPTIONAL IN EFI_FORM_ID FormId,IN EFI_HII_PACKAGE_HEADER * Package,IN HII_LIB_OPCODE_BUFFER * OpCodeBufferStart,IN HII_LIB_OPCODE_BUFFER * OpCodeBufferEnd,OPTIONAL OUT EFI_HII_PACKAGE_HEADER * TempPackage)3991 InternalHiiUpdateFormPackageData (
3992 IN EFI_GUID *FormSetGuid, OPTIONAL
3993 IN EFI_FORM_ID FormId,
3994 IN EFI_HII_PACKAGE_HEADER *Package,
3995 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferStart,
3996 IN HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd, OPTIONAL
3997 OUT EFI_HII_PACKAGE_HEADER *TempPackage
3998 )
3999 {
4000 UINTN AddSize;
4001 UINT8 *BufferPos;
4002 EFI_HII_PACKAGE_HEADER PackageHeader;
4003 UINTN Offset;
4004 EFI_IFR_OP_HEADER *IfrOpHdr;
4005 EFI_IFR_OP_HEADER *UpdateIfrOpHdr;
4006 BOOLEAN GetFormSet;
4007 BOOLEAN GetForm;
4008 BOOLEAN Updated;
4009 UINTN UpdatePackageLength;
4010
4011 CopyMem (TempPackage, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4012 UpdatePackageLength = sizeof (EFI_HII_PACKAGE_HEADER);
4013 BufferPos = (UINT8 *) (TempPackage + 1);
4014
4015 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4016 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));
4017 Offset = sizeof (EFI_HII_PACKAGE_HEADER);
4018 GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);
4019 GetForm = FALSE;
4020 Updated = FALSE;
4021
4022 while (Offset < PackageHeader.Length) {
4023 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
4024 BufferPos += IfrOpHdr->Length;
4025 UpdatePackageLength += IfrOpHdr->Length;
4026
4027 //
4028 // Find the matched FormSet and Form
4029 //
4030 if ((IfrOpHdr->OpCode == EFI_IFR_FORM_SET_OP) && (FormSetGuid != NULL)) {
4031 if (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
4032 GetFormSet = TRUE;
4033 } else {
4034 GetFormSet = FALSE;
4035 }
4036 } else if (IfrOpHdr->OpCode == EFI_IFR_FORM_OP || IfrOpHdr->OpCode == EFI_IFR_FORM_MAP_OP) {
4037 if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {
4038 GetForm = TRUE;
4039 } else {
4040 GetForm = FALSE;
4041 }
4042 }
4043
4044 //
4045 // The matched Form is found, and Update data in this form
4046 //
4047 if (GetFormSet && GetForm) {
4048 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer;
4049 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
4050 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
4051 //
4052 // Remove the original data when End OpCode buffer exist.
4053 //
4054 if (OpCodeBufferEnd != NULL) {
4055 Offset += IfrOpHdr->Length;
4056 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
4057 UpdateIfrOpHdr = (EFI_IFR_OP_HEADER *) OpCodeBufferEnd->Buffer;
4058 while (Offset < PackageHeader.Length) {
4059 //
4060 // Search the matched end opcode
4061 //
4062 if ((UpdateIfrOpHdr->Length == IfrOpHdr->Length) && \
4063 (CompareMem (IfrOpHdr, UpdateIfrOpHdr, UpdateIfrOpHdr->Length) == 0)) {
4064 break;
4065 }
4066 //
4067 // Go to the next Op-Code
4068 //
4069 Offset += IfrOpHdr->Length;
4070 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) (IfrOpHdr) + IfrOpHdr->Length);
4071 }
4072
4073 if (Offset >= PackageHeader.Length) {
4074 //
4075 // The end opcode is not found.
4076 //
4077 return EFI_NOT_FOUND;
4078 }
4079 }
4080
4081 //
4082 // Insert the updated data
4083 //
4084 AddSize = ((EFI_IFR_OP_HEADER *) OpCodeBufferStart->Buffer)->Length;
4085 CopyMem (BufferPos, OpCodeBufferStart->Buffer + AddSize, OpCodeBufferStart->Position - AddSize);
4086 BufferPos += OpCodeBufferStart->Position - AddSize;
4087 UpdatePackageLength += OpCodeBufferStart->Position - AddSize;
4088
4089 if (OpCodeBufferEnd != NULL) {
4090 //
4091 // Add the end opcode
4092 //
4093 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);
4094 BufferPos += IfrOpHdr->Length;
4095 UpdatePackageLength += IfrOpHdr->Length;
4096 }
4097
4098 //
4099 // Copy the left package data.
4100 //
4101 Offset += IfrOpHdr->Length;
4102 CopyMem (BufferPos, (UINT8 *) Package + Offset, PackageHeader.Length - Offset);
4103 UpdatePackageLength += PackageHeader.Length - Offset;
4104
4105 //
4106 // Set update flag
4107 //
4108 Updated = TRUE;
4109 break;
4110 }
4111 }
4112
4113 //
4114 // Go to the next Op-Code
4115 //
4116 Offset += IfrOpHdr->Length;
4117 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);
4118 }
4119
4120 if (!Updated) {
4121 //
4122 // The updated opcode buffer is not found.
4123 //
4124 return EFI_NOT_FOUND;
4125 }
4126 //
4127 // Update the package length.
4128 //
4129 PackageHeader.Length = (UINT32) UpdatePackageLength;
4130 CopyMem (TempPackage, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
4131
4132 return EFI_SUCCESS;
4133 }
4134
4135 /**
4136 This function updates a form that has previously been registered with the HII
4137 Database. This function will perform at most one update operation.
4138
4139 The form to update is specified by Handle, FormSetGuid, and FormId. Binary
4140 comparisons of IFR opcodes are performed from the beginning of the form being
4141 updated until an IFR opcode is found that exactly matches the first IFR opcode
4142 specified by StartOpCodeHandle. The following rules are used to determine if
4143 an insert, replace, or delete operation is performed.
4144
4145 1) If no matches are found, then NULL is returned.
4146 2) If a match is found, and EndOpCodeHandle is NULL, then all of the IFR opcodes
4147 from StartOpCodeHandle except the first opcode are inserted immediately after
4148 the matching IFR opcode in the form to be updated.
4149 3) If a match is found, and EndOpCodeHandle is not NULL, then a search is made
4150 from the matching IFR opcode until an IFR opcode exactly matches the first
4151 IFR opcode specified by EndOpCodeHandle. If no match is found for the first
4152 IFR opcode specified by EndOpCodeHandle, then NULL is returned. If a match
4153 is found, then all of the IFR opcodes between the start match and the end
4154 match are deleted from the form being updated and all of the IFR opcodes
4155 from StartOpCodeHandle except the first opcode are inserted immediately after
4156 the matching start IFR opcode. If StartOpCcodeHandle only contains one
4157 IFR instruction, then the result of this operation will delete all of the IFR
4158 opcodes between the start end matches.
4159
4160 If HiiHandle is NULL, then ASSERT().
4161 If StartOpCodeHandle is NULL, then ASSERT().
4162
4163 @param[in] HiiHandle The HII Handle of the form to update.
4164 @param[in] FormSetGuid The Formset GUID of the form to update. This
4165 is an optional parameter that may be NULL.
4166 If it is NULL, all FormSet will be updated.
4167 @param[in] FormId The ID of the form to update.
4168 @param[in] StartOpCodeHandle An OpCode Handle that contains the set of IFR
4169 opcodes to be inserted or replaced in the form.
4170 The first IFR instruction in StartOpCodeHandle
4171 is used to find matching IFR opcode in the
4172 form.
4173 @param[in] EndOpCodeHandle An OpCcode Handle that contains the IFR opcode
4174 that marks the end of a replace operation in
4175 the form. This is an optional parameter that
4176 may be NULL. If it is NULL, then an the IFR
4177 opcodes specified by StartOpCodeHandle are
4178 inserted into the form.
4179
4180 @retval EFI_OUT_OF_RESOURCES No enough memory resource is allocated.
4181 @retval EFI_NOT_FOUND The following cases will return EFI_NOT_FOUND.
4182 1) The form specified by HiiHandle, FormSetGuid,
4183 and FormId could not be found in the HII Database.
4184 2) No IFR opcodes in the target form match the first
4185 IFR opcode in StartOpCodeHandle.
4186 3) EndOpCOde is not NULL, and no IFR opcodes in the
4187 target form following a matching start opcode match
4188 the first IFR opcode in EndOpCodeHandle.
4189 @retval EFI_SUCCESS The matched form is updated by StartOpcode.
4190
4191 **/
4192 EFI_STATUS
4193 EFIAPI
HiiUpdateForm(IN EFI_HII_HANDLE HiiHandle,IN EFI_GUID * FormSetGuid,OPTIONAL IN EFI_FORM_ID FormId,IN VOID * StartOpCodeHandle,IN VOID * EndOpCodeHandle OPTIONAL)4194 HiiUpdateForm (
4195 IN EFI_HII_HANDLE HiiHandle,
4196 IN EFI_GUID *FormSetGuid, OPTIONAL
4197 IN EFI_FORM_ID FormId,
4198 IN VOID *StartOpCodeHandle,
4199 IN VOID *EndOpCodeHandle OPTIONAL
4200 )
4201 {
4202 EFI_STATUS Status;
4203 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
4204 UINT32 PackageListLength;
4205 UINT32 Offset;
4206 EFI_HII_PACKAGE_LIST_HEADER *UpdatePackageList;
4207 UINTN BufferSize;
4208 UINT8 *UpdateBufferPos;
4209 EFI_HII_PACKAGE_HEADER *Package;
4210 EFI_HII_PACKAGE_HEADER *TempPackage;
4211 EFI_HII_PACKAGE_HEADER PackageHeader;
4212 BOOLEAN Updated;
4213 HII_LIB_OPCODE_BUFFER *OpCodeBufferStart;
4214 HII_LIB_OPCODE_BUFFER *OpCodeBufferEnd;
4215
4216 //
4217 // Input update data can't be NULL.
4218 //
4219 ASSERT (HiiHandle != NULL);
4220 ASSERT (StartOpCodeHandle != NULL);
4221 UpdatePackageList = NULL;
4222 TempPackage = NULL;
4223 HiiPackageList = NULL;
4224
4225 //
4226 // Retrieve buffer data from Opcode Handle
4227 //
4228 OpCodeBufferStart = (HII_LIB_OPCODE_BUFFER *) StartOpCodeHandle;
4229 OpCodeBufferEnd = (HII_LIB_OPCODE_BUFFER *) EndOpCodeHandle;
4230
4231 //
4232 // Get the original package list
4233 //
4234 BufferSize = 0;
4235 HiiPackageList = NULL;
4236 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
4237 //
4238 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
4239 //
4240 if (Status != EFI_BUFFER_TOO_SMALL) {
4241 return Status;
4242 }
4243
4244 HiiPackageList = AllocatePool (BufferSize);
4245 if (HiiPackageList == NULL) {
4246 Status = EFI_OUT_OF_RESOURCES;
4247 goto Finish;
4248 }
4249
4250 Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
4251 if (EFI_ERROR (Status)) {
4252 goto Finish;
4253 }
4254
4255 //
4256 // Calculate and allocate space for retrieval of IFR data
4257 //
4258 BufferSize += OpCodeBufferStart->Position;
4259 UpdatePackageList = AllocateZeroPool (BufferSize);
4260 if (UpdatePackageList == NULL) {
4261 Status = EFI_OUT_OF_RESOURCES;
4262 goto Finish;
4263 }
4264
4265 //
4266 // Allocate temp buffer to store the temp updated package buffer
4267 //
4268 TempPackage = AllocateZeroPool (BufferSize);
4269 if (TempPackage == NULL) {
4270 Status = EFI_OUT_OF_RESOURCES;
4271 goto Finish;
4272 }
4273
4274 UpdateBufferPos = (UINT8 *) UpdatePackageList;
4275
4276 //
4277 // Copy the package list header
4278 //
4279 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
4280 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4281
4282 //
4283 // Go through each package to find the matched package and update one by one
4284 //
4285 Updated = FALSE;
4286 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
4287 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
4288 while (Offset < PackageListLength) {
4289 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
4290 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4291 Offset += Package->Length;
4292
4293 if (Package->Type == EFI_HII_PACKAGE_FORMS) {
4294 //
4295 // Check this package is the matched package.
4296 //
4297 Status = InternalHiiUpdateFormPackageData (FormSetGuid, FormId, Package, OpCodeBufferStart, OpCodeBufferEnd, TempPackage);
4298 //
4299 // The matched package is found. Its package buffer will be updated by the input new data.
4300 //
4301 if (!EFI_ERROR(Status)) {
4302 //
4303 // Set Update Flag
4304 //
4305 Updated = TRUE;
4306 //
4307 // Add updated package buffer
4308 //
4309 Package = TempPackage;
4310 }
4311 }
4312
4313 //
4314 // Add pacakge buffer
4315 //
4316 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
4317 CopyMem (UpdateBufferPos, Package, PackageHeader.Length);
4318 UpdateBufferPos += PackageHeader.Length;
4319 }
4320
4321 if (Updated) {
4322 //
4323 // Update package list length
4324 //
4325 BufferSize = UpdateBufferPos - (UINT8 *) UpdatePackageList;
4326 WriteUnaligned32 (&UpdatePackageList->PackageLength, (UINT32) BufferSize);
4327
4328 //
4329 // Update Package to show form
4330 //
4331 Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, HiiHandle, UpdatePackageList);
4332 } else {
4333 //
4334 // Not matched form is found and updated.
4335 //
4336 Status = EFI_NOT_FOUND;
4337 }
4338
4339 Finish:
4340 if (HiiPackageList != NULL) {
4341 FreePool (HiiPackageList);
4342 }
4343
4344 if (UpdatePackageList != NULL) {
4345 FreePool (UpdatePackageList);
4346 }
4347
4348 if (TempPackage != NULL) {
4349 FreePool (TempPackage);
4350 }
4351
4352 return Status;
4353 }
4354