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