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