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