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
;
275 Adjusts the size of a previously allocated buffer.
278 @param OldPool A pointer to the buffer whose size is being adjusted.
279 @param OldSize The size of the current buffer.
280 @param NewSize The size of the new buffer.
282 @return The new buffer allocated.
296 NewPool
= AllocateZeroPool (NewSize
);
299 if (OldPool
!= NULL
) {
300 if (NewPool
!= NULL
) {
301 CopyMem (NewPool
, OldPool
, OldSize
< NewSize
? OldSize
: NewSize
);
304 gBS
->FreePool (OldPool
);
312 Append a string to a multi-string format.
314 This is a internal function.
316 @param MultiString String in <MultiConfigRequest>,
317 <MultiConfigAltResp>, or <MultiConfigResp>. On
318 input, the buffer length of this string is
319 MAX_STRING_LENGTH. On output, the buffer length
321 @param AppendString NULL-terminated Unicode string.
323 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
324 @retval EFI_SUCCESS AppendString is append to the end of MultiString
328 AppendToMultiString (
329 IN OUT EFI_STRING
*MultiString
,
330 IN EFI_STRING AppendString
333 UINTN AppendStringSize
;
334 UINTN MultiStringSize
;
336 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
337 return EFI_INVALID_PARAMETER
;
340 AppendStringSize
= StrSize (AppendString
);
341 MultiStringSize
= StrSize (*MultiString
);
344 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
346 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
347 MultiStringSize
> MAX_STRING_LENGTH
) {
348 *MultiString
= (EFI_STRING
) ReallocatePool (
349 (VOID
*) (*MultiString
),
351 MultiStringSize
+ AppendStringSize
356 // Append the incoming string
358 StrCat (*MultiString
, AppendString
);
365 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
367 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
369 This is a internal function.
371 @param StringPtr String in <BlockConfig> format and points to the
372 first character of <Number>.
373 @param Number The output value. Caller takes the responsibility
375 @param Len Length of the <Number>, in characters.
377 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
379 @retval EFI_SUCCESS Value of <Number> is outputted in Number
385 IN EFI_STRING StringPtr
,
396 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
397 ASSERT (*StringPtr
!= 0);
402 while (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
405 *Len
= StringPtr
- TmpPtr
;
408 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
410 Status
= EFI_OUT_OF_RESOURCES
;
413 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
416 Length
= (Length
+ 1) / 2;
417 Buf
= (UINT8
*) AllocateZeroPool (Length
);
419 Status
= EFI_OUT_OF_RESOURCES
;
423 Status
= HexStringToBuf (Buf
, &Length
, Str
, NULL
);
424 if (EFI_ERROR (Status
)) {
429 Status
= EFI_SUCCESS
;
440 This function allows a caller to extract the current configuration
441 for one or more named elements from one or more drivers.
443 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
445 @param Request A null-terminated Unicode string in
446 <MultiConfigRequest> format.
447 @param Progress On return, points to a character in the Request
448 string. Points to the string's null terminator if
449 request was successful. Points to the most recent
450 & before the first failing name / value pair (or
451 the beginning of the string if the failure is in
452 the first name / value pair) if the request was
454 @param Results Null-terminated Unicode string in
455 <MultiConfigAltResp> format which has all values
456 filled in for the names in the Request string.
457 String to be allocated by the called function.
459 @retval EFI_SUCCESS The Results string is filled with the values
460 corresponding to all requested names.
461 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
462 results that must be stored awaiting possible
464 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
465 Progress set to the "G" in "GUID" of the routing
466 header that doesn't match. Note: There is no
467 requirement that all routing data be validated
468 before any configuration extraction.
469 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
470 parameter would result in this type of error. The
471 Progress parameter is set to NULL.
472 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
473 before the error or the beginning of the string.
474 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
480 HiiConfigRoutingExtractConfig (
481 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
482 IN CONST EFI_STRING Request
,
483 OUT EFI_STRING
*Progress
,
484 OUT EFI_STRING
*Results
487 HII_DATABASE_PRIVATE_DATA
*Private
;
488 EFI_STRING StringPtr
;
489 EFI_STRING ConfigRequest
;
491 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
494 HII_DATABASE_RECORD
*Database
;
495 UINT8
*DevicePathPkg
;
496 UINT8
*CurrentDevicePath
;
497 EFI_HANDLE DriverHandle
;
498 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
499 EFI_STRING AccessProgress
;
500 EFI_STRING AccessResults
;
501 BOOLEAN FirstElement
;
504 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
505 // as FALSE. But this renders the system to not 100% compliant with
506 // UEFI 2.1. Use this with caution.
508 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
509 return EFI_UNSUPPORTED
;
512 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
513 return EFI_INVALID_PARAMETER
;
516 if (Request
== NULL
) {
518 return EFI_INVALID_PARAMETER
;
521 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
523 *Progress
= StringPtr
;
526 // The first element of <MultiConfigRequest> should be
527 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
529 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
530 return EFI_INVALID_PARAMETER
;
536 // Allocate a fix length of memory to store Results. Reallocate memory for
537 // Results if this fix length is insufficient.
539 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
540 if (*Results
== NULL
) {
541 return EFI_OUT_OF_RESOURCES
;
544 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
546 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
547 // or most recent & before the error.
549 if (StringPtr
== Request
) {
550 *Progress
= StringPtr
;
552 *Progress
= StringPtr
- 1;
556 // Process each <ConfigRequest> of <MultiConfigRequest>
558 Length
= CalculateConfigStringLen (StringPtr
);
559 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
560 if (ConfigRequest
== NULL
) {
561 return EFI_OUT_OF_RESOURCES
;
563 *(ConfigRequest
+ Length
) = 0;
566 // Get the UEFI device path
568 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
569 if (EFI_ERROR (Status
)) {
570 FreePool (ConfigRequest
);
575 // Find driver which matches the routing data.
578 for (Link
= Private
->DatabaseList
.ForwardLink
;
579 Link
!= &Private
->DatabaseList
;
580 Link
= Link
->ForwardLink
582 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
584 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
585 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
589 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
591 DriverHandle
= Database
->DriverHandle
;
597 FreePool (DevicePath
);
599 if (DriverHandle
== NULL
) {
601 // Routing data does not match any known driver.
602 // Set Progress to the 'G' in "GUID" of the routing header.
604 *Progress
= StringPtr
;
605 FreePool (ConfigRequest
);
606 return EFI_NOT_FOUND
;
610 // Call corresponding ConfigAccess protocol to extract settings
612 Status
= gBS
->HandleProtocol (
614 &gEfiHiiConfigAccessProtocolGuid
,
615 (VOID
**) &ConfigAccess
617 ASSERT_EFI_ERROR (Status
);
619 Status
= ConfigAccess
->ExtractConfig (
625 if (EFI_ERROR (Status
)) {
627 // AccessProgress indicates the parsing progress on <ConfigRequest>.
628 // Map it to the progress on <MultiConfigRequest> then return it.
630 *Progress
= StrStr (StringPtr
, AccessProgress
);
631 FreePool (ConfigRequest
);
636 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
637 // which seperates the first <ConfigAltResp> and the following ones.
639 ASSERT (*AccessProgress
== 0);
642 Status
= AppendToMultiString (Results
, L
"&");
643 ASSERT_EFI_ERROR (Status
);
646 Status
= AppendToMultiString (Results
, AccessResults
);
647 ASSERT_EFI_ERROR (Status
);
649 FirstElement
= FALSE
;
651 FreePool (AccessResults
);
652 AccessResults
= NULL
;
653 FreePool (ConfigRequest
);
654 ConfigRequest
= NULL
;
657 // Go to next <ConfigRequest> (skip '&').
660 if (*StringPtr
== 0) {
661 *Progress
= StringPtr
;
675 This function allows the caller to request the current configuration for the
676 entirety of the current HII database and returns the data in a
677 null-terminated Unicode string.
679 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
681 @param Results Null-terminated Unicode string in
682 <MultiConfigAltResp> format which has all values
683 filled in for the names in the Request string.
684 String to be allocated by the called function.
685 De-allocation is up to the caller.
687 @retval EFI_SUCCESS The Results string is filled with the values
688 corresponding to all requested names.
689 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
690 results that must be stored awaiting possible
692 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
693 parameter would result in this type of error.
698 HiiConfigRoutingExportConfig (
699 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
700 OUT EFI_STRING
*Results
704 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
705 EFI_STRING AccessResults
;
707 EFI_HANDLE
*ConfigAccessHandles
;
708 UINTN NumberConfigAccessHandles
;
709 BOOLEAN FirstElement
;
712 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
713 // as FALSE. But this renders the system to not 100% compliant with
714 // UEFI 2.1. Use this with caution.
716 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
717 return EFI_UNSUPPORTED
;
720 if (This
== NULL
|| Results
== NULL
) {
721 return EFI_INVALID_PARAMETER
;
725 // Allocate a fix length of memory to store Results. Reallocate memory for
726 // Results if this fix length is insufficient.
728 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
729 if (*Results
== NULL
) {
730 return EFI_OUT_OF_RESOURCES
;
733 NumberConfigAccessHandles
= 0;
734 Status
= gBS
->LocateHandleBuffer (
736 &gEfiHiiConfigAccessProtocolGuid
,
738 &NumberConfigAccessHandles
,
741 if (EFI_ERROR (Status
)) {
747 for (Index
= 0; Index
< NumberConfigAccessHandles
; Index
++) {
748 Status
= gBS
->HandleProtocol (
749 ConfigAccessHandles
[Index
],
750 &gEfiHiiConfigAccessProtocolGuid
,
751 (VOID
**) &ConfigAccess
753 if (EFI_ERROR (Status
)) {
757 Status
= ConfigAccess
->ExtractConfig (
763 if (!EFI_ERROR (Status
)) {
765 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
766 // which seperates the first <ConfigAltResp> and the following ones.
769 Status
= AppendToMultiString (Results
, L
"&");
770 ASSERT_EFI_ERROR (Status
);
773 Status
= AppendToMultiString (Results
, AccessResults
);
774 ASSERT_EFI_ERROR (Status
);
776 FirstElement
= FALSE
;
778 FreePool (AccessResults
);
779 AccessResults
= NULL
;
782 gBS
->FreePool (ConfigAccessHandles
);
789 This function processes the results of processing forms and routes it to the
790 appropriate handlers or storage.
792 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
794 @param Configuration A null-terminated Unicode string in
795 <MulltiConfigResp> format.
796 @param Progress A pointer to a string filled in with the offset of
797 the most recent & before the first failing name /
798 value pair (or the beginning of the string if the
799 failure is in the first name / value pair) or the
800 terminating NULL if all was successful.
802 @retval EFI_SUCCESS The results have been distributed or are awaiting
804 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
805 results that must be stored awaiting possible
807 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
808 would result in this type of error.
809 @retval EFI_NOT_FOUND Target for the specified routing data was not
815 HiiConfigRoutingRouteConfig (
816 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
817 IN CONST EFI_STRING Configuration
,
818 OUT EFI_STRING
*Progress
821 HII_DATABASE_PRIVATE_DATA
*Private
;
822 EFI_STRING StringPtr
;
823 EFI_STRING ConfigResp
;
826 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
828 HII_DATABASE_RECORD
*Database
;
829 UINT8
*DevicePathPkg
;
830 UINT8
*CurrentDevicePath
;
831 EFI_HANDLE DriverHandle
;
832 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
833 EFI_STRING AccessProgress
;
836 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
837 // as FALSE. But this renders the system to not 100% compliant with
838 // UEFI 2.1. Use this with caution.
840 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
841 return EFI_UNSUPPORTED
;
844 if (This
== NULL
|| Progress
== NULL
) {
845 return EFI_INVALID_PARAMETER
;
848 if (Configuration
== NULL
) {
850 return EFI_INVALID_PARAMETER
;
853 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
854 StringPtr
= Configuration
;
855 *Progress
= StringPtr
;
858 // The first element of <MultiConfigResp> should be
859 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
861 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
862 return EFI_INVALID_PARAMETER
;
865 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
867 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
868 // or most recent & before the error.
870 if (StringPtr
== Configuration
) {
871 *Progress
= StringPtr
;
873 *Progress
= StringPtr
- 1;
877 // Process each <ConfigResp> of <MultiConfigResp>
879 Length
= CalculateConfigStringLen (StringPtr
);
880 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
881 if (ConfigResp
== NULL
) {
882 return EFI_OUT_OF_RESOURCES
;
885 // Append '\0' to the end of ConfigRequest
887 *(ConfigResp
+ Length
) = 0;
890 // Get the UEFI device path
892 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
893 if (EFI_ERROR (Status
)) {
894 FreePool (ConfigResp
);
899 // Find driver which matches the routing data.
902 for (Link
= Private
->DatabaseList
.ForwardLink
;
903 Link
!= &Private
->DatabaseList
;
904 Link
= Link
->ForwardLink
906 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
908 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
909 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
913 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
915 DriverHandle
= Database
->DriverHandle
;
921 FreePool (DevicePath
);
923 if (DriverHandle
== NULL
) {
925 // Routing data does not match any known driver.
926 // Set Progress to the 'G' in "GUID" of the routing header.
928 *Progress
= StringPtr
;
929 FreePool (ConfigResp
);
930 return EFI_NOT_FOUND
;
934 // Call corresponding ConfigAccess protocol to route settings
936 Status
= gBS
->HandleProtocol (
938 &gEfiHiiConfigAccessProtocolGuid
,
939 (VOID
**) &ConfigAccess
941 ASSERT_EFI_ERROR (Status
);
943 Status
= ConfigAccess
->RouteConfig (
949 if (EFI_ERROR (Status
)) {
951 // AccessProgress indicates the parsing progress on <ConfigResp>.
952 // Map it to the progress on <MultiConfigResp> then return it.
954 *Progress
= StrStr (StringPtr
, AccessProgress
);
956 FreePool (ConfigResp
);
960 FreePool (ConfigResp
);
964 // Go to next <ConfigResp> (skip '&').
967 if (*StringPtr
== 0) {
968 *Progress
= StringPtr
;
981 This helper function is to be called by drivers to map configuration data
982 stored in byte array ("block") formats such as UEFI Variables into current
983 configuration strings.
985 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
987 @param ConfigRequest A null-terminated Unicode string in
988 <ConfigRequest> format.
989 @param Block Array of bytes defining the block's configuration.
990 @param BlockSize Length in bytes of Block.
991 @param Config Filled-in configuration string. String allocated
992 by the function. Returned only if call is
994 @param Progress A pointer to a string filled in with the offset of
995 the most recent & before the first failing
996 name/value pair (or the beginning of the string if
997 the failure is in the first name / value pair) or
998 the terminating NULL if all was successful.
1000 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1001 terminator at the end of the ConfigRequest
1003 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1004 points to the first character of ConfigRequest.
1005 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1006 Block parameter would result in this type of
1007 error. Progress points to the first character of
1009 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1010 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1011 Block is left updated and Progress points at
1012 the "&" preceding the first non-<BlockName>.
1018 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1019 IN CONST EFI_STRING ConfigRequest
,
1020 IN CONST UINT8
*Block
,
1021 IN CONST UINTN BlockSize
,
1022 OUT EFI_STRING
*Config
,
1023 OUT EFI_STRING
*Progress
1026 HII_DATABASE_PRIVATE_DATA
*Private
;
1027 EFI_STRING StringPtr
;
1035 EFI_STRING ValueStr
;
1036 EFI_STRING ConfigElement
;
1038 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1039 return EFI_INVALID_PARAMETER
;
1042 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1043 *Progress
= ConfigRequest
;
1044 return EFI_INVALID_PARAMETER
;
1048 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1049 ASSERT (Private
!= NULL
);
1051 StringPtr
= ConfigRequest
;
1054 ConfigElement
= NULL
;
1057 // Allocate a fix length of memory to store Results. Reallocate memory for
1058 // Results if this fix length is insufficient.
1060 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1061 if (*Config
== NULL
) {
1062 return EFI_OUT_OF_RESOURCES
;
1068 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1069 *Progress
= StringPtr
;
1070 Status
= EFI_INVALID_PARAMETER
;
1073 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1076 if (*StringPtr
== 0) {
1077 *Progress
= StringPtr
;
1078 Status
= EFI_INVALID_PARAMETER
;
1082 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1085 if (*StringPtr
== 0) {
1086 *Progress
= StringPtr
;
1087 Status
= EFI_INVALID_PARAMETER
;
1096 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1098 Length
= StringPtr
- ConfigRequest
;
1099 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1102 // Parse each <RequestElement> if exists
1103 // Only <BlockName> format is supported by this help function.
1104 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1106 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1108 // Back up the header of one <BlockName>
1112 StringPtr
+= StrLen (L
"OFFSET=");
1116 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1117 if (Status
== EFI_OUT_OF_RESOURCES
) {
1118 *Progress
= ConfigRequest
;
1125 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1127 FreePool (TmpBuffer
);
1129 StringPtr
+= Length
;
1130 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1131 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1132 Status
= EFI_INVALID_PARAMETER
;
1135 StringPtr
+= StrLen (L
"&WIDTH=");
1140 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1141 if (Status
== EFI_OUT_OF_RESOURCES
) {
1142 *Progress
= ConfigRequest
;
1149 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1151 FreePool (TmpBuffer
);
1153 StringPtr
+= Length
;
1154 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1155 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1156 Status
= EFI_INVALID_PARAMETER
;
1161 // Calculate Value and convert it to hex string.
1163 if (Offset
+ Width
> BlockSize
) {
1164 *Progress
= StringPtr
;
1165 Status
= EFI_DEVICE_ERROR
;
1169 Value
= (UINT8
*) AllocateZeroPool (Width
);
1170 if (Value
== NULL
) {
1171 *Progress
= ConfigRequest
;
1172 Status
= EFI_OUT_OF_RESOURCES
;
1176 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1178 Length
= Width
* 2 + 1;
1179 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1180 if (ValueStr
== NULL
) {
1181 *Progress
= ConfigRequest
;
1182 Status
= EFI_OUT_OF_RESOURCES
;
1186 Status
= BufToHexString (ValueStr
, &Length
, Value
, Width
);
1187 ASSERT_EFI_ERROR (Status
);
1194 // Build a ConfigElement
1196 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1197 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1198 if (ConfigElement
== NULL
) {
1199 Status
= EFI_OUT_OF_RESOURCES
;
1202 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1203 if (*StringPtr
== 0) {
1204 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1206 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1207 StrCat (ConfigElement
, L
"VALUE=");
1208 StrCat (ConfigElement
, ValueStr
);
1210 AppendToMultiString (Config
, ConfigElement
);
1212 FreePool (ConfigElement
);
1213 FreePool (ValueStr
);
1214 ConfigElement
= NULL
;
1218 // If '\0', parsing is finished. Otherwise skip '&' to continue
1220 if (*StringPtr
== 0) {
1223 AppendToMultiString (Config
, L
"&");
1228 if (*StringPtr
!= 0) {
1229 *Progress
= StringPtr
- 1;
1230 Status
= EFI_INVALID_PARAMETER
;
1234 *Progress
= StringPtr
;
1239 if (ValueStr
!= NULL
) {
1240 FreePool (ValueStr
);
1242 if (Value
!= NULL
) {
1245 if (ConfigElement
) {
1246 FreePool (ConfigElement
);
1255 This helper function is to be called by drivers to map configuration strings
1256 to configurations stored in byte array ("block") formats such as UEFI Variables.
1258 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1260 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1262 @param Block A possibly null array of bytes representing the
1263 current block. Only bytes referenced in the
1264 ConfigResp string in the block are modified. If
1265 this parameter is null or if the *BlockSize
1266 parameter is (on input) shorter than required by
1267 the Configuration string, only the BlockSize
1268 parameter is updated and an appropriate status
1269 (see below) is returned.
1270 @param BlockSize The length of the Block in units of UINT8. On
1271 input, this is the size of the Block. On output,
1272 if successful, contains the index of the last
1273 modified byte in the Block.
1274 @param Progress On return, points to an element of the ConfigResp
1275 string filled in with the offset of the most
1276 recent '&' before the first failing name / value
1277 pair (or the beginning of the string if the
1278 failure is in the first name / value pair) or the
1279 terminating NULL if all was successful.
1281 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1282 terminator at the end of the ConfigResp string.
1283 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1284 points to the first character of ConfigResp.
1285 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1286 Block parameter would result in this type of
1287 error. Progress points to the first character of
1289 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1290 value pair. Block is left updated and
1291 Progress points at the '&' preceding the first
1298 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1299 IN CONST EFI_STRING ConfigResp
,
1300 IN OUT UINT8
*Block
,
1301 IN OUT UINTN
*BlockSize
,
1302 OUT EFI_STRING
*Progress
1305 HII_DATABASE_PRIVATE_DATA
*Private
;
1306 EFI_STRING StringPtr
;
1315 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1316 return EFI_INVALID_PARAMETER
;
1319 if (ConfigResp
== NULL
|| Block
== NULL
) {
1320 *Progress
= ConfigResp
;
1321 return EFI_INVALID_PARAMETER
;
1324 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1325 ASSERT (Private
!= NULL
);
1327 StringPtr
= ConfigResp
;
1328 BufferSize
= *BlockSize
;
1334 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1335 *Progress
= StringPtr
;
1336 Status
= EFI_INVALID_PARAMETER
;
1339 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1342 if (*StringPtr
== 0) {
1343 *Progress
= StringPtr
;
1344 Status
= EFI_INVALID_PARAMETER
;
1348 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1351 if (*StringPtr
== 0) {
1352 *Progress
= StringPtr
;
1353 Status
= EFI_INVALID_PARAMETER
;
1362 // Parse each <ConfigElement> if exists
1363 // Only <BlockConfig> format is supported by this help function.
1364 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1366 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1367 StringPtr
+= StrLen (L
"OFFSET=");
1371 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1372 if (Status
== EFI_OUT_OF_RESOURCES
) {
1373 *Progress
= ConfigResp
;
1380 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1382 FreePool (TmpBuffer
);
1384 StringPtr
+= Length
;
1385 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1386 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1387 Status
= EFI_INVALID_PARAMETER
;
1390 StringPtr
+= StrLen (L
"&WIDTH=");
1395 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1396 if (Status
== EFI_OUT_OF_RESOURCES
) {
1397 *Progress
= ConfigResp
;
1404 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1406 FreePool (TmpBuffer
);
1408 StringPtr
+= Length
;
1409 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1410 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1411 Status
= EFI_INVALID_PARAMETER
;
1414 StringPtr
+= StrLen (L
"&VALUE=");
1419 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1420 if (Status
== EFI_OUT_OF_RESOURCES
) {
1421 *Progress
= ConfigResp
;
1425 StringPtr
+= Length
;
1426 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1427 *Progress
= StringPtr
- Length
- 7;
1428 Status
= EFI_INVALID_PARAMETER
;
1433 // Update the Block with configuration info
1436 if (Offset
+ Width
> BufferSize
) {
1437 return EFI_DEVICE_ERROR
;
1440 CopyMem (Block
+ Offset
, Value
, Width
);
1441 *BlockSize
= Offset
+ Width
- 1;
1447 // If '\0', parsing is finished. Otherwise skip '&' to continue
1449 if (*StringPtr
== 0) {
1456 if (*StringPtr
!= 0) {
1457 *Progress
= StringPtr
- 1;
1458 Status
= EFI_INVALID_PARAMETER
;
1462 *Progress
= StringPtr
;
1467 if (Value
!= NULL
) {
1475 This helper function is to be called by drivers to extract portions of
1476 a larger configuration string.
1478 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1480 @param Configuration A null-terminated Unicode string in
1481 <MultiConfigAltResp> format.
1482 @param Guid A pointer to the GUID value to search for in the
1483 routing portion of the ConfigResp string when
1484 retrieving the requested data. If Guid is NULL,
1485 then all GUID values will be searched for.
1486 @param Name A pointer to the NAME value to search for in the
1487 routing portion of the ConfigResp string when
1488 retrieving the requested data. If Name is NULL,
1489 then all Name values will be searched for.
1490 @param DevicePath A pointer to the PATH value to search for in the
1491 routing portion of the ConfigResp string when
1492 retrieving the requested data. If DevicePath is
1493 NULL, then all DevicePath values will be searched
1495 @param AltCfgId A pointer to the ALTCFG value to search for in the
1496 routing portion of the ConfigResp string when
1497 retrieving the requested data. If this parameter
1498 is NULL, then the current setting will be
1500 @param AltCfgResp A pointer to a buffer which will be allocated by
1501 the function which contains the retrieved string
1502 as requested. This buffer is only allocated if
1503 the call was successful.
1505 @retval EFI_SUCCESS The request succeeded. The requested data was
1506 extracted and placed in the newly allocated
1508 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1509 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1510 @retval EFI_NOT_FOUND Target for the specified routing data was not
1517 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1518 IN CONST EFI_STRING Configuration
,
1519 IN CONST EFI_GUID
*Guid
,
1520 IN CONST EFI_STRING Name
,
1521 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1522 IN CONST UINT16
*AltCfgId
,
1523 OUT EFI_STRING
*AltCfgResp
1527 EFI_STRING StringPtr
;
1528 EFI_STRING HdrStart
;
1535 EFI_STRING AltIdStr
;
1542 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1543 // as FALSE. But this renders the system to not 100% compliant with
1544 // UEFI 2.1. Use this with caution.
1546 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1547 return EFI_UNSUPPORTED
;
1561 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1562 return EFI_INVALID_PARAMETER
;
1565 StringPtr
= Configuration
;
1566 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1567 return EFI_INVALID_PARAMETER
;
1571 // Generate the sub string for later matching.
1573 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1576 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1577 (VOID
*) DevicePath
,
1581 if (AltCfgId
!= NULL
) {
1582 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1585 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1587 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1590 while (*StringPtr
!= 0) {
1592 // Try to match the GUID
1595 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1596 if (TmpPtr
== NULL
) {
1597 Status
= EFI_NOT_FOUND
;
1603 // Jump to <NameHdr>
1606 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1608 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1609 if (StringPtr
== NULL
) {
1610 Status
= EFI_NOT_FOUND
;
1618 // Try to match the NAME
1620 if (GuidFlag
&& !NameFlag
) {
1621 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1625 // Jump to <PathHdr>
1628 StringPtr
+= StrLen (NameStr
);
1630 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1631 if (StringPtr
== NULL
) {
1632 Status
= EFI_NOT_FOUND
;
1641 // Try to match the DevicePath
1643 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1644 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1649 // Jump to '&' before <DescHdr> or <ConfigBody>
1651 if (DevicePath
!= NULL
) {
1652 StringPtr
+= StrLen (PathStr
);
1654 StringPtr
= StrStr (StringPtr
, L
"&");
1655 if (StringPtr
== NULL
) {
1656 Status
= EFI_NOT_FOUND
;
1661 HdrEnd
= ++StringPtr
;
1666 // Try to match the AltCfgId
1668 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1669 if (AltCfgId
== NULL
) {
1671 // Return Current Setting when AltCfgId is NULL.
1673 Status
= OutputConfigBody (StringPtr
, &Result
);
1677 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1679 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1684 Status
= OutputConfigBody (StringPtr
, &Result
);
1690 Status
= EFI_NOT_FOUND
;
1694 if (!EFI_ERROR (Status
)) {
1696 // Copy the <ConfigHdr> and <ConfigBody>
1698 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1699 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1700 if (*AltCfgResp
== NULL
) {
1701 Status
= EFI_OUT_OF_RESOURCES
;
1703 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1704 StrCat (*AltCfgResp
, Result
);
1705 Status
= EFI_SUCCESS
;
1709 if (GuidStr
!= NULL
) {
1712 if (NameStr
!= NULL
) {
1715 if (PathStr
!= NULL
) {
1718 if (AltIdStr
!= NULL
) {
1719 FreePool (AltIdStr
);
1721 if (Result
!= NULL
) {