]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Make HiiDatabase module not depend on HiiLib; otherwise it will inherit HII_DATABASE_...
[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
93e3992d 143/**\r
144 Generate a sub string then output it.\r
145\r
e90b081a 146 This is a internal function.\r
147\r
93e3992d 148 @param String A constant string which is the prefix of the to be\r
149 generated string, e.g. GUID=\r
150 @param BufferLen The length of the Buffer in bytes.\r
813acf3a 151 @param Buffer Points to a buffer which will be converted to be the \r
152 content of the generated string.\r
153 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in \r
154 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;\r
155 if 3, the buffer contains other data.\r
93e3992d 156 @param SubStr Points to the output string. It's caller's\r
157 responsibility to free this buffer.\r
158\r
159\r
160**/\r
93e3992d 161VOID\r
162GenerateSubStr (\r
163 IN CONST EFI_STRING String,\r
164 IN UINTN BufferLen,\r
813acf3a 165 IN VOID *Buffer,\r
166 IN UINT8 Flag,\r
93e3992d 167 OUT EFI_STRING *SubStr\r
168 )\r
169{\r
170 UINTN Length;\r
171 EFI_STRING Str;\r
172 EFI_STATUS Status;\r
813acf3a 173 EFI_STRING StringHeader;\r
93e3992d 174\r
175 ASSERT (String != NULL && SubStr != NULL);\r
176\r
177 if (Buffer == NULL) {\r
178 *SubStr = AllocateCopyPool (StrSize (String), String);\r
179 ASSERT (*SubStr != NULL);\r
180 return ;\r
181 }\r
182\r
813acf3a 183 Length = StrLen (String) + BufferLen * 2 + 1 + 1;\r
93e3992d 184 Str = AllocateZeroPool (Length * sizeof (CHAR16));\r
185 ASSERT (Str != NULL);\r
186\r
187 StrCpy (Str, String);\r
188 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);\r
189\r
813acf3a 190 Status = EFI_SUCCESS;\r
191 StringHeader = Str + StrLen (String);\r
192\r
193 switch (Flag) {\r
194 case 1:\r
5e580cf7 195 Status = BufInReverseOrderToHexString (StringHeader, (UINT8 *) Buffer, BufferLen);\r
813acf3a 196 break;\r
197 case 2:\r
198 Status = UnicodeToConfigString (StringHeader, &Length, (CHAR16 *) Buffer);\r
199 break;\r
200 case 3:\r
201 Status = BufToHexString (StringHeader, &Length, (UINT8 *) Buffer, BufferLen);\r
202 //\r
203 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.\r
204 //\r
205 ToLower (StringHeader);\r
206 break;\r
207 default:\r
208 break;\r
209 }\r
93e3992d 210\r
211 ASSERT_EFI_ERROR (Status);\r
212 StrCat (Str, L"&");\r
213\r
214 *SubStr = Str;\r
215}\r
216\r
217\r
218/**\r
219 Retrieve the <ConfigBody> from String then output it.\r
220\r
e90b081a 221 This is a internal function.\r
222\r
93e3992d 223 @param String A sub string of a configuration string in\r
224 <MultiConfigAltResp> format.\r
225 @param ConfigBody Points to the output string. It's caller's\r
226 responsibility to free this buffer.\r
227\r
228 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.\r
229 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.\r
230 @retval EFI_SUCCESS All existing storage is exported.\r
231\r
232**/\r
93e3992d 233EFI_STATUS\r
234OutputConfigBody (\r
235 IN EFI_STRING String,\r
236 OUT EFI_STRING *ConfigBody\r
237 )\r
238{\r
239 EFI_STRING TmpPtr;\r
240 EFI_STRING Result;\r
241 UINTN Length;\r
242\r
243 if (String == NULL || ConfigBody == NULL) {\r
244 return EFI_INVALID_PARAMETER;\r
245 }\r
246\r
247 TmpPtr = StrStr (String, L"GUID=");\r
248 if (TmpPtr == NULL) {\r
249 //\r
250 // It is the last <ConfigResp> of the incoming configuration string.\r
251 //\r
252 Result = AllocateCopyPool (StrSize (String), String);\r
253 if (Result == NULL) {\r
254 return EFI_OUT_OF_RESOURCES;\r
255 } else {\r
256 *ConfigBody = Result;\r
257 return EFI_SUCCESS;\r
258 }\r
259 }\r
260\r
261 Length = TmpPtr - String;\r
262 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);\r
263 if (Result == NULL) {\r
264 return EFI_OUT_OF_RESOURCES;\r
265 }\r
266\r
267 *(Result + Length - 1) = 0;\r
268 *ConfigBody = Result;\r
269 return EFI_SUCCESS;\r
270\r
271}\r
272\r
93e3992d 273/**\r
274 Append a string to a multi-string format.\r
275\r
e90b081a 276 This is a internal function.\r
277\r
93e3992d 278 @param MultiString String in <MultiConfigRequest>,\r
279 <MultiConfigAltResp>, or <MultiConfigResp>. On\r
280 input, the buffer length of this string is\r
281 MAX_STRING_LENGTH. On output, the buffer length\r
282 might be updated.\r
283 @param AppendString NULL-terminated Unicode string.\r
284\r
285 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.\r
286 @retval EFI_SUCCESS AppendString is append to the end of MultiString\r
287\r
288**/\r
93e3992d 289EFI_STATUS\r
290AppendToMultiString (\r
291 IN OUT EFI_STRING *MultiString,\r
292 IN EFI_STRING AppendString\r
293 )\r
294{\r
295 UINTN AppendStringSize;\r
296 UINTN MultiStringSize;\r
297\r
298 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {\r
299 return EFI_INVALID_PARAMETER;\r
300 }\r
301\r
302 AppendStringSize = StrSize (AppendString);\r
303 MultiStringSize = StrSize (*MultiString);\r
304\r
305 //\r
306 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.\r
307 //\r
308 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||\r
309 MultiStringSize > MAX_STRING_LENGTH) {\r
310 *MultiString = (EFI_STRING) ReallocatePool (\r
93e3992d 311 MultiStringSize,\r
c4648495 312 MultiStringSize + AppendStringSize,\r
313 (VOID *) (*MultiString)\r
93e3992d 314 );\r
315 }\r
316\r
317 //\r
318 // Append the incoming string\r
319 //\r
320 StrCat (*MultiString, AppendString);\r
321\r
322 return EFI_SUCCESS;\r
323}\r
324\r
325\r
326/**\r
327 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET\r
328 or WIDTH or VALUE.\r
329 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>\r
330\r
e90b081a 331 This is a internal function.\r
332\r
93e3992d 333 @param StringPtr String in <BlockConfig> format and points to the\r
334 first character of <Number>.\r
335 @param Number The output value. Caller takes the responsibility\r
336 to free memory.\r
337 @param Len Length of the <Number>, in characters.\r
338\r
339 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary\r
340 structures.\r
341 @retval EFI_SUCCESS Value of <Number> is outputted in Number\r
342 successfully.\r
343\r
344**/\r
93e3992d 345EFI_STATUS\r
346GetValueOfNumber (\r
347 IN EFI_STRING StringPtr,\r
348 OUT UINT8 **Number,\r
349 OUT UINTN *Len\r
350 )\r
351{\r
352 EFI_STRING TmpPtr;\r
353 UINTN Length;\r
354 EFI_STRING Str;\r
355 UINT8 *Buf;\r
356 EFI_STATUS Status;\r
357\r
358 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);\r
359 ASSERT (*StringPtr != 0);\r
360\r
361 Buf = NULL;\r
362\r
363 TmpPtr = StringPtr;\r
364 while (*StringPtr != 0 && *StringPtr != L'&') {\r
365 StringPtr++;\r
366 }\r
367 *Len = StringPtr - TmpPtr;\r
368 Length = *Len + 1;\r
369\r
370 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));\r
371 if (Str == NULL) {\r
372 Status = EFI_OUT_OF_RESOURCES;\r
373 goto Exit;\r
374 }\r
375 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));\r
376 *(Str + *Len) = 0;\r
377\r
378 Length = (Length + 1) / 2;\r
379 Buf = (UINT8 *) AllocateZeroPool (Length);\r
380 if (Buf == NULL) {\r
381 Status = EFI_OUT_OF_RESOURCES;\r
382 goto Exit;\r
383 }\r
384\r
36fe40c2 385 Status = HexStringToBuf (Buf, &Length, Str, NULL);\r
93e3992d 386 if (EFI_ERROR (Status)) {\r
387 goto Exit;\r
388 }\r
389\r
390 *Number = Buf;\r
391 Status = EFI_SUCCESS;\r
392\r
393Exit:\r
676df92c 394 if (Str != NULL) {\r
395 FreePool (Str);\r
396 }\r
93e3992d 397 return Status;\r
398}\r
399\r
400\r
401/**\r
402 This function allows a caller to extract the current configuration\r
403 for one or more named elements from one or more drivers.\r
404\r
405 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
406 instance.\r
407 @param Request A null-terminated Unicode string in\r
408 <MultiConfigRequest> format.\r
409 @param Progress On return, points to a character in the Request\r
410 string. Points to the string's null terminator if\r
411 request was successful. Points to the most recent\r
412 & before the first failing name / value pair (or\r
413 the beginning of the string if the failure is in\r
414 the first name / value pair) if the request was\r
415 not successful.\r
416 @param Results Null-terminated Unicode string in\r
417 <MultiConfigAltResp> format which has all values\r
418 filled in for the names in the Request string.\r
419 String to be allocated by the called function.\r
420\r
421 @retval EFI_SUCCESS The Results string is filled with the values\r
422 corresponding to all requested names.\r
423 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
424 results that must be stored awaiting possible\r
425 future protocols.\r
426 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.\r
427 Progress set to the "G" in "GUID" of the routing\r
428 header that doesn't match. Note: There is no\r
429 requirement that all routing data be validated\r
430 before any configuration extraction.\r
431 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request\r
432 parameter would result in this type of error. The\r
433 Progress parameter is set to NULL.\r
434 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &\r
435 before the error or the beginning of the string.\r
436 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the\r
437 name in question.\r
438\r
439**/\r
440EFI_STATUS\r
441EFIAPI\r
442HiiConfigRoutingExtractConfig (\r
443 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
444 IN CONST EFI_STRING Request,\r
445 OUT EFI_STRING *Progress,\r
446 OUT EFI_STRING *Results\r
447 )\r
448{\r
93e3992d 449 HII_DATABASE_PRIVATE_DATA *Private;\r
450 EFI_STRING StringPtr;\r
451 EFI_STRING ConfigRequest;\r
452 UINTN Length;\r
453 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
454 EFI_STATUS Status;\r
455 LIST_ENTRY *Link;\r
456 HII_DATABASE_RECORD *Database;\r
08e6463a 457 UINT8 *DevicePathPkg;\r
93e3992d 458 UINT8 *CurrentDevicePath;\r
459 EFI_HANDLE DriverHandle;\r
460 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
461 EFI_STRING AccessProgress;\r
462 EFI_STRING AccessResults;\r
8d00a0f1 463 BOOLEAN FirstElement;\r
93e3992d 464\r
e94358a3 465 //\r
466 // For size reduction, please define PcdSupportFullConfigRoutingProtocol \r
467 // as FALSE. But this renders the system to not 100% compliant with\r
468 // UEFI 2.1. Use this with caution.\r
469 //\r
470 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {\r
471 return EFI_UNSUPPORTED;\r
472 }\r
473\r
93e3992d 474 if (This == NULL || Progress == NULL || Results == NULL) {\r
475 return EFI_INVALID_PARAMETER;\r
476 }\r
477\r
478 if (Request == NULL) {\r
479 *Progress = NULL;\r
480 return EFI_INVALID_PARAMETER;\r
481 }\r
482\r
483 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
484 StringPtr = Request;\r
485 *Progress = StringPtr;\r
486\r
487 //\r
488 // The first element of <MultiConfigRequest> should be\r
489 // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
490 //\r
491 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
492 return EFI_INVALID_PARAMETER;\r
493 }\r
494\r
8d00a0f1 495 FirstElement = TRUE;\r
496\r
93e3992d 497 //\r
498 // Allocate a fix length of memory to store Results. Reallocate memory for\r
499 // Results if this fix length is insufficient.\r
500 //\r
501 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
502 if (*Results == NULL) {\r
503 return EFI_OUT_OF_RESOURCES;\r
504 }\r
505\r
506 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
507 //\r
508 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>\r
509 // or most recent & before the error.\r
510 //\r
511 if (StringPtr == Request) {\r
512 *Progress = StringPtr;\r
513 } else {\r
514 *Progress = StringPtr - 1;\r
515 }\r
516\r
517 //\r
518 // Process each <ConfigRequest> of <MultiConfigRequest>\r
519 //\r
520 Length = CalculateConfigStringLen (StringPtr);\r
521 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
522 if (ConfigRequest == NULL) {\r
523 return EFI_OUT_OF_RESOURCES;\r
524 }\r
525 *(ConfigRequest + Length) = 0;\r
526\r
527 //\r
528 // Get the UEFI device path\r
529 //\r
530 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);\r
531 if (EFI_ERROR (Status)) {\r
676df92c 532 FreePool (ConfigRequest);\r
93e3992d 533 return Status;\r
534 }\r
535\r
536 //\r
537 // Find driver which matches the routing data.\r
538 //\r
539 DriverHandle = NULL;\r
540 for (Link = Private->DatabaseList.ForwardLink;\r
541 Link != &Private->DatabaseList;\r
542 Link = Link->ForwardLink\r
543 ) {\r
544 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
08e6463a 545 \r
546 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {\r
547 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
93e3992d 548 if (CompareMem (\r
549 DevicePath,\r
550 CurrentDevicePath,\r
551 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
552 ) == 0) {\r
553 DriverHandle = Database->DriverHandle;\r
554 break;\r
555 }\r
556 }\r
557 }\r
558\r
676df92c 559 FreePool (DevicePath);\r
93e3992d 560\r
561 if (DriverHandle == NULL) {\r
562 //\r
563 // Routing data does not match any known driver.\r
564 // Set Progress to the 'G' in "GUID" of the routing header.\r
565 //\r
566 *Progress = StringPtr;\r
676df92c 567 FreePool (ConfigRequest);\r
93e3992d 568 return EFI_NOT_FOUND;\r
569 }\r
570\r
571 //\r
572 // Call corresponding ConfigAccess protocol to extract settings\r
573 //\r
574 Status = gBS->HandleProtocol (\r
575 DriverHandle,\r
576 &gEfiHiiConfigAccessProtocolGuid,\r
577 (VOID **) &ConfigAccess\r
578 );\r
579 ASSERT_EFI_ERROR (Status);\r
580\r
581 Status = ConfigAccess->ExtractConfig (\r
582 ConfigAccess,\r
583 ConfigRequest,\r
584 &AccessProgress,\r
585 &AccessResults\r
586 );\r
587 if (EFI_ERROR (Status)) {\r
588 //\r
589 // AccessProgress indicates the parsing progress on <ConfigRequest>.\r
590 // Map it to the progress on <MultiConfigRequest> then return it.\r
591 //\r
8d00a0f1 592 *Progress = StrStr (StringPtr, AccessProgress);\r
676df92c 593 FreePool (ConfigRequest);\r
93e3992d 594 return Status;\r
595 }\r
596\r
597 //\r
8d00a0f1 598 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'\r
599 // which seperates the first <ConfigAltResp> and the following ones.\r
93e3992d 600 //\r
601 ASSERT (*AccessProgress == 0);\r
8d00a0f1 602\r
603 if (!FirstElement) {\r
604 Status = AppendToMultiString (Results, L"&");\r
605 ASSERT_EFI_ERROR (Status);\r
606 }\r
607 \r
93e3992d 608 Status = AppendToMultiString (Results, AccessResults);\r
609 ASSERT_EFI_ERROR (Status);\r
8d00a0f1 610\r
611 FirstElement = FALSE;\r
612 \r
676df92c 613 FreePool (AccessResults);\r
93e3992d 614 AccessResults = NULL;\r
676df92c 615 FreePool (ConfigRequest);\r
93e3992d 616 ConfigRequest = NULL;\r
617\r
618 //\r
619 // Go to next <ConfigRequest> (skip '&').\r
620 //\r
621 StringPtr += Length;\r
622 if (*StringPtr == 0) {\r
623 *Progress = StringPtr;\r
624 break;\r
625 }\r
626\r
627 StringPtr++;\r
628\r
629 }\r
630\r
631 return EFI_SUCCESS;\r
93e3992d 632\r
633}\r
634\r
635\r
636/**\r
637 This function allows the caller to request the current configuration for the\r
638 entirety of the current HII database and returns the data in a\r
639 null-terminated Unicode string.\r
640\r
641 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
642 instance.\r
643 @param Results Null-terminated Unicode string in\r
644 <MultiConfigAltResp> format which has all values\r
645 filled in for the names in the Request string.\r
646 String to be allocated by the called function.\r
647 De-allocation is up to the caller.\r
648\r
649 @retval EFI_SUCCESS The Results string is filled with the values\r
650 corresponding to all requested names.\r
651 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
652 results that must be stored awaiting possible\r
653 future protocols.\r
654 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results\r
655 parameter would result in this type of error.\r
656\r
657**/\r
658EFI_STATUS\r
659EFIAPI\r
660HiiConfigRoutingExportConfig (\r
661 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
662 OUT EFI_STRING *Results\r
663 )\r
664{\r
93e3992d 665 EFI_STATUS Status;\r
93e3992d 666 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
8d00a0f1 667 EFI_STRING AccessResults; \r
668 UINTN Index;\r
669 EFI_HANDLE *ConfigAccessHandles;\r
670 UINTN NumberConfigAccessHandles;\r
671 BOOLEAN FirstElement;\r
93e3992d 672\r
e94358a3 673 //\r
674 // For size reduction, please define PcdSupportFullConfigRoutingProtocol \r
675 // as FALSE. But this renders the system to not 100% compliant with\r
676 // UEFI 2.1. Use this with caution.\r
677 //\r
678 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {\r
679 return EFI_UNSUPPORTED;\r
680 }\r
681\r
93e3992d 682 if (This == NULL || Results == NULL) {\r
683 return EFI_INVALID_PARAMETER;\r
684 }\r
685\r
93e3992d 686 //\r
687 // Allocate a fix length of memory to store Results. Reallocate memory for\r
688 // Results if this fix length is insufficient.\r
689 //\r
690 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
691 if (*Results == NULL) {\r
692 return EFI_OUT_OF_RESOURCES;\r
693 }\r
694\r
8d00a0f1 695 NumberConfigAccessHandles = 0;\r
696 Status = gBS->LocateHandleBuffer (\r
697 ByProtocol,\r
698 &gEfiHiiConfigAccessProtocolGuid,\r
699 NULL,\r
700 &NumberConfigAccessHandles,\r
701 &ConfigAccessHandles\r
702 );\r
703 if (EFI_ERROR (Status)) {\r
704 return Status;\r
705 }\r
93e3992d 706\r
8d00a0f1 707 FirstElement = TRUE;\r
93e3992d 708\r
8d00a0f1 709 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {\r
93e3992d 710 Status = gBS->HandleProtocol (\r
8d00a0f1 711 ConfigAccessHandles[Index],\r
93e3992d 712 &gEfiHiiConfigAccessProtocolGuid,\r
8d00a0f1 713 (VOID **) &ConfigAccess\r
93e3992d 714 );\r
8d00a0f1 715 if (EFI_ERROR (Status)) {\r
716 continue;\r
717 }\r
93e3992d 718\r
719 Status = ConfigAccess->ExtractConfig (\r
720 ConfigAccess,\r
8d00a0f1 721 NULL,\r
722 NULL,\r
93e3992d 723 &AccessResults\r
724 );\r
8d00a0f1 725 if (!EFI_ERROR (Status)) {\r
726 //\r
727 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'\r
728 // which seperates the first <ConfigAltResp> and the following ones. \r
729 //\r
730 if (!FirstElement) {\r
731 Status = AppendToMultiString (Results, L"&");\r
732 ASSERT_EFI_ERROR (Status);\r
676df92c 733 }\r
8d00a0f1 734 \r
735 Status = AppendToMultiString (Results, AccessResults);\r
736 ASSERT_EFI_ERROR (Status);\r
93e3992d 737\r
8d00a0f1 738 FirstElement = FALSE;\r
739 \r
740 FreePool (AccessResults);\r
741 AccessResults = NULL;\r
742 }\r
93e3992d 743 }\r
f4113e1f 744 FreePool (ConfigAccessHandles);\r
93e3992d 745\r
8d00a0f1 746 return EFI_SUCCESS; \r
93e3992d 747}\r
748\r
749\r
750/**\r
751 This function processes the results of processing forms and routes it to the\r
752 appropriate handlers or storage.\r
753\r
754 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
755 instance.\r
756 @param Configuration A null-terminated Unicode string in\r
757 <MulltiConfigResp> format.\r
758 @param Progress A pointer to a string filled in with the offset of\r
759 the most recent & before the first failing name /\r
760 value pair (or the beginning of the string if the\r
761 failure is in the first name / value pair) or the\r
762 terminating NULL if all was successful.\r
763\r
764 @retval EFI_SUCCESS The results have been distributed or are awaiting\r
765 distribution.\r
766 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the\r
767 results that must be stored awaiting possible\r
768 future protocols.\r
769 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter\r
770 would result in this type of error.\r
771 @retval EFI_NOT_FOUND Target for the specified routing data was not\r
772 found.\r
773\r
774**/\r
775EFI_STATUS\r
776EFIAPI\r
813acf3a 777HiiConfigRoutingRouteConfig (\r
93e3992d 778 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
779 IN CONST EFI_STRING Configuration,\r
780 OUT EFI_STRING *Progress\r
781 )\r
782{\r
93e3992d 783 HII_DATABASE_PRIVATE_DATA *Private;\r
784 EFI_STRING StringPtr;\r
785 EFI_STRING ConfigResp;\r
786 UINTN Length;\r
787 EFI_STATUS Status;\r
788 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
789 LIST_ENTRY *Link;\r
790 HII_DATABASE_RECORD *Database;\r
08e6463a 791 UINT8 *DevicePathPkg;\r
93e3992d 792 UINT8 *CurrentDevicePath;\r
793 EFI_HANDLE DriverHandle;\r
794 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
795 EFI_STRING AccessProgress;\r
93e3992d 796\r
e94358a3 797 //\r
798 // For size reduction, please define PcdSupportFullConfigRoutingProtocol \r
799 // as FALSE. But this renders the system to not 100% compliant with\r
800 // UEFI 2.1. Use this with caution.\r
801 //\r
802 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {\r
803 return EFI_UNSUPPORTED;\r
804 }\r
805\r
93e3992d 806 if (This == NULL || Progress == NULL) {\r
807 return EFI_INVALID_PARAMETER;\r
808 }\r
809\r
810 if (Configuration == NULL) {\r
811 *Progress = NULL;\r
812 return EFI_INVALID_PARAMETER;\r
813 }\r
814\r
815 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
816 StringPtr = Configuration;\r
817 *Progress = StringPtr;\r
818\r
819 //\r
820 // The first element of <MultiConfigResp> should be\r
821 // <GuidHdr>, which is in 'GUID='<Guid> syntax.\r
822 //\r
823 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
824 return EFI_INVALID_PARAMETER;\r
825 }\r
826\r
827 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {\r
828 //\r
829 // If parsing error, set Progress to the beginning of the <MultiConfigResp>\r
830 // or most recent & before the error.\r
831 //\r
832 if (StringPtr == Configuration) {\r
833 *Progress = StringPtr;\r
834 } else {\r
835 *Progress = StringPtr - 1;\r
836 }\r
837\r
838 //\r
839 // Process each <ConfigResp> of <MultiConfigResp>\r
840 //\r
841 Length = CalculateConfigStringLen (StringPtr);\r
842 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);\r
843 if (ConfigResp == NULL) {\r
844 return EFI_OUT_OF_RESOURCES;\r
845 }\r
846 //\r
847 // Append '\0' to the end of ConfigRequest\r
848 //\r
849 *(ConfigResp + Length) = 0;\r
850\r
851 //\r
852 // Get the UEFI device path\r
853 //\r
854 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);\r
855 if (EFI_ERROR (Status)) {\r
676df92c 856 FreePool (ConfigResp);\r
93e3992d 857 return Status;\r
858 }\r
859\r
860 //\r
861 // Find driver which matches the routing data.\r
862 //\r
863 DriverHandle = NULL;\r
864 for (Link = Private->DatabaseList.ForwardLink;\r
865 Link != &Private->DatabaseList;\r
866 Link = Link->ForwardLink\r
867 ) {\r
868 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);\r
08e6463a 869\r
870 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {\r
871 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);\r
93e3992d 872 if (CompareMem (\r
873 DevicePath,\r
874 CurrentDevicePath,\r
875 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)\r
876 ) == 0) {\r
877 DriverHandle = Database->DriverHandle;\r
878 break;\r
879 }\r
880 }\r
881 }\r
882\r
676df92c 883 FreePool (DevicePath);\r
93e3992d 884\r
885 if (DriverHandle == NULL) {\r
886 //\r
887 // Routing data does not match any known driver.\r
888 // Set Progress to the 'G' in "GUID" of the routing header.\r
889 //\r
890 *Progress = StringPtr;\r
676df92c 891 FreePool (ConfigResp);\r
93e3992d 892 return EFI_NOT_FOUND;\r
893 }\r
894\r
895 //\r
896 // Call corresponding ConfigAccess protocol to route settings\r
897 //\r
898 Status = gBS->HandleProtocol (\r
899 DriverHandle,\r
900 &gEfiHiiConfigAccessProtocolGuid,\r
901 (VOID **) &ConfigAccess\r
902 );\r
903 ASSERT_EFI_ERROR (Status);\r
904\r
905 Status = ConfigAccess->RouteConfig (\r
906 ConfigAccess,\r
907 ConfigResp,\r
908 &AccessProgress\r
909 );\r
910\r
911 if (EFI_ERROR (Status)) {\r
912 //\r
913 // AccessProgress indicates the parsing progress on <ConfigResp>.\r
914 // Map it to the progress on <MultiConfigResp> then return it.\r
915 //\r
8d00a0f1 916 *Progress = StrStr (StringPtr, AccessProgress);\r
93e3992d 917\r
676df92c 918 FreePool (ConfigResp);\r
93e3992d 919 return Status;\r
920 }\r
921\r
676df92c 922 FreePool (ConfigResp);\r
93e3992d 923 ConfigResp = NULL;\r
924\r
925 //\r
926 // Go to next <ConfigResp> (skip '&').\r
927 //\r
928 StringPtr += Length;\r
929 if (*StringPtr == 0) {\r
930 *Progress = StringPtr;\r
931 break;\r
932 }\r
933\r
934 StringPtr++;\r
935\r
936 }\r
937\r
938 return EFI_SUCCESS;\r
93e3992d 939}\r
940\r
941\r
942/**\r
943 This helper function is to be called by drivers to map configuration data\r
944 stored in byte array ("block") formats such as UEFI Variables into current\r
945 configuration strings.\r
946\r
947 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
948 instance.\r
949 @param ConfigRequest A null-terminated Unicode string in\r
950 <ConfigRequest> format.\r
951 @param Block Array of bytes defining the block's configuration.\r
952 @param BlockSize Length in bytes of Block.\r
953 @param Config Filled-in configuration string. String allocated\r
954 by the function. Returned only if call is\r
955 successful.\r
956 @param Progress A pointer to a string filled in with the offset of\r
957 the most recent & before the first failing\r
958 name/value pair (or the beginning of the string if\r
959 the failure is in the first name / value pair) or\r
960 the terminating NULL if all was successful.\r
961\r
962 @retval EFI_SUCCESS The request succeeded. Progress points to the null\r
963 terminator at the end of the ConfigRequest\r
964 string.\r
965 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress\r
966 points to the first character of ConfigRequest.\r
967 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or\r
968 Block parameter would result in this type of\r
969 error. Progress points to the first character of\r
970 ConfigRequest.\r
971 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.\r
972 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.\r
973 Block is left updated and Progress points at\r
974 the "&" preceding the first non-<BlockName>.\r
975\r
976**/\r
977EFI_STATUS\r
978EFIAPI\r
979HiiBlockToConfig (\r
980 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
981 IN CONST EFI_STRING ConfigRequest,\r
982 IN CONST UINT8 *Block,\r
983 IN CONST UINTN BlockSize,\r
984 OUT EFI_STRING *Config,\r
985 OUT EFI_STRING *Progress\r
986 )\r
987{\r
988 HII_DATABASE_PRIVATE_DATA *Private;\r
989 EFI_STRING StringPtr;\r
990 UINTN Length;\r
991 EFI_STATUS Status;\r
992 EFI_STRING TmpPtr;\r
993 UINT8 *TmpBuffer;\r
994 UINTN Offset;\r
995 UINTN Width;\r
996 UINT8 *Value;\r
997 EFI_STRING ValueStr;\r
998 EFI_STRING ConfigElement;\r
999\r
1000 if (This == NULL || Progress == NULL || Config == NULL) {\r
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
1003\r
1004 if (Block == NULL || ConfigRequest == NULL) {\r
1005 *Progress = ConfigRequest;\r
1006 return EFI_INVALID_PARAMETER;\r
1007 }\r
1008\r
1009\r
1010 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1011 ASSERT (Private != NULL);\r
1012\r
1013 StringPtr = ConfigRequest;\r
1014 ValueStr = NULL;\r
1015 Value = NULL;\r
1016 ConfigElement = NULL;\r
1017\r
1018 //\r
1019 // Allocate a fix length of memory to store Results. Reallocate memory for\r
1020 // Results if this fix length is insufficient.\r
1021 //\r
1022 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);\r
1023 if (*Config == NULL) {\r
1024 return EFI_OUT_OF_RESOURCES;\r
1025 }\r
1026\r
1027 //\r
1028 // Jump <ConfigHdr>\r
1029 //\r
1030 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1031 *Progress = StringPtr;\r
1032 Status = EFI_INVALID_PARAMETER;\r
1033 goto Exit;\r
1034 }\r
1035 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {\r
1036 StringPtr++;\r
1037 }\r
1038 if (*StringPtr == 0) {\r
1039 *Progress = StringPtr;\r
1040 Status = EFI_INVALID_PARAMETER;\r
1041 goto Exit;\r
1042 }\r
08e6463a 1043\r
1044 while (*StringPtr != L'&' && *StringPtr != 0) {\r
1045 StringPtr++;\r
1046 }\r
1047 if (*StringPtr == 0) {\r
1048 *Progress = StringPtr;\r
1049 Status = EFI_INVALID_PARAMETER;\r
1050 goto Exit;\r
1051 }\r
1052 //\r
1053 // Skip '&'\r
1054 //\r
1055 StringPtr++;\r
93e3992d 1056\r
1057 //\r
1058 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>\r
1059 //\r
1060 Length = StringPtr - ConfigRequest;\r
1061 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));\r
1062\r
1063 //\r
1064 // Parse each <RequestElement> if exists\r
1065 // Only <BlockName> format is supported by this help function.\r
1066 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>\r
1067 //\r
1068 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {\r
1069 //\r
1070 // Back up the header of one <BlockName>\r
1071 //\r
1072 TmpPtr = StringPtr;\r
1073\r
1074 StringPtr += StrLen (L"OFFSET=");\r
1075 //\r
1076 // Get Offset\r
1077 //\r
1078 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1079 if (Status == EFI_OUT_OF_RESOURCES) {\r
1080 *Progress = ConfigRequest;\r
1081 goto Exit;\r
1082 }\r
1083 Offset = 0;\r
1084 CopyMem (\r
1085 &Offset,\r
1086 TmpBuffer,\r
1087 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1088 );\r
676df92c 1089 FreePool (TmpBuffer);\r
93e3992d 1090\r
1091 StringPtr += Length;\r
1092 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
1093 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;\r
1094 Status = EFI_INVALID_PARAMETER;\r
1095 goto Exit;\r
1096 }\r
1097 StringPtr += StrLen (L"&WIDTH=");\r
1098\r
1099 //\r
1100 // Get Width\r
1101 //\r
1102 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1103 if (Status == EFI_OUT_OF_RESOURCES) {\r
1104 *Progress = ConfigRequest;\r
1105 goto Exit;\r
1106 }\r
1107 Width = 0;\r
1108 CopyMem (\r
1109 &Width,\r
1110 TmpBuffer,\r
1111 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1112 );\r
676df92c 1113 FreePool (TmpBuffer);\r
93e3992d 1114\r
1115 StringPtr += Length;\r
1116 if (*StringPtr != 0 && *StringPtr != L'&') {\r
1117 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");\r
1118 Status = EFI_INVALID_PARAMETER;\r
1119 goto Exit;\r
1120 }\r
1121\r
1122 //\r
1123 // Calculate Value and convert it to hex string.\r
1124 //\r
1125 if (Offset + Width > BlockSize) {\r
1126 *Progress = StringPtr;\r
1127 Status = EFI_DEVICE_ERROR;\r
1128 goto Exit;\r
1129 }\r
1130\r
1131 Value = (UINT8 *) AllocateZeroPool (Width);\r
1132 if (Value == NULL) {\r
1133 *Progress = ConfigRequest;\r
1134 Status = EFI_OUT_OF_RESOURCES;\r
1135 goto Exit;\r
1136 }\r
1137\r
1138 CopyMem (Value, (UINT8 *) Block + Offset, Width);\r
1139\r
1140 Length = Width * 2 + 1;\r
1141 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
1142 if (ValueStr == NULL) {\r
1143 *Progress = ConfigRequest;\r
1144 Status = EFI_OUT_OF_RESOURCES;\r
1145 goto Exit;\r
1146 }\r
1147\r
36fe40c2 1148 Status = BufToHexString (ValueStr, &Length, Value, Width);\r
93e3992d 1149 ASSERT_EFI_ERROR (Status);\r
813acf3a 1150 ToLower (ValueStr);\r
1151\r
676df92c 1152 FreePool (Value);\r
93e3992d 1153 Value = NULL;\r
1154\r
1155 //\r
1156 // Build a ConfigElement\r
1157 //\r
1158 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");\r
1159 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));\r
1160 if (ConfigElement == NULL) {\r
1161 Status = EFI_OUT_OF_RESOURCES;\r
1162 goto Exit;\r
1163 }\r
1164 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));\r
1165 if (*StringPtr == 0) {\r
1166 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';\r
1167 }\r
1168 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;\r
1169 StrCat (ConfigElement, L"VALUE=");\r
1170 StrCat (ConfigElement, ValueStr);\r
1171\r
1172 AppendToMultiString (Config, ConfigElement);\r
1173\r
676df92c 1174 FreePool (ConfigElement);\r
1175 FreePool (ValueStr);\r
93e3992d 1176 ConfigElement = NULL;\r
1177 ValueStr = NULL;\r
1178\r
1179 //\r
1180 // If '\0', parsing is finished. Otherwise skip '&' to continue\r
1181 //\r
1182 if (*StringPtr == 0) {\r
1183 break;\r
1184 }\r
1185 AppendToMultiString (Config, L"&");\r
1186 StringPtr++;\r
1187\r
1188 }\r
1189\r
1190 if (*StringPtr != 0) {\r
1191 *Progress = StringPtr - 1;\r
1192 Status = EFI_INVALID_PARAMETER;\r
1193 goto Exit;\r
1194 }\r
1195\r
1196 *Progress = StringPtr;\r
1197 return EFI_SUCCESS;\r
1198\r
1199Exit:\r
676df92c 1200 FreePool (*Config);\r
1201 if (ValueStr != NULL) {\r
1202 FreePool (ValueStr);\r
1203 }\r
1204 if (Value != NULL) {\r
1205 FreePool (Value);\r
1206 }\r
69367b5b 1207 if (ConfigElement != NULL) {\r
676df92c 1208 FreePool (ConfigElement);\r
1209 }\r
93e3992d 1210\r
1211 return Status;\r
1212\r
1213}\r
1214\r
1215\r
1216/**\r
1217 This helper function is to be called by drivers to map configuration strings\r
1218 to configurations stored in byte array ("block") formats such as UEFI Variables.\r
1219\r
1220 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1221 instance.\r
1222 @param ConfigResp A null-terminated Unicode string in <ConfigResp>\r
1223 format.\r
1224 @param Block A possibly null array of bytes representing the\r
1225 current block. Only bytes referenced in the\r
1226 ConfigResp string in the block are modified. If\r
1227 this parameter is null or if the *BlockSize\r
1228 parameter is (on input) shorter than required by\r
1229 the Configuration string, only the BlockSize\r
1230 parameter is updated and an appropriate status\r
1231 (see below) is returned.\r
1232 @param BlockSize The length of the Block in units of UINT8. On\r
1233 input, this is the size of the Block. On output,\r
1234 if successful, contains the index of the last\r
1235 modified byte in the Block.\r
1236 @param Progress On return, points to an element of the ConfigResp\r
1237 string filled in with the offset of the most\r
1238 recent '&' before the first failing name / value\r
1239 pair (or the beginning of the string if the\r
1240 failure is in the first name / value pair) or the\r
1241 terminating NULL if all was successful.\r
1242\r
1243 @retval EFI_SUCCESS The request succeeded. Progress points to the null\r
1244 terminator at the end of the ConfigResp string.\r
1245 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress\r
1246 points to the first character of ConfigResp.\r
1247 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or\r
1248 Block parameter would result in this type of\r
1249 error. Progress points to the first character of\r
1250 ConfigResp.\r
1251 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /\r
1252 value pair. Block is left updated and\r
1253 Progress points at the '&' preceding the first\r
1254 non-<BlockName>.\r
1255\r
1256**/\r
1257EFI_STATUS\r
1258EFIAPI\r
1259HiiConfigToBlock (\r
1260 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1261 IN CONST EFI_STRING ConfigResp,\r
1262 IN OUT UINT8 *Block,\r
1263 IN OUT UINTN *BlockSize,\r
1264 OUT EFI_STRING *Progress\r
1265 )\r
1266{\r
1267 HII_DATABASE_PRIVATE_DATA *Private;\r
1268 EFI_STRING StringPtr;\r
1269 UINTN Length;\r
1270 EFI_STATUS Status;\r
1271 UINT8 *TmpBuffer;\r
1272 UINTN Offset;\r
1273 UINTN Width;\r
1274 UINT8 *Value;\r
1275 UINTN BufferSize;\r
1276\r
1277 if (This == NULL || BlockSize == NULL || Progress == NULL) {\r
1278 return EFI_INVALID_PARAMETER;\r
1279 }\r
1280\r
1281 if (ConfigResp == NULL || Block == NULL) {\r
1282 *Progress = ConfigResp;\r
1283 return EFI_INVALID_PARAMETER;\r
1284 }\r
1285\r
1286 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);\r
1287 ASSERT (Private != NULL);\r
1288\r
1289 StringPtr = ConfigResp;\r
1290 BufferSize = *BlockSize;\r
1291 Value = NULL;\r
1292\r
1293 //\r
1294 // Jump <ConfigHdr>\r
1295 //\r
1296 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1297 *Progress = StringPtr;\r
1298 Status = EFI_INVALID_PARAMETER;\r
1299 goto Exit;\r
1300 }\r
1301 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {\r
1302 StringPtr++;\r
1303 }\r
1304 if (*StringPtr == 0) {\r
1305 *Progress = StringPtr;\r
1306 Status = EFI_INVALID_PARAMETER;\r
1307 goto Exit;\r
1308 }\r
08e6463a 1309\r
1310 while (*StringPtr != L'&' && *StringPtr != 0) {\r
1311 StringPtr++;\r
1312 }\r
1313 if (*StringPtr == 0) {\r
1314 *Progress = StringPtr;\r
1315 Status = EFI_INVALID_PARAMETER;\r
1316 goto Exit;\r
1317 }\r
1318 //\r
1319 // Skip '&'\r
1320 //\r
1321 StringPtr++;\r
93e3992d 1322\r
1323 //\r
1324 // Parse each <ConfigElement> if exists\r
1325 // Only <BlockConfig> format is supported by this help function.\r
1326 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>\r
1327 //\r
1328 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {\r
1329 StringPtr += StrLen (L"OFFSET=");\r
1330 //\r
1331 // Get Offset\r
1332 //\r
1333 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1334 if (Status == EFI_OUT_OF_RESOURCES) {\r
1335 *Progress = ConfigResp;\r
1336 goto Exit;\r
1337 }\r
1338 Offset = 0;\r
1339 CopyMem (\r
1340 &Offset,\r
1341 TmpBuffer,\r
1342 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1343 );\r
676df92c 1344 FreePool (TmpBuffer);\r
93e3992d 1345\r
1346 StringPtr += Length;\r
1347 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {\r
1348 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;\r
1349 Status = EFI_INVALID_PARAMETER;\r
1350 goto Exit;\r
1351 }\r
1352 StringPtr += StrLen (L"&WIDTH=");\r
1353\r
1354 //\r
1355 // Get Width\r
1356 //\r
1357 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);\r
1358 if (Status == EFI_OUT_OF_RESOURCES) {\r
1359 *Progress = ConfigResp;\r
1360 goto Exit;\r
1361 }\r
1362 Width = 0;\r
1363 CopyMem (\r
1364 &Width,\r
1365 TmpBuffer,\r
1366 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)\r
1367 );\r
676df92c 1368 FreePool (TmpBuffer);\r
93e3992d 1369\r
1370 StringPtr += Length;\r
1371 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {\r
1372 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");\r
1373 Status = EFI_INVALID_PARAMETER;\r
1374 goto Exit;\r
1375 }\r
1376 StringPtr += StrLen (L"&VALUE=");\r
1377\r
1378 //\r
1379 // Get Value\r
1380 //\r
1381 Status = GetValueOfNumber (StringPtr, &Value, &Length);\r
1382 if (Status == EFI_OUT_OF_RESOURCES) {\r
1383 *Progress = ConfigResp;\r
1384 goto Exit;\r
1385 }\r
1386\r
1387 StringPtr += Length;\r
1388 if (*StringPtr != 0 && *StringPtr != L'&') {\r
1389 *Progress = StringPtr - Length - 7;\r
1390 Status = EFI_INVALID_PARAMETER;\r
1391 goto Exit;\r
1392 }\r
1393\r
1394 //\r
1395 // Update the Block with configuration info\r
1396 //\r
1397\r
1398 if (Offset + Width > BufferSize) {\r
1399 return EFI_DEVICE_ERROR;\r
1400 }\r
1401\r
1402 CopyMem (Block + Offset, Value, Width);\r
1403 *BlockSize = Offset + Width - 1;\r
1404\r
676df92c 1405 FreePool (Value);\r
93e3992d 1406 Value = NULL;\r
1407\r
1408 //\r
1409 // If '\0', parsing is finished. Otherwise skip '&' to continue\r
1410 //\r
1411 if (*StringPtr == 0) {\r
1412 break;\r
1413 }\r
1414\r
1415 StringPtr++;\r
1416 }\r
1417\r
1418 if (*StringPtr != 0) {\r
1419 *Progress = StringPtr - 1;\r
1420 Status = EFI_INVALID_PARAMETER;\r
1421 goto Exit;\r
1422 }\r
1423\r
1424 *Progress = StringPtr;\r
1425 return EFI_SUCCESS;\r
1426\r
1427Exit:\r
1428\r
676df92c 1429 if (Value != NULL) {\r
1430 FreePool (Value);\r
1431 }\r
93e3992d 1432 return Status;\r
1433}\r
1434\r
1435\r
1436/**\r
1437 This helper function is to be called by drivers to extract portions of\r
1438 a larger configuration string.\r
1439\r
1440 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL\r
1441 instance.\r
1442 @param Configuration A null-terminated Unicode string in\r
1443 <MultiConfigAltResp> format.\r
1444 @param Guid A pointer to the GUID value to search for in the\r
1445 routing portion of the ConfigResp string when\r
1446 retrieving the requested data. If Guid is NULL,\r
1447 then all GUID values will be searched for.\r
1448 @param Name A pointer to the NAME value to search for in the\r
1449 routing portion of the ConfigResp string when\r
1450 retrieving the requested data. If Name is NULL,\r
1451 then all Name values will be searched for.\r
1452 @param DevicePath A pointer to the PATH value to search for in the\r
1453 routing portion of the ConfigResp string when\r
1454 retrieving the requested data. If DevicePath is\r
1455 NULL, then all DevicePath values will be searched\r
1456 for.\r
1457 @param AltCfgId A pointer to the ALTCFG value to search for in the\r
1458 routing portion of the ConfigResp string when\r
1459 retrieving the requested data. If this parameter\r
1460 is NULL, then the current setting will be\r
1461 retrieved.\r
1462 @param AltCfgResp A pointer to a buffer which will be allocated by\r
1463 the function which contains the retrieved string\r
1464 as requested. This buffer is only allocated if\r
1465 the call was successful.\r
1466\r
1467 @retval EFI_SUCCESS The request succeeded. The requested data was\r
1468 extracted and placed in the newly allocated\r
1469 AltCfgResp buffer.\r
1470 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.\r
1471 @retval EFI_INVALID_PARAMETER Any parameter is invalid.\r
1472 @retval EFI_NOT_FOUND Target for the specified routing data was not\r
1473 found.\r
1474\r
1475**/\r
1476EFI_STATUS\r
1477EFIAPI\r
1478HiiGetAltCfg (\r
1479 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,\r
1480 IN CONST EFI_STRING Configuration,\r
1481 IN CONST EFI_GUID *Guid,\r
1482 IN CONST EFI_STRING Name,\r
1483 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1484 IN CONST UINT16 *AltCfgId,\r
1485 OUT EFI_STRING *AltCfgResp\r
1486 )\r
1487{\r
93e3992d 1488 EFI_STATUS Status;\r
1489 EFI_STRING StringPtr;\r
e90b081a 1490 EFI_STRING HdrStart;\r
1491 EFI_STRING HdrEnd;\r
93e3992d 1492 EFI_STRING TmpPtr;\r
1493 UINTN Length;\r
e90b081a 1494 EFI_STRING GuidStr;\r
1495 EFI_STRING NameStr;\r
1496 EFI_STRING PathStr;\r
1497 EFI_STRING AltIdStr;\r
1498 EFI_STRING Result;\r
1499 BOOLEAN GuidFlag;\r
1500 BOOLEAN NameFlag;\r
1501 BOOLEAN PathFlag;\r
1502\r
e94358a3 1503 //\r
1504 // For size reduction, please define PcdSupportFullConfigRoutingProtocol \r
1505 // as FALSE. But this renders the system to not 100% compliant with\r
1506 // UEFI 2.1. Use this with caution.\r
1507 //\r
1508 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {\r
1509 return EFI_UNSUPPORTED;\r
1510 }\r
1511\r
e90b081a 1512 HdrStart = NULL;\r
1513 HdrEnd = NULL;\r
1514 GuidStr = NULL;\r
1515 NameStr = NULL;\r
1516 PathStr = NULL;\r
1517 AltIdStr = NULL;\r
1518 Result = NULL;\r
1519 GuidFlag = FALSE;\r
1520 NameFlag = FALSE;\r
1521 PathFlag = FALSE;\r
93e3992d 1522\r
1523 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {\r
1524 return EFI_INVALID_PARAMETER;\r
1525 }\r
1526\r
1527 StringPtr = Configuration;\r
1528 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {\r
1529 return EFI_INVALID_PARAMETER;\r
1530 }\r
1531\r
1532 //\r
1533 // Generate the sub string for later matching.\r
1534 //\r
813acf3a 1535 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);\r
93e3992d 1536 GenerateSubStr (\r
1537 L"PATH=",\r
1538 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),\r
813acf3a 1539 (VOID *) DevicePath,\r
1540 1,\r
93e3992d 1541 &PathStr\r
1542 );\r
1543 if (AltCfgId != NULL) {\r
813acf3a 1544 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr); \r
93e3992d 1545 }\r
1546 if (Name != NULL) {\r
813acf3a 1547 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr); \r
93e3992d 1548 } else {\r
813acf3a 1549 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);\r
93e3992d 1550 }\r
1551\r
1552 while (*StringPtr != 0) {\r
1553 //\r
1554 // Try to match the GUID\r
1555 //\r
1556 if (!GuidFlag) {\r
1557 TmpPtr = StrStr (StringPtr, GuidStr);\r
1558 if (TmpPtr == NULL) {\r
1559 Status = EFI_NOT_FOUND;\r
1560 goto Exit;\r
1561 }\r
1562 HdrStart = TmpPtr;\r
1563\r
1564 //\r
1565 // Jump to <NameHdr>\r
1566 //\r
1567 if (Guid != NULL) {\r
1568 StringPtr = TmpPtr + StrLen (GuidStr);\r
1569 } else {\r
1570 StringPtr = StrStr (TmpPtr, L"NAME=");\r
1571 if (StringPtr == NULL) {\r
1572 Status = EFI_NOT_FOUND;\r
1573 goto Exit;\r
1574 }\r
1575 }\r
1576 GuidFlag = TRUE;\r
1577 }\r
1578\r
1579 //\r
1580 // Try to match the NAME\r
1581 //\r
1582 if (GuidFlag && !NameFlag) {\r
1583 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {\r
1584 GuidFlag = FALSE;\r
1585 } else {\r
1586 //\r
1587 // Jump to <PathHdr>\r
1588 //\r
1589 if (Name != NULL) {\r
1590 StringPtr += StrLen (NameStr);\r
1591 } else {\r
1592 StringPtr = StrStr (StringPtr, L"PATH=");\r
1593 if (StringPtr == NULL) {\r
1594 Status = EFI_NOT_FOUND;\r
1595 goto Exit;\r
1596 }\r
1597 }\r
1598 NameFlag = TRUE;\r
1599 }\r
1600 }\r
1601\r
1602 //\r
1603 // Try to match the DevicePath\r
1604 //\r
1605 if (GuidFlag && NameFlag && !PathFlag) {\r
1606 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {\r
1607 GuidFlag = FALSE;\r
1608 NameFlag = FALSE;\r
1609 } else {\r
1610 //\r
1611 // Jump to '&' before <DescHdr> or <ConfigBody>\r
1612 //\r
1613 if (DevicePath != NULL) {\r
1614 StringPtr += StrLen (PathStr);\r
1615 } else {\r
1616 StringPtr = StrStr (StringPtr, L"&");\r
1617 if (StringPtr == NULL) {\r
1618 Status = EFI_NOT_FOUND;\r
1619 goto Exit;\r
1620 }\r
1621 }\r
1622 PathFlag = TRUE;\r
1623 HdrEnd = ++StringPtr;\r
1624 }\r
1625 }\r
1626\r
1627 //\r
1628 // Try to match the AltCfgId\r
1629 //\r
1630 if (GuidFlag && NameFlag && PathFlag) {\r
1631 if (AltCfgId == NULL) {\r
1632 //\r
1633 // Return Current Setting when AltCfgId is NULL.\r
1634 //\r
1635 Status = OutputConfigBody (StringPtr, &Result);\r
1636 goto Exit;\r
1637 }\r
1638 //\r
1639 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.\r
1640 //\r
1641 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {\r
1642 GuidFlag = FALSE;\r
1643 NameFlag = FALSE;\r
1644 PathFlag = FALSE;\r
1645 } else {\r
1646 Status = OutputConfigBody (StringPtr, &Result);\r
1647 goto Exit;\r
1648 }\r
1649 }\r
1650 }\r
1651\r
1652 Status = EFI_NOT_FOUND;\r
1653\r
1654Exit:\r
1655\r
1656 if (!EFI_ERROR (Status)) {\r
1657 //\r
1658 // Copy the <ConfigHdr> and <ConfigBody>\r
1659 //\r
1660 Length = HdrEnd - HdrStart + StrLen (Result);\r
1661 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));\r
1662 if (*AltCfgResp == NULL) {\r
1663 Status = EFI_OUT_OF_RESOURCES;\r
1664 } else {\r
1665 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);\r
1666 StrCat (*AltCfgResp, Result);\r
1667 Status = EFI_SUCCESS;\r
1668 }\r
1669 }\r
1670\r
676df92c 1671 if (GuidStr != NULL) {\r
1672 FreePool (GuidStr);\r
1673 }\r
1674 if (NameStr != NULL) {\r
1675 FreePool (NameStr);\r
1676 }\r
1677 if (PathStr != NULL) {\r
1678 FreePool (PathStr);\r
1679 }\r
1680 if (AltIdStr != NULL) {\r
1681 FreePool (AltIdStr);\r
1682 }\r
1683 if (Result != NULL) {\r
1684 FreePool (Result);\r
1685 }\r
93e3992d 1686\r
1687 return Status;\r
1688\r
93e3992d 1689}\r
1690\r
36fe40c2 1691\r