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