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