3 Copyright (c) 2007 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL.
26 #include "HiiDatabase.h"
29 Calculate the number of Unicode characters of the incoming Configuration string,
30 not including NULL terminator.
32 This is a internal function.
34 @param String String in <MultiConfigRequest> or
35 <MultiConfigResp> format.
37 @return The number of Unicode characters.
41 CalculateConfigStringLen (
48 // "GUID=" should be the first element of incoming string.
50 ASSERT (String
!= NULL
);
51 ASSERT (StrnCmp (String
, L
"GUID=", StrLen (L
"GUID=")) == 0);
53 Length
= StrLen (L
"GUID=");
57 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
58 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
60 while (*String
!= 0 && StrnCmp (String
, L
"&GUID=", StrLen (L
"&GUID=")) != 0) {
70 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
71 from <PathHdr> of <ConfigHdr>.
73 This is a internal function.
75 @param String UEFI configuration string
76 @param DevicePath binary of a UEFI device path.
78 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
79 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
80 @retval EFI_SUCCESS The device path is retrieved and translated to
87 OUT UINT8
**DevicePath
92 EFI_STRING DevicePathString
;
94 if (String
== NULL
|| DevicePath
== NULL
) {
95 return EFI_INVALID_PARAMETER
;
99 // Find the 'PATH=' of <PathHdr> and skip it.
101 for (; (*String
!= 0 && StrnCmp (String
, L
"PATH=", StrLen (L
"PATH=")) != 0); String
++);
103 return EFI_INVALID_PARAMETER
;
106 String
+= StrLen (L
"PATH=");
110 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
111 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
112 // of UEFI device path.
114 for (Length
= 0; *String
!= 0 && *String
!= L
'&'; String
++, Length
++);
115 DevicePathString
= (EFI_STRING
) AllocateZeroPool ((Length
+ 1) * sizeof (CHAR16
));
116 if (DevicePathString
== NULL
) {
117 return EFI_OUT_OF_RESOURCES
;
119 StrnCpy (DevicePathString
, PathHdr
, Length
);
120 *(DevicePathString
+ Length
) = 0;
123 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
124 // as the device path resides in RAM memory.
125 // Translate the data into binary.
128 *DevicePath
= (UINT8
*) AllocateZeroPool (Length
);
129 if (*DevicePath
== NULL
) {
130 FreePool (DevicePathString
);
131 return EFI_OUT_OF_RESOURCES
;
134 HexStringToBufInReverseOrder (*DevicePath
, &Length
, DevicePathString
);
136 FreePool (DevicePathString
);
144 Generate a sub string then output it.
146 This is a internal function.
148 @param String A constant string which is the prefix of the to be
149 generated string, e.g. GUID=
150 @param BufferLen The length of the Buffer in bytes.
151 @param Buffer Points to a buffer which will be converted to be the
152 content of the generated string.
153 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
154 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
155 if 3, the buffer contains other data.
156 @param SubStr Points to the output string. It's caller's
157 responsibility to free this buffer.
163 IN CONST EFI_STRING String
,
167 OUT EFI_STRING
*SubStr
173 EFI_STRING StringHeader
;
175 ASSERT (String
!= NULL
&& SubStr
!= NULL
);
177 if (Buffer
== NULL
) {
178 *SubStr
= AllocateCopyPool (StrSize (String
), String
);
179 ASSERT (*SubStr
!= NULL
);
183 Length
= StrLen (String
) + BufferLen
* 2 + 1 + 1;
184 Str
= AllocateZeroPool (Length
* sizeof (CHAR16
));
185 ASSERT (Str
!= NULL
);
187 StrCpy (Str
, String
);
188 Length
= (BufferLen
* 2 + 1) * sizeof (CHAR16
);
190 Status
= EFI_SUCCESS
;
191 StringHeader
= Str
+ StrLen (String
);
195 Status
= BufInReverseOrderToHexString (StringHeader
, (UINT8
*) Buffer
, BufferLen
);
198 Status
= UnicodeToConfigString (StringHeader
, &Length
, (CHAR16
*) Buffer
);
201 Status
= BufToHexString (StringHeader
, &Length
, (UINT8
*) Buffer
, BufferLen
);
203 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
205 ToLower (StringHeader
);
211 ASSERT_EFI_ERROR (Status
);
219 Retrieve the <ConfigBody> from String then output it.
221 This is a internal function.
223 @param String A sub string of a configuration string in
224 <MultiConfigAltResp> format.
225 @param ConfigBody Points to the output string. It's caller's
226 responsibility to free this buffer.
228 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
229 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
230 @retval EFI_SUCCESS All existing storage is exported.
235 IN EFI_STRING String
,
236 OUT EFI_STRING
*ConfigBody
243 if (String
== NULL
|| ConfigBody
== NULL
) {
244 return EFI_INVALID_PARAMETER
;
247 TmpPtr
= StrStr (String
, L
"GUID=");
248 if (TmpPtr
== NULL
) {
250 // It is the last <ConfigResp> of the incoming configuration string.
252 Result
= AllocateCopyPool (StrSize (String
), String
);
253 if (Result
== NULL
) {
254 return EFI_OUT_OF_RESOURCES
;
256 *ConfigBody
= Result
;
261 Length
= TmpPtr
- String
;
262 Result
= AllocateCopyPool (Length
* sizeof (CHAR16
), String
);
263 if (Result
== NULL
) {
264 return EFI_OUT_OF_RESOURCES
;
267 *(Result
+ Length
- 1) = 0;
268 *ConfigBody
= Result
;
274 Append a string to a multi-string format.
276 This is a internal function.
278 @param MultiString String in <MultiConfigRequest>,
279 <MultiConfigAltResp>, or <MultiConfigResp>. On
280 input, the buffer length of this string is
281 MAX_STRING_LENGTH. On output, the buffer length
283 @param AppendString NULL-terminated Unicode string.
285 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
286 @retval EFI_SUCCESS AppendString is append to the end of MultiString
290 AppendToMultiString (
291 IN OUT EFI_STRING
*MultiString
,
292 IN EFI_STRING AppendString
295 UINTN AppendStringSize
;
296 UINTN MultiStringSize
;
298 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
299 return EFI_INVALID_PARAMETER
;
302 AppendStringSize
= StrSize (AppendString
);
303 MultiStringSize
= StrSize (*MultiString
);
306 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
308 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
309 MultiStringSize
> MAX_STRING_LENGTH
) {
310 *MultiString
= (EFI_STRING
) ReallocatePool (
312 MultiStringSize
+ AppendStringSize
,
313 (VOID
*) (*MultiString
)
318 // Append the incoming string
320 StrCat (*MultiString
, AppendString
);
327 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
329 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
331 This is a internal function.
333 @param StringPtr String in <BlockConfig> format and points to the
334 first character of <Number>.
335 @param Number The output value. Caller takes the responsibility
337 @param Len Length of the <Number>, in characters.
339 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
341 @retval EFI_SUCCESS Value of <Number> is outputted in Number
347 IN EFI_STRING StringPtr
,
358 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
359 ASSERT (*StringPtr
!= 0);
364 while (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
367 *Len
= StringPtr
- TmpPtr
;
370 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
372 Status
= EFI_OUT_OF_RESOURCES
;
375 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
378 Length
= (Length
+ 1) / 2;
379 Buf
= (UINT8
*) AllocateZeroPool (Length
);
381 Status
= EFI_OUT_OF_RESOURCES
;
385 Status
= HexStringToBuf (Buf
, &Length
, Str
, NULL
);
386 if (EFI_ERROR (Status
)) {
391 Status
= EFI_SUCCESS
;
402 This function allows a caller to extract the current configuration
403 for one or more named elements from one or more drivers.
405 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
407 @param Request A null-terminated Unicode string in
408 <MultiConfigRequest> format.
409 @param Progress On return, points to a character in the Request
410 string. Points to the string's null terminator if
411 request was successful. Points to the most recent
412 & before the first failing name / value pair (or
413 the beginning of the string if the failure is in
414 the first name / value pair) if the request was
416 @param Results Null-terminated Unicode string in
417 <MultiConfigAltResp> format which has all values
418 filled in for the names in the Request string.
419 String to be allocated by the called function.
421 @retval EFI_SUCCESS The Results string is filled with the values
422 corresponding to all requested names.
423 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
424 results that must be stored awaiting possible
426 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
427 Progress set to the "G" in "GUID" of the routing
428 header that doesn't match. Note: There is no
429 requirement that all routing data be validated
430 before any configuration extraction.
431 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
432 parameter would result in this type of error. The
433 Progress parameter is set to NULL.
434 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
435 before the error or the beginning of the string.
436 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
442 HiiConfigRoutingExtractConfig (
443 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
444 IN CONST EFI_STRING Request
,
445 OUT EFI_STRING
*Progress
,
446 OUT EFI_STRING
*Results
449 HII_DATABASE_PRIVATE_DATA
*Private
;
450 EFI_STRING StringPtr
;
451 EFI_STRING ConfigRequest
;
453 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
456 HII_DATABASE_RECORD
*Database
;
457 UINT8
*DevicePathPkg
;
458 UINT8
*CurrentDevicePath
;
459 EFI_HANDLE DriverHandle
;
460 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
461 EFI_STRING AccessProgress
;
462 EFI_STRING AccessResults
;
463 BOOLEAN FirstElement
;
466 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
467 // as FALSE. But this renders the system to not 100% compliant with
468 // UEFI 2.1. Use this with caution.
470 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
471 return EFI_UNSUPPORTED
;
474 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
475 return EFI_INVALID_PARAMETER
;
478 if (Request
== NULL
) {
480 return EFI_INVALID_PARAMETER
;
483 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
485 *Progress
= StringPtr
;
488 // The first element of <MultiConfigRequest> should be
489 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
491 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
492 return EFI_INVALID_PARAMETER
;
498 // Allocate a fix length of memory to store Results. Reallocate memory for
499 // Results if this fix length is insufficient.
501 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
502 if (*Results
== NULL
) {
503 return EFI_OUT_OF_RESOURCES
;
506 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
508 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
509 // or most recent & before the error.
511 if (StringPtr
== Request
) {
512 *Progress
= StringPtr
;
514 *Progress
= StringPtr
- 1;
518 // Process each <ConfigRequest> of <MultiConfigRequest>
520 Length
= CalculateConfigStringLen (StringPtr
);
521 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
522 if (ConfigRequest
== NULL
) {
523 return EFI_OUT_OF_RESOURCES
;
525 *(ConfigRequest
+ Length
) = 0;
528 // Get the UEFI device path
530 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
531 if (EFI_ERROR (Status
)) {
532 FreePool (ConfigRequest
);
537 // Find driver which matches the routing data.
540 for (Link
= Private
->DatabaseList
.ForwardLink
;
541 Link
!= &Private
->DatabaseList
;
542 Link
= Link
->ForwardLink
544 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
546 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
547 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
551 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
553 DriverHandle
= Database
->DriverHandle
;
559 FreePool (DevicePath
);
561 if (DriverHandle
== NULL
) {
563 // Routing data does not match any known driver.
564 // Set Progress to the 'G' in "GUID" of the routing header.
566 *Progress
= StringPtr
;
567 FreePool (ConfigRequest
);
568 return EFI_NOT_FOUND
;
572 // Call corresponding ConfigAccess protocol to extract settings
574 Status
= gBS
->HandleProtocol (
576 &gEfiHiiConfigAccessProtocolGuid
,
577 (VOID
**) &ConfigAccess
579 ASSERT_EFI_ERROR (Status
);
581 Status
= ConfigAccess
->ExtractConfig (
587 if (EFI_ERROR (Status
)) {
589 // AccessProgress indicates the parsing progress on <ConfigRequest>.
590 // Map it to the progress on <MultiConfigRequest> then return it.
592 *Progress
= StrStr (StringPtr
, AccessProgress
);
593 FreePool (ConfigRequest
);
598 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
599 // which seperates the first <ConfigAltResp> and the following ones.
601 ASSERT (*AccessProgress
== 0);
604 Status
= AppendToMultiString (Results
, L
"&");
605 ASSERT_EFI_ERROR (Status
);
608 Status
= AppendToMultiString (Results
, AccessResults
);
609 ASSERT_EFI_ERROR (Status
);
611 FirstElement
= FALSE
;
613 FreePool (AccessResults
);
614 AccessResults
= NULL
;
615 FreePool (ConfigRequest
);
616 ConfigRequest
= NULL
;
619 // Go to next <ConfigRequest> (skip '&').
622 if (*StringPtr
== 0) {
623 *Progress
= StringPtr
;
637 This function allows the caller to request the current configuration for the
638 entirety of the current HII database and returns the data in a
639 null-terminated Unicode string.
641 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
643 @param Results Null-terminated Unicode string in
644 <MultiConfigAltResp> format which has all values
645 filled in for the names in the Request string.
646 String to be allocated by the called function.
647 De-allocation is up to the caller.
649 @retval EFI_SUCCESS The Results string is filled with the values
650 corresponding to all requested names.
651 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
652 results that must be stored awaiting possible
654 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
655 parameter would result in this type of error.
660 HiiConfigRoutingExportConfig (
661 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
662 OUT EFI_STRING
*Results
666 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
667 EFI_STRING AccessResults
;
669 EFI_HANDLE
*ConfigAccessHandles
;
670 UINTN NumberConfigAccessHandles
;
671 BOOLEAN FirstElement
;
674 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
675 // as FALSE. But this renders the system to not 100% compliant with
676 // UEFI 2.1. Use this with caution.
678 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
679 return EFI_UNSUPPORTED
;
682 if (This
== NULL
|| Results
== NULL
) {
683 return EFI_INVALID_PARAMETER
;
687 // Allocate a fix length of memory to store Results. Reallocate memory for
688 // Results if this fix length is insufficient.
690 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
691 if (*Results
== NULL
) {
692 return EFI_OUT_OF_RESOURCES
;
695 NumberConfigAccessHandles
= 0;
696 Status
= gBS
->LocateHandleBuffer (
698 &gEfiHiiConfigAccessProtocolGuid
,
700 &NumberConfigAccessHandles
,
703 if (EFI_ERROR (Status
)) {
709 for (Index
= 0; Index
< NumberConfigAccessHandles
; Index
++) {
710 Status
= gBS
->HandleProtocol (
711 ConfigAccessHandles
[Index
],
712 &gEfiHiiConfigAccessProtocolGuid
,
713 (VOID
**) &ConfigAccess
715 if (EFI_ERROR (Status
)) {
719 Status
= ConfigAccess
->ExtractConfig (
725 if (!EFI_ERROR (Status
)) {
727 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
728 // which seperates the first <ConfigAltResp> and the following ones.
731 Status
= AppendToMultiString (Results
, L
"&");
732 ASSERT_EFI_ERROR (Status
);
735 Status
= AppendToMultiString (Results
, AccessResults
);
736 ASSERT_EFI_ERROR (Status
);
738 FirstElement
= FALSE
;
740 FreePool (AccessResults
);
741 AccessResults
= NULL
;
744 FreePool (ConfigAccessHandles
);
751 This function processes the results of processing forms and routes it to the
752 appropriate handlers or storage.
754 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
756 @param Configuration A null-terminated Unicode string in
757 <MulltiConfigResp> format.
758 @param Progress A pointer to a string filled in with the offset of
759 the most recent & before the first failing name /
760 value pair (or the beginning of the string if the
761 failure is in the first name / value pair) or the
762 terminating NULL if all was successful.
764 @retval EFI_SUCCESS The results have been distributed or are awaiting
766 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
767 results that must be stored awaiting possible
769 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
770 would result in this type of error.
771 @retval EFI_NOT_FOUND Target for the specified routing data was not
777 HiiConfigRoutingRouteConfig (
778 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
779 IN CONST EFI_STRING Configuration
,
780 OUT EFI_STRING
*Progress
783 HII_DATABASE_PRIVATE_DATA
*Private
;
784 EFI_STRING StringPtr
;
785 EFI_STRING ConfigResp
;
788 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
790 HII_DATABASE_RECORD
*Database
;
791 UINT8
*DevicePathPkg
;
792 UINT8
*CurrentDevicePath
;
793 EFI_HANDLE DriverHandle
;
794 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
795 EFI_STRING AccessProgress
;
798 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
799 // as FALSE. But this renders the system to not 100% compliant with
800 // UEFI 2.1. Use this with caution.
802 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
803 return EFI_UNSUPPORTED
;
806 if (This
== NULL
|| Progress
== NULL
) {
807 return EFI_INVALID_PARAMETER
;
810 if (Configuration
== NULL
) {
812 return EFI_INVALID_PARAMETER
;
815 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
816 StringPtr
= Configuration
;
817 *Progress
= StringPtr
;
820 // The first element of <MultiConfigResp> should be
821 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
823 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
824 return EFI_INVALID_PARAMETER
;
827 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
829 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
830 // or most recent & before the error.
832 if (StringPtr
== Configuration
) {
833 *Progress
= StringPtr
;
835 *Progress
= StringPtr
- 1;
839 // Process each <ConfigResp> of <MultiConfigResp>
841 Length
= CalculateConfigStringLen (StringPtr
);
842 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
843 if (ConfigResp
== NULL
) {
844 return EFI_OUT_OF_RESOURCES
;
847 // Append '\0' to the end of ConfigRequest
849 *(ConfigResp
+ Length
) = 0;
852 // Get the UEFI device path
854 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
855 if (EFI_ERROR (Status
)) {
856 FreePool (ConfigResp
);
861 // Find driver which matches the routing data.
864 for (Link
= Private
->DatabaseList
.ForwardLink
;
865 Link
!= &Private
->DatabaseList
;
866 Link
= Link
->ForwardLink
868 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
870 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
871 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
875 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
877 DriverHandle
= Database
->DriverHandle
;
883 FreePool (DevicePath
);
885 if (DriverHandle
== NULL
) {
887 // Routing data does not match any known driver.
888 // Set Progress to the 'G' in "GUID" of the routing header.
890 *Progress
= StringPtr
;
891 FreePool (ConfigResp
);
892 return EFI_NOT_FOUND
;
896 // Call corresponding ConfigAccess protocol to route settings
898 Status
= gBS
->HandleProtocol (
900 &gEfiHiiConfigAccessProtocolGuid
,
901 (VOID
**) &ConfigAccess
903 ASSERT_EFI_ERROR (Status
);
905 Status
= ConfigAccess
->RouteConfig (
911 if (EFI_ERROR (Status
)) {
913 // AccessProgress indicates the parsing progress on <ConfigResp>.
914 // Map it to the progress on <MultiConfigResp> then return it.
916 *Progress
= StrStr (StringPtr
, AccessProgress
);
918 FreePool (ConfigResp
);
922 FreePool (ConfigResp
);
926 // Go to next <ConfigResp> (skip '&').
929 if (*StringPtr
== 0) {
930 *Progress
= StringPtr
;
943 This helper function is to be called by drivers to map configuration data
944 stored in byte array ("block") formats such as UEFI Variables into current
945 configuration strings.
947 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
949 @param ConfigRequest A null-terminated Unicode string in
950 <ConfigRequest> format.
951 @param Block Array of bytes defining the block's configuration.
952 @param BlockSize Length in bytes of Block.
953 @param Config Filled-in configuration string. String allocated
954 by the function. Returned only if call is
956 @param Progress A pointer to a string filled in with the offset of
957 the most recent & before the first failing
958 name/value pair (or the beginning of the string if
959 the failure is in the first name / value pair) or
960 the terminating NULL if all was successful.
962 @retval EFI_SUCCESS The request succeeded. Progress points to the null
963 terminator at the end of the ConfigRequest
965 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
966 points to the first character of ConfigRequest.
967 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
968 Block parameter would result in this type of
969 error. Progress points to the first character of
971 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
972 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
973 Block is left updated and Progress points at
974 the "&" preceding the first non-<BlockName>.
980 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
981 IN CONST EFI_STRING ConfigRequest
,
982 IN CONST UINT8
*Block
,
983 IN CONST UINTN BlockSize
,
984 OUT EFI_STRING
*Config
,
985 OUT EFI_STRING
*Progress
988 HII_DATABASE_PRIVATE_DATA
*Private
;
989 EFI_STRING StringPtr
;
998 EFI_STRING ConfigElement
;
1000 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1001 return EFI_INVALID_PARAMETER
;
1004 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1005 *Progress
= ConfigRequest
;
1006 return EFI_INVALID_PARAMETER
;
1010 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1011 ASSERT (Private
!= NULL
);
1013 StringPtr
= ConfigRequest
;
1016 ConfigElement
= NULL
;
1019 // Allocate a fix length of memory to store Results. Reallocate memory for
1020 // Results if this fix length is insufficient.
1022 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1023 if (*Config
== NULL
) {
1024 return EFI_OUT_OF_RESOURCES
;
1030 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1031 *Progress
= StringPtr
;
1032 Status
= EFI_INVALID_PARAMETER
;
1035 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1038 if (*StringPtr
== 0) {
1039 *Progress
= StringPtr
;
1040 Status
= EFI_INVALID_PARAMETER
;
1044 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1047 if (*StringPtr
== 0) {
1048 *Progress
= StringPtr
;
1049 Status
= EFI_INVALID_PARAMETER
;
1058 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1060 Length
= StringPtr
- ConfigRequest
;
1061 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1064 // Parse each <RequestElement> if exists
1065 // Only <BlockName> format is supported by this help function.
1066 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1068 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1070 // Back up the header of one <BlockName>
1074 StringPtr
+= StrLen (L
"OFFSET=");
1078 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1079 if (Status
== EFI_OUT_OF_RESOURCES
) {
1080 *Progress
= ConfigRequest
;
1087 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1089 FreePool (TmpBuffer
);
1091 StringPtr
+= Length
;
1092 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1093 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1094 Status
= EFI_INVALID_PARAMETER
;
1097 StringPtr
+= StrLen (L
"&WIDTH=");
1102 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1103 if (Status
== EFI_OUT_OF_RESOURCES
) {
1104 *Progress
= ConfigRequest
;
1111 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1113 FreePool (TmpBuffer
);
1115 StringPtr
+= Length
;
1116 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1117 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1118 Status
= EFI_INVALID_PARAMETER
;
1123 // Calculate Value and convert it to hex string.
1125 if (Offset
+ Width
> BlockSize
) {
1126 *Progress
= StringPtr
;
1127 Status
= EFI_DEVICE_ERROR
;
1131 Value
= (UINT8
*) AllocateZeroPool (Width
);
1132 if (Value
== NULL
) {
1133 *Progress
= ConfigRequest
;
1134 Status
= EFI_OUT_OF_RESOURCES
;
1138 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1140 Length
= Width
* 2 + 1;
1141 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1142 if (ValueStr
== NULL
) {
1143 *Progress
= ConfigRequest
;
1144 Status
= EFI_OUT_OF_RESOURCES
;
1148 Status
= BufToHexString (ValueStr
, &Length
, Value
, Width
);
1149 ASSERT_EFI_ERROR (Status
);
1156 // Build a ConfigElement
1158 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1159 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1160 if (ConfigElement
== NULL
) {
1161 Status
= EFI_OUT_OF_RESOURCES
;
1164 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1165 if (*StringPtr
== 0) {
1166 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1168 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1169 StrCat (ConfigElement
, L
"VALUE=");
1170 StrCat (ConfigElement
, ValueStr
);
1172 AppendToMultiString (Config
, ConfigElement
);
1174 FreePool (ConfigElement
);
1175 FreePool (ValueStr
);
1176 ConfigElement
= NULL
;
1180 // If '\0', parsing is finished. Otherwise skip '&' to continue
1182 if (*StringPtr
== 0) {
1185 AppendToMultiString (Config
, L
"&");
1190 if (*StringPtr
!= 0) {
1191 *Progress
= StringPtr
- 1;
1192 Status
= EFI_INVALID_PARAMETER
;
1196 *Progress
= StringPtr
;
1201 if (ValueStr
!= NULL
) {
1202 FreePool (ValueStr
);
1204 if (Value
!= NULL
) {
1207 if (ConfigElement
!= NULL
) {
1208 FreePool (ConfigElement
);
1217 This helper function is to be called by drivers to map configuration strings
1218 to configurations stored in byte array ("block") formats such as UEFI Variables.
1220 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1222 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1224 @param Block A possibly null array of bytes representing the
1225 current block. Only bytes referenced in the
1226 ConfigResp string in the block are modified. If
1227 this parameter is null or if the *BlockSize
1228 parameter is (on input) shorter than required by
1229 the Configuration string, only the BlockSize
1230 parameter is updated and an appropriate status
1231 (see below) is returned.
1232 @param BlockSize The length of the Block in units of UINT8. On
1233 input, this is the size of the Block. On output,
1234 if successful, contains the index of the last
1235 modified byte in the Block.
1236 @param Progress On return, points to an element of the ConfigResp
1237 string filled in with the offset of the most
1238 recent '&' before the first failing name / value
1239 pair (or the beginning of the string if the
1240 failure is in the first name / value pair) or the
1241 terminating NULL if all was successful.
1243 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1244 terminator at the end of the ConfigResp string.
1245 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1246 points to the first character of ConfigResp.
1247 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1248 Block parameter would result in this type of
1249 error. Progress points to the first character of
1251 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1252 value pair. Block is left updated and
1253 Progress points at the '&' preceding the first
1260 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1261 IN CONST EFI_STRING ConfigResp
,
1262 IN OUT UINT8
*Block
,
1263 IN OUT UINTN
*BlockSize
,
1264 OUT EFI_STRING
*Progress
1267 HII_DATABASE_PRIVATE_DATA
*Private
;
1268 EFI_STRING StringPtr
;
1277 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1278 return EFI_INVALID_PARAMETER
;
1281 if (ConfigResp
== NULL
|| Block
== NULL
) {
1282 *Progress
= ConfigResp
;
1283 return EFI_INVALID_PARAMETER
;
1286 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1287 ASSERT (Private
!= NULL
);
1289 StringPtr
= ConfigResp
;
1290 BufferSize
= *BlockSize
;
1296 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1297 *Progress
= StringPtr
;
1298 Status
= EFI_INVALID_PARAMETER
;
1301 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1304 if (*StringPtr
== 0) {
1305 *Progress
= StringPtr
;
1306 Status
= EFI_INVALID_PARAMETER
;
1310 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1313 if (*StringPtr
== 0) {
1314 *Progress
= StringPtr
;
1315 Status
= EFI_INVALID_PARAMETER
;
1324 // Parse each <ConfigElement> if exists
1325 // Only <BlockConfig> format is supported by this help function.
1326 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1328 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1329 StringPtr
+= StrLen (L
"OFFSET=");
1333 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1334 if (Status
== EFI_OUT_OF_RESOURCES
) {
1335 *Progress
= ConfigResp
;
1342 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1344 FreePool (TmpBuffer
);
1346 StringPtr
+= Length
;
1347 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1348 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1349 Status
= EFI_INVALID_PARAMETER
;
1352 StringPtr
+= StrLen (L
"&WIDTH=");
1357 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1358 if (Status
== EFI_OUT_OF_RESOURCES
) {
1359 *Progress
= ConfigResp
;
1366 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1368 FreePool (TmpBuffer
);
1370 StringPtr
+= Length
;
1371 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1372 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1373 Status
= EFI_INVALID_PARAMETER
;
1376 StringPtr
+= StrLen (L
"&VALUE=");
1381 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1382 if (Status
== EFI_OUT_OF_RESOURCES
) {
1383 *Progress
= ConfigResp
;
1387 StringPtr
+= Length
;
1388 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1389 *Progress
= StringPtr
- Length
- 7;
1390 Status
= EFI_INVALID_PARAMETER
;
1395 // Update the Block with configuration info
1398 if (Offset
+ Width
> BufferSize
) {
1399 return EFI_DEVICE_ERROR
;
1402 CopyMem (Block
+ Offset
, Value
, Width
);
1403 *BlockSize
= Offset
+ Width
- 1;
1409 // If '\0', parsing is finished. Otherwise skip '&' to continue
1411 if (*StringPtr
== 0) {
1418 if (*StringPtr
!= 0) {
1419 *Progress
= StringPtr
- 1;
1420 Status
= EFI_INVALID_PARAMETER
;
1424 *Progress
= StringPtr
;
1429 if (Value
!= NULL
) {
1437 This helper function is to be called by drivers to extract portions of
1438 a larger configuration string.
1440 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1442 @param Configuration A null-terminated Unicode string in
1443 <MultiConfigAltResp> format.
1444 @param Guid A pointer to the GUID value to search for in the
1445 routing portion of the ConfigResp string when
1446 retrieving the requested data. If Guid is NULL,
1447 then all GUID values will be searched for.
1448 @param Name A pointer to the NAME value to search for in the
1449 routing portion of the ConfigResp string when
1450 retrieving the requested data. If Name is NULL,
1451 then all Name values will be searched for.
1452 @param DevicePath A pointer to the PATH value to search for in the
1453 routing portion of the ConfigResp string when
1454 retrieving the requested data. If DevicePath is
1455 NULL, then all DevicePath values will be searched
1457 @param AltCfgId A pointer to the ALTCFG value to search for in the
1458 routing portion of the ConfigResp string when
1459 retrieving the requested data. If this parameter
1460 is NULL, then the current setting will be
1462 @param AltCfgResp A pointer to a buffer which will be allocated by
1463 the function which contains the retrieved string
1464 as requested. This buffer is only allocated if
1465 the call was successful.
1467 @retval EFI_SUCCESS The request succeeded. The requested data was
1468 extracted and placed in the newly allocated
1470 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1471 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1472 @retval EFI_NOT_FOUND Target for the specified routing data was not
1479 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1480 IN CONST EFI_STRING Configuration
,
1481 IN CONST EFI_GUID
*Guid
,
1482 IN CONST EFI_STRING Name
,
1483 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1484 IN CONST UINT16
*AltCfgId
,
1485 OUT EFI_STRING
*AltCfgResp
1489 EFI_STRING StringPtr
;
1490 EFI_STRING HdrStart
;
1497 EFI_STRING AltIdStr
;
1504 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1505 // as FALSE. But this renders the system to not 100% compliant with
1506 // UEFI 2.1. Use this with caution.
1508 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1509 return EFI_UNSUPPORTED
;
1523 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1524 return EFI_INVALID_PARAMETER
;
1527 StringPtr
= Configuration
;
1528 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1529 return EFI_INVALID_PARAMETER
;
1533 // Generate the sub string for later matching.
1535 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1538 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1539 (VOID
*) DevicePath
,
1543 if (AltCfgId
!= NULL
) {
1544 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1547 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1549 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1552 while (*StringPtr
!= 0) {
1554 // Try to match the GUID
1557 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1558 if (TmpPtr
== NULL
) {
1559 Status
= EFI_NOT_FOUND
;
1565 // Jump to <NameHdr>
1568 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1570 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1571 if (StringPtr
== NULL
) {
1572 Status
= EFI_NOT_FOUND
;
1580 // Try to match the NAME
1582 if (GuidFlag
&& !NameFlag
) {
1583 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1587 // Jump to <PathHdr>
1590 StringPtr
+= StrLen (NameStr
);
1592 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1593 if (StringPtr
== NULL
) {
1594 Status
= EFI_NOT_FOUND
;
1603 // Try to match the DevicePath
1605 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1606 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1611 // Jump to '&' before <DescHdr> or <ConfigBody>
1613 if (DevicePath
!= NULL
) {
1614 StringPtr
+= StrLen (PathStr
);
1616 StringPtr
= StrStr (StringPtr
, L
"&");
1617 if (StringPtr
== NULL
) {
1618 Status
= EFI_NOT_FOUND
;
1623 HdrEnd
= ++StringPtr
;
1628 // Try to match the AltCfgId
1630 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1631 if (AltCfgId
== NULL
) {
1633 // Return Current Setting when AltCfgId is NULL.
1635 Status
= OutputConfigBody (StringPtr
, &Result
);
1639 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1641 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1646 Status
= OutputConfigBody (StringPtr
, &Result
);
1652 Status
= EFI_NOT_FOUND
;
1656 if (!EFI_ERROR (Status
)) {
1658 // Copy the <ConfigHdr> and <ConfigBody>
1660 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1661 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1662 if (*AltCfgResp
== NULL
) {
1663 Status
= EFI_OUT_OF_RESOURCES
;
1665 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1666 StrCat (*AltCfgResp
, Result
);
1667 Status
= EFI_SUCCESS
;
1671 if (GuidStr
!= NULL
) {
1674 if (NameStr
!= NULL
) {
1677 if (PathStr
!= NULL
) {
1680 if (AltIdStr
!= NULL
) {
1681 FreePool (AltIdStr
);
1683 if (Result
!= NULL
) {