]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
UEFI HII: Merge UEFI HII support changes from branch.
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
CommitLineData
93e3992d 1/** @file\r
2\r
3Copyright (c) 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 ConfigRouting.c\r
15\r
16Abstract:\r
17\r
18 Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL.\r
19\r
20Revision History\r
21\r
22\r
23**/\r
24\r
25\r
26#include "HiiDatabase.h"\r
27\r
28#ifndef DISABLE_UNUSED_HII_PROTOCOLS\r
29\r
30STATIC\r
31CHAR16\r
32NibbleToHexCharPrivate (\r
33 IN UINT8 Nibble\r
34 )\r
35/*++\r
36\r
37 Routine Description:\r
38 Converts the low nibble of a byte to hex unicode character.\r
39\r
40 Arguments:\r
41 Nibble - lower nibble of a byte.\r
42\r
43 Returns:\r
44 Hex unicode character between L'0' to L'f'.\r
45\r
46--*/\r
47{\r
48 Nibble &= 0x0F;\r
49\r
50 if (Nibble <= 0x9) {\r
51 return (CHAR16)(Nibble + L'0');\r
52 }\r
53\r
54 return (CHAR16)(Nibble - 0xA + L'a');\r
55}\r
56\r
57\r
58/**\r
59 Converts Unicode string to binary buffer.\r
60 The conversion may be partial.\r
61 The first character in the string that is not hex digit stops the conversion.\r
62 At a minimum, any blob of data could be represented as a hex string.\r
63\r
64 @param Buf Pointer to buffer that receives the data.\r
65 @param Len Length in bytes of the buffer to hold converted\r
66 data. If routine return with EFI_SUCCESS,\r
67 containing length of converted data. If routine\r
68 return with EFI_BUFFER_TOO_SMALL, containg length\r
69 of buffer desired.\r
70 @param Str String to be converted from.\r
71 @param ConvertedStrLen Length of the Hex String consumed.\r
72\r
73 @retval EFI_SUCCESS Routine Success.\r
74 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data.\r
75\r
76**/\r
77STATIC\r
78EFI_STATUS\r
79HexStringToBufPrivate (\r
80 IN OUT UINT8 *Buf,\r
81 IN OUT UINTN *Len,\r
82 IN CHAR16 *Str,\r
83 OUT UINTN *ConvertedStrLen OPTIONAL\r
84 )\r
85{\r
86 UINTN HexCnt;\r
87 UINTN Idx;\r
88 UINTN BufferLength;\r
89 UINT8 Digit;\r
90 UINT8 Byte;\r
91\r
92 //\r
93 // Find out how many hex characters the string has.\r
94 //\r
95 for (Idx = 0, HexCnt = 0; R8_IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++);\r
96\r
97 if (HexCnt == 0) {\r
98 *Len = 0;\r
99 return EFI_SUCCESS;\r
100 }\r
101 //\r
102 // Two Unicode characters make up 1 buffer byte. Round up.\r
103 //\r
104 BufferLength = (HexCnt + 1) / 2;\r
105\r
106 //\r
107 // Test if buffer is passed enough.\r
108 //\r
109 if (BufferLength > (*Len)) {\r
110 *Len = BufferLength;\r
111 return EFI_BUFFER_TOO_SMALL;\r
112 }\r
113\r
114 *Len = BufferLength;\r
115\r
116 for (Idx = 0; Idx < HexCnt; Idx++) {\r
117\r
118 R8_IsHexDigit (&Digit, Str[Idx]);\r
119\r
120 //\r
121 // For odd charaters, write the lower nibble for each buffer byte,\r
122 // and for even characters, the upper nibble.\r
123 //\r
124 if ((Idx & 1) == 0) {\r
125 Byte = (UINT8) (Digit << 4);\r
126 } else {\r
127 Byte = Buf[Idx / 2];\r
128 Byte &= 0xF0;\r
129 Byte = (UINT8) (Byte | Digit);\r
130 }\r
131\r
132 Buf[Idx / 2] = Byte;\r
133 }\r
134\r
135 if (ConvertedStrLen != NULL) {\r
136 *ConvertedStrLen = HexCnt;\r
137 }\r
138\r
139 return EFI_SUCCESS;\r
140}\r
141\r
142\r
143/**\r
144 Converts binary buffer to Unicode string.\r
145 At a minimum, any blob of data could be represented as a hex string.\r
146\r
147 @param Str Pointer to the string.\r
148 @param HexStringBufferLength Length in bytes of buffer to hold the hex string.\r
149 Includes tailing '\0' character. If routine return\r
150 with EFI_SUCCESS, containing length of hex string\r
151 buffer. If routine return with\r
152 EFI_BUFFER_TOO_SMALL, containg length of hex\r
153 string buffer desired.\r
154 @param Buf Buffer to be converted from.\r
155 @param Len Length in bytes of the buffer to be converted.\r
156 @param Flag If TRUE, encode the data in the same order as the\r
157 it resides in the Buf. Else encode it in the\r
158 reverse direction.\r
159\r
160 @retval EFI_SUCCESS Routine success.\r
161 @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small.\r
162\r
163**/\r
164STATIC\r
165EFI_STATUS\r
166BufToHexStringPrivate (\r
167 IN OUT CHAR16 *Str,\r
168 IN OUT UINTN *HexStringBufferLength,\r
169 IN UINT8 *Buf,\r
170 IN UINTN Len,\r
171 IN BOOLEAN Flag\r
172 )\r
173{\r
174 UINTN Idx;\r
175 UINT8 Byte;\r
176 UINTN StrLen;\r
177\r
178 //\r
179 // Make sure string is either passed or allocate enough.\r
180 // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.\r
181 // Plus the Unicode termination character.\r
182 //\r
183 StrLen = Len * 2;\r
184 if ((*HexStringBufferLength) < (StrLen + 1) * sizeof (CHAR16)) {\r
185 *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);\r
186 return EFI_BUFFER_TOO_SMALL;\r
187 }\r
188\r
189 *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);\r
190\r
191 //\r
192 // Ends the string.\r
193 //\r
194 Str[StrLen] = 0;\r
195\r
196 for (Idx = 0; Idx < Len; Idx++) {\r
197\r
198 Byte = Buf[Idx];\r
199 if (Flag) {\r
200 Str[Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));\r
201 Str[Idx * 2 + 1] = NibbleToHexCharPrivate (Byte);\r
202 } else {\r
203 Str[StrLen - 1 - Idx * 2] = NibbleToHexCharPrivate (Byte);\r
204 Str[StrLen - 2 - Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));\r
205 }\r
206 }\r
207\r
208 return EFI_SUCCESS;\r
209}\r
210\r
211\r
212\r
213/**\r
214 Calculate the number of Unicode characters of the incoming Configuration string,\r
215 not including NULL terminator.\r
216\r
217 @param String String in <MultiConfigRequest> or\r
218 <MultiConfigResp> format.\r
219\r
220 @return The number of Unicode characters.\r
221\r
222**/\r
223STATIC\r
224UINTN\r
225CalculateConfigStringLen (\r
226 IN EFI_STRING String\r
227 )\r
228{\r
229 UINTN Length;\r
230\r
231 //\r
232 // "GUID=" should be the first element of incoming string.\r
233 //\r
234 ASSERT (String != NULL);\r
235 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);\r
236\r
237 Length = StrLen (L"GUID=");\r
238 String += Length;\r
239\r
240 //\r
241 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".\r
242 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.\r
243 //\r
244 while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {\r
245 Length++;\r
246 String++;\r
247 }\r
248\r
249 return Length;\r
250}\r
251\r
252\r
253/**\r
254 Convert the hex UNICODE %02x encoding of a UEFI device path to binary\r
255 from <PathHdr> of <ConfigHdr>.\r
256\r
257 @param String UEFI configuration string\r
258 @param DevicePath binary of a UEFI device path.\r
259\r
260 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.\r
261 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.\r
262 @retval EFI_SUCCESS The device path is retrieved and translated to\r
263 binary format.\r
264\r
265**/\r
266STATIC\r
267EFI_STATUS\r
268GetDevicePath (\r
269 IN EFI_STRING String,\r
270 OUT UINT8 **DevicePath\r
271 )\r
272{\r
273 UINTN Length;\r
274 EFI_STRING PathHdr;\r
275 EFI_STRING DevicePathString;\r
276\r
277 if (String == NULL || DevicePath == NULL) {\r
278 return EFI_INVALID_PARAMETER;\r
279 }\r
280\r
281 //\r
282 // Find the 'PATH=' of <PathHdr> and skip it.\r
283 //\r
284 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);\r
285 if (*String == 0) {\r
286 return EFI_INVALID_PARAMETER;\r
287 }\r
288\r
289 String += StrLen (L"PATH=");\r
290 PathHdr = String;\r
291\r
292 //\r
293 // The content between 'PATH=' of <ConfigHdr> and '&' of next element\r
294 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding\r
295 // of UEFI device path.\r
296 //\r
297 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);\r
298 DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));\r
299 if (DevicePathString == NULL) {\r
300 return EFI_OUT_OF_RESOURCES;\r
301 }\r
302 StrnCpy (DevicePathString, PathHdr, Length);\r
303 *(DevicePathString + Length) = 0;\r
304\r
305 //\r
306 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order\r
307 // as the device path resides in RAM memory.\r
308 // Translate the data into binary.\r
309 // Two Unicode characters make up 1 buffer byte.\r
310 //\r
311 Length /= 2;\r
312 *DevicePath = (UINT8 *) AllocateZeroPool (Length);\r
313 if (*DevicePath == NULL) {\r
314 SafeFreePool (DevicePathString);\r
315 return EFI_OUT_OF_RESOURCES;\r
316 }\r
317\r
318 HexStringToBufPrivate (*DevicePath, &Length, DevicePathString, NULL);\r
319\r
320 SafeFreePool (DevicePathString);\r
321\r
322 return EFI_SUCCESS;\r
323\r
324}\r
325\r
326\r
327/**\r
328 Extract Storage from all Form Packages in current hii database.\r
329\r
330 @param HiiDatabase EFI_HII_DATABASE_PROTOCOL instance.\r
331 @param StorageListHead Storage link List head.\r
332\r
333 @retval EFI_NOT_FOUND There is no form package in current hii database.\r
334 @retval EFI_INVALID_PARAMETER Any parameter is invalid.\r
335 @retval EFI_SUCCESS All existing storage is exported.\r
336\r
337**/\r
338STATIC\r
339EFI_STATUS\r
340ExportAllStorage (\r
341 IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,\r
342 IN OUT LIST_ENTRY *StorageListHead\r
343)\r
344{\r
345 EFI_STATUS Status;\r
346 UINTN BufferSize;\r
347 UINTN HandleCount;\r
348 EFI_HII_HANDLE *HandleBuffer;\r
349 UINTN Index;\r
350 UINTN Index2;\r
351 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
352 EFI_HII_PACKAGE_HEADER *Package;\r
353 UINT8 *OpCodeData;\r
354 UINT8 Operand;\r
355 UINT32 Offset;\r
356 HII_FORMSET_STORAGE *Storage;\r
357 EFI_HII_HANDLE HiiHandle;\r
358 EFI_HANDLE DriverHandle;\r
359 CHAR8 *AsciiString;\r
360 UINT32 PackageListLength;\r
361 EFI_HII_PACKAGE_HEADER PackageHeader;\r
362\r
363 //\r
364 // Find the package list which contains Form package.\r
365 //\r
366 BufferSize = 0;\r
367 HandleBuffer = NULL;\r
368 Status = HiiListPackageLists (\r
369 HiiDatabase,\r
370 EFI_HII_PACKAGE_FORM,\r
371 NULL,\r
372 &BufferSize,\r
373 HandleBuffer\r
374 );\r
375 if (Status == EFI_BUFFER_TOO_SMALL) {\r
376 HandleBuffer = AllocateZeroPool (BufferSize);\r
377 ASSERT (HandleBuffer != NULL);\r
378\r
379 Status = HiiListPackageLists (\r
380 HiiDatabase,\r
381 EFI_HII_PACKAGE_FORM,\r
382 NULL,\r
383 &BufferSize,\r
384 HandleBuffer\r
385 );\r
386 }\r
387 if (EFI_ERROR (Status)) {\r
388 SafeFreePool (HandleBuffer);\r
389 return Status;\r
390 }\r
391\r
392 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);\r
393 for (Index = 0; Index < HandleCount; Index++) {\r
394 HiiHandle = HandleBuffer[Index];\r
395\r
396 BufferSize = 0;\r
397 HiiPackageList = NULL;\r
398 Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
399 if (Status == EFI_BUFFER_TOO_SMALL) {\r
400 HiiPackageList = AllocateZeroPool (BufferSize);\r
401 ASSERT (HiiPackageList != NULL);\r
402 Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);\r
403 }\r
404 if (EFI_ERROR (Status)) {\r
405 SafeFreePool (HandleBuffer);\r
406 SafeFreePool (HiiPackageList);\r
407 return Status;\r
408 }\r
409\r
410 //\r
411 // Get Form package from this HII package List\r
412 //\r
413 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
414 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
415 Package = NULL;\r
416 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
417\r
418 while (Offset < PackageListLength) {\r
419 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);\r
420 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
421 if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {\r
422 break;\r
423 }\r
424 Offset += PackageHeader.Length;\r
425 }\r
426 if (Offset >= PackageListLength) {\r
427 //\r
428 // Error here: No Form package found in this Package List\r
429 //\r
430 ASSERT (FALSE);\r
431 }\r
432\r
433 //\r
434 // Search Storage definition in this Form package\r
435 //\r
436 Offset = sizeof (EFI_HII_PACKAGE_HEADER);\r
437 while (Offset < PackageHeader.Length) {\r
438 OpCodeData = ((UINT8 *) Package) + Offset;\r
439 Offset += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
440\r
441 Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;\r
442\r
443 if ((Operand == EFI_IFR_VARSTORE_OP) ||\r
444 (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||\r
445 (Operand == EFI_IFR_VARSTORE_EFI_OP)) {\r
446\r
447 Storage = AllocateZeroPool (sizeof (HII_FORMSET_STORAGE));\r
448 ASSERT (Storage != NULL);\r
449 InsertTailList (StorageListHead, &Storage->Entry);\r
450\r
451 Storage->Signature = HII_FORMSET_STORAGE_SIGNATURE;\r
452 Storage->HiiHandle = HiiHandle;\r
453\r
454 Status = HiiGetPackageListHandle (HiiDatabase, HiiHandle, &DriverHandle);\r
455 if (EFI_ERROR (Status)) {\r
456 SafeFreePool (HandleBuffer);\r
457 SafeFreePool (HiiPackageList);\r
458 SafeFreePool (Storage);\r
459 return Status;\r
460 }\r
461 Storage->DriverHandle = DriverHandle;\r
462\r
463 if (Operand == EFI_IFR_VARSTORE_OP) {\r
464 Storage->Type = EFI_HII_VARSTORE_BUFFER;\r
465\r
466 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
467 CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));\r
468\r
469 AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;\r
470 Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2);\r
471 ASSERT (Storage->Name != NULL);\r
472 for (Index2 = 0; AsciiString[Index2] != 0; Index2++) {\r
473 Storage->Name[Index2] = (CHAR16) AsciiString[Index2];\r
474 }\r
475 //\r
476 // Append '\0' to the end of the unicode string.\r
477 //\r
478 Storage->Name[Index2] = 0;\r
479 } else if (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) {\r
480 Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;\r
481\r
482 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
483 } else if (Operand == EFI_IFR_VARSTORE_EFI_OP) {\r
484 Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE;\r
485\r
486 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));\r
487 }\r
488 }\r
489 }\r
490\r
491 SafeFreePool (HiiPackageList);\r
492 }\r
493\r
494 SafeFreePool (HandleBuffer);\r
495\r
496 return EFI_SUCCESS;\r
497}\r
498\r
499\r
500/**\r
501 Generate a sub string then output it.\r
502\r
503 @param String A constant string which is the prefix of the to be\r
504 generated string, e.g. GUID=\r
505 @param BufferLen The length of the Buffer in bytes.\r
506 @param Buffer Points to a buffer which will be converted to hex\r
507 string and to be the content of the generated\r
508 string.\r
509 @param Flag If TRUE, convert the buffer data in the same order\r
510 as the it resides in the Buffer. Else convert it\r
511 in the reverse direction.\r
512 @param SubStr Points to the output string. It's caller's\r
513 responsibility to free this buffer.\r
514\r
515\r
516**/\r
517STATIC\r
518VOID\r
519GenerateSubStr (\r
520 IN CONST EFI_STRING String,\r
521 IN UINTN BufferLen,\r
522 IN UINT8 *Buffer,\r
523 IN BOOLEAN Flag,\r
524 OUT EFI_STRING *SubStr\r
525 )\r
526{\r
527 UINTN Length;\r
528 EFI_STRING Str;\r
529 EFI_STATUS Status;\r
530\r
531 ASSERT (String != NULL && SubStr != NULL);\r
532\r
533 if (Buffer == NULL) {\r
534 *SubStr = AllocateCopyPool (StrSize (String), String);\r
535 ASSERT (*SubStr != NULL);\r
536 return ;\r
537 }\r
538\r
539 Length = BufferLen * 2 + 1 + StrLen (String) + 1;\r
540 Str = AllocateZeroPool (Length * sizeof (CHAR16));\r
541 ASSERT (Str != NULL);\r
542\r
543 StrCpy (Str, String);\r
544 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);\r
545\r
546 Status = BufToHexStringPrivate (\r
547 Str + StrLen (String),\r
548 &Length,\r
549 Buffer,\r
550 BufferLen,\r
551 Flag\r
552 );\r
553\r
554 ASSERT_EFI_ERROR (Status);\r
555 StrCat (Str, L"&");\r
556\r
557 *SubStr = Str;\r
558}\r
559\r
560\r
561/**\r
562 Retrieve the <ConfigBody> from String then output it.\r
563\r
564 @param String A sub string of a configuration string in\r
565 <MultiConfigAltResp> format.\r
566 @param ConfigBody Points to the output string. It's caller's\r
567 responsibility to free this buffer.\r
568\r
569 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.\r
570 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.\r
571 @retval EFI_SUCCESS All existing storage is exported.\r
572\r
573**/\r
574STATIC\r
575EFI_STATUS\r
576OutputConfigBody (\r
577 IN EFI_STRING String,\r
578 OUT EFI_STRING *ConfigBody\r
579 )\r
580{\r
581 EFI_STRING TmpPtr;\r
582 EFI_STRING Result;\r
583 UINTN Length;\r
584\r
585 if (String == NULL || ConfigBody == NULL) {\r
586 return EFI_INVALID_PARAMETER;\r
587 }\r
588\r
589 TmpPtr = StrStr (String, L"GUID=");\r
590 if (TmpPtr == NULL) {\r
591 //\r
592 // It is the last <ConfigResp> of the incoming configuration string.\r
593 //\r
594 Result = AllocateCopyPool (StrSize (String), String);\r
595 if (Result == NULL) {\r
596 return EFI_OUT_OF_RESOURCES;\r
597 } else {\r
598 *ConfigBody = Result;\r
599 return EFI_SUCCESS;\r
600 }\r
601 }\r
602\r
603 Length = TmpPtr - String;\r
604 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);\r
605 if (Result == NULL) {\r
606 return EFI_OUT_OF_RESOURCES;\r
607 }\r
608\r
609 *(Result + Length - 1) = 0;\r
610 *ConfigBody = Result;\r
611 return EFI_SUCCESS;\r
612\r
613}\r
614\r
615\r
616#endif\r
617\r
618VOID *\r
619ReallocatePool (\r
620 IN VOID *OldPool,\r
621 IN UINTN OldSize,\r
622 IN UINTN NewSize\r
623 )\r
624/*++\r
625\r
626Routine Description:\r
627 Adjusts the size of a previously allocated buffer.\r
628\r
629Arguments:\r
630 OldPool - A pointer to the buffer whose size is being adjusted.\r
631 OldSize - The size of the current buffer.\r
632 NewSize - The size of the new buffer.\r
633\r
634Returns:\r
635 Points to the new buffer\r
636\r
637--*/\r
638{\r
639 VOID *NewPool;\r
640\r
641 NewPool = NULL;\r
642 if (NewSize) {\r
643 NewPool = AllocateZeroPool (NewSize);\r
644 }\r
645\r
646 if (OldPool) {\r
647 if (NewPool) {\r
648 CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);\r
649 }\r
650\r
651 gBS->FreePool (OldPool);\r
652 }\r
653\r
654 return NewPool;\r
655}\r
656\r
657\r
658/**\r
659 Append a string to a multi-string format.\r
660\r
661 @param MultiString String in <MultiConfigRequest>,\r
662 <MultiConfigAltResp>, or <MultiConfigResp>. On\r
663 input, the buffer length of this string is\r
664 MAX_STRING_LENGTH. On output, the buffer length\r
665 might be updated.\r
666 @param AppendString NULL-terminated Unicode string.\r
667\r
668 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.\r
669 @retval EFI_SUCCESS AppendString is append to the end of MultiString\r
670\r
671**/\r
672STATIC\r
673EFI_STATUS\r
674AppendToMultiString (\r
675 IN OUT EFI_STRING *MultiString,\r
676 IN EFI_STRING AppendString\r
677 )\r
678{\r
679 UINTN AppendStringSize;\r
680 UINTN MultiStringSize;\r
681\r
682 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {\r
683 return EFI_INVALID_PARAMETER;\r
684 }\r
685\r
686 AppendStringSize = StrSize (AppendString);\r
687 MultiStringSize = StrSize (*MultiString);\r
688\r
689 //\r
690 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.\r
691 //\r
692 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||\r
693 MultiStringSize > MAX_STRING_LENGTH) {\r
694 *MultiString = (EFI_STRING) ReallocatePool (\r
695 (VOID *) (*MultiString),\r
696 MultiStringSize,\r
697 MultiStringSize + AppendStringSize\r
698 );\r
699 }\r
700\r
701 //\r
702 // Append the incoming string\r
703 //\r
704 StrCat (*MultiString, AppendString);\r
705\r
706 return EFI_SUCCESS;\r
707}\r
708\r
709\r
710/**\r
711 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET\r
712 or WIDTH or VALUE.\r
713 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>\r
714\r
715 @param StringPtr String in <BlockConfig> format and points to the\r
716 first character of <Number>.\r
717 @param Number The output value. Caller takes the responsibility\r
718 to free memory.\r
719 @param Len Length of the <Number>, in characters.\r
720\r
721 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary\r
722 structures.\r
723 @retval EFI_SUCCESS Value of <Number> is outputted in Number\r
724 successfully.\r
725\r
726**/\r
727STATIC\r
728EFI_STATUS\r
729GetValueOfNumber (\r
730 IN EFI_STRING StringPtr,\r
731 OUT UINT8 **Number,\r
732 OUT UINTN *Len\r
733 )\r
734{\r
735 EFI_STRING TmpPtr;\r
736 UINTN Length;\r
737 EFI_STRING Str;\r
738 UINT8 *Buf;\r
739 EFI_STATUS Status;\r
740\r
741 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);\r
742 ASSERT (*StringPtr != 0);\r
743\r
744 Buf = NULL;\r
745\r
746 TmpPtr = StringPtr;\r
747 while (*StringPtr != 0 && *StringPtr != L'&') {\r
748 StringPtr++;\r
749 }\r
750 *Len = StringPtr - TmpPtr;\r
751 Length = *Len + 1;\r
752\r
753 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));\r
754 if (Str == NULL) {\r
755 Status = EFI_OUT_OF_RESOURCES;\r
756 goto Exit;\r
757 }\r
758 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));\r
759 *(Str + *Len) = 0;\r
760\r
761 Length = (Length + 1) / 2;\r
762 Buf = (UINT8 *) AllocateZeroPool (Length);\r
763 if (Buf == NULL) {\r
764 Status = EFI_OUT_OF_RESOURCES;\r
765 goto Exit;\r
766 }\r
767\r
768 Status = R8_HexStringToBuf (Buf, &Length, Str, NULL);\r
769 if (EFI_ERROR (Status)) {\r
770 goto Exit;\r
771 }\r
772\r
773 *Number = Buf;\r
774 Status = EFI_SUCCESS;\r
775\r
776Exit:\r
777 SafeFreePool (Str);\r
778 return Status;\r
779}\r
780\r
781\r
782/**\r
783 This function allows a caller to extract the current configuration\r
784 for one or more named elements from one or more drivers.\r
785\r
786 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
787 instance.\r
788 @param Request A null-terminated Unicode string in\r
789 <MultiConfigRequest> format.\r
790 @param Progress On return, points to a character in the Request\r
791 string. Points to the string's null terminator if\r
792 request was successful. Points to the most recent\r
793 & before the first failing name / value pair (or\r
794 the beginning of the string if the failure is in\r
795 the first name / value pair) if the request was\r
796 not successful.\r
797 @param Results Null-terminated Unicode string in\r
798 <MultiConfigAltResp> format which has all values\r
799 filled in for the names in the Request string.\r
800 String to be allocated by the called function.\r
801\r
802 @retval EFI_SUCCESS The Results string is filled with the values\r
803 corresponding to all requested names.\r
804 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
805 results that must be stored awaiting possible\r
806 future protocols.\r
807 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.\r
808 Progress set to the "G" in "GUID" of the routing\r
809 header that doesn't match. Note: There is no\r
810 requirement that all routing data be validated\r
811 before any configuration extraction.\r
812 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request\r
813 parameter would result in this type of error. The\r
814 Progress parameter is set to NULL.\r
815 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &\r
816 before the error or the beginning of the string.\r
817 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the\r
818 name in question.\r
819\r
820**/\r
821EFI_STATUS\r
822EFIAPI\r
823HiiConfigRoutingExtractConfig (\r
824 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
825 IN CONST EFI_STRING Request,\r
826 OUT EFI_STRING *Progress,\r
827 OUT EFI_STRING *Results\r
828 )\r
829{\r
830#ifndef DISABLE_UNUSED_HII_PROTOCOLS\r
831\r
832 HII_DATABASE_PRIVATE_DATA *Private;\r
833 EFI_STRING StringPtr;\r
834 EFI_STRING ConfigRequest;\r
835 UINTN Length;\r
836 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
837 EFI_STATUS Status;\r
838 LIST_ENTRY *Link;\r
839 HII_DATABASE_RECORD *Database;\r
840 UINT8 *CurrentDevicePath;\r
841 EFI_HANDLE DriverHandle;\r
842 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
843 EFI_STRING AccessProgress;\r
844 EFI_STRING AccessResults;\r
845 UINTN RemainSize;\r
846 EFI_STRING TmpPtr;\r
847\r
848 if (This == NULL || Progress == NULL || Results == NULL) {\r
849 return EFI_INVALID_PARAMETER;\r
850 }\r
851\r
852 if (Request == NULL) {\r
853 *Progress = NULL;\r
854 return EFI_INVALID_PARAMETER;\r
855 }\r
856\r
857 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
858 StringPtr = Request;\r
859 *Progress = StringPtr;\r
860\r
861 //\r
862 // The first element of <MultiConfigRequest> should be\r
863 // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
864 //\r
865 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
866 return EFI_INVALID_PARAMETER;\r
867 }\r
868\r
869 //\r
870 // Allocate a fix length of memory to store Results. Reallocate memory for\r
871 // Results if this fix length is insufficient.\r
872 //\r
873 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
874 if (*Results == NULL) {\r
875 return EFI_OUT_OF_RESOURCES;\r
876 }\r
877\r
878 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
879 //\r
880 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>\r
881 // or most recent & before the error.\r
882 //\r
883 if (StringPtr == Request) {\r
884 *Progress = StringPtr;\r
885 } else {\r
886 *Progress = StringPtr - 1;\r
887 }\r
888\r
889 //\r
890 // Process each <ConfigRequest> of <MultiConfigRequest>\r
891 //\r
892 Length = CalculateConfigStringLen (StringPtr);\r
893 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
894 if (ConfigRequest == NULL) {\r
895 return EFI_OUT_OF_RESOURCES;\r
896 }\r
897 *(ConfigRequest + Length) = 0;\r
898\r
899 //\r
900 // Get the UEFI device path\r
901 //\r
902 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);\r
903 if (EFI_ERROR (Status)) {\r
904 SafeFreePool (ConfigRequest);\r
905 return Status;\r
906 }\r
907\r
908 //\r
909 // Find driver which matches the routing data.\r
910 //\r
911 DriverHandle = NULL;\r
912 for (Link = Private->DatabaseList.ForwardLink;\r
913 Link != &Private->DatabaseList;\r
914 Link = Link->ForwardLink\r
915 ) {\r
916 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
917 CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
918 if (CurrentDevicePath != NULL) {\r
919 if (CompareMem (\r
920 DevicePath,\r
921 CurrentDevicePath,\r
922 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
923 ) == 0) {\r
924 DriverHandle = Database->DriverHandle;\r
925 break;\r
926 }\r
927 }\r
928 }\r
929\r
930 SafeFreePool (DevicePath);\r
931\r
932 if (DriverHandle == NULL) {\r
933 //\r
934 // Routing data does not match any known driver.\r
935 // Set Progress to the 'G' in "GUID" of the routing header.\r
936 //\r
937 *Progress = StringPtr;\r
938 SafeFreePool (ConfigRequest);\r
939 return EFI_NOT_FOUND;\r
940 }\r
941\r
942 //\r
943 // Call corresponding ConfigAccess protocol to extract settings\r
944 //\r
945 Status = gBS->HandleProtocol (\r
946 DriverHandle,\r
947 &gEfiHiiConfigAccessProtocolGuid,\r
948 (VOID **) &ConfigAccess\r
949 );\r
950 ASSERT_EFI_ERROR (Status);\r
951\r
952 Status = ConfigAccess->ExtractConfig (\r
953 ConfigAccess,\r
954 ConfigRequest,\r
955 &AccessProgress,\r
956 &AccessResults\r
957 );\r
958 if (EFI_ERROR (Status)) {\r
959 //\r
960 // AccessProgress indicates the parsing progress on <ConfigRequest>.\r
961 // Map it to the progress on <MultiConfigRequest> then return it.\r
962 //\r
963 RemainSize = StrSize (AccessProgress);\r
964 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);\r
965 *Progress = TmpPtr;\r
966\r
967 SafeFreePool (ConfigRequest);\r
968 return Status;\r
969 }\r
970\r
971 //\r
972 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>\r
973 //\r
974 ASSERT (*AccessProgress == 0);\r
975 Status = AppendToMultiString (Results, AccessResults);\r
976 ASSERT_EFI_ERROR (Status);\r
977 SafeFreePool (AccessResults);\r
978 AccessResults = NULL;\r
979 SafeFreePool (ConfigRequest);\r
980 ConfigRequest = NULL;\r
981\r
982 //\r
983 // Go to next <ConfigRequest> (skip '&').\r
984 //\r
985 StringPtr += Length;\r
986 if (*StringPtr == 0) {\r
987 *Progress = StringPtr;\r
988 break;\r
989 }\r
990\r
991 StringPtr++;\r
992\r
993 }\r
994\r
995 return EFI_SUCCESS;\r
996#else\r
997 return EFI_UNSUPPORTED;\r
998#endif\r
999\r
1000}\r
1001\r
1002\r
1003/**\r
1004 This function allows the caller to request the current configuration for the\r
1005 entirety of the current HII database and returns the data in a\r
1006 null-terminated Unicode string.\r
1007\r
1008 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1009 instance.\r
1010 @param Results Null-terminated Unicode string in\r
1011 <MultiConfigAltResp> format which has all values\r
1012 filled in for the names in the Request string.\r
1013 String to be allocated by the called function.\r
1014 De-allocation is up to the caller.\r
1015\r
1016 @retval EFI_SUCCESS The Results string is filled with the values\r
1017 corresponding to all requested names.\r
1018 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
1019 results that must be stored awaiting possible\r
1020 future protocols.\r
1021 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results\r
1022 parameter would result in this type of error.\r
1023\r
1024**/\r
1025EFI_STATUS\r
1026EFIAPI\r
1027HiiConfigRoutingExportConfig (\r
1028 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1029 OUT EFI_STRING *Results\r
1030 )\r
1031{\r
1032#ifndef DISABLE_UNUSED_HII_PROTOCOLS\r
1033\r
1034 EFI_STATUS Status;\r
1035 HII_DATABASE_PRIVATE_DATA *Private;\r
1036 LIST_ENTRY StorageListHdr;\r
1037 HII_FORMSET_STORAGE *Storage;\r
1038 LIST_ENTRY *Link;\r
1039 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1040 UINTN Length;\r
1041 EFI_STRING PathHdr;\r
1042 UINTN PathHdrSize;\r
1043 EFI_STRING ConfigRequest;\r
1044 UINTN RequestSize;\r
1045 EFI_STRING StringPtr;\r
1046 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
1047 EFI_STRING AccessProgress;\r
1048 EFI_STRING AccessResults;\r
1049 UINTN TmpSize;\r
1050\r
1051 if (This == NULL || Results == NULL) {\r
1052 return EFI_INVALID_PARAMETER;\r
1053 }\r
1054\r
1055 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1056\r
1057 InitializeListHead (&StorageListHdr);\r
1058\r
1059 Status = ExportAllStorage (&Private->HiiDatabase, &StorageListHdr);\r
1060 if (EFI_ERROR (Status)) {\r
1061 return Status;\r
1062 }\r
1063\r
1064 //\r
1065 // Allocate a fix length of memory to store Results. Reallocate memory for\r
1066 // Results if this fix length is insufficient.\r
1067 //\r
1068 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
1069 if (*Results == NULL) {\r
1070 return EFI_OUT_OF_RESOURCES;\r
1071 }\r
1072\r
1073 //\r
1074 // Parsing all formset storages.\r
1075 //\r
1076 for (Link = StorageListHdr.ForwardLink; Link != &StorageListHdr; Link = Link->ForwardLink) {\r
1077 Storage = CR (Link, HII_FORMSET_STORAGE, Entry, HII_FORMSET_STORAGE_SIGNATURE);\r
1078 //\r
1079 // Find the corresponding device path instance\r
1080 //\r
1081 Status = gBS->HandleProtocol (\r
1082 Storage->DriverHandle,\r
1083 &gEfiDevicePathProtocolGuid,\r
1084 (VOID **) &DevicePath\r
1085 );\r
1086 if (EFI_ERROR (Status)) {\r
1087 return Status;\r
1088 }\r
1089 //\r
1090 // Convert the device path binary to hex UNICODE %02x bytes in the same order\r
1091 // as the device path resides in RAM memory.\r
1092 //\r
1093 Length = GetDevicePathSize (DevicePath);\r
1094 PathHdrSize = (Length * 2 + 1) * sizeof (CHAR16);\r
1095 PathHdr = (EFI_STRING) AllocateZeroPool (PathHdrSize);\r
1096 if (PathHdr == NULL) {\r
1097 return EFI_OUT_OF_RESOURCES;\r
1098 }\r
1099 Status = BufToHexStringPrivate (PathHdr, &PathHdrSize, (UINT8 *) DevicePath, Length, TRUE);\r
1100 ASSERT_EFI_ERROR (Status);\r
1101\r
1102 //\r
1103 // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.\r
1104 // It means extract all possible configurations from this specific driver.\r
1105 //\r
1106 TmpSize = StrLen (L"GUID=&NAME=&PATH=");\r
1107 RequestSize = (TmpSize + sizeof (EFI_GUID) * 2 + StrLen (Storage->Name))\r
1108 * sizeof (CHAR16) + PathHdrSize;\r
1109 ConfigRequest = (EFI_STRING) AllocateZeroPool (RequestSize);\r
1110 if (ConfigRequest == NULL) {\r
1111 SafeFreePool (PathHdr);\r
1112 return EFI_OUT_OF_RESOURCES;\r
1113 }\r
1114\r
1115 //\r
1116 // Add <GuidHdr>\r
1117 // <GuidHdr> ::= 'GUID='<Guid>\r
1118 //\r
1119 StringPtr = ConfigRequest;\r
1120 StrnCpy (StringPtr, L"GUID=", StrLen (L"GUID="));\r
1121 StringPtr += StrLen (L"GUID=");\r
1122\r
1123 Status = BufToHexStringPrivate (\r
1124 StringPtr,\r
1125 &RequestSize,\r
1126 (UINT8 *) (&Storage->Guid),\r
1127 sizeof (EFI_GUID),\r
1128 FALSE\r
1129 );\r
1130 ASSERT_EFI_ERROR (Status);\r
1131 StringPtr += RequestSize / 2 - 1;\r
1132 ASSERT (*StringPtr == 0);\r
1133 *StringPtr = L'&';\r
1134 StringPtr++;\r
1135\r
1136 //\r
1137 // Add <NameHdr>\r
1138 // <NameHdr> ::= 'NAME='<String>\r
1139 //\r
1140 StrnCpy (StringPtr, L"NAME=", StrLen (L"NAME="));\r
1141 StringPtr += StrLen (L"NAME=");\r
1142 StrnCpy (StringPtr, Storage->Name, StrLen (Storage->Name));\r
1143 StringPtr += StrLen (Storage->Name);\r
1144 *StringPtr = L'&';\r
1145 StringPtr++;\r
1146\r
1147 //\r
1148 // Add <PathHdr>\r
1149 // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>\r
1150 //\r
1151 StrnCpy (StringPtr, L"PATH=", StrLen (L"PATH="));\r
1152 StringPtr += StrLen (L"PATH=");\r
1153 StrCpy (StringPtr, PathHdr);\r
1154\r
1155 SafeFreePool (PathHdr);\r
1156 PathHdr = NULL;\r
1157\r
1158 //\r
1159 // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the\r
1160 // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>\r
1161 // is required to call ConfigAccess.ExtractConfig().\r
1162 //\r
1163 // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess\r
1164 // to handle such kind of "ConfigRequest". It is not supported till now.\r
1165 //\r
1166 // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()\r
1167 // will be updated as soon as the decision is made.\r
1168\r
1169 //\r
1170 // Route the request to corresponding ConfigAccess protocol to extract settings.\r
1171 //\r
1172 Status = gBS->HandleProtocol (\r
1173 Storage->DriverHandle,\r
1174 &gEfiHiiConfigAccessProtocolGuid,\r
1175 (VOID **) &ConfigAccess\r
1176 );\r
1177 ASSERT_EFI_ERROR (Status);\r
1178\r
1179 Status = ConfigAccess->ExtractConfig (\r
1180 ConfigAccess,\r
1181 ConfigRequest,\r
1182 &AccessProgress,\r
1183 &AccessResults\r
1184 );\r
1185 if (EFI_ERROR (Status)) {\r
1186 SafeFreePool (ConfigRequest);\r
1187 SafeFreePool (AccessResults);\r
1188 return EFI_INVALID_PARAMETER;\r
1189 }\r
1190\r
1191 //\r
1192 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>\r
1193 //\r
1194 ASSERT (*AccessProgress == 0);\r
1195 Status = AppendToMultiString (Results, AccessResults);\r
1196 ASSERT_EFI_ERROR (Status);\r
1197 SafeFreePool (AccessResults);\r
1198 AccessResults = NULL;\r
1199 SafeFreePool (ConfigRequest);\r
1200 ConfigRequest = NULL;\r
1201\r
1202 }\r
1203\r
1204 //\r
1205 // Free the exported storage resource\r
1206 //\r
1207 while (!IsListEmpty (&StorageListHdr)) {\r
1208 Storage = CR (\r
1209 StorageListHdr.ForwardLink,\r
1210 HII_FORMSET_STORAGE,\r
1211 Entry,\r
1212 HII_FORMSET_STORAGE_SIGNATURE\r
1213 );\r
1214 RemoveEntryList (&Storage->Entry);\r
1215 SafeFreePool (Storage->Name);\r
1216 SafeFreePool (Storage);\r
1217 }\r
1218\r
1219 return EFI_SUCCESS;\r
1220#else\r
1221 return EFI_UNSUPPORTED;\r
1222#endif\r
1223}\r
1224\r
1225\r
1226/**\r
1227 This function processes the results of processing forms and routes it to the\r
1228 appropriate handlers or storage.\r
1229\r
1230 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1231 instance.\r
1232 @param Configuration A null-terminated Unicode string in\r
1233 <MulltiConfigResp> format.\r
1234 @param Progress A pointer to a string filled in with the offset of\r
1235 the most recent & before the first failing name /\r
1236 value pair (or the beginning of the string if the\r
1237 failure is in the first name / value pair) or the\r
1238 terminating NULL if all was successful.\r
1239\r
1240 @retval EFI_SUCCESS The results have been distributed or are awaiting\r
1241 distribution.\r
1242 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
1243 results that must be stored awaiting possible\r
1244 future protocols.\r
1245 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter\r
1246 would result in this type of error.\r
1247 @retval EFI_NOT_FOUND Target for the specified routing data was not\r
1248 found.\r
1249\r
1250**/\r
1251EFI_STATUS\r
1252EFIAPI\r
1253HiiConfigRoutingRoutConfig (\r
1254 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1255 IN CONST EFI_STRING Configuration,\r
1256 OUT EFI_STRING *Progress\r
1257 )\r
1258{\r
1259#ifndef DISABLE_UNUSED_HII_PROTOCOLS\r
1260\r
1261 HII_DATABASE_PRIVATE_DATA *Private;\r
1262 EFI_STRING StringPtr;\r
1263 EFI_STRING ConfigResp;\r
1264 UINTN Length;\r
1265 EFI_STATUS Status;\r
1266 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1267 LIST_ENTRY *Link;\r
1268 HII_DATABASE_RECORD *Database;\r
1269 UINT8 *CurrentDevicePath;\r
1270 EFI_HANDLE DriverHandle;\r
1271 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
1272 EFI_STRING AccessProgress;\r
1273 UINTN RemainSize;\r
1274 EFI_STRING TmpPtr;\r
1275\r
1276 if (This == NULL || Progress == NULL) {\r
1277 return EFI_INVALID_PARAMETER;\r
1278 }\r
1279\r
1280 if (Configuration == NULL) {\r
1281 *Progress = NULL;\r
1282 return EFI_INVALID_PARAMETER;\r
1283 }\r
1284\r
1285 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1286 StringPtr = Configuration;\r
1287 *Progress = StringPtr;\r
1288\r
1289 //\r
1290 // The first element of <MultiConfigResp> should be\r
1291 // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
1292 //\r
1293 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1294 return EFI_INVALID_PARAMETER;\r
1295 }\r
1296\r
1297 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
1298 //\r
1299 // If parsing error, set Progress to the beginning of the <MultiConfigResp>\r
1300 // or most recent & before the error.\r
1301 //\r
1302 if (StringPtr == Configuration) {\r
1303 *Progress = StringPtr;\r
1304 } else {\r
1305 *Progress = StringPtr - 1;\r
1306 }\r
1307\r
1308 //\r
1309 // Process each <ConfigResp> of <MultiConfigResp>\r
1310 //\r
1311 Length = CalculateConfigStringLen (StringPtr);\r
1312 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
1313 if (ConfigResp == NULL) {\r
1314 return EFI_OUT_OF_RESOURCES;\r
1315 }\r
1316 //\r
1317 // Append '\0' to the end of ConfigRequest\r
1318 //\r
1319 *(ConfigResp + Length) = 0;\r
1320\r
1321 //\r
1322 // Get the UEFI device path\r
1323 //\r
1324 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);\r
1325 if (EFI_ERROR (Status)) {\r
1326 SafeFreePool (ConfigResp);\r
1327 return Status;\r
1328 }\r
1329\r
1330 //\r
1331 // Find driver which matches the routing data.\r
1332 //\r
1333 DriverHandle = NULL;\r
1334 for (Link = Private->DatabaseList.ForwardLink;\r
1335 Link != &Private->DatabaseList;\r
1336 Link = Link->ForwardLink\r
1337 ) {\r
1338 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
1339 CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
1340 if (CurrentDevicePath != NULL) {\r
1341 if (CompareMem (\r
1342 DevicePath,\r
1343 CurrentDevicePath,\r
1344 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
1345 ) == 0) {\r
1346 DriverHandle = Database->DriverHandle;\r
1347 break;\r
1348 }\r
1349 }\r
1350 }\r
1351\r
1352 SafeFreePool (DevicePath);\r
1353\r
1354 if (DriverHandle == NULL) {\r
1355 //\r
1356 // Routing data does not match any known driver.\r
1357 // Set Progress to the 'G' in "GUID" of the routing header.\r
1358 //\r
1359 *Progress = StringPtr;\r
1360 SafeFreePool (ConfigResp);\r
1361 return EFI_NOT_FOUND;\r
1362 }\r
1363\r
1364 //\r
1365 // Call corresponding ConfigAccess protocol to route settings\r
1366 //\r
1367 Status = gBS->HandleProtocol (\r
1368 DriverHandle,\r
1369 &gEfiHiiConfigAccessProtocolGuid,\r
1370 (VOID **) &ConfigAccess\r
1371 );\r
1372 ASSERT_EFI_ERROR (Status);\r
1373\r
1374 Status = ConfigAccess->RouteConfig (\r
1375 ConfigAccess,\r
1376 ConfigResp,\r
1377 &AccessProgress\r
1378 );\r
1379\r
1380 if (EFI_ERROR (Status)) {\r
1381 //\r
1382 // AccessProgress indicates the parsing progress on <ConfigResp>.\r
1383 // Map it to the progress on <MultiConfigResp> then return it.\r
1384 //\r
1385 RemainSize = StrSize (AccessProgress);\r
1386 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);\r
1387 *Progress = TmpPtr;\r
1388\r
1389 SafeFreePool (ConfigResp);\r
1390 return Status;\r
1391 }\r
1392\r
1393 SafeFreePool (ConfigResp);\r
1394 ConfigResp = NULL;\r
1395\r
1396 //\r
1397 // Go to next <ConfigResp> (skip '&').\r
1398 //\r
1399 StringPtr += Length;\r
1400 if (*StringPtr == 0) {\r
1401 *Progress = StringPtr;\r
1402 break;\r
1403 }\r
1404\r
1405 StringPtr++;\r
1406\r
1407 }\r
1408\r
1409 return EFI_SUCCESS;\r
1410#else\r
1411 return EFI_UNSUPPORTED;\r
1412#endif\r
1413}\r
1414\r
1415\r
1416/**\r
1417 This helper function is to be called by drivers to map configuration data\r
1418 stored in byte array ("block") formats such as UEFI Variables into current\r
1419 configuration strings.\r
1420\r
1421 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1422 instance.\r
1423 @param ConfigRequest A null-terminated Unicode string in\r
1424 <ConfigRequest> format.\r
1425 @param Block Array of bytes defining the block's configuration.\r
1426 @param BlockSize Length in bytes of Block.\r
1427 @param Config Filled-in configuration string. String allocated\r
1428 by the function. Returned only if call is\r
1429 successful.\r
1430 @param Progress A pointer to a string filled in with the offset of\r
1431 the most recent & before the first failing\r
1432 name/value pair (or the beginning of the string if\r
1433 the failure is in the first name / value pair) or\r
1434 the terminating NULL if all was successful.\r
1435\r
1436 @retval EFI_SUCCESS The request succeeded. Progress points to the null\r
1437 terminator at the end of the ConfigRequest\r
1438 string.\r
1439 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress\r
1440 points to the first character of ConfigRequest.\r
1441 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or\r
1442 Block parameter would result in this type of\r
1443 error. Progress points to the first character of\r
1444 ConfigRequest.\r
1445 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.\r
1446 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.\r
1447 Block is left updated and Progress points at\r
1448 the "&" preceding the first non-<BlockName>.\r
1449\r
1450**/\r
1451EFI_STATUS\r
1452EFIAPI\r
1453HiiBlockToConfig (\r
1454 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1455 IN CONST EFI_STRING ConfigRequest,\r
1456 IN CONST UINT8 *Block,\r
1457 IN CONST UINTN BlockSize,\r
1458 OUT EFI_STRING *Config,\r
1459 OUT EFI_STRING *Progress\r
1460 )\r
1461{\r
1462 HII_DATABASE_PRIVATE_DATA *Private;\r
1463 EFI_STRING StringPtr;\r
1464 UINTN Length;\r
1465 EFI_STATUS Status;\r
1466 EFI_STRING TmpPtr;\r
1467 UINT8 *TmpBuffer;\r
1468 UINTN Offset;\r
1469 UINTN Width;\r
1470 UINT8 *Value;\r
1471 EFI_STRING ValueStr;\r
1472 EFI_STRING ConfigElement;\r
1473\r
1474 if (This == NULL || Progress == NULL || Config == NULL) {\r
1475 return EFI_INVALID_PARAMETER;\r
1476 }\r
1477\r
1478 if (Block == NULL || ConfigRequest == NULL) {\r
1479 *Progress = ConfigRequest;\r
1480 return EFI_INVALID_PARAMETER;\r
1481 }\r
1482\r
1483\r
1484 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1485 ASSERT (Private != NULL);\r
1486\r
1487 StringPtr = ConfigRequest;\r
1488 ValueStr = NULL;\r
1489 Value = NULL;\r
1490 ConfigElement = NULL;\r
1491\r
1492 //\r
1493 // Allocate a fix length of memory to store Results. Reallocate memory for\r
1494 // Results if this fix length is insufficient.\r
1495 //\r
1496 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
1497 if (*Config == NULL) {\r
1498 return EFI_OUT_OF_RESOURCES;\r
1499 }\r
1500\r
1501 //\r
1502 // Jump <ConfigHdr>\r
1503 //\r
1504 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1505 *Progress = StringPtr;\r
1506 Status = EFI_INVALID_PARAMETER;\r
1507 goto Exit;\r
1508 }\r
1509 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {\r
1510 StringPtr++;\r
1511 }\r
1512 if (*StringPtr == 0) {\r
1513 *Progress = StringPtr;\r
1514 Status = EFI_INVALID_PARAMETER;\r
1515 goto Exit;\r
1516 }\r
1517 while (*StringPtr++ != L'&');\r
1518\r
1519 //\r
1520 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>\r
1521 //\r
1522 Length = StringPtr - ConfigRequest;\r
1523 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));\r
1524\r
1525 //\r
1526 // Parse each <RequestElement> if exists\r
1527 // Only <BlockName> format is supported by this help function.\r
1528 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>\r
1529 //\r
1530 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {\r
1531 //\r
1532 // Back up the header of one <BlockName>\r
1533 //\r
1534 TmpPtr = StringPtr;\r
1535\r
1536 StringPtr += StrLen (L"OFFSET=");\r
1537 //\r
1538 // Get Offset\r
1539 //\r
1540 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1541 if (Status == EFI_OUT_OF_RESOURCES) {\r
1542 *Progress = ConfigRequest;\r
1543 goto Exit;\r
1544 }\r
1545 Offset = 0;\r
1546 CopyMem (\r
1547 &Offset,\r
1548 TmpBuffer,\r
1549 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1550 );\r
1551 SafeFreePool (TmpBuffer);\r
1552\r
1553 StringPtr += Length;\r
1554 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
1555 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;\r
1556 Status = EFI_INVALID_PARAMETER;\r
1557 goto Exit;\r
1558 }\r
1559 StringPtr += StrLen (L"&WIDTH=");\r
1560\r
1561 //\r
1562 // Get Width\r
1563 //\r
1564 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1565 if (Status == EFI_OUT_OF_RESOURCES) {\r
1566 *Progress = ConfigRequest;\r
1567 goto Exit;\r
1568 }\r
1569 Width = 0;\r
1570 CopyMem (\r
1571 &Width,\r
1572 TmpBuffer,\r
1573 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1574 );\r
1575 SafeFreePool (TmpBuffer);\r
1576\r
1577 StringPtr += Length;\r
1578 if (*StringPtr != 0 && *StringPtr != L'&') {\r
1579 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");\r
1580 Status = EFI_INVALID_PARAMETER;\r
1581 goto Exit;\r
1582 }\r
1583\r
1584 //\r
1585 // Calculate Value and convert it to hex string.\r
1586 //\r
1587 if (Offset + Width > BlockSize) {\r
1588 *Progress = StringPtr;\r
1589 Status = EFI_DEVICE_ERROR;\r
1590 goto Exit;\r
1591 }\r
1592\r
1593 Value = (UINT8 *) AllocateZeroPool (Width);\r
1594 if (Value == NULL) {\r
1595 *Progress = ConfigRequest;\r
1596 Status = EFI_OUT_OF_RESOURCES;\r
1597 goto Exit;\r
1598 }\r
1599\r
1600 CopyMem (Value, (UINT8 *) Block + Offset, Width);\r
1601\r
1602 Length = Width * 2 + 1;\r
1603 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
1604 if (ValueStr == NULL) {\r
1605 *Progress = ConfigRequest;\r
1606 Status = EFI_OUT_OF_RESOURCES;\r
1607 goto Exit;\r
1608 }\r
1609\r
1610 Status = R8_BufToHexString (ValueStr, &Length, Value, Width);\r
1611 ASSERT_EFI_ERROR (Status);\r
1612 SafeFreePool (Value);\r
1613 Value = NULL;\r
1614\r
1615 //\r
1616 // Build a ConfigElement\r
1617 //\r
1618 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");\r
1619 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
1620 if (ConfigElement == NULL) {\r
1621 Status = EFI_OUT_OF_RESOURCES;\r
1622 goto Exit;\r
1623 }\r
1624 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));\r
1625 if (*StringPtr == 0) {\r
1626 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';\r
1627 }\r
1628 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;\r
1629 StrCat (ConfigElement, L"VALUE=");\r
1630 StrCat (ConfigElement, ValueStr);\r
1631\r
1632 AppendToMultiString (Config, ConfigElement);\r
1633\r
1634 SafeFreePool (ConfigElement);\r
1635 SafeFreePool (ValueStr);\r
1636 ConfigElement = NULL;\r
1637 ValueStr = NULL;\r
1638\r
1639 //\r
1640 // If '\0', parsing is finished. Otherwise skip '&' to continue\r
1641 //\r
1642 if (*StringPtr == 0) {\r
1643 break;\r
1644 }\r
1645 AppendToMultiString (Config, L"&");\r
1646 StringPtr++;\r
1647\r
1648 }\r
1649\r
1650 if (*StringPtr != 0) {\r
1651 *Progress = StringPtr - 1;\r
1652 Status = EFI_INVALID_PARAMETER;\r
1653 goto Exit;\r
1654 }\r
1655\r
1656 *Progress = StringPtr;\r
1657 return EFI_SUCCESS;\r
1658\r
1659Exit:\r
1660\r
1661 SafeFreePool (*Config);\r
1662 SafeFreePool (ValueStr);\r
1663 SafeFreePool (Value);\r
1664 SafeFreePool (ConfigElement);\r
1665\r
1666 return Status;\r
1667\r
1668}\r
1669\r
1670\r
1671/**\r
1672 This helper function is to be called by drivers to map configuration strings\r
1673 to configurations stored in byte array ("block") formats such as UEFI Variables.\r
1674\r
1675 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1676 instance.\r
1677 @param ConfigResp A null-terminated Unicode string in <ConfigResp>\r
1678 format.\r
1679 @param Block A possibly null array of bytes representing the\r
1680 current block. Only bytes referenced in the\r
1681 ConfigResp string in the block are modified. If\r
1682 this parameter is null or if the *BlockSize\r
1683 parameter is (on input) shorter than required by\r
1684 the Configuration string, only the BlockSize\r
1685 parameter is updated and an appropriate status\r
1686 (see below) is returned.\r
1687 @param BlockSize The length of the Block in units of UINT8. On\r
1688 input, this is the size of the Block. On output,\r
1689 if successful, contains the index of the last\r
1690 modified byte in the Block.\r
1691 @param Progress On return, points to an element of the ConfigResp\r
1692 string filled in with the offset of the most\r
1693 recent '&' before the first failing name / value\r
1694 pair (or the beginning of the string if the\r
1695 failure is in the first name / value pair) or the\r
1696 terminating NULL if all was successful.\r
1697\r
1698 @retval EFI_SUCCESS The request succeeded. Progress points to the null\r
1699 terminator at the end of the ConfigResp string.\r
1700 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress\r
1701 points to the first character of ConfigResp.\r
1702 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or\r
1703 Block parameter would result in this type of\r
1704 error. Progress points to the first character of\r
1705 ConfigResp.\r
1706 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /\r
1707 value pair. Block is left updated and\r
1708 Progress points at the '&' preceding the first\r
1709 non-<BlockName>.\r
1710\r
1711**/\r
1712EFI_STATUS\r
1713EFIAPI\r
1714HiiConfigToBlock (\r
1715 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1716 IN CONST EFI_STRING ConfigResp,\r
1717 IN OUT UINT8 *Block,\r
1718 IN OUT UINTN *BlockSize,\r
1719 OUT EFI_STRING *Progress\r
1720 )\r
1721{\r
1722 HII_DATABASE_PRIVATE_DATA *Private;\r
1723 EFI_STRING StringPtr;\r
1724 UINTN Length;\r
1725 EFI_STATUS Status;\r
1726 UINT8 *TmpBuffer;\r
1727 UINTN Offset;\r
1728 UINTN Width;\r
1729 UINT8 *Value;\r
1730 UINTN BufferSize;\r
1731\r
1732 if (This == NULL || BlockSize == NULL || Progress == NULL) {\r
1733 return EFI_INVALID_PARAMETER;\r
1734 }\r
1735\r
1736 if (ConfigResp == NULL || Block == NULL) {\r
1737 *Progress = ConfigResp;\r
1738 return EFI_INVALID_PARAMETER;\r
1739 }\r
1740\r
1741 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1742 ASSERT (Private != NULL);\r
1743\r
1744 StringPtr = ConfigResp;\r
1745 BufferSize = *BlockSize;\r
1746 Value = NULL;\r
1747\r
1748 //\r
1749 // Jump <ConfigHdr>\r
1750 //\r
1751 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1752 *Progress = StringPtr;\r
1753 Status = EFI_INVALID_PARAMETER;\r
1754 goto Exit;\r
1755 }\r
1756 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {\r
1757 StringPtr++;\r
1758 }\r
1759 if (*StringPtr == 0) {\r
1760 *Progress = StringPtr;\r
1761 Status = EFI_INVALID_PARAMETER;\r
1762 goto Exit;\r
1763 }\r
1764 while (*StringPtr++ != L'&');\r
1765\r
1766 //\r
1767 // Parse each <ConfigElement> if exists\r
1768 // Only <BlockConfig> format is supported by this help function.\r
1769 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>\r
1770 //\r
1771 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {\r
1772 StringPtr += StrLen (L"OFFSET=");\r
1773 //\r
1774 // Get Offset\r
1775 //\r
1776 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1777 if (Status == EFI_OUT_OF_RESOURCES) {\r
1778 *Progress = ConfigResp;\r
1779 goto Exit;\r
1780 }\r
1781 Offset = 0;\r
1782 CopyMem (\r
1783 &Offset,\r
1784 TmpBuffer,\r
1785 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1786 );\r
1787 SafeFreePool (TmpBuffer);\r
1788\r
1789 StringPtr += Length;\r
1790 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
1791 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;\r
1792 Status = EFI_INVALID_PARAMETER;\r
1793 goto Exit;\r
1794 }\r
1795 StringPtr += StrLen (L"&WIDTH=");\r
1796\r
1797 //\r
1798 // Get Width\r
1799 //\r
1800 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1801 if (Status == EFI_OUT_OF_RESOURCES) {\r
1802 *Progress = ConfigResp;\r
1803 goto Exit;\r
1804 }\r
1805 Width = 0;\r
1806 CopyMem (\r
1807 &Width,\r
1808 TmpBuffer,\r
1809 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1810 );\r
1811 SafeFreePool (TmpBuffer);\r
1812\r
1813 StringPtr += Length;\r
1814 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {\r
1815 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");\r
1816 Status = EFI_INVALID_PARAMETER;\r
1817 goto Exit;\r
1818 }\r
1819 StringPtr += StrLen (L"&VALUE=");\r
1820\r
1821 //\r
1822 // Get Value\r
1823 //\r
1824 Status = GetValueOfNumber (StringPtr, &Value, &Length);\r
1825 if (Status == EFI_OUT_OF_RESOURCES) {\r
1826 *Progress = ConfigResp;\r
1827 goto Exit;\r
1828 }\r
1829\r
1830 StringPtr += Length;\r
1831 if (*StringPtr != 0 && *StringPtr != L'&') {\r
1832 *Progress = StringPtr - Length - 7;\r
1833 Status = EFI_INVALID_PARAMETER;\r
1834 goto Exit;\r
1835 }\r
1836\r
1837 //\r
1838 // Update the Block with configuration info\r
1839 //\r
1840\r
1841 if (Offset + Width > BufferSize) {\r
1842 return EFI_DEVICE_ERROR;\r
1843 }\r
1844\r
1845 CopyMem (Block + Offset, Value, Width);\r
1846 *BlockSize = Offset + Width - 1;\r
1847\r
1848 SafeFreePool (Value);\r
1849 Value = NULL;\r
1850\r
1851 //\r
1852 // If '\0', parsing is finished. Otherwise skip '&' to continue\r
1853 //\r
1854 if (*StringPtr == 0) {\r
1855 break;\r
1856 }\r
1857\r
1858 StringPtr++;\r
1859 }\r
1860\r
1861 if (*StringPtr != 0) {\r
1862 *Progress = StringPtr - 1;\r
1863 Status = EFI_INVALID_PARAMETER;\r
1864 goto Exit;\r
1865 }\r
1866\r
1867 *Progress = StringPtr;\r
1868 return EFI_SUCCESS;\r
1869\r
1870Exit:\r
1871\r
1872 SafeFreePool (Value);\r
1873 return Status;\r
1874}\r
1875\r
1876\r
1877/**\r
1878 This helper function is to be called by drivers to extract portions of\r
1879 a larger configuration string.\r
1880\r
1881 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1882 instance.\r
1883 @param Configuration A null-terminated Unicode string in\r
1884 <MultiConfigAltResp> format.\r
1885 @param Guid A pointer to the GUID value to search for in the\r
1886 routing portion of the ConfigResp string when\r
1887 retrieving the requested data. If Guid is NULL,\r
1888 then all GUID values will be searched for.\r
1889 @param Name A pointer to the NAME value to search for in the\r
1890 routing portion of the ConfigResp string when\r
1891 retrieving the requested data. If Name is NULL,\r
1892 then all Name values will be searched for.\r
1893 @param DevicePath A pointer to the PATH value to search for in the\r
1894 routing portion of the ConfigResp string when\r
1895 retrieving the requested data. If DevicePath is\r
1896 NULL, then all DevicePath values will be searched\r
1897 for.\r
1898 @param AltCfgId A pointer to the ALTCFG value to search for in the\r
1899 routing portion of the ConfigResp string when\r
1900 retrieving the requested data. If this parameter\r
1901 is NULL, then the current setting will be\r
1902 retrieved.\r
1903 @param AltCfgResp A pointer to a buffer which will be allocated by\r
1904 the function which contains the retrieved string\r
1905 as requested. This buffer is only allocated if\r
1906 the call was successful.\r
1907\r
1908 @retval EFI_SUCCESS The request succeeded. The requested data was\r
1909 extracted and placed in the newly allocated\r
1910 AltCfgResp buffer.\r
1911 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.\r
1912 @retval EFI_INVALID_PARAMETER Any parameter is invalid.\r
1913 @retval EFI_NOT_FOUND Target for the specified routing data was not\r
1914 found.\r
1915\r
1916**/\r
1917EFI_STATUS\r
1918EFIAPI\r
1919HiiGetAltCfg (\r
1920 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1921 IN CONST EFI_STRING Configuration,\r
1922 IN CONST EFI_GUID *Guid,\r
1923 IN CONST EFI_STRING Name,\r
1924 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1925 IN CONST UINT16 *AltCfgId,\r
1926 OUT EFI_STRING *AltCfgResp\r
1927 )\r
1928{\r
1929#ifndef DISABLE_UNUSED_HII_PROTOCOLS\r
1930\r
1931 EFI_STATUS Status;\r
1932 EFI_STRING StringPtr;\r
1933 EFI_STRING HdrStart = NULL;\r
1934 EFI_STRING HdrEnd = NULL;\r
1935 EFI_STRING TmpPtr;\r
1936 UINTN Length;\r
1937 EFI_STRING GuidStr = NULL;\r
1938 EFI_STRING NameStr = NULL;\r
1939 EFI_STRING PathStr = NULL;\r
1940 EFI_STRING AltIdStr = NULL;\r
1941 EFI_STRING Result = NULL;\r
1942 BOOLEAN GuidFlag = FALSE;\r
1943 BOOLEAN NameFlag = FALSE;\r
1944 BOOLEAN PathFlag = FALSE;\r
1945\r
1946 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {\r
1947 return EFI_INVALID_PARAMETER;\r
1948 }\r
1949\r
1950 StringPtr = Configuration;\r
1951 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1952 return EFI_INVALID_PARAMETER;\r
1953 }\r
1954\r
1955 //\r
1956 // Generate the sub string for later matching.\r
1957 //\r
1958 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (UINT8 *) Guid, FALSE, &GuidStr);\r
1959 GenerateSubStr (\r
1960 L"PATH=",\r
1961 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),\r
1962 (UINT8 *) DevicePath,\r
1963 TRUE,\r
1964 &PathStr\r
1965 );\r
1966 if (AltCfgId != NULL) {\r
1967 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (UINT8 *) AltCfgId, FALSE, &AltIdStr);\r
1968 }\r
1969 if (Name != NULL) {\r
1970 Length = StrLen (Name);\r
1971 Length += StrLen (L"NAME=&") + 1;\r
1972 NameStr = AllocateZeroPool (Length * sizeof (CHAR16));\r
1973 if (NameStr == NULL) {\r
1974 Status = EFI_OUT_OF_RESOURCES;\r
1975 goto Exit;\r
1976 }\r
1977 StrCpy (NameStr, L"NAME=");\r
1978 StrCat (NameStr, Name);\r
1979 StrCat (NameStr, L"&");\r
1980 } else {\r
1981 GenerateSubStr (L"NAME=", 0, NULL, FALSE, &NameStr);\r
1982 }\r
1983\r
1984 while (*StringPtr != 0) {\r
1985 //\r
1986 // Try to match the GUID\r
1987 //\r
1988 if (!GuidFlag) {\r
1989 TmpPtr = StrStr (StringPtr, GuidStr);\r
1990 if (TmpPtr == NULL) {\r
1991 Status = EFI_NOT_FOUND;\r
1992 goto Exit;\r
1993 }\r
1994 HdrStart = TmpPtr;\r
1995\r
1996 //\r
1997 // Jump to <NameHdr>\r
1998 //\r
1999 if (Guid != NULL) {\r
2000 StringPtr = TmpPtr + StrLen (GuidStr);\r
2001 } else {\r
2002 StringPtr = StrStr (TmpPtr, L"NAME=");\r
2003 if (StringPtr == NULL) {\r
2004 Status = EFI_NOT_FOUND;\r
2005 goto Exit;\r
2006 }\r
2007 }\r
2008 GuidFlag = TRUE;\r
2009 }\r
2010\r
2011 //\r
2012 // Try to match the NAME\r
2013 //\r
2014 if (GuidFlag && !NameFlag) {\r
2015 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {\r
2016 GuidFlag = FALSE;\r
2017 } else {\r
2018 //\r
2019 // Jump to <PathHdr>\r
2020 //\r
2021 if (Name != NULL) {\r
2022 StringPtr += StrLen (NameStr);\r
2023 } else {\r
2024 StringPtr = StrStr (StringPtr, L"PATH=");\r
2025 if (StringPtr == NULL) {\r
2026 Status = EFI_NOT_FOUND;\r
2027 goto Exit;\r
2028 }\r
2029 }\r
2030 NameFlag = TRUE;\r
2031 }\r
2032 }\r
2033\r
2034 //\r
2035 // Try to match the DevicePath\r
2036 //\r
2037 if (GuidFlag && NameFlag && !PathFlag) {\r
2038 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {\r
2039 GuidFlag = FALSE;\r
2040 NameFlag = FALSE;\r
2041 } else {\r
2042 //\r
2043 // Jump to '&' before <DescHdr> or <ConfigBody>\r
2044 //\r
2045 if (DevicePath != NULL) {\r
2046 StringPtr += StrLen (PathStr);\r
2047 } else {\r
2048 StringPtr = StrStr (StringPtr, L"&");\r
2049 if (StringPtr == NULL) {\r
2050 Status = EFI_NOT_FOUND;\r
2051 goto Exit;\r
2052 }\r
2053 }\r
2054 PathFlag = TRUE;\r
2055 HdrEnd = ++StringPtr;\r
2056 }\r
2057 }\r
2058\r
2059 //\r
2060 // Try to match the AltCfgId\r
2061 //\r
2062 if (GuidFlag && NameFlag && PathFlag) {\r
2063 if (AltCfgId == NULL) {\r
2064 //\r
2065 // Return Current Setting when AltCfgId is NULL.\r
2066 //\r
2067 Status = OutputConfigBody (StringPtr, &Result);\r
2068 goto Exit;\r
2069 }\r
2070 //\r
2071 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.\r
2072 //\r
2073 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {\r
2074 GuidFlag = FALSE;\r
2075 NameFlag = FALSE;\r
2076 PathFlag = FALSE;\r
2077 } else {\r
2078 Status = OutputConfigBody (StringPtr, &Result);\r
2079 goto Exit;\r
2080 }\r
2081 }\r
2082 }\r
2083\r
2084 Status = EFI_NOT_FOUND;\r
2085\r
2086Exit:\r
2087\r
2088 if (!EFI_ERROR (Status)) {\r
2089 //\r
2090 // Copy the <ConfigHdr> and <ConfigBody>\r
2091 //\r
2092 Length = HdrEnd - HdrStart + StrLen (Result);\r
2093 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));\r
2094 if (*AltCfgResp == NULL) {\r
2095 Status = EFI_OUT_OF_RESOURCES;\r
2096 } else {\r
2097 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);\r
2098 StrCat (*AltCfgResp, Result);\r
2099 Status = EFI_SUCCESS;\r
2100 }\r
2101 }\r
2102\r
2103 SafeFreePool (GuidStr);\r
2104 SafeFreePool (NameStr);\r
2105 SafeFreePool (PathStr);\r
2106 SafeFreePool (AltIdStr);\r
2107 SafeFreePool (Result);\r
2108\r
2109 return Status;\r
2110\r
2111#else\r
2112 return EFI_UNSUPPORTED;\r
2113#endif\r
2114\r
2115}\r
2116\r