2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
4 Copyright (c) 2007 - 2008, 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 HII_DATABASE_PRIVATE_DATA
*Private
;
510 EFI_STRING StringPtr
;
511 EFI_STRING ConfigRequest
;
513 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
516 HII_DATABASE_RECORD
*Database
;
517 UINT8
*DevicePathPkg
;
518 UINT8
*CurrentDevicePath
;
519 EFI_HANDLE DriverHandle
;
520 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
521 EFI_STRING AccessProgress
;
522 EFI_STRING AccessResults
;
523 BOOLEAN FirstElement
;
525 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
526 return EFI_INVALID_PARAMETER
;
529 if (Request
== NULL
) {
531 return EFI_INVALID_PARAMETER
;
534 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
536 *Progress
= StringPtr
;
539 // The first element of <MultiConfigRequest> should be
540 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
542 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
543 return EFI_INVALID_PARAMETER
;
549 // Allocate a fix length of memory to store Results. Reallocate memory for
550 // Results if this fix length is insufficient.
552 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
553 if (*Results
== NULL
) {
554 return EFI_OUT_OF_RESOURCES
;
557 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
559 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
560 // or most recent & before the error.
562 if (StringPtr
== Request
) {
563 *Progress
= StringPtr
;
565 *Progress
= StringPtr
- 1;
569 // Process each <ConfigRequest> of <MultiConfigRequest>
571 Length
= CalculateConfigStringLen (StringPtr
);
572 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
573 if (ConfigRequest
== NULL
) {
574 return EFI_OUT_OF_RESOURCES
;
576 *(ConfigRequest
+ Length
) = 0;
579 // Get the UEFI device path
581 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
582 if (EFI_ERROR (Status
)) {
583 FreePool (ConfigRequest
);
588 // Find driver which matches the routing data.
591 for (Link
= Private
->DatabaseList
.ForwardLink
;
592 Link
!= &Private
->DatabaseList
;
593 Link
= Link
->ForwardLink
595 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
597 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
598 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
602 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
604 DriverHandle
= Database
->DriverHandle
;
610 FreePool (DevicePath
);
612 if (DriverHandle
== NULL
) {
614 // Routing data does not match any known driver.
615 // Set Progress to the 'G' in "GUID" of the routing header.
617 *Progress
= StringPtr
;
618 FreePool (ConfigRequest
);
619 return EFI_NOT_FOUND
;
623 // Call corresponding ConfigAccess protocol to extract settings
625 Status
= gBS
->HandleProtocol (
627 &gEfiHiiConfigAccessProtocolGuid
,
628 (VOID
**) &ConfigAccess
630 ASSERT_EFI_ERROR (Status
);
632 Status
= ConfigAccess
->ExtractConfig (
638 if (EFI_ERROR (Status
)) {
640 // AccessProgress indicates the parsing progress on <ConfigRequest>.
641 // Map it to the progress on <MultiConfigRequest> then return it.
643 *Progress
= StrStr (StringPtr
, AccessProgress
);
644 FreePool (ConfigRequest
);
649 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
650 // which seperates the first <ConfigAltResp> and the following ones.
652 ASSERT (*AccessProgress
== 0);
655 Status
= AppendToMultiString (Results
, L
"&");
656 ASSERT_EFI_ERROR (Status
);
659 Status
= AppendToMultiString (Results
, AccessResults
);
660 ASSERT_EFI_ERROR (Status
);
662 FirstElement
= FALSE
;
664 FreePool (AccessResults
);
665 AccessResults
= NULL
;
666 FreePool (ConfigRequest
);
667 ConfigRequest
= NULL
;
670 // Go to next <ConfigRequest> (skip '&').
673 if (*StringPtr
== 0) {
674 *Progress
= StringPtr
;
688 This function allows the caller to request the current configuration for the
689 entirety of the current HII database and returns the data in a
690 null-terminated Unicode string.
692 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
694 @param Results Null-terminated Unicode string in
695 <MultiConfigAltResp> format which has all values
696 filled in for the names in the Request string.
697 String to be allocated by the called function.
698 De-allocation is up to the caller.
700 @retval EFI_SUCCESS The Results string is filled with the values
701 corresponding to all requested names.
702 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
703 results that must be stored awaiting possible
705 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
706 parameter would result in this type of error.
711 HiiConfigRoutingExportConfig (
712 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
713 OUT EFI_STRING
*Results
717 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
718 EFI_STRING AccessResults
;
720 EFI_HANDLE
*ConfigAccessHandles
;
721 UINTN NumberConfigAccessHandles
;
722 BOOLEAN FirstElement
;
724 if (This
== NULL
|| Results
== NULL
) {
725 return EFI_INVALID_PARAMETER
;
729 // Allocate a fix length of memory to store Results. Reallocate memory for
730 // Results if this fix length is insufficient.
732 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
733 if (*Results
== NULL
) {
734 return EFI_OUT_OF_RESOURCES
;
737 NumberConfigAccessHandles
= 0;
738 Status
= gBS
->LocateHandleBuffer (
740 &gEfiHiiConfigAccessProtocolGuid
,
742 &NumberConfigAccessHandles
,
745 if (EFI_ERROR (Status
)) {
751 for (Index
= 0; Index
< NumberConfigAccessHandles
; Index
++) {
752 Status
= gBS
->HandleProtocol (
753 ConfigAccessHandles
[Index
],
754 &gEfiHiiConfigAccessProtocolGuid
,
755 (VOID
**) &ConfigAccess
757 if (EFI_ERROR (Status
)) {
761 Status
= ConfigAccess
->ExtractConfig (
767 if (!EFI_ERROR (Status
)) {
769 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
770 // which seperates the first <ConfigAltResp> and the following ones.
773 Status
= AppendToMultiString (Results
, L
"&");
774 ASSERT_EFI_ERROR (Status
);
777 Status
= AppendToMultiString (Results
, AccessResults
);
778 ASSERT_EFI_ERROR (Status
);
780 FirstElement
= FALSE
;
782 FreePool (AccessResults
);
783 AccessResults
= NULL
;
786 FreePool (ConfigAccessHandles
);
793 This function processes the results of processing forms and routes it to the
794 appropriate handlers or storage.
796 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
798 @param Configuration A null-terminated Unicode string in
799 <MulltiConfigResp> format.
800 @param Progress A pointer to a string filled in with the offset of
801 the most recent & before the first failing name /
802 value pair (or the beginning of the string if the
803 failure is in the first name / value pair) or the
804 terminating NULL if all was successful.
806 @retval EFI_SUCCESS The results have been distributed or are awaiting
808 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
809 results that must be stored awaiting possible
811 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
812 would result in this type of error.
813 @retval EFI_NOT_FOUND Target for the specified routing data was not
819 HiiConfigRoutingRouteConfig (
820 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
821 IN CONST EFI_STRING Configuration
,
822 OUT EFI_STRING
*Progress
825 HII_DATABASE_PRIVATE_DATA
*Private
;
826 EFI_STRING StringPtr
;
827 EFI_STRING ConfigResp
;
830 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
832 HII_DATABASE_RECORD
*Database
;
833 UINT8
*DevicePathPkg
;
834 UINT8
*CurrentDevicePath
;
835 EFI_HANDLE DriverHandle
;
836 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
837 EFI_STRING AccessProgress
;
839 if (This
== NULL
|| Progress
== NULL
) {
840 return EFI_INVALID_PARAMETER
;
843 if (Configuration
== NULL
) {
845 return EFI_INVALID_PARAMETER
;
848 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
849 StringPtr
= Configuration
;
850 *Progress
= StringPtr
;
853 // The first element of <MultiConfigResp> should be
854 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
856 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
857 return EFI_INVALID_PARAMETER
;
860 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
862 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
863 // or most recent & before the error.
865 if (StringPtr
== Configuration
) {
866 *Progress
= StringPtr
;
868 *Progress
= StringPtr
- 1;
872 // Process each <ConfigResp> of <MultiConfigResp>
874 Length
= CalculateConfigStringLen (StringPtr
);
875 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
876 if (ConfigResp
== NULL
) {
877 return EFI_OUT_OF_RESOURCES
;
880 // Append '\0' to the end of ConfigRequest
882 *(ConfigResp
+ Length
) = 0;
885 // Get the UEFI device path
887 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
888 if (EFI_ERROR (Status
)) {
889 FreePool (ConfigResp
);
894 // Find driver which matches the routing data.
897 for (Link
= Private
->DatabaseList
.ForwardLink
;
898 Link
!= &Private
->DatabaseList
;
899 Link
= Link
->ForwardLink
901 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
903 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
904 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
908 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
910 DriverHandle
= Database
->DriverHandle
;
916 FreePool (DevicePath
);
918 if (DriverHandle
== NULL
) {
920 // Routing data does not match any known driver.
921 // Set Progress to the 'G' in "GUID" of the routing header.
923 *Progress
= StringPtr
;
924 FreePool (ConfigResp
);
925 return EFI_NOT_FOUND
;
929 // Call corresponding ConfigAccess protocol to route settings
931 Status
= gBS
->HandleProtocol (
933 &gEfiHiiConfigAccessProtocolGuid
,
934 (VOID
**) &ConfigAccess
936 ASSERT_EFI_ERROR (Status
);
938 Status
= ConfigAccess
->RouteConfig (
944 if (EFI_ERROR (Status
)) {
946 // AccessProgress indicates the parsing progress on <ConfigResp>.
947 // Map it to the progress on <MultiConfigResp> then return it.
949 *Progress
= StrStr (StringPtr
, AccessProgress
);
951 FreePool (ConfigResp
);
955 FreePool (ConfigResp
);
959 // Go to next <ConfigResp> (skip '&').
962 if (*StringPtr
== 0) {
963 *Progress
= StringPtr
;
976 This helper function is to be called by drivers to map configuration data
977 stored in byte array ("block") formats such as UEFI Variables into current
978 configuration strings.
980 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
982 @param ConfigRequest A null-terminated Unicode string in
983 <ConfigRequest> format.
984 @param Block Array of bytes defining the block's configuration.
985 @param BlockSize Length in bytes of Block.
986 @param Config Filled-in configuration string. String allocated
987 by the function. Returned only if call is
989 @param Progress A pointer to a string filled in with the offset of
990 the most recent & before the first failing
991 name/value pair (or the beginning of the string if
992 the failure is in the first name / value pair) or
993 the terminating NULL if all was successful.
995 @retval EFI_SUCCESS The request succeeded. Progress points to the null
996 terminator at the end of the ConfigRequest
998 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
999 points to the first character of ConfigRequest.
1000 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1001 Block parameter would result in this type of
1002 error. Progress points to the first character of
1004 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1005 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1006 Block is left updated and Progress points at
1007 the "&" preceding the first non-<BlockName>.
1013 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1014 IN CONST EFI_STRING ConfigRequest
,
1015 IN CONST UINT8
*Block
,
1016 IN CONST UINTN BlockSize
,
1017 OUT EFI_STRING
*Config
,
1018 OUT EFI_STRING
*Progress
1021 HII_DATABASE_PRIVATE_DATA
*Private
;
1022 EFI_STRING StringPtr
;
1030 EFI_STRING ValueStr
;
1031 EFI_STRING ConfigElement
;
1036 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1037 return EFI_INVALID_PARAMETER
;
1040 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1041 *Progress
= ConfigRequest
;
1042 return EFI_INVALID_PARAMETER
;
1046 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1047 ASSERT (Private
!= NULL
);
1049 StringPtr
= ConfigRequest
;
1052 ConfigElement
= NULL
;
1055 // Allocate a fix length of memory to store Results. Reallocate memory for
1056 // Results if this fix length is insufficient.
1058 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1059 if (*Config
== NULL
) {
1060 return EFI_OUT_OF_RESOURCES
;
1066 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1067 *Progress
= StringPtr
;
1068 Status
= EFI_INVALID_PARAMETER
;
1071 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1074 if (*StringPtr
== 0) {
1075 *Progress
= StringPtr
;
1076 Status
= EFI_INVALID_PARAMETER
;
1080 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1083 if (*StringPtr
== 0) {
1084 *Progress
= StringPtr
;
1085 Status
= EFI_INVALID_PARAMETER
;
1094 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1096 Length
= StringPtr
- ConfigRequest
;
1097 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1100 // Parse each <RequestElement> if exists
1101 // Only <BlockName> format is supported by this help function.
1102 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1104 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1106 // Back up the header of one <BlockName>
1110 StringPtr
+= StrLen (L
"OFFSET=");
1114 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1115 if (Status
== EFI_OUT_OF_RESOURCES
) {
1116 *Progress
= ConfigRequest
;
1123 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1125 FreePool (TmpBuffer
);
1127 StringPtr
+= Length
;
1128 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1129 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1130 Status
= EFI_INVALID_PARAMETER
;
1133 StringPtr
+= StrLen (L
"&WIDTH=");
1138 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1139 if (Status
== EFI_OUT_OF_RESOURCES
) {
1140 *Progress
= ConfigRequest
;
1147 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1149 FreePool (TmpBuffer
);
1151 StringPtr
+= Length
;
1152 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1153 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1154 Status
= EFI_INVALID_PARAMETER
;
1159 // Calculate Value and convert it to hex string.
1161 if (Offset
+ Width
> BlockSize
) {
1162 *Progress
= StringPtr
;
1163 Status
= EFI_DEVICE_ERROR
;
1167 Value
= (UINT8
*) AllocateZeroPool (Width
);
1168 if (Value
== NULL
) {
1169 *Progress
= ConfigRequest
;
1170 Status
= EFI_OUT_OF_RESOURCES
;
1174 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1176 Length
= Width
* 2 + 1;
1177 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1178 if (ValueStr
== NULL
) {
1179 *Progress
= ConfigRequest
;
1180 Status
= EFI_OUT_OF_RESOURCES
;
1184 TemString
= ValueStr
;
1185 TemBuffer
= Value
+ Width
- 1;
1186 for (Index
= 0; Index
< Width
; Index
++, TemBuffer
--) {
1187 TemString
+= UnicodeValueToString (TemString
, PREFIX_ZERO
| RADIX_HEX
, *TemBuffer
, 2);
1189 HiiToLower (ValueStr
);
1195 // Build a ConfigElement
1197 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1198 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1199 if (ConfigElement
== NULL
) {
1200 Status
= EFI_OUT_OF_RESOURCES
;
1203 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1204 if (*StringPtr
== 0) {
1205 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1207 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1208 StrCat (ConfigElement
, L
"VALUE=");
1209 StrCat (ConfigElement
, ValueStr
);
1211 AppendToMultiString (Config
, ConfigElement
);
1213 FreePool (ConfigElement
);
1214 FreePool (ValueStr
);
1215 ConfigElement
= NULL
;
1219 // If '\0', parsing is finished. Otherwise skip '&' to continue
1221 if (*StringPtr
== 0) {
1224 AppendToMultiString (Config
, L
"&");
1229 if (*StringPtr
!= 0) {
1230 *Progress
= StringPtr
- 1;
1231 Status
= EFI_INVALID_PARAMETER
;
1235 *Progress
= StringPtr
;
1240 if (ValueStr
!= NULL
) {
1241 FreePool (ValueStr
);
1243 if (Value
!= NULL
) {
1246 if (ConfigElement
!= NULL
) {
1247 FreePool (ConfigElement
);
1256 This helper function is to be called by drivers to map configuration strings
1257 to configurations stored in byte array ("block") formats such as UEFI Variables.
1259 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1261 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1263 @param Block A possibly null array of bytes representing the
1264 current block. Only bytes referenced in the
1265 ConfigResp string in the block are modified. If
1266 this parameter is null or if the *BlockSize
1267 parameter is (on input) shorter than required by
1268 the Configuration string, only the BlockSize
1269 parameter is updated and an appropriate status
1270 (see below) is returned.
1271 @param BlockSize The length of the Block in units of UINT8. On
1272 input, this is the size of the Block. On output,
1273 if successful, contains the index of the last
1274 modified byte in the Block.
1275 @param Progress On return, points to an element of the ConfigResp
1276 string filled in with the offset of the most
1277 recent '&' before the first failing name / value
1278 pair (or the beginning of the string if the
1279 failure is in the first name / value pair) or the
1280 terminating NULL if all was successful.
1282 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1283 terminator at the end of the ConfigResp string.
1284 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1285 points to the first character of ConfigResp.
1286 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1287 Block parameter would result in this type of
1288 error. Progress points to the first character of
1290 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1291 value pair. Block is left updated and
1292 Progress points at the '&' preceding the first
1299 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1300 IN CONST EFI_STRING ConfigResp
,
1301 IN OUT UINT8
*Block
,
1302 IN OUT UINTN
*BlockSize
,
1303 OUT EFI_STRING
*Progress
1306 HII_DATABASE_PRIVATE_DATA
*Private
;
1307 EFI_STRING StringPtr
;
1316 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1317 return EFI_INVALID_PARAMETER
;
1320 if (ConfigResp
== NULL
|| Block
== NULL
) {
1321 *Progress
= ConfigResp
;
1322 return EFI_INVALID_PARAMETER
;
1325 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1326 ASSERT (Private
!= NULL
);
1328 StringPtr
= ConfigResp
;
1329 BufferSize
= *BlockSize
;
1335 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1336 *Progress
= StringPtr
;
1337 Status
= EFI_INVALID_PARAMETER
;
1340 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1343 if (*StringPtr
== 0) {
1344 *Progress
= StringPtr
;
1345 Status
= EFI_INVALID_PARAMETER
;
1349 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1352 if (*StringPtr
== 0) {
1353 *Progress
= StringPtr
;
1354 Status
= EFI_INVALID_PARAMETER
;
1363 // Parse each <ConfigElement> if exists
1364 // Only <BlockConfig> format is supported by this help function.
1365 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1367 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1368 StringPtr
+= StrLen (L
"OFFSET=");
1372 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1373 if (EFI_ERROR (Status
)) {
1374 *Progress
= ConfigResp
;
1381 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1383 FreePool (TmpBuffer
);
1385 StringPtr
+= Length
;
1386 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1387 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1388 Status
= EFI_INVALID_PARAMETER
;
1391 StringPtr
+= StrLen (L
"&WIDTH=");
1396 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1397 if (Status
== EFI_OUT_OF_RESOURCES
) {
1398 *Progress
= ConfigResp
;
1405 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1407 FreePool (TmpBuffer
);
1409 StringPtr
+= Length
;
1410 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1411 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1412 Status
= EFI_INVALID_PARAMETER
;
1415 StringPtr
+= StrLen (L
"&VALUE=");
1420 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1421 if (EFI_ERROR (Status
)) {
1422 *Progress
= ConfigResp
;
1426 StringPtr
+= Length
;
1427 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1428 *Progress
= StringPtr
- Length
- 7;
1429 Status
= EFI_INVALID_PARAMETER
;
1434 // Update the Block with configuration info
1437 if (Offset
+ Width
> BufferSize
) {
1438 return EFI_DEVICE_ERROR
;
1441 CopyMem (Block
+ Offset
, Value
, Width
);
1442 *BlockSize
= Offset
+ Width
- 1;
1448 // If '\0', parsing is finished. Otherwise skip '&' to continue
1450 if (*StringPtr
== 0) {
1457 if (*StringPtr
!= 0) {
1458 *Progress
= StringPtr
- 1;
1459 Status
= EFI_INVALID_PARAMETER
;
1463 *Progress
= StringPtr
;
1468 if (Value
!= NULL
) {
1476 This helper function is to be called by drivers to extract portions of
1477 a larger configuration string.
1479 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1481 @param Configuration A null-terminated Unicode string in
1482 <MultiConfigAltResp> format.
1483 @param Guid A pointer to the GUID value to search for in the
1484 routing portion of the ConfigResp string when
1485 retrieving the requested data. If Guid is NULL,
1486 then all GUID values will be searched for.
1487 @param Name A pointer to the NAME value to search for in the
1488 routing portion of the ConfigResp string when
1489 retrieving the requested data. If Name is NULL,
1490 then all Name values will be searched for.
1491 @param DevicePath A pointer to the PATH value to search for in the
1492 routing portion of the ConfigResp string when
1493 retrieving the requested data. If DevicePath is
1494 NULL, then all DevicePath values will be searched
1496 @param AltCfgId A pointer to the ALTCFG value to search for in the
1497 routing portion of the ConfigResp string when
1498 retrieving the requested data. If this parameter
1499 is NULL, then the current setting will be
1501 @param AltCfgResp A pointer to a buffer which will be allocated by
1502 the function which contains the retrieved string
1503 as requested. This buffer is only allocated if
1504 the call was successful.
1506 @retval EFI_SUCCESS The request succeeded. The requested data was
1507 extracted and placed in the newly allocated
1509 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1510 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1511 @retval EFI_NOT_FOUND Target for the specified routing data was not
1518 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1519 IN CONST EFI_STRING Configuration
,
1520 IN CONST EFI_GUID
*Guid
,
1521 IN CONST EFI_STRING Name
,
1522 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1523 IN CONST UINT16
*AltCfgId
,
1524 OUT EFI_STRING
*AltCfgResp
1528 EFI_STRING StringPtr
;
1529 EFI_STRING HdrStart
;
1536 EFI_STRING AltIdStr
;
1553 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1554 return EFI_INVALID_PARAMETER
;
1557 StringPtr
= Configuration
;
1558 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1559 return EFI_INVALID_PARAMETER
;
1563 // Generate the sub string for later matching.
1565 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1568 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1569 (VOID
*) DevicePath
,
1573 if (AltCfgId
!= NULL
) {
1574 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1577 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1579 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1582 while (*StringPtr
!= 0) {
1584 // Try to match the GUID
1587 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1588 if (TmpPtr
== NULL
) {
1589 Status
= EFI_NOT_FOUND
;
1595 // Jump to <NameHdr>
1598 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1600 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1601 if (StringPtr
== NULL
) {
1602 Status
= EFI_NOT_FOUND
;
1610 // Try to match the NAME
1612 if (GuidFlag
&& !NameFlag
) {
1613 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1617 // Jump to <PathHdr>
1620 StringPtr
+= StrLen (NameStr
);
1622 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1623 if (StringPtr
== NULL
) {
1624 Status
= EFI_NOT_FOUND
;
1633 // Try to match the DevicePath
1635 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1636 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1641 // Jump to '&' before <DescHdr> or <ConfigBody>
1643 if (DevicePath
!= NULL
) {
1644 StringPtr
+= StrLen (PathStr
);
1646 StringPtr
= StrStr (StringPtr
, L
"&");
1647 if (StringPtr
== NULL
) {
1648 Status
= EFI_NOT_FOUND
;
1653 HdrEnd
= ++StringPtr
;
1658 // Try to match the AltCfgId
1660 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1661 if (AltCfgId
== NULL
) {
1663 // Return Current Setting when AltCfgId is NULL.
1665 Status
= OutputConfigBody (StringPtr
, &Result
);
1669 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1671 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1676 Status
= OutputConfigBody (StringPtr
, &Result
);
1682 Status
= EFI_NOT_FOUND
;
1686 if (!EFI_ERROR (Status
) && (Result
!= NULL
)) {
1688 // Copy the <ConfigHdr> and <ConfigBody>
1690 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1691 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1692 if (*AltCfgResp
== NULL
) {
1693 Status
= EFI_OUT_OF_RESOURCES
;
1695 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1696 StrCat (*AltCfgResp
, Result
);
1697 Status
= EFI_SUCCESS
;
1701 if (GuidStr
!= NULL
) {
1704 if (NameStr
!= NULL
) {
1707 if (PathStr
!= NULL
) {
1710 if (AltIdStr
!= NULL
) {
1711 FreePool (AltIdStr
);
1713 if (Result
!= NULL
) {