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