2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
4 Copyright (c) 2007 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "HiiDatabase.h"
19 Calculate the number of Unicode characters of the incoming Configuration string,
20 not including NULL terminator.
22 This is a internal function.
24 @param String String in <MultiConfigRequest> or
25 <MultiConfigResp> format.
27 @return The number of Unicode characters.
31 CalculateConfigStringLen (
38 // "GUID=" should be the first element of incoming string.
40 ASSERT (String
!= NULL
);
41 ASSERT (StrnCmp (String
, L
"GUID=", StrLen (L
"GUID=")) == 0);
43 Length
= StrLen (L
"GUID=");
47 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
48 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
50 while (*String
!= 0 && StrnCmp (String
, L
"&GUID=", StrLen (L
"&GUID=")) != 0) {
60 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
61 from <PathHdr> of <ConfigHdr>.
63 This is a internal function.
65 @param String UEFI configuration string
66 @param DevicePath binary of a UEFI device path.
68 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
69 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
70 @retval EFI_SUCCESS The device path is retrieved and translated to
77 OUT UINT8
**DevicePath
82 EFI_STRING DevicePathString
;
83 UINT8
*DevicePathBuffer
;
88 if (String
== NULL
|| DevicePath
== NULL
) {
89 return EFI_INVALID_PARAMETER
;
93 // Find the 'PATH=' of <PathHdr> and skip it.
95 for (; (*String
!= 0 && StrnCmp (String
, L
"PATH=", StrLen (L
"PATH=")) != 0); String
++);
97 return EFI_INVALID_PARAMETER
;
100 String
+= StrLen (L
"PATH=");
104 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
105 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
106 // of UEFI device path.
108 for (Length
= 0; *String
!= 0 && *String
!= L
'&'; String
++, Length
++);
109 DevicePathString
= (EFI_STRING
) AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
110 if (DevicePathString
== NULL
) {
111 return EFI_OUT_OF_RESOURCES
;
113 StrnCpy (DevicePathString
, PathHdr
, Length
);
114 *(DevicePathString
+ Length
) = 0;
117 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
118 // as the device path resides in RAM memory.
119 // Translate the data into binary.
121 DevicePathBuffer
= (UINT8
*) AllocateZeroPool ((Length
+ 1) / 2);
122 if (DevicePathBuffer
== NULL
) {
123 FreePool (DevicePathString
);
124 return EFI_OUT_OF_RESOURCES
;
127 ZeroMem (TemStr
, sizeof (TemStr
));
128 for (Index
= 0; DevicePathString
[Index
] != L
'\0'; Index
++) {
129 TemStr
[0] = DevicePathString
[Index
];
130 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
131 if ((Index
& 1) == 0) {
132 DevicePathBuffer
[Index
/2] = DigitUint8
;
134 DevicePathBuffer
[Index
/2] = (UINT8
) ((DevicePathBuffer
[Index
/2] << 4) + DigitUint8
);
138 FreePool (DevicePathString
);
140 *DevicePath
= DevicePathBuffer
;
147 Converts the unicode character of the string from uppercase to lowercase.
148 This is a internal function.
150 @param Str String to be converted
161 for (Ptr
= Str
; *Ptr
!= L
'\0'; Ptr
++) {
162 if (*Ptr
>= L
'A' && *Ptr
<= L
'Z') {
163 *Ptr
= (CHAR16
) (*Ptr
- L
'A' + L
'a');
169 Generate a sub string then output it.
171 This is a internal function.
173 @param String A constant string which is the prefix of the to be
174 generated string, e.g. GUID=
175 @param BufferLen The length of the Buffer in bytes.
176 @param Buffer Points to a buffer which will be converted to be the
177 content of the generated string.
178 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
179 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
180 if 3, the buffer contains other data.
181 @param SubStr Points to the output string. It's caller's
182 responsibility to free this buffer.
188 IN CONST EFI_STRING String
,
192 OUT EFI_STRING
*SubStr
197 EFI_STRING StringHeader
;
203 ASSERT (String
!= NULL
&& SubStr
!= NULL
);
205 if (Buffer
== NULL
) {
206 *SubStr
= AllocateCopyPool (StrSize (String
), String
);
207 ASSERT (*SubStr
!= NULL
);
211 Length
= StrLen (String
) + BufferLen
* 2 + 1 + 1;
212 Str
= AllocateZeroPool (Length
* sizeof (CHAR16
));
213 ASSERT (Str
!= NULL
);
215 StrCpy (Str
, String
);
216 Length
= (BufferLen
* 2 + 1) * sizeof (CHAR16
);
218 StringHeader
= Str
+ StrLen (String
);
219 TemString
= (CHAR16
*) StringHeader
;
224 // Convert Buffer to Hex String in reverse order
226 TemBuffer
= ((UINT8
*) Buffer
);
227 for (Index
= 0; Index
< BufferLen
; Index
++, TemBuffer
++) {
228 TemString
+= UnicodeValueToString (TemString
, PREFIX_ZERO
| RADIX_HEX
, *TemBuffer
, 2);
233 // Check buffer is enough
235 TemName
= (CHAR16
*) Buffer
;
236 ASSERT (Length
< ((StrLen (TemName
) * 4 + 1) * sizeof (CHAR16
)));
238 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
240 for (; *TemName
!= L
'\0'; TemName
++) {
241 TemString
+= UnicodeValueToString (TemString
, PREFIX_ZERO
| RADIX_HEX
, *TemName
, 4);
246 // Convert Buffer to Hex String
248 TemBuffer
= ((UINT8
*) Buffer
) + BufferLen
- 1;
249 for (Index
= 0; Index
< BufferLen
; Index
++, TemBuffer
--) {
250 TemString
+= UnicodeValueToString (TemString
, PREFIX_ZERO
| RADIX_HEX
, *TemBuffer
, 2);
258 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
260 HiiToLower (StringHeader
);
268 Retrieve the <ConfigBody> from String then output it.
270 This is a internal function.
272 @param String A sub string of a configuration string in
273 <MultiConfigAltResp> format.
274 @param ConfigBody Points to the output string. It's caller's
275 responsibility to free this buffer.
277 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
278 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
279 @retval EFI_SUCCESS All existing storage is exported.
284 IN EFI_STRING String
,
285 OUT EFI_STRING
*ConfigBody
292 if (String
== NULL
|| ConfigBody
== NULL
) {
293 return EFI_INVALID_PARAMETER
;
296 TmpPtr
= StrStr (String
, L
"GUID=");
297 if (TmpPtr
== NULL
) {
299 // It is the last <ConfigResp> of the incoming configuration string.
301 Result
= AllocateCopyPool (StrSize (String
), String
);
302 if (Result
== NULL
) {
303 return EFI_OUT_OF_RESOURCES
;
305 *ConfigBody
= Result
;
310 Length
= TmpPtr
- String
;
311 Result
= AllocateCopyPool (Length
* sizeof (CHAR16
), String
);
312 if (Result
== NULL
) {
313 return EFI_OUT_OF_RESOURCES
;
316 *(Result
+ Length
- 1) = 0;
317 *ConfigBody
= Result
;
323 Append a string to a multi-string format.
325 This is a internal function.
327 @param MultiString String in <MultiConfigRequest>,
328 <MultiConfigAltResp>, or <MultiConfigResp>. On
329 input, the buffer length of this string is
330 MAX_STRING_LENGTH. On output, the buffer length
332 @param AppendString NULL-terminated Unicode string.
334 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
335 @retval EFI_SUCCESS AppendString is append to the end of MultiString
339 AppendToMultiString (
340 IN OUT EFI_STRING
*MultiString
,
341 IN EFI_STRING AppendString
344 UINTN AppendStringSize
;
345 UINTN MultiStringSize
;
347 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
348 return EFI_INVALID_PARAMETER
;
351 AppendStringSize
= StrSize (AppendString
);
352 MultiStringSize
= StrSize (*MultiString
);
355 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
357 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
358 MultiStringSize
> MAX_STRING_LENGTH
) {
359 *MultiString
= (EFI_STRING
) ReallocatePool (
361 MultiStringSize
+ AppendStringSize
,
362 (VOID
*) (*MultiString
)
364 ASSERT (*MultiString
!= NULL
);
367 // Append the incoming string
369 StrCat (*MultiString
, AppendString
);
376 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
378 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
380 This is a internal function.
382 @param StringPtr String in <BlockConfig> format and points to the
383 first character of <Number>.
384 @param Number The output value. Caller takes the responsibility
386 @param Len Length of the <Number>, in characters.
388 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
390 @retval EFI_SUCCESS Value of <Number> is outputted in Number
396 IN EFI_STRING StringPtr
,
410 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
411 ASSERT (*StringPtr
!= L
'\0');
416 while (*StringPtr
!= L
'\0' && *StringPtr
!= L
'&') {
419 *Len
= StringPtr
- TmpPtr
;
422 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
424 Status
= EFI_OUT_OF_RESOURCES
;
427 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
428 *(Str
+ *Len
) = L
'\0';
430 Length
= (Length
+ 1) / 2;
431 Buf
= (UINT8
*) AllocateZeroPool (Length
);
433 Status
= EFI_OUT_OF_RESOURCES
;
438 ZeroMem (TemStr
, sizeof (TemStr
));
439 for (Index
= 0; Index
< Length
; Index
++) {
440 TemStr
[0] = Str
[Length
- Index
- 1];
441 DigitUint8
= (UINT8
) StrHexToUint64 (TemStr
);
442 if ((Index
& 1) == 0) {
443 Buf
[Index
/2] = DigitUint8
;
445 Buf
[Index
/2] = (UINT8
) ((DigitUint8
<< 4) + Buf
[Index
/2]);
450 Status
= EFI_SUCCESS
;
462 This function allows a caller to extract the current configuration
463 for one or more named elements from one or more drivers.
465 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
467 @param Request A null-terminated Unicode string in
468 <MultiConfigRequest> format.
469 @param Progress On return, points to a character in the Request
470 string. Points to the string's null terminator if
471 request was successful. Points to the most recent
472 & before the first failing name / value pair (or
473 the beginning of the string if the failure is in
474 the first name / value pair) if the request was
476 @param Results Null-terminated Unicode string in
477 <MultiConfigAltResp> format which has all values
478 filled in for the names in the Request string.
479 String to be allocated by the called function.
481 @retval EFI_SUCCESS The Results string is filled with the values
482 corresponding to all requested names.
483 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
484 results that must be stored awaiting possible
486 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
487 Progress set to the "G" in "GUID" of the routing
488 header that doesn't match. Note: There is no
489 requirement that all routing data be validated
490 before any configuration extraction.
491 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
492 parameter would result in this type of error. The
493 Progress parameter is set to NULL.
494 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
495 before the error or the beginning of the string.
496 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
502 HiiConfigRoutingExtractConfig (
503 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
504 IN CONST EFI_STRING Request
,
505 OUT EFI_STRING
*Progress
,
506 OUT EFI_STRING
*Results
509 EFI_STRING StringPtr
;
510 EFI_STRING ConfigRequest
;
512 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
513 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
515 EFI_HANDLE DriverHandle
;
516 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
517 EFI_STRING AccessProgress
;
518 EFI_STRING AccessResults
;
519 BOOLEAN FirstElement
;
521 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
522 return EFI_INVALID_PARAMETER
;
525 if (Request
== NULL
) {
527 return EFI_INVALID_PARAMETER
;
531 *Progress
= StringPtr
;
534 // The first element of <MultiConfigRequest> should be
535 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
537 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
538 return EFI_INVALID_PARAMETER
;
544 // Allocate a fix length of memory to store Results. Reallocate memory for
545 // Results if this fix length is insufficient.
547 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
548 if (*Results
== NULL
) {
549 return EFI_OUT_OF_RESOURCES
;
552 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
554 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
555 // or most recent & before the error.
557 if (StringPtr
== Request
) {
558 *Progress
= StringPtr
;
560 *Progress
= StringPtr
- 1;
564 // Process each <ConfigRequest> of <MultiConfigRequest>
566 Length
= CalculateConfigStringLen (StringPtr
);
567 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
568 if (ConfigRequest
== NULL
) {
569 return EFI_OUT_OF_RESOURCES
;
571 *(ConfigRequest
+ Length
) = 0;
574 // Get the UEFI device path
576 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
577 if (EFI_ERROR (Status
)) {
578 FreePool (ConfigRequest
);
583 // Find driver handle by device path
586 TempDevicePath
= DevicePath
;
587 Status
= gBS
->LocateDevicePath (
588 &gEfiDevicePathProtocolGuid
,
592 FreePool (DevicePath
);
594 if (EFI_ERROR (Status
) || (DriverHandle
== NULL
)) {
596 // Cannot find any known driver.
597 // Set Progress to the 'G' in "GUID" of the routing header.
599 *Progress
= StringPtr
;
600 FreePool (ConfigRequest
);
601 return EFI_NOT_FOUND
;
605 // Call corresponding ConfigAccess protocol to extract settings
607 Status
= gBS
->HandleProtocol (
609 &gEfiHiiConfigAccessProtocolGuid
,
610 (VOID
**) &ConfigAccess
612 ASSERT_EFI_ERROR (Status
);
614 Status
= ConfigAccess
->ExtractConfig (
620 if (EFI_ERROR (Status
)) {
622 // AccessProgress indicates the parsing progress on <ConfigRequest>.
623 // Map it to the progress on <MultiConfigRequest> then return it.
625 *Progress
= StrStr (StringPtr
, AccessProgress
);
626 FreePool (ConfigRequest
);
631 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
632 // which seperates the first <ConfigAltResp> and the following ones.
634 ASSERT (*AccessProgress
== 0);
637 Status
= AppendToMultiString (Results
, L
"&");
638 ASSERT_EFI_ERROR (Status
);
641 Status
= AppendToMultiString (Results
, AccessResults
);
642 ASSERT_EFI_ERROR (Status
);
644 FirstElement
= FALSE
;
646 FreePool (AccessResults
);
647 AccessResults
= NULL
;
648 FreePool (ConfigRequest
);
649 ConfigRequest
= NULL
;
652 // Go to next <ConfigRequest> (skip '&').
655 if (*StringPtr
== 0) {
656 *Progress
= StringPtr
;
670 This function allows the caller to request the current configuration for the
671 entirety of the current HII database and returns the data in a
672 null-terminated Unicode string.
674 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
676 @param Results Null-terminated Unicode string in
677 <MultiConfigAltResp> format which has all values
678 filled in for the names in the Request string.
679 String to be allocated by the called function.
680 De-allocation is up to the caller.
682 @retval EFI_SUCCESS The Results string is filled with the values
683 corresponding to all requested names.
684 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
685 results that must be stored awaiting possible
687 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
688 parameter would result in this type of error.
693 HiiConfigRoutingExportConfig (
694 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
695 OUT EFI_STRING
*Results
699 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
700 EFI_STRING AccessResults
;
702 EFI_HANDLE
*ConfigAccessHandles
;
703 UINTN NumberConfigAccessHandles
;
704 BOOLEAN FirstElement
;
706 if (This
== NULL
|| Results
== NULL
) {
707 return EFI_INVALID_PARAMETER
;
711 // Allocate a fix length of memory to store Results. Reallocate memory for
712 // Results if this fix length is insufficient.
714 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
715 if (*Results
== NULL
) {
716 return EFI_OUT_OF_RESOURCES
;
719 NumberConfigAccessHandles
= 0;
720 Status
= gBS
->LocateHandleBuffer (
722 &gEfiHiiConfigAccessProtocolGuid
,
724 &NumberConfigAccessHandles
,
727 if (EFI_ERROR (Status
)) {
733 for (Index
= 0; Index
< NumberConfigAccessHandles
; Index
++) {
734 Status
= gBS
->HandleProtocol (
735 ConfigAccessHandles
[Index
],
736 &gEfiHiiConfigAccessProtocolGuid
,
737 (VOID
**) &ConfigAccess
739 if (EFI_ERROR (Status
)) {
743 Status
= ConfigAccess
->ExtractConfig (
749 if (!EFI_ERROR (Status
)) {
751 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
752 // which seperates the first <ConfigAltResp> and the following ones.
755 Status
= AppendToMultiString (Results
, L
"&");
756 ASSERT_EFI_ERROR (Status
);
759 Status
= AppendToMultiString (Results
, AccessResults
);
760 ASSERT_EFI_ERROR (Status
);
762 FirstElement
= FALSE
;
764 FreePool (AccessResults
);
765 AccessResults
= NULL
;
768 FreePool (ConfigAccessHandles
);
775 This function processes the results of processing forms and routes it to the
776 appropriate handlers or storage.
778 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
780 @param Configuration A null-terminated Unicode string in
781 <MulltiConfigResp> format.
782 @param Progress A pointer to a string filled in with the offset of
783 the most recent & before the first failing name /
784 value pair (or the beginning of the string if the
785 failure is in the first name / value pair) or the
786 terminating NULL if all was successful.
788 @retval EFI_SUCCESS The results have been distributed or are awaiting
790 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
791 results that must be stored awaiting possible
793 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
794 would result in this type of error.
795 @retval EFI_NOT_FOUND Target for the specified routing data was not
801 HiiConfigRoutingRouteConfig (
802 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
803 IN CONST EFI_STRING Configuration
,
804 OUT EFI_STRING
*Progress
807 EFI_STRING StringPtr
;
808 EFI_STRING ConfigResp
;
811 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
812 EFI_DEVICE_PATH_PROTOCOL
*TempDevicePath
;
813 EFI_HANDLE DriverHandle
;
814 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
815 EFI_STRING AccessProgress
;
817 if (This
== NULL
|| Progress
== NULL
) {
818 return EFI_INVALID_PARAMETER
;
821 if (Configuration
== NULL
) {
823 return EFI_INVALID_PARAMETER
;
826 StringPtr
= Configuration
;
827 *Progress
= StringPtr
;
830 // The first element of <MultiConfigResp> should be
831 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
833 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
834 return EFI_INVALID_PARAMETER
;
837 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
839 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
840 // or most recent & before the error.
842 if (StringPtr
== Configuration
) {
843 *Progress
= StringPtr
;
845 *Progress
= StringPtr
- 1;
849 // Process each <ConfigResp> of <MultiConfigResp>
851 Length
= CalculateConfigStringLen (StringPtr
);
852 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
853 if (ConfigResp
== NULL
) {
854 return EFI_OUT_OF_RESOURCES
;
857 // Append '\0' to the end of ConfigRequest
859 *(ConfigResp
+ Length
) = 0;
862 // Get the UEFI device path
864 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
865 if (EFI_ERROR (Status
)) {
866 FreePool (ConfigResp
);
871 // Find driver handle by device path
874 TempDevicePath
= DevicePath
;
875 Status
= gBS
->LocateDevicePath (
876 &gEfiDevicePathProtocolGuid
,
880 FreePool (DevicePath
);
882 if (EFI_ERROR (Status
) || (DriverHandle
== NULL
)) {
884 // Cannot find any known driver.
885 // Set Progress to the 'G' in "GUID" of the routing header.
887 *Progress
= StringPtr
;
888 FreePool (ConfigResp
);
889 return EFI_NOT_FOUND
;
893 // Call corresponding ConfigAccess protocol to route settings
895 Status
= gBS
->HandleProtocol (
897 &gEfiHiiConfigAccessProtocolGuid
,
898 (VOID
**) &ConfigAccess
900 ASSERT_EFI_ERROR (Status
);
902 Status
= ConfigAccess
->RouteConfig (
908 if (EFI_ERROR (Status
)) {
910 // AccessProgress indicates the parsing progress on <ConfigResp>.
911 // Map it to the progress on <MultiConfigResp> then return it.
913 *Progress
= StrStr (StringPtr
, AccessProgress
);
915 FreePool (ConfigResp
);
919 FreePool (ConfigResp
);
923 // Go to next <ConfigResp> (skip '&').
926 if (*StringPtr
== 0) {
927 *Progress
= StringPtr
;
940 This helper function is to be called by drivers to map configuration data
941 stored in byte array ("block") formats such as UEFI Variables into current
942 configuration strings.
944 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
946 @param ConfigRequest A null-terminated Unicode string in
947 <ConfigRequest> format.
948 @param Block Array of bytes defining the block's configuration.
949 @param BlockSize Length in bytes of Block.
950 @param Config Filled-in configuration string. String allocated
951 by the function. Returned only if call is
953 @param Progress A pointer to a string filled in with the offset of
954 the most recent & before the first failing
955 name/value pair (or the beginning of the string if
956 the failure is in the first name / value pair) or
957 the terminating NULL if all was successful.
959 @retval EFI_SUCCESS The request succeeded. Progress points to the null
960 terminator at the end of the ConfigRequest
962 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
963 points to the first character of ConfigRequest.
964 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
965 Block parameter would result in this type of
966 error. Progress points to the first character of
968 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
969 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
970 Block is left updated and Progress points at
971 the "&" preceding the first non-<BlockName>.
977 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
978 IN CONST EFI_STRING ConfigRequest
,
979 IN CONST UINT8
*Block
,
980 IN CONST UINTN BlockSize
,
981 OUT EFI_STRING
*Config
,
982 OUT EFI_STRING
*Progress
985 EFI_STRING StringPtr
;
994 EFI_STRING ConfigElement
;
999 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1000 return EFI_INVALID_PARAMETER
;
1003 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1004 *Progress
= ConfigRequest
;
1005 return EFI_INVALID_PARAMETER
;
1008 StringPtr
= ConfigRequest
;
1011 ConfigElement
= NULL
;
1014 // Allocate a fix length of memory to store Results. Reallocate memory for
1015 // Results if this fix length is insufficient.
1017 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1018 if (*Config
== NULL
) {
1019 return EFI_OUT_OF_RESOURCES
;
1025 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1026 *Progress
= StringPtr
;
1027 Status
= EFI_INVALID_PARAMETER
;
1030 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1033 if (*StringPtr
== 0) {
1034 *Progress
= StringPtr
;
1035 Status
= EFI_INVALID_PARAMETER
;
1039 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1042 if (*StringPtr
== 0) {
1043 *Progress
= StringPtr
;
1044 Status
= EFI_INVALID_PARAMETER
;
1053 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1055 Length
= StringPtr
- ConfigRequest
;
1056 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1059 // Parse each <RequestElement> if exists
1060 // Only <BlockName> format is supported by this help function.
1061 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1063 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1065 // Back up the header of one <BlockName>
1069 StringPtr
+= StrLen (L
"OFFSET=");
1073 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1074 if (Status
== EFI_OUT_OF_RESOURCES
) {
1075 *Progress
= ConfigRequest
;
1082 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1084 FreePool (TmpBuffer
);
1086 StringPtr
+= Length
;
1087 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1088 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1089 Status
= EFI_INVALID_PARAMETER
;
1092 StringPtr
+= StrLen (L
"&WIDTH=");
1097 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1098 if (Status
== EFI_OUT_OF_RESOURCES
) {
1099 *Progress
= ConfigRequest
;
1106 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1108 FreePool (TmpBuffer
);
1110 StringPtr
+= Length
;
1111 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1112 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1113 Status
= EFI_INVALID_PARAMETER
;
1118 // Calculate Value and convert it to hex string.
1120 if (Offset
+ Width
> BlockSize
) {
1121 *Progress
= StringPtr
;
1122 Status
= EFI_DEVICE_ERROR
;
1126 Value
= (UINT8
*) AllocateZeroPool (Width
);
1127 if (Value
== NULL
) {
1128 *Progress
= ConfigRequest
;
1129 Status
= EFI_OUT_OF_RESOURCES
;
1133 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1135 Length
= Width
* 2 + 1;
1136 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1137 if (ValueStr
== NULL
) {
1138 *Progress
= ConfigRequest
;
1139 Status
= EFI_OUT_OF_RESOURCES
;
1143 TemString
= ValueStr
;
1144 TemBuffer
= Value
+ Width
- 1;
1145 for (Index
= 0; Index
< Width
; Index
++, TemBuffer
--) {
1146 TemString
+= UnicodeValueToString (TemString
, PREFIX_ZERO
| RADIX_HEX
, *TemBuffer
, 2);
1148 HiiToLower (ValueStr
);
1154 // Build a ConfigElement
1156 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1157 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1158 if (ConfigElement
== NULL
) {
1159 Status
= EFI_OUT_OF_RESOURCES
;
1162 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1163 if (*StringPtr
== 0) {
1164 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1166 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1167 StrCat (ConfigElement
, L
"VALUE=");
1168 StrCat (ConfigElement
, ValueStr
);
1170 AppendToMultiString (Config
, ConfigElement
);
1172 FreePool (ConfigElement
);
1173 FreePool (ValueStr
);
1174 ConfigElement
= NULL
;
1178 // If '\0', parsing is finished. Otherwise skip '&' to continue
1180 if (*StringPtr
== 0) {
1183 AppendToMultiString (Config
, L
"&");
1188 if (*StringPtr
!= 0) {
1189 *Progress
= StringPtr
- 1;
1190 Status
= EFI_INVALID_PARAMETER
;
1194 *Progress
= StringPtr
;
1199 if (ValueStr
!= NULL
) {
1200 FreePool (ValueStr
);
1202 if (Value
!= NULL
) {
1205 if (ConfigElement
!= NULL
) {
1206 FreePool (ConfigElement
);
1215 This helper function is to be called by drivers to map configuration strings
1216 to configurations stored in byte array ("block") formats such as UEFI Variables.
1218 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1220 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1222 @param Block A possibly null array of bytes representing the
1223 current block. Only bytes referenced in the
1224 ConfigResp string in the block are modified. If
1225 this parameter is null or if the *BlockSize
1226 parameter is (on input) shorter than required by
1227 the Configuration string, only the BlockSize
1228 parameter is updated and an appropriate status
1229 (see below) is returned.
1230 @param BlockSize The length of the Block in units of UINT8. On
1231 input, this is the size of the Block. On output,
1232 if successful, contains the index of the last
1233 modified byte in the Block.
1234 @param Progress On return, points to an element of the ConfigResp
1235 string filled in with the offset of the most
1236 recent '&' before the first failing name / value
1237 pair (or the beginning of the string if the
1238 failure is in the first name / value pair) or the
1239 terminating NULL if all was successful.
1241 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1242 terminator at the end of the ConfigResp string.
1243 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1244 points to the first character of ConfigResp.
1245 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1246 Block parameter would result in this type of
1247 error. Progress points to the first character of
1249 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1250 value pair. Block is left updated and
1251 Progress points at the '&' preceding the first
1258 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1259 IN CONST EFI_STRING ConfigResp
,
1260 IN OUT UINT8
*Block
,
1261 IN OUT UINTN
*BlockSize
,
1262 OUT EFI_STRING
*Progress
1265 HII_DATABASE_PRIVATE_DATA
*Private
;
1266 EFI_STRING StringPtr
;
1275 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1276 return EFI_INVALID_PARAMETER
;
1279 if (ConfigResp
== NULL
|| Block
== NULL
) {
1280 *Progress
= ConfigResp
;
1281 return EFI_INVALID_PARAMETER
;
1284 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1285 ASSERT (Private
!= NULL
);
1287 StringPtr
= ConfigResp
;
1288 BufferSize
= *BlockSize
;
1294 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1295 *Progress
= StringPtr
;
1296 Status
= EFI_INVALID_PARAMETER
;
1299 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1302 if (*StringPtr
== 0) {
1303 *Progress
= StringPtr
;
1304 Status
= EFI_INVALID_PARAMETER
;
1308 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1311 if (*StringPtr
== 0) {
1312 *Progress
= StringPtr
;
1313 Status
= EFI_INVALID_PARAMETER
;
1322 // Parse each <ConfigElement> if exists
1323 // Only <BlockConfig> format is supported by this help function.
1324 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1326 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1327 StringPtr
+= StrLen (L
"OFFSET=");
1331 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1332 if (EFI_ERROR (Status
)) {
1333 *Progress
= ConfigResp
;
1340 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1342 FreePool (TmpBuffer
);
1344 StringPtr
+= Length
;
1345 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1346 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1347 Status
= EFI_INVALID_PARAMETER
;
1350 StringPtr
+= StrLen (L
"&WIDTH=");
1355 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1356 if (Status
== EFI_OUT_OF_RESOURCES
) {
1357 *Progress
= ConfigResp
;
1364 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1366 FreePool (TmpBuffer
);
1368 StringPtr
+= Length
;
1369 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1370 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1371 Status
= EFI_INVALID_PARAMETER
;
1374 StringPtr
+= StrLen (L
"&VALUE=");
1379 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1380 if (EFI_ERROR (Status
)) {
1381 *Progress
= ConfigResp
;
1385 StringPtr
+= Length
;
1386 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1387 *Progress
= StringPtr
- Length
- 7;
1388 Status
= EFI_INVALID_PARAMETER
;
1393 // Update the Block with configuration info
1396 if (Offset
+ Width
> BufferSize
) {
1397 return EFI_DEVICE_ERROR
;
1400 CopyMem (Block
+ Offset
, Value
, Width
);
1401 *BlockSize
= Offset
+ Width
- 1;
1407 // If '\0', parsing is finished. Otherwise skip '&' to continue
1409 if (*StringPtr
== 0) {
1416 if (*StringPtr
!= 0) {
1417 *Progress
= StringPtr
- 1;
1418 Status
= EFI_INVALID_PARAMETER
;
1422 *Progress
= StringPtr
;
1427 if (Value
!= NULL
) {
1435 This helper function is to be called by drivers to extract portions of
1436 a larger configuration string.
1438 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1440 @param Configuration A null-terminated Unicode string in
1441 <MultiConfigAltResp> format.
1442 @param Guid A pointer to the GUID value to search for in the
1443 routing portion of the ConfigResp string when
1444 retrieving the requested data. If Guid is NULL,
1445 then all GUID values will be searched for.
1446 @param Name A pointer to the NAME value to search for in the
1447 routing portion of the ConfigResp string when
1448 retrieving the requested data. If Name is NULL,
1449 then all Name values will be searched for.
1450 @param DevicePath A pointer to the PATH value to search for in the
1451 routing portion of the ConfigResp string when
1452 retrieving the requested data. If DevicePath is
1453 NULL, then all DevicePath values will be searched
1455 @param AltCfgId A pointer to the ALTCFG value to search for in the
1456 routing portion of the ConfigResp string when
1457 retrieving the requested data. If this parameter
1458 is NULL, then the current setting will be
1460 @param AltCfgResp A pointer to a buffer which will be allocated by
1461 the function which contains the retrieved string
1462 as requested. This buffer is only allocated if
1463 the call was successful.
1465 @retval EFI_SUCCESS The request succeeded. The requested data was
1466 extracted and placed in the newly allocated
1468 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1469 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1470 @retval EFI_NOT_FOUND Target for the specified routing data was not
1477 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1478 IN CONST EFI_STRING Configuration
,
1479 IN CONST EFI_GUID
*Guid
,
1480 IN CONST EFI_STRING Name
,
1481 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1482 IN CONST UINT16
*AltCfgId
,
1483 OUT EFI_STRING
*AltCfgResp
1487 EFI_STRING StringPtr
;
1488 EFI_STRING HdrStart
;
1495 EFI_STRING AltIdStr
;
1512 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1513 return EFI_INVALID_PARAMETER
;
1516 StringPtr
= Configuration
;
1517 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1518 return EFI_INVALID_PARAMETER
;
1522 // Generate the sub string for later matching.
1524 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1527 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1528 (VOID
*) DevicePath
,
1532 if (AltCfgId
!= NULL
) {
1533 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1536 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1538 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1541 while (*StringPtr
!= 0) {
1543 // Try to match the GUID
1546 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1547 if (TmpPtr
== NULL
) {
1548 Status
= EFI_NOT_FOUND
;
1554 // Jump to <NameHdr>
1557 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1559 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1560 if (StringPtr
== NULL
) {
1561 Status
= EFI_NOT_FOUND
;
1569 // Try to match the NAME
1571 if (GuidFlag
&& !NameFlag
) {
1572 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1576 // Jump to <PathHdr>
1579 StringPtr
+= StrLen (NameStr
);
1581 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1582 if (StringPtr
== NULL
) {
1583 Status
= EFI_NOT_FOUND
;
1592 // Try to match the DevicePath
1594 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1595 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1600 // Jump to '&' before <DescHdr> or <ConfigBody>
1602 if (DevicePath
!= NULL
) {
1603 StringPtr
+= StrLen (PathStr
);
1605 StringPtr
= StrStr (StringPtr
, L
"&");
1606 if (StringPtr
== NULL
) {
1607 Status
= EFI_NOT_FOUND
;
1612 HdrEnd
= ++StringPtr
;
1617 // Try to match the AltCfgId
1619 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1620 if (AltCfgId
== NULL
) {
1622 // Return Current Setting when AltCfgId is NULL.
1624 Status
= OutputConfigBody (StringPtr
, &Result
);
1628 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1630 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1635 Status
= OutputConfigBody (StringPtr
, &Result
);
1641 Status
= EFI_NOT_FOUND
;
1645 if (!EFI_ERROR (Status
) && (Result
!= NULL
)) {
1647 // Copy the <ConfigHdr> and <ConfigBody>
1649 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1650 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1651 if (*AltCfgResp
== NULL
) {
1652 Status
= EFI_OUT_OF_RESOURCES
;
1654 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1655 StrCat (*AltCfgResp
, Result
);
1656 Status
= EFI_SUCCESS
;
1660 if (GuidStr
!= NULL
) {
1663 if (NameStr
!= NULL
) {
1666 if (PathStr
!= NULL
) {
1669 if (AltIdStr
!= NULL
) {
1670 FreePool (AltIdStr
);
1672 if (Result
!= NULL
) {