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