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
;
84 if (String
== NULL
|| DevicePath
== NULL
) {
85 return EFI_INVALID_PARAMETER
;
89 // Find the 'PATH=' of <PathHdr> and skip it.
91 for (; (*String
!= 0 && StrnCmp (String
, L
"PATH=", StrLen (L
"PATH=")) != 0); String
++);
93 return EFI_INVALID_PARAMETER
;
96 String
+= StrLen (L
"PATH=");
100 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
101 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
102 // of UEFI device path.
104 for (Length
= 0; *String
!= 0 && *String
!= L
'&'; String
++, Length
++);
105 DevicePathString
= (EFI_STRING
) AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
106 if (DevicePathString
== NULL
) {
107 return EFI_OUT_OF_RESOURCES
;
109 StrnCpy (DevicePathString
, PathHdr
, Length
);
110 *(DevicePathString
+ Length
) = 0;
113 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
114 // as the device path resides in RAM memory.
115 // Translate the data into binary.
118 *DevicePath
= (UINT8
*) AllocateZeroPool (Length
);
119 if (*DevicePath
== NULL
) {
120 FreePool (DevicePathString
);
121 return EFI_OUT_OF_RESOURCES
;
124 HexStringToBufInReverseOrder (*DevicePath
, &Length
, DevicePathString
);
126 FreePool (DevicePathString
);
134 Generate a sub string then output it.
136 This is a internal function.
138 @param String A constant string which is the prefix of the to be
139 generated string, e.g. GUID=
140 @param BufferLen The length of the Buffer in bytes.
141 @param Buffer Points to a buffer which will be converted to be the
142 content of the generated string.
143 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
144 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
145 if 3, the buffer contains other data.
146 @param SubStr Points to the output string. It's caller's
147 responsibility to free this buffer.
153 IN CONST EFI_STRING String
,
157 OUT EFI_STRING
*SubStr
163 EFI_STRING StringHeader
;
165 ASSERT (String
!= NULL
&& SubStr
!= NULL
);
167 if (Buffer
== NULL
) {
168 *SubStr
= AllocateCopyPool (StrSize (String
), String
);
169 ASSERT (*SubStr
!= NULL
);
173 Length
= StrLen (String
) + BufferLen
* 2 + 1 + 1;
174 Str
= AllocateZeroPool (Length
* sizeof (CHAR16
));
175 ASSERT (Str
!= NULL
);
177 StrCpy (Str
, String
);
178 Length
= (BufferLen
* 2 + 1) * sizeof (CHAR16
);
180 Status
= EFI_SUCCESS
;
181 StringHeader
= Str
+ StrLen (String
);
185 Status
= BufInReverseOrderToHexString (StringHeader
, (UINT8
*) Buffer
, BufferLen
);
188 Status
= UnicodeToConfigString (StringHeader
, &Length
, (CHAR16
*) Buffer
);
191 Status
= BufToHexString (StringHeader
, &Length
, (UINT8
*) Buffer
, BufferLen
);
193 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
195 ToLower (StringHeader
);
201 ASSERT_EFI_ERROR (Status
);
209 Retrieve the <ConfigBody> from String then output it.
211 This is a internal function.
213 @param String A sub string of a configuration string in
214 <MultiConfigAltResp> format.
215 @param ConfigBody Points to the output string. It's caller's
216 responsibility to free this buffer.
218 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
219 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
220 @retval EFI_SUCCESS All existing storage is exported.
225 IN EFI_STRING String
,
226 OUT EFI_STRING
*ConfigBody
233 if (String
== NULL
|| ConfigBody
== NULL
) {
234 return EFI_INVALID_PARAMETER
;
237 TmpPtr
= StrStr (String
, L
"GUID=");
238 if (TmpPtr
== NULL
) {
240 // It is the last <ConfigResp> of the incoming configuration string.
242 Result
= AllocateCopyPool (StrSize (String
), String
);
243 if (Result
== NULL
) {
244 return EFI_OUT_OF_RESOURCES
;
246 *ConfigBody
= Result
;
251 Length
= TmpPtr
- String
;
252 Result
= AllocateCopyPool (Length
* sizeof (CHAR16
), String
);
253 if (Result
== NULL
) {
254 return EFI_OUT_OF_RESOURCES
;
257 *(Result
+ Length
- 1) = 0;
258 *ConfigBody
= Result
;
264 Append a string to a multi-string format.
266 This is a internal function.
268 @param MultiString String in <MultiConfigRequest>,
269 <MultiConfigAltResp>, or <MultiConfigResp>. On
270 input, the buffer length of this string is
271 MAX_STRING_LENGTH. On output, the buffer length
273 @param AppendString NULL-terminated Unicode string.
275 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
276 @retval EFI_SUCCESS AppendString is append to the end of MultiString
280 AppendToMultiString (
281 IN OUT EFI_STRING
*MultiString
,
282 IN EFI_STRING AppendString
285 UINTN AppendStringSize
;
286 UINTN MultiStringSize
;
288 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
289 return EFI_INVALID_PARAMETER
;
292 AppendStringSize
= StrSize (AppendString
);
293 MultiStringSize
= StrSize (*MultiString
);
296 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
298 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
299 MultiStringSize
> MAX_STRING_LENGTH
) {
300 *MultiString
= (EFI_STRING
) ReallocatePool (
302 MultiStringSize
+ AppendStringSize
,
303 (VOID
*) (*MultiString
)
305 ASSERT (*MultiString
!= NULL
);
308 // Append the incoming string
310 StrCat (*MultiString
, AppendString
);
317 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
319 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
321 This is a internal function.
323 @param StringPtr String in <BlockConfig> format and points to the
324 first character of <Number>.
325 @param Number The output value. Caller takes the responsibility
327 @param Len Length of the <Number>, in characters.
329 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
331 @retval EFI_SUCCESS Value of <Number> is outputted in Number
337 IN EFI_STRING StringPtr
,
348 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
349 ASSERT (*StringPtr
!= 0);
354 while (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
357 *Len
= StringPtr
- TmpPtr
;
360 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
362 Status
= EFI_OUT_OF_RESOURCES
;
365 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
368 Length
= (Length
+ 1) / 2;
369 Buf
= (UINT8
*) AllocateZeroPool (Length
);
371 Status
= EFI_OUT_OF_RESOURCES
;
375 Status
= HexStringToBuf (Buf
, &Length
, Str
, NULL
);
376 if (EFI_ERROR (Status
)) {
381 Status
= EFI_SUCCESS
;
392 This function allows a caller to extract the current configuration
393 for one or more named elements from one or more drivers.
395 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
397 @param Request A null-terminated Unicode string in
398 <MultiConfigRequest> format.
399 @param Progress On return, points to a character in the Request
400 string. Points to the string's null terminator if
401 request was successful. Points to the most recent
402 & before the first failing name / value pair (or
403 the beginning of the string if the failure is in
404 the first name / value pair) if the request was
406 @param Results Null-terminated Unicode string in
407 <MultiConfigAltResp> format which has all values
408 filled in for the names in the Request string.
409 String to be allocated by the called function.
411 @retval EFI_SUCCESS The Results string is filled with the values
412 corresponding to all requested names.
413 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
414 results that must be stored awaiting possible
416 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
417 Progress set to the "G" in "GUID" of the routing
418 header that doesn't match. Note: There is no
419 requirement that all routing data be validated
420 before any configuration extraction.
421 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
422 parameter would result in this type of error. The
423 Progress parameter is set to NULL.
424 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
425 before the error or the beginning of the string.
426 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
432 HiiConfigRoutingExtractConfig (
433 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
434 IN CONST EFI_STRING Request
,
435 OUT EFI_STRING
*Progress
,
436 OUT EFI_STRING
*Results
439 HII_DATABASE_PRIVATE_DATA
*Private
;
440 EFI_STRING StringPtr
;
441 EFI_STRING ConfigRequest
;
443 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
446 HII_DATABASE_RECORD
*Database
;
447 UINT8
*DevicePathPkg
;
448 UINT8
*CurrentDevicePath
;
449 EFI_HANDLE DriverHandle
;
450 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
451 EFI_STRING AccessProgress
;
452 EFI_STRING AccessResults
;
453 BOOLEAN FirstElement
;
456 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
457 // as FALSE. But this renders the system to not 100% compliant with
458 // UEFI 2.1. Use this with caution.
460 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
461 return EFI_UNSUPPORTED
;
464 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
465 return EFI_INVALID_PARAMETER
;
468 if (Request
== NULL
) {
470 return EFI_INVALID_PARAMETER
;
473 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
475 *Progress
= StringPtr
;
478 // The first element of <MultiConfigRequest> should be
479 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
481 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
482 return EFI_INVALID_PARAMETER
;
488 // Allocate a fix length of memory to store Results. Reallocate memory for
489 // Results if this fix length is insufficient.
491 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
492 if (*Results
== NULL
) {
493 return EFI_OUT_OF_RESOURCES
;
496 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
498 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
499 // or most recent & before the error.
501 if (StringPtr
== Request
) {
502 *Progress
= StringPtr
;
504 *Progress
= StringPtr
- 1;
508 // Process each <ConfigRequest> of <MultiConfigRequest>
510 Length
= CalculateConfigStringLen (StringPtr
);
511 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
512 if (ConfigRequest
== NULL
) {
513 return EFI_OUT_OF_RESOURCES
;
515 *(ConfigRequest
+ Length
) = 0;
518 // Get the UEFI device path
520 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
521 if (EFI_ERROR (Status
)) {
522 FreePool (ConfigRequest
);
527 // Find driver which matches the routing data.
530 for (Link
= Private
->DatabaseList
.ForwardLink
;
531 Link
!= &Private
->DatabaseList
;
532 Link
= Link
->ForwardLink
534 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
536 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
537 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
541 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
543 DriverHandle
= Database
->DriverHandle
;
549 FreePool (DevicePath
);
551 if (DriverHandle
== NULL
) {
553 // Routing data does not match any known driver.
554 // Set Progress to the 'G' in "GUID" of the routing header.
556 *Progress
= StringPtr
;
557 FreePool (ConfigRequest
);
558 return EFI_NOT_FOUND
;
562 // Call corresponding ConfigAccess protocol to extract settings
564 Status
= gBS
->HandleProtocol (
566 &gEfiHiiConfigAccessProtocolGuid
,
567 (VOID
**) &ConfigAccess
569 ASSERT_EFI_ERROR (Status
);
571 Status
= ConfigAccess
->ExtractConfig (
577 if (EFI_ERROR (Status
)) {
579 // AccessProgress indicates the parsing progress on <ConfigRequest>.
580 // Map it to the progress on <MultiConfigRequest> then return it.
582 *Progress
= StrStr (StringPtr
, AccessProgress
);
583 FreePool (ConfigRequest
);
588 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
589 // which seperates the first <ConfigAltResp> and the following ones.
591 ASSERT (*AccessProgress
== 0);
594 Status
= AppendToMultiString (Results
, L
"&");
595 ASSERT_EFI_ERROR (Status
);
598 Status
= AppendToMultiString (Results
, AccessResults
);
599 ASSERT_EFI_ERROR (Status
);
601 FirstElement
= FALSE
;
603 FreePool (AccessResults
);
604 AccessResults
= NULL
;
605 FreePool (ConfigRequest
);
606 ConfigRequest
= NULL
;
609 // Go to next <ConfigRequest> (skip '&').
612 if (*StringPtr
== 0) {
613 *Progress
= StringPtr
;
627 This function allows the caller to request the current configuration for the
628 entirety of the current HII database and returns the data in a
629 null-terminated Unicode string.
631 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
633 @param Results Null-terminated Unicode string in
634 <MultiConfigAltResp> format which has all values
635 filled in for the names in the Request string.
636 String to be allocated by the called function.
637 De-allocation is up to the caller.
639 @retval EFI_SUCCESS The Results string is filled with the values
640 corresponding to all requested names.
641 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
642 results that must be stored awaiting possible
644 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
645 parameter would result in this type of error.
650 HiiConfigRoutingExportConfig (
651 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
652 OUT EFI_STRING
*Results
656 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
657 EFI_STRING AccessResults
;
659 EFI_HANDLE
*ConfigAccessHandles
;
660 UINTN NumberConfigAccessHandles
;
661 BOOLEAN FirstElement
;
664 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
665 // as FALSE. But this renders the system to not 100% compliant with
666 // UEFI 2.1. Use this with caution.
668 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
669 return EFI_UNSUPPORTED
;
672 if (This
== NULL
|| Results
== NULL
) {
673 return EFI_INVALID_PARAMETER
;
677 // Allocate a fix length of memory to store Results. Reallocate memory for
678 // Results if this fix length is insufficient.
680 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
681 if (*Results
== NULL
) {
682 return EFI_OUT_OF_RESOURCES
;
685 NumberConfigAccessHandles
= 0;
686 Status
= gBS
->LocateHandleBuffer (
688 &gEfiHiiConfigAccessProtocolGuid
,
690 &NumberConfigAccessHandles
,
693 if (EFI_ERROR (Status
)) {
699 for (Index
= 0; Index
< NumberConfigAccessHandles
; Index
++) {
700 Status
= gBS
->HandleProtocol (
701 ConfigAccessHandles
[Index
],
702 &gEfiHiiConfigAccessProtocolGuid
,
703 (VOID
**) &ConfigAccess
705 if (EFI_ERROR (Status
)) {
709 Status
= ConfigAccess
->ExtractConfig (
715 if (!EFI_ERROR (Status
)) {
717 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
718 // which seperates the first <ConfigAltResp> and the following ones.
721 Status
= AppendToMultiString (Results
, L
"&");
722 ASSERT_EFI_ERROR (Status
);
725 Status
= AppendToMultiString (Results
, AccessResults
);
726 ASSERT_EFI_ERROR (Status
);
728 FirstElement
= FALSE
;
730 FreePool (AccessResults
);
731 AccessResults
= NULL
;
734 FreePool (ConfigAccessHandles
);
741 This function processes the results of processing forms and routes it to the
742 appropriate handlers or storage.
744 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
746 @param Configuration A null-terminated Unicode string in
747 <MulltiConfigResp> format.
748 @param Progress A pointer to a string filled in with the offset of
749 the most recent & before the first failing name /
750 value pair (or the beginning of the string if the
751 failure is in the first name / value pair) or the
752 terminating NULL if all was successful.
754 @retval EFI_SUCCESS The results have been distributed or are awaiting
756 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
757 results that must be stored awaiting possible
759 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
760 would result in this type of error.
761 @retval EFI_NOT_FOUND Target for the specified routing data was not
767 HiiConfigRoutingRouteConfig (
768 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
769 IN CONST EFI_STRING Configuration
,
770 OUT EFI_STRING
*Progress
773 HII_DATABASE_PRIVATE_DATA
*Private
;
774 EFI_STRING StringPtr
;
775 EFI_STRING ConfigResp
;
778 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
780 HII_DATABASE_RECORD
*Database
;
781 UINT8
*DevicePathPkg
;
782 UINT8
*CurrentDevicePath
;
783 EFI_HANDLE DriverHandle
;
784 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
785 EFI_STRING AccessProgress
;
788 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
789 // as FALSE. But this renders the system to not 100% compliant with
790 // UEFI 2.1. Use this with caution.
792 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
793 return EFI_UNSUPPORTED
;
796 if (This
== NULL
|| Progress
== NULL
) {
797 return EFI_INVALID_PARAMETER
;
800 if (Configuration
== NULL
) {
802 return EFI_INVALID_PARAMETER
;
805 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
806 StringPtr
= Configuration
;
807 *Progress
= StringPtr
;
810 // The first element of <MultiConfigResp> should be
811 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
813 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
814 return EFI_INVALID_PARAMETER
;
817 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
819 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
820 // or most recent & before the error.
822 if (StringPtr
== Configuration
) {
823 *Progress
= StringPtr
;
825 *Progress
= StringPtr
- 1;
829 // Process each <ConfigResp> of <MultiConfigResp>
831 Length
= CalculateConfigStringLen (StringPtr
);
832 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
833 if (ConfigResp
== NULL
) {
834 return EFI_OUT_OF_RESOURCES
;
837 // Append '\0' to the end of ConfigRequest
839 *(ConfigResp
+ Length
) = 0;
842 // Get the UEFI device path
844 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
845 if (EFI_ERROR (Status
)) {
846 FreePool (ConfigResp
);
851 // Find driver which matches the routing data.
854 for (Link
= Private
->DatabaseList
.ForwardLink
;
855 Link
!= &Private
->DatabaseList
;
856 Link
= Link
->ForwardLink
858 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
860 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
861 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
865 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
867 DriverHandle
= Database
->DriverHandle
;
873 FreePool (DevicePath
);
875 if (DriverHandle
== NULL
) {
877 // Routing data does not match any known driver.
878 // Set Progress to the 'G' in "GUID" of the routing header.
880 *Progress
= StringPtr
;
881 FreePool (ConfigResp
);
882 return EFI_NOT_FOUND
;
886 // Call corresponding ConfigAccess protocol to route settings
888 Status
= gBS
->HandleProtocol (
890 &gEfiHiiConfigAccessProtocolGuid
,
891 (VOID
**) &ConfigAccess
893 ASSERT_EFI_ERROR (Status
);
895 Status
= ConfigAccess
->RouteConfig (
901 if (EFI_ERROR (Status
)) {
903 // AccessProgress indicates the parsing progress on <ConfigResp>.
904 // Map it to the progress on <MultiConfigResp> then return it.
906 *Progress
= StrStr (StringPtr
, AccessProgress
);
908 FreePool (ConfigResp
);
912 FreePool (ConfigResp
);
916 // Go to next <ConfigResp> (skip '&').
919 if (*StringPtr
== 0) {
920 *Progress
= StringPtr
;
933 This helper function is to be called by drivers to map configuration data
934 stored in byte array ("block") formats such as UEFI Variables into current
935 configuration strings.
937 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
939 @param ConfigRequest A null-terminated Unicode string in
940 <ConfigRequest> format.
941 @param Block Array of bytes defining the block's configuration.
942 @param BlockSize Length in bytes of Block.
943 @param Config Filled-in configuration string. String allocated
944 by the function. Returned only if call is
946 @param Progress A pointer to a string filled in with the offset of
947 the most recent & before the first failing
948 name/value pair (or the beginning of the string if
949 the failure is in the first name / value pair) or
950 the terminating NULL if all was successful.
952 @retval EFI_SUCCESS The request succeeded. Progress points to the null
953 terminator at the end of the ConfigRequest
955 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
956 points to the first character of ConfigRequest.
957 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
958 Block parameter would result in this type of
959 error. Progress points to the first character of
961 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
962 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
963 Block is left updated and Progress points at
964 the "&" preceding the first non-<BlockName>.
970 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
971 IN CONST EFI_STRING ConfigRequest
,
972 IN CONST UINT8
*Block
,
973 IN CONST UINTN BlockSize
,
974 OUT EFI_STRING
*Config
,
975 OUT EFI_STRING
*Progress
978 HII_DATABASE_PRIVATE_DATA
*Private
;
979 EFI_STRING StringPtr
;
988 EFI_STRING ConfigElement
;
990 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
991 return EFI_INVALID_PARAMETER
;
994 if (Block
== NULL
|| ConfigRequest
== NULL
) {
995 *Progress
= ConfigRequest
;
996 return EFI_INVALID_PARAMETER
;
1000 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1001 ASSERT (Private
!= NULL
);
1003 StringPtr
= ConfigRequest
;
1006 ConfigElement
= NULL
;
1009 // Allocate a fix length of memory to store Results. Reallocate memory for
1010 // Results if this fix length is insufficient.
1012 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1013 if (*Config
== NULL
) {
1014 return EFI_OUT_OF_RESOURCES
;
1020 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1021 *Progress
= StringPtr
;
1022 Status
= EFI_INVALID_PARAMETER
;
1025 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1028 if (*StringPtr
== 0) {
1029 *Progress
= StringPtr
;
1030 Status
= EFI_INVALID_PARAMETER
;
1034 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1037 if (*StringPtr
== 0) {
1038 *Progress
= StringPtr
;
1039 Status
= EFI_INVALID_PARAMETER
;
1048 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1050 Length
= StringPtr
- ConfigRequest
;
1051 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1054 // Parse each <RequestElement> if exists
1055 // Only <BlockName> format is supported by this help function.
1056 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1058 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1060 // Back up the header of one <BlockName>
1064 StringPtr
+= StrLen (L
"OFFSET=");
1068 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1069 if (Status
== EFI_OUT_OF_RESOURCES
) {
1070 *Progress
= ConfigRequest
;
1077 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1079 FreePool (TmpBuffer
);
1081 StringPtr
+= Length
;
1082 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1083 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1084 Status
= EFI_INVALID_PARAMETER
;
1087 StringPtr
+= StrLen (L
"&WIDTH=");
1092 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1093 if (Status
== EFI_OUT_OF_RESOURCES
) {
1094 *Progress
= ConfigRequest
;
1101 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1103 FreePool (TmpBuffer
);
1105 StringPtr
+= Length
;
1106 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1107 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1108 Status
= EFI_INVALID_PARAMETER
;
1113 // Calculate Value and convert it to hex string.
1115 if (Offset
+ Width
> BlockSize
) {
1116 *Progress
= StringPtr
;
1117 Status
= EFI_DEVICE_ERROR
;
1121 Value
= (UINT8
*) AllocateZeroPool (Width
);
1122 if (Value
== NULL
) {
1123 *Progress
= ConfigRequest
;
1124 Status
= EFI_OUT_OF_RESOURCES
;
1128 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1130 Length
= Width
* 2 + 1;
1131 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1132 if (ValueStr
== NULL
) {
1133 *Progress
= ConfigRequest
;
1134 Status
= EFI_OUT_OF_RESOURCES
;
1138 Status
= BufToHexString (ValueStr
, &Length
, Value
, Width
);
1139 ASSERT_EFI_ERROR (Status
);
1146 // Build a ConfigElement
1148 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1149 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1150 if (ConfigElement
== NULL
) {
1151 Status
= EFI_OUT_OF_RESOURCES
;
1154 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1155 if (*StringPtr
== 0) {
1156 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1158 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1159 StrCat (ConfigElement
, L
"VALUE=");
1160 StrCat (ConfigElement
, ValueStr
);
1162 AppendToMultiString (Config
, ConfigElement
);
1164 FreePool (ConfigElement
);
1165 FreePool (ValueStr
);
1166 ConfigElement
= NULL
;
1170 // If '\0', parsing is finished. Otherwise skip '&' to continue
1172 if (*StringPtr
== 0) {
1175 AppendToMultiString (Config
, L
"&");
1180 if (*StringPtr
!= 0) {
1181 *Progress
= StringPtr
- 1;
1182 Status
= EFI_INVALID_PARAMETER
;
1186 *Progress
= StringPtr
;
1191 if (ValueStr
!= NULL
) {
1192 FreePool (ValueStr
);
1194 if (Value
!= NULL
) {
1197 if (ConfigElement
!= NULL
) {
1198 FreePool (ConfigElement
);
1207 This helper function is to be called by drivers to map configuration strings
1208 to configurations stored in byte array ("block") formats such as UEFI Variables.
1210 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1212 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1214 @param Block A possibly null array of bytes representing the
1215 current block. Only bytes referenced in the
1216 ConfigResp string in the block are modified. If
1217 this parameter is null or if the *BlockSize
1218 parameter is (on input) shorter than required by
1219 the Configuration string, only the BlockSize
1220 parameter is updated and an appropriate status
1221 (see below) is returned.
1222 @param BlockSize The length of the Block in units of UINT8. On
1223 input, this is the size of the Block. On output,
1224 if successful, contains the index of the last
1225 modified byte in the Block.
1226 @param Progress On return, points to an element of the ConfigResp
1227 string filled in with the offset of the most
1228 recent '&' before the first failing name / value
1229 pair (or the beginning of the string if the
1230 failure is in the first name / value pair) or the
1231 terminating NULL if all was successful.
1233 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1234 terminator at the end of the ConfigResp string.
1235 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1236 points to the first character of ConfigResp.
1237 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1238 Block parameter would result in this type of
1239 error. Progress points to the first character of
1241 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1242 value pair. Block is left updated and
1243 Progress points at the '&' preceding the first
1250 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1251 IN CONST EFI_STRING ConfigResp
,
1252 IN OUT UINT8
*Block
,
1253 IN OUT UINTN
*BlockSize
,
1254 OUT EFI_STRING
*Progress
1257 HII_DATABASE_PRIVATE_DATA
*Private
;
1258 EFI_STRING StringPtr
;
1267 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1268 return EFI_INVALID_PARAMETER
;
1271 if (ConfigResp
== NULL
|| Block
== NULL
) {
1272 *Progress
= ConfigResp
;
1273 return EFI_INVALID_PARAMETER
;
1276 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1277 ASSERT (Private
!= NULL
);
1279 StringPtr
= ConfigResp
;
1280 BufferSize
= *BlockSize
;
1286 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1287 *Progress
= StringPtr
;
1288 Status
= EFI_INVALID_PARAMETER
;
1291 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1294 if (*StringPtr
== 0) {
1295 *Progress
= StringPtr
;
1296 Status
= EFI_INVALID_PARAMETER
;
1300 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1303 if (*StringPtr
== 0) {
1304 *Progress
= StringPtr
;
1305 Status
= EFI_INVALID_PARAMETER
;
1314 // Parse each <ConfigElement> if exists
1315 // Only <BlockConfig> format is supported by this help function.
1316 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1318 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1319 StringPtr
+= StrLen (L
"OFFSET=");
1323 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1324 if (Status
== EFI_OUT_OF_RESOURCES
) {
1325 *Progress
= ConfigResp
;
1332 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1334 FreePool (TmpBuffer
);
1336 StringPtr
+= Length
;
1337 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1338 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1339 Status
= EFI_INVALID_PARAMETER
;
1342 StringPtr
+= StrLen (L
"&WIDTH=");
1347 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1348 if (Status
== EFI_OUT_OF_RESOURCES
) {
1349 *Progress
= ConfigResp
;
1356 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1358 FreePool (TmpBuffer
);
1360 StringPtr
+= Length
;
1361 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1362 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1363 Status
= EFI_INVALID_PARAMETER
;
1366 StringPtr
+= StrLen (L
"&VALUE=");
1371 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1372 if (Status
== EFI_OUT_OF_RESOURCES
) {
1373 *Progress
= ConfigResp
;
1377 StringPtr
+= Length
;
1378 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1379 *Progress
= StringPtr
- Length
- 7;
1380 Status
= EFI_INVALID_PARAMETER
;
1385 // Update the Block with configuration info
1388 if (Offset
+ Width
> BufferSize
) {
1389 return EFI_DEVICE_ERROR
;
1392 CopyMem (Block
+ Offset
, Value
, Width
);
1393 *BlockSize
= Offset
+ Width
- 1;
1399 // If '\0', parsing is finished. Otherwise skip '&' to continue
1401 if (*StringPtr
== 0) {
1408 if (*StringPtr
!= 0) {
1409 *Progress
= StringPtr
- 1;
1410 Status
= EFI_INVALID_PARAMETER
;
1414 *Progress
= StringPtr
;
1419 if (Value
!= NULL
) {
1427 This helper function is to be called by drivers to extract portions of
1428 a larger configuration string.
1430 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1432 @param Configuration A null-terminated Unicode string in
1433 <MultiConfigAltResp> format.
1434 @param Guid A pointer to the GUID value to search for in the
1435 routing portion of the ConfigResp string when
1436 retrieving the requested data. If Guid is NULL,
1437 then all GUID values will be searched for.
1438 @param Name A pointer to the NAME value to search for in the
1439 routing portion of the ConfigResp string when
1440 retrieving the requested data. If Name is NULL,
1441 then all Name values will be searched for.
1442 @param DevicePath A pointer to the PATH value to search for in the
1443 routing portion of the ConfigResp string when
1444 retrieving the requested data. If DevicePath is
1445 NULL, then all DevicePath values will be searched
1447 @param AltCfgId A pointer to the ALTCFG value to search for in the
1448 routing portion of the ConfigResp string when
1449 retrieving the requested data. If this parameter
1450 is NULL, then the current setting will be
1452 @param AltCfgResp A pointer to a buffer which will be allocated by
1453 the function which contains the retrieved string
1454 as requested. This buffer is only allocated if
1455 the call was successful.
1457 @retval EFI_SUCCESS The request succeeded. The requested data was
1458 extracted and placed in the newly allocated
1460 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1461 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1462 @retval EFI_NOT_FOUND Target for the specified routing data was not
1469 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1470 IN CONST EFI_STRING Configuration
,
1471 IN CONST EFI_GUID
*Guid
,
1472 IN CONST EFI_STRING Name
,
1473 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1474 IN CONST UINT16
*AltCfgId
,
1475 OUT EFI_STRING
*AltCfgResp
1479 EFI_STRING StringPtr
;
1480 EFI_STRING HdrStart
;
1487 EFI_STRING AltIdStr
;
1494 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1495 // as FALSE. But this renders the system to not 100% compliant with
1496 // UEFI 2.1. Use this with caution.
1498 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1499 return EFI_UNSUPPORTED
;
1513 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1514 return EFI_INVALID_PARAMETER
;
1517 StringPtr
= Configuration
;
1518 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1519 return EFI_INVALID_PARAMETER
;
1523 // Generate the sub string for later matching.
1525 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1528 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1529 (VOID
*) DevicePath
,
1533 if (AltCfgId
!= NULL
) {
1534 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1537 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1539 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1542 while (*StringPtr
!= 0) {
1544 // Try to match the GUID
1547 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1548 if (TmpPtr
== NULL
) {
1549 Status
= EFI_NOT_FOUND
;
1555 // Jump to <NameHdr>
1558 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1560 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1561 if (StringPtr
== NULL
) {
1562 Status
= EFI_NOT_FOUND
;
1570 // Try to match the NAME
1572 if (GuidFlag
&& !NameFlag
) {
1573 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1577 // Jump to <PathHdr>
1580 StringPtr
+= StrLen (NameStr
);
1582 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1583 if (StringPtr
== NULL
) {
1584 Status
= EFI_NOT_FOUND
;
1593 // Try to match the DevicePath
1595 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1596 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1601 // Jump to '&' before <DescHdr> or <ConfigBody>
1603 if (DevicePath
!= NULL
) {
1604 StringPtr
+= StrLen (PathStr
);
1606 StringPtr
= StrStr (StringPtr
, L
"&");
1607 if (StringPtr
== NULL
) {
1608 Status
= EFI_NOT_FOUND
;
1613 HdrEnd
= ++StringPtr
;
1618 // Try to match the AltCfgId
1620 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1621 if (AltCfgId
== NULL
) {
1623 // Return Current Setting when AltCfgId is NULL.
1625 Status
= OutputConfigBody (StringPtr
, &Result
);
1629 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1631 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1636 Status
= OutputConfigBody (StringPtr
, &Result
);
1642 Status
= EFI_NOT_FOUND
;
1646 if (!EFI_ERROR (Status
)) {
1648 // Copy the <ConfigHdr> and <ConfigBody>
1650 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1651 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1652 if (*AltCfgResp
== NULL
) {
1653 Status
= EFI_OUT_OF_RESOURCES
;
1655 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1656 StrCat (*AltCfgResp
, Result
);
1657 Status
= EFI_SUCCESS
;
1661 if (GuidStr
!= NULL
) {
1664 if (NameStr
!= NULL
) {
1667 if (PathStr
!= NULL
) {
1670 if (AltIdStr
!= NULL
) {
1671 FreePool (AltIdStr
);
1673 if (Result
!= NULL
) {