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 Extract Storage from all Form Packages in current hii database.
146 This is a internal function.
148 @param HiiDatabase EFI_HII_DATABASE_PROTOCOL instance.
149 @param StorageListHead Storage link List head.
151 @retval EFI_NOT_FOUND There is no form package in current hii database.
152 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
153 @retval EFI_SUCCESS All existing storage is exported.
158 IN EFI_HII_DATABASE_PROTOCOL
*HiiDatabase
,
159 IN OUT LIST_ENTRY
*StorageListHead
165 EFI_HII_HANDLE
*HandleBuffer
;
168 EFI_HII_PACKAGE_LIST_HEADER
*HiiPackageList
;
169 EFI_HII_PACKAGE_HEADER
*Package
;
173 HII_FORMSET_STORAGE
*Storage
;
174 EFI_HII_HANDLE HiiHandle
;
175 EFI_HANDLE DriverHandle
;
177 UINT32 PackageListLength
;
178 EFI_HII_PACKAGE_HEADER PackageHeader
;
181 // Find the package list which contains Form package.
185 Status
= HiiListPackageLists (
187 EFI_HII_PACKAGE_FORM
,
192 if (Status
== EFI_BUFFER_TOO_SMALL
) {
193 HandleBuffer
= AllocateZeroPool (BufferSize
);
194 ASSERT (HandleBuffer
!= NULL
);
196 Status
= HiiListPackageLists (
198 EFI_HII_PACKAGE_FORM
,
204 if (EFI_ERROR (Status
)) {
205 if (HandleBuffer
!= NULL
) {
206 FreePool (HandleBuffer
);
211 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
212 for (Index
= 0; Index
< HandleCount
; Index
++) {
213 HiiHandle
= HandleBuffer
[Index
];
216 HiiPackageList
= NULL
;
217 Status
= HiiExportPackageLists (HiiDatabase
, HiiHandle
, &BufferSize
, HiiPackageList
);
218 if (Status
== EFI_BUFFER_TOO_SMALL
) {
219 HiiPackageList
= AllocateZeroPool (BufferSize
);
220 ASSERT (HiiPackageList
!= NULL
);
221 Status
= HiiExportPackageLists (HiiDatabase
, HiiHandle
, &BufferSize
, HiiPackageList
);
223 if (EFI_ERROR (Status
)) {
224 FreePool (HandleBuffer
);
225 FreePool (HiiPackageList
);
230 // Get Form package from this HII package List
232 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
233 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
235 ZeroMem (&PackageHeader
, sizeof (EFI_HII_PACKAGE_HEADER
));
237 while (Offset
< PackageListLength
) {
238 Package
= (EFI_HII_PACKAGE_HEADER
*) (((UINT8
*) HiiPackageList
) + Offset
);
239 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
240 if (PackageHeader
.Type
== EFI_HII_PACKAGE_FORM
) {
243 Offset
+= PackageHeader
.Length
;
245 if (Offset
>= PackageListLength
) {
247 // Error here: No Form package found in this Package List
253 // Search Storage definition in this Form package
255 Offset
= sizeof (EFI_HII_PACKAGE_HEADER
);
256 while (Offset
< PackageHeader
.Length
) {
257 OpCodeData
= ((UINT8
*) Package
) + Offset
;
258 Offset
+= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
260 Operand
= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->OpCode
;
262 if ((Operand
== EFI_IFR_VARSTORE_OP
) ||
263 (Operand
== EFI_IFR_VARSTORE_NAME_VALUE_OP
) ||
264 (Operand
== EFI_IFR_VARSTORE_EFI_OP
)) {
266 Storage
= AllocateZeroPool (sizeof (HII_FORMSET_STORAGE
));
267 ASSERT (Storage
!= NULL
);
268 InsertTailList (StorageListHead
, &Storage
->Entry
);
270 Storage
->Signature
= HII_FORMSET_STORAGE_SIGNATURE
;
271 Storage
->HiiHandle
= HiiHandle
;
273 Status
= HiiGetPackageListHandle (HiiDatabase
, HiiHandle
, &DriverHandle
);
274 if (EFI_ERROR (Status
)) {
275 FreePool (HandleBuffer
);
276 FreePool (HiiPackageList
);
280 Storage
->DriverHandle
= DriverHandle
;
282 if (Operand
== EFI_IFR_VARSTORE_OP
) {
283 Storage
->Type
= EFI_HII_VARSTORE_BUFFER
;
285 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
286 CopyMem (&Storage
->Size
, &((EFI_IFR_VARSTORE
*) OpCodeData
)->Size
, sizeof (UINT16
));
288 AsciiString
= (CHAR8
*) ((EFI_IFR_VARSTORE
*) OpCodeData
)->Name
;
289 Storage
->Name
= AllocateZeroPool (AsciiStrSize (AsciiString
) * 2);
290 ASSERT (Storage
->Name
!= NULL
);
291 for (Index2
= 0; AsciiString
[Index2
] != 0; Index2
++) {
292 Storage
->Name
[Index2
] = (CHAR16
) AsciiString
[Index2
];
295 // Append '\0' to the end of the unicode string.
297 Storage
->Name
[Index2
] = 0;
298 } else if (Operand
== EFI_IFR_VARSTORE_NAME_VALUE_OP
) {
299 Storage
->Type
= EFI_HII_VARSTORE_NAME_VALUE
;
301 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE_NAME_VALUE
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
302 } else if (Operand
== EFI_IFR_VARSTORE_EFI_OP
) {
303 Storage
->Type
= EFI_HII_VARSTORE_EFI_VARIABLE
;
305 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE_EFI
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
310 FreePool (HiiPackageList
);
313 FreePool (HandleBuffer
);
320 Generate a sub string then output it.
322 This is a internal function.
324 @param String A constant string which is the prefix of the to be
325 generated string, e.g. GUID=
326 @param BufferLen The length of the Buffer in bytes.
327 @param Buffer Points to a buffer which will be converted to be the
328 content of the generated string.
329 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
330 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
331 if 3, the buffer contains other data.
332 @param SubStr Points to the output string. It's caller's
333 responsibility to free this buffer.
339 IN CONST EFI_STRING String
,
343 OUT EFI_STRING
*SubStr
349 EFI_STRING StringHeader
;
351 ASSERT (String
!= NULL
&& SubStr
!= NULL
);
353 if (Buffer
== NULL
) {
354 *SubStr
= AllocateCopyPool (StrSize (String
), String
);
355 ASSERT (*SubStr
!= NULL
);
359 Length
= StrLen (String
) + BufferLen
* 2 + 1 + 1;
360 Str
= AllocateZeroPool (Length
* sizeof (CHAR16
));
361 ASSERT (Str
!= NULL
);
363 StrCpy (Str
, String
);
364 Length
= (BufferLen
* 2 + 1) * sizeof (CHAR16
);
366 Status
= EFI_SUCCESS
;
367 StringHeader
= Str
+ StrLen (String
);
371 Status
= BufInReverseOrderToHexString (StringHeader
, (UINT8
*) Buffer
, BufferLen
);
374 Status
= UnicodeToConfigString (StringHeader
, &Length
, (CHAR16
*) Buffer
);
377 Status
= BufToHexString (StringHeader
, &Length
, (UINT8
*) Buffer
, BufferLen
);
379 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
381 ToLower (StringHeader
);
387 ASSERT_EFI_ERROR (Status
);
395 Retrieve the <ConfigBody> from String then output it.
397 This is a internal function.
399 @param String A sub string of a configuration string in
400 <MultiConfigAltResp> format.
401 @param ConfigBody Points to the output string. It's caller's
402 responsibility to free this buffer.
404 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
405 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
406 @retval EFI_SUCCESS All existing storage is exported.
411 IN EFI_STRING String
,
412 OUT EFI_STRING
*ConfigBody
419 if (String
== NULL
|| ConfigBody
== NULL
) {
420 return EFI_INVALID_PARAMETER
;
423 TmpPtr
= StrStr (String
, L
"GUID=");
424 if (TmpPtr
== NULL
) {
426 // It is the last <ConfigResp> of the incoming configuration string.
428 Result
= AllocateCopyPool (StrSize (String
), String
);
429 if (Result
== NULL
) {
430 return EFI_OUT_OF_RESOURCES
;
432 *ConfigBody
= Result
;
437 Length
= TmpPtr
- String
;
438 Result
= AllocateCopyPool (Length
* sizeof (CHAR16
), String
);
439 if (Result
== NULL
) {
440 return EFI_OUT_OF_RESOURCES
;
443 *(Result
+ Length
- 1) = 0;
444 *ConfigBody
= Result
;
451 Adjusts the size of a previously allocated buffer.
454 @param OldPool A pointer to the buffer whose size is being adjusted.
455 @param OldSize The size of the current buffer.
456 @param NewSize The size of the new buffer.
458 @return The new buffer allocated.
472 NewPool
= AllocateZeroPool (NewSize
);
475 if (OldPool
!= NULL
) {
476 if (NewPool
!= NULL
) {
477 CopyMem (NewPool
, OldPool
, OldSize
< NewSize
? OldSize
: NewSize
);
480 gBS
->FreePool (OldPool
);
488 Append a string to a multi-string format.
490 This is a internal function.
492 @param MultiString String in <MultiConfigRequest>,
493 <MultiConfigAltResp>, or <MultiConfigResp>. On
494 input, the buffer length of this string is
495 MAX_STRING_LENGTH. On output, the buffer length
497 @param AppendString NULL-terminated Unicode string.
499 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
500 @retval EFI_SUCCESS AppendString is append to the end of MultiString
504 AppendToMultiString (
505 IN OUT EFI_STRING
*MultiString
,
506 IN EFI_STRING AppendString
509 UINTN AppendStringSize
;
510 UINTN MultiStringSize
;
512 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
513 return EFI_INVALID_PARAMETER
;
516 AppendStringSize
= StrSize (AppendString
);
517 MultiStringSize
= StrSize (*MultiString
);
520 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
522 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
523 MultiStringSize
> MAX_STRING_LENGTH
) {
524 *MultiString
= (EFI_STRING
) ReallocatePool (
525 (VOID
*) (*MultiString
),
527 MultiStringSize
+ AppendStringSize
532 // Append the incoming string
534 StrCat (*MultiString
, AppendString
);
541 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
543 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
545 This is a internal function.
547 @param StringPtr String in <BlockConfig> format and points to the
548 first character of <Number>.
549 @param Number The output value. Caller takes the responsibility
551 @param Len Length of the <Number>, in characters.
553 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
555 @retval EFI_SUCCESS Value of <Number> is outputted in Number
561 IN EFI_STRING StringPtr
,
572 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
573 ASSERT (*StringPtr
!= 0);
578 while (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
581 *Len
= StringPtr
- TmpPtr
;
584 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
586 Status
= EFI_OUT_OF_RESOURCES
;
589 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
592 Length
= (Length
+ 1) / 2;
593 Buf
= (UINT8
*) AllocateZeroPool (Length
);
595 Status
= EFI_OUT_OF_RESOURCES
;
599 Status
= HexStringToBuf (Buf
, &Length
, Str
, NULL
);
600 if (EFI_ERROR (Status
)) {
605 Status
= EFI_SUCCESS
;
616 This function allows a caller to extract the current configuration
617 for one or more named elements from one or more drivers.
619 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
621 @param Request A null-terminated Unicode string in
622 <MultiConfigRequest> format.
623 @param Progress On return, points to a character in the Request
624 string. Points to the string's null terminator if
625 request was successful. Points to the most recent
626 & before the first failing name / value pair (or
627 the beginning of the string if the failure is in
628 the first name / value pair) if the request was
630 @param Results Null-terminated Unicode string in
631 <MultiConfigAltResp> format which has all values
632 filled in for the names in the Request string.
633 String to be allocated by the called function.
635 @retval EFI_SUCCESS The Results string is filled with the values
636 corresponding to all requested names.
637 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
638 results that must be stored awaiting possible
640 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
641 Progress set to the "G" in "GUID" of the routing
642 header that doesn't match. Note: There is no
643 requirement that all routing data be validated
644 before any configuration extraction.
645 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
646 parameter would result in this type of error. The
647 Progress parameter is set to NULL.
648 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
649 before the error or the beginning of the string.
650 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
656 HiiConfigRoutingExtractConfig (
657 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
658 IN CONST EFI_STRING Request
,
659 OUT EFI_STRING
*Progress
,
660 OUT EFI_STRING
*Results
663 HII_DATABASE_PRIVATE_DATA
*Private
;
664 EFI_STRING StringPtr
;
665 EFI_STRING ConfigRequest
;
667 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
670 HII_DATABASE_RECORD
*Database
;
671 UINT8
*DevicePathPkg
;
672 UINT8
*CurrentDevicePath
;
673 EFI_HANDLE DriverHandle
;
674 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
675 EFI_STRING AccessProgress
;
676 EFI_STRING AccessResults
;
681 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
682 // as FALSE. But this renders the system to not 100% compliant with
683 // UEFI 2.1. Use this with caution.
685 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
686 return EFI_UNSUPPORTED
;
689 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
690 return EFI_INVALID_PARAMETER
;
693 if (Request
== NULL
) {
695 return EFI_INVALID_PARAMETER
;
698 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
700 *Progress
= StringPtr
;
703 // The first element of <MultiConfigRequest> should be
704 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
706 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
707 return EFI_INVALID_PARAMETER
;
711 // Allocate a fix length of memory to store Results. Reallocate memory for
712 // Results if this fix length is insufficient.
714 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
715 if (*Results
== NULL
) {
716 return EFI_OUT_OF_RESOURCES
;
719 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
721 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
722 // or most recent & before the error.
724 if (StringPtr
== Request
) {
725 *Progress
= StringPtr
;
727 *Progress
= StringPtr
- 1;
731 // Process each <ConfigRequest> of <MultiConfigRequest>
733 Length
= CalculateConfigStringLen (StringPtr
);
734 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
735 if (ConfigRequest
== NULL
) {
736 return EFI_OUT_OF_RESOURCES
;
738 *(ConfigRequest
+ Length
) = 0;
741 // Get the UEFI device path
743 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
744 if (EFI_ERROR (Status
)) {
745 FreePool (ConfigRequest
);
750 // Find driver which matches the routing data.
753 for (Link
= Private
->DatabaseList
.ForwardLink
;
754 Link
!= &Private
->DatabaseList
;
755 Link
= Link
->ForwardLink
757 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
759 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
760 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
764 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
766 DriverHandle
= Database
->DriverHandle
;
772 FreePool (DevicePath
);
774 if (DriverHandle
== NULL
) {
776 // Routing data does not match any known driver.
777 // Set Progress to the 'G' in "GUID" of the routing header.
779 *Progress
= StringPtr
;
780 FreePool (ConfigRequest
);
781 return EFI_NOT_FOUND
;
785 // Call corresponding ConfigAccess protocol to extract settings
787 Status
= gBS
->HandleProtocol (
789 &gEfiHiiConfigAccessProtocolGuid
,
790 (VOID
**) &ConfigAccess
792 ASSERT_EFI_ERROR (Status
);
794 Status
= ConfigAccess
->ExtractConfig (
800 if (EFI_ERROR (Status
)) {
802 // AccessProgress indicates the parsing progress on <ConfigRequest>.
803 // Map it to the progress on <MultiConfigRequest> then return it.
805 RemainSize
= StrSize (AccessProgress
);
806 for (TmpPtr
= StringPtr
; CompareMem (TmpPtr
, AccessProgress
, RemainSize
) != 0; TmpPtr
++);
809 FreePool (ConfigRequest
);
814 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
816 ASSERT (*AccessProgress
== 0);
817 Status
= AppendToMultiString (Results
, AccessResults
);
818 ASSERT_EFI_ERROR (Status
);
819 FreePool (AccessResults
);
820 AccessResults
= NULL
;
821 FreePool (ConfigRequest
);
822 ConfigRequest
= NULL
;
825 // Go to next <ConfigRequest> (skip '&').
828 if (*StringPtr
== 0) {
829 *Progress
= StringPtr
;
843 This function allows the caller to request the current configuration for the
844 entirety of the current HII database and returns the data in a
845 null-terminated Unicode string.
847 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
849 @param Results Null-terminated Unicode string in
850 <MultiConfigAltResp> format which has all values
851 filled in for the names in the Request string.
852 String to be allocated by the called function.
853 De-allocation is up to the caller.
855 @retval EFI_SUCCESS The Results string is filled with the values
856 corresponding to all requested names.
857 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
858 results that must be stored awaiting possible
860 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
861 parameter would result in this type of error.
866 HiiConfigRoutingExportConfig (
867 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
868 OUT EFI_STRING
*Results
872 HII_DATABASE_PRIVATE_DATA
*Private
;
873 LIST_ENTRY StorageListHdr
;
874 HII_FORMSET_STORAGE
*Storage
;
876 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
880 EFI_STRING ConfigRequest
;
882 EFI_STRING StringPtr
;
883 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
884 EFI_STRING AccessProgress
;
885 EFI_STRING AccessResults
;
888 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
889 // as FALSE. But this renders the system to not 100% compliant with
890 // UEFI 2.1. Use this with caution.
892 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
893 return EFI_UNSUPPORTED
;
896 if (This
== NULL
|| Results
== NULL
) {
897 return EFI_INVALID_PARAMETER
;
900 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
902 InitializeListHead (&StorageListHdr
);
904 Status
= ExportAllStorage (&Private
->HiiDatabase
, &StorageListHdr
);
905 if (EFI_ERROR (Status
)) {
910 // Allocate a fix length of memory to store Results. Reallocate memory for
911 // Results if this fix length is insufficient.
913 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
914 if (*Results
== NULL
) {
915 return EFI_OUT_OF_RESOURCES
;
919 // Parsing all formset storages.
921 for (Link
= StorageListHdr
.ForwardLink
; Link
!= &StorageListHdr
; Link
= Link
->ForwardLink
) {
922 Storage
= CR (Link
, HII_FORMSET_STORAGE
, Entry
, HII_FORMSET_STORAGE_SIGNATURE
);
924 // Find the corresponding device path instance
926 Status
= gBS
->HandleProtocol (
927 Storage
->DriverHandle
,
928 &gEfiDevicePathProtocolGuid
,
929 (VOID
**) &DevicePath
931 if (EFI_ERROR (Status
)) {
935 // Convert the device path binary to hex UNICODE %02x bytes in the same order
936 // as the device path resides in RAM memory.
938 Length
= GetDevicePathSize (DevicePath
);
939 PathHdrSize
= (Length
* 2 + 1) * sizeof (CHAR16
);
940 PathHdr
= (EFI_STRING
) AllocateZeroPool (PathHdrSize
);
941 if (PathHdr
== NULL
) {
942 return EFI_OUT_OF_RESOURCES
;
944 Status
= BufInReverseOrderToHexString (PathHdr
, (UINT8
*) DevicePath
, Length
);
945 ASSERT_EFI_ERROR (Status
);
948 // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
949 // It means extract all possible configurations from this specific driver.
951 RequestSize
= (StrLen (L
"GUID=&NAME=&PATH=") + 32) * sizeof (CHAR16
) + PathHdrSize
;
952 if (Storage
->Name
!= NULL
) {
953 RequestSize
+= StrLen (Storage
->Name
) * 4 * sizeof (CHAR16
);
956 ConfigRequest
= (EFI_STRING
) AllocateZeroPool (RequestSize
);
957 if (ConfigRequest
== NULL
) {
959 return EFI_OUT_OF_RESOURCES
;
964 // <GuidHdr> ::= 'GUID='<Guid>
965 // Convert <Guid> in the same order as it resides in RAM memory.
967 StringPtr
= ConfigRequest
;
968 StrnCpy (StringPtr
, L
"GUID=", StrLen (L
"GUID="));
969 StringPtr
+= StrLen (L
"GUID=");
971 Status
= BufInReverseOrderToHexString (StringPtr
, (UINT8
*) (&Storage
->Guid
), sizeof (EFI_GUID
));
972 ASSERT_EFI_ERROR (Status
);
975 ASSERT (*StringPtr
== 0);
981 // <NameHdr> ::= 'NAME='<String>
983 StrnCpy (StringPtr
, L
"NAME=", StrLen (L
"NAME="));
984 StringPtr
+= StrLen (L
"NAME=");
986 if (Storage
->Name
!= NULL
) {
987 Length
= (StrLen (Storage
->Name
) * 4 + 1) * sizeof (CHAR16
);
988 Status
= UnicodeToConfigString (StringPtr
, &Length
, Storage
->Name
);
989 ASSERT_EFI_ERROR (Status
);
990 StringPtr
+= StrLen (Storage
->Name
) * 4;
998 // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
1000 StrnCpy (StringPtr
, L
"PATH=", StrLen (L
"PATH="));
1001 StringPtr
+= StrLen (L
"PATH=");
1002 StrCpy (StringPtr
, PathHdr
);
1008 // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
1009 // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
1010 // is required to call ConfigAccess.ExtractConfig().
1012 // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
1013 // to handle such kind of "ConfigRequest". It is not supported till now.
1015 // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
1016 // will be updated as soon as the decision is made.
1019 // Route the request to corresponding ConfigAccess protocol to extract settings.
1021 Status
= gBS
->HandleProtocol (
1022 Storage
->DriverHandle
,
1023 &gEfiHiiConfigAccessProtocolGuid
,
1024 (VOID
**) &ConfigAccess
1026 ASSERT_EFI_ERROR (Status
);
1028 AccessProgress
= NULL
;
1029 AccessResults
= NULL
;
1030 Status
= ConfigAccess
->ExtractConfig (
1036 if (EFI_ERROR (Status
)) {
1037 FreePool (ConfigRequest
);
1038 if (AccessProgress
!= NULL
) {
1039 FreePool (AccessProgress
);
1041 if (AccessResults
!= NULL
) {
1042 FreePool (AccessResults
);
1044 return EFI_INVALID_PARAMETER
;
1048 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
1050 ASSERT (*AccessProgress
== 0);
1051 Status
= AppendToMultiString (Results
, AccessResults
);
1052 ASSERT_EFI_ERROR (Status
);
1053 FreePool (AccessResults
);
1054 AccessResults
= NULL
;
1055 FreePool (ConfigRequest
);
1056 ConfigRequest
= NULL
;
1061 // Free the exported storage resource
1063 while (!IsListEmpty (&StorageListHdr
)) {
1065 StorageListHdr
.ForwardLink
,
1066 HII_FORMSET_STORAGE
,
1068 HII_FORMSET_STORAGE_SIGNATURE
1070 RemoveEntryList (&Storage
->Entry
);
1071 FreePool (Storage
->Name
);
1080 This function processes the results of processing forms and routes it to the
1081 appropriate handlers or storage.
1083 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1085 @param Configuration A null-terminated Unicode string in
1086 <MulltiConfigResp> format.
1087 @param Progress A pointer to a string filled in with the offset of
1088 the most recent & before the first failing name /
1089 value pair (or the beginning of the string if the
1090 failure is in the first name / value pair) or the
1091 terminating NULL if all was successful.
1093 @retval EFI_SUCCESS The results have been distributed or are awaiting
1095 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
1096 results that must be stored awaiting possible
1098 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
1099 would result in this type of error.
1100 @retval EFI_NOT_FOUND Target for the specified routing data was not
1106 HiiConfigRoutingRouteConfig (
1107 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1108 IN CONST EFI_STRING Configuration
,
1109 OUT EFI_STRING
*Progress
1112 HII_DATABASE_PRIVATE_DATA
*Private
;
1113 EFI_STRING StringPtr
;
1114 EFI_STRING ConfigResp
;
1117 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1119 HII_DATABASE_RECORD
*Database
;
1120 UINT8
*DevicePathPkg
;
1121 UINT8
*CurrentDevicePath
;
1122 EFI_HANDLE DriverHandle
;
1123 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
1124 EFI_STRING AccessProgress
;
1129 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1130 // as FALSE. But this renders the system to not 100% compliant with
1131 // UEFI 2.1. Use this with caution.
1133 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1134 return EFI_UNSUPPORTED
;
1137 if (This
== NULL
|| Progress
== NULL
) {
1138 return EFI_INVALID_PARAMETER
;
1141 if (Configuration
== NULL
) {
1143 return EFI_INVALID_PARAMETER
;
1146 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1147 StringPtr
= Configuration
;
1148 *Progress
= StringPtr
;
1151 // The first element of <MultiConfigResp> should be
1152 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
1154 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1155 return EFI_INVALID_PARAMETER
;
1158 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
1160 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
1161 // or most recent & before the error.
1163 if (StringPtr
== Configuration
) {
1164 *Progress
= StringPtr
;
1166 *Progress
= StringPtr
- 1;
1170 // Process each <ConfigResp> of <MultiConfigResp>
1172 Length
= CalculateConfigStringLen (StringPtr
);
1173 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
1174 if (ConfigResp
== NULL
) {
1175 return EFI_OUT_OF_RESOURCES
;
1178 // Append '\0' to the end of ConfigRequest
1180 *(ConfigResp
+ Length
) = 0;
1183 // Get the UEFI device path
1185 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
1186 if (EFI_ERROR (Status
)) {
1187 FreePool (ConfigResp
);
1192 // Find driver which matches the routing data.
1194 DriverHandle
= NULL
;
1195 for (Link
= Private
->DatabaseList
.ForwardLink
;
1196 Link
!= &Private
->DatabaseList
;
1197 Link
= Link
->ForwardLink
1199 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
1201 if ((DevicePathPkg
= Database
->PackageList
->DevicePathPkg
) != NULL
) {
1202 CurrentDevicePath
= DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
1206 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
1208 DriverHandle
= Database
->DriverHandle
;
1214 FreePool (DevicePath
);
1216 if (DriverHandle
== NULL
) {
1218 // Routing data does not match any known driver.
1219 // Set Progress to the 'G' in "GUID" of the routing header.
1221 *Progress
= StringPtr
;
1222 FreePool (ConfigResp
);
1223 return EFI_NOT_FOUND
;
1227 // Call corresponding ConfigAccess protocol to route settings
1229 Status
= gBS
->HandleProtocol (
1231 &gEfiHiiConfigAccessProtocolGuid
,
1232 (VOID
**) &ConfigAccess
1234 ASSERT_EFI_ERROR (Status
);
1236 Status
= ConfigAccess
->RouteConfig (
1242 if (EFI_ERROR (Status
)) {
1244 // AccessProgress indicates the parsing progress on <ConfigResp>.
1245 // Map it to the progress on <MultiConfigResp> then return it.
1247 RemainSize
= StrSize (AccessProgress
);
1248 for (TmpPtr
= StringPtr
; CompareMem (TmpPtr
, AccessProgress
, RemainSize
) != 0; TmpPtr
++);
1251 FreePool (ConfigResp
);
1255 FreePool (ConfigResp
);
1259 // Go to next <ConfigResp> (skip '&').
1261 StringPtr
+= Length
;
1262 if (*StringPtr
== 0) {
1263 *Progress
= StringPtr
;
1276 This helper function is to be called by drivers to map configuration data
1277 stored in byte array ("block") formats such as UEFI Variables into current
1278 configuration strings.
1280 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1282 @param ConfigRequest A null-terminated Unicode string in
1283 <ConfigRequest> format.
1284 @param Block Array of bytes defining the block's configuration.
1285 @param BlockSize Length in bytes of Block.
1286 @param Config Filled-in configuration string. String allocated
1287 by the function. Returned only if call is
1289 @param Progress A pointer to a string filled in with the offset of
1290 the most recent & before the first failing
1291 name/value pair (or the beginning of the string if
1292 the failure is in the first name / value pair) or
1293 the terminating NULL if all was successful.
1295 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1296 terminator at the end of the ConfigRequest
1298 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1299 points to the first character of ConfigRequest.
1300 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1301 Block parameter would result in this type of
1302 error. Progress points to the first character of
1304 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1305 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1306 Block is left updated and Progress points at
1307 the "&" preceding the first non-<BlockName>.
1313 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1314 IN CONST EFI_STRING ConfigRequest
,
1315 IN CONST UINT8
*Block
,
1316 IN CONST UINTN BlockSize
,
1317 OUT EFI_STRING
*Config
,
1318 OUT EFI_STRING
*Progress
1321 HII_DATABASE_PRIVATE_DATA
*Private
;
1322 EFI_STRING StringPtr
;
1330 EFI_STRING ValueStr
;
1331 EFI_STRING ConfigElement
;
1333 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1334 return EFI_INVALID_PARAMETER
;
1337 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1338 *Progress
= ConfigRequest
;
1339 return EFI_INVALID_PARAMETER
;
1343 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1344 ASSERT (Private
!= NULL
);
1346 StringPtr
= ConfigRequest
;
1349 ConfigElement
= NULL
;
1352 // Allocate a fix length of memory to store Results. Reallocate memory for
1353 // Results if this fix length is insufficient.
1355 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1356 if (*Config
== NULL
) {
1357 return EFI_OUT_OF_RESOURCES
;
1363 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1364 *Progress
= StringPtr
;
1365 Status
= EFI_INVALID_PARAMETER
;
1368 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1371 if (*StringPtr
== 0) {
1372 *Progress
= StringPtr
;
1373 Status
= EFI_INVALID_PARAMETER
;
1377 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1380 if (*StringPtr
== 0) {
1381 *Progress
= StringPtr
;
1382 Status
= EFI_INVALID_PARAMETER
;
1391 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1393 Length
= StringPtr
- ConfigRequest
;
1394 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1397 // Parse each <RequestElement> if exists
1398 // Only <BlockName> format is supported by this help function.
1399 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1401 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1403 // Back up the header of one <BlockName>
1407 StringPtr
+= StrLen (L
"OFFSET=");
1411 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1412 if (Status
== EFI_OUT_OF_RESOURCES
) {
1413 *Progress
= ConfigRequest
;
1420 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1422 FreePool (TmpBuffer
);
1424 StringPtr
+= Length
;
1425 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1426 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1427 Status
= EFI_INVALID_PARAMETER
;
1430 StringPtr
+= StrLen (L
"&WIDTH=");
1435 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1436 if (Status
== EFI_OUT_OF_RESOURCES
) {
1437 *Progress
= ConfigRequest
;
1444 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1446 FreePool (TmpBuffer
);
1448 StringPtr
+= Length
;
1449 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1450 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1451 Status
= EFI_INVALID_PARAMETER
;
1456 // Calculate Value and convert it to hex string.
1458 if (Offset
+ Width
> BlockSize
) {
1459 *Progress
= StringPtr
;
1460 Status
= EFI_DEVICE_ERROR
;
1464 Value
= (UINT8
*) AllocateZeroPool (Width
);
1465 if (Value
== NULL
) {
1466 *Progress
= ConfigRequest
;
1467 Status
= EFI_OUT_OF_RESOURCES
;
1471 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1473 Length
= Width
* 2 + 1;
1474 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1475 if (ValueStr
== NULL
) {
1476 *Progress
= ConfigRequest
;
1477 Status
= EFI_OUT_OF_RESOURCES
;
1481 Status
= BufToHexString (ValueStr
, &Length
, Value
, Width
);
1482 ASSERT_EFI_ERROR (Status
);
1489 // Build a ConfigElement
1491 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1492 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1493 if (ConfigElement
== NULL
) {
1494 Status
= EFI_OUT_OF_RESOURCES
;
1497 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1498 if (*StringPtr
== 0) {
1499 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1501 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1502 StrCat (ConfigElement
, L
"VALUE=");
1503 StrCat (ConfigElement
, ValueStr
);
1505 AppendToMultiString (Config
, ConfigElement
);
1507 FreePool (ConfigElement
);
1508 FreePool (ValueStr
);
1509 ConfigElement
= NULL
;
1513 // If '\0', parsing is finished. Otherwise skip '&' to continue
1515 if (*StringPtr
== 0) {
1518 AppendToMultiString (Config
, L
"&");
1523 if (*StringPtr
!= 0) {
1524 *Progress
= StringPtr
- 1;
1525 Status
= EFI_INVALID_PARAMETER
;
1529 *Progress
= StringPtr
;
1534 if (ValueStr
!= NULL
) {
1535 FreePool (ValueStr
);
1537 if (Value
!= NULL
) {
1540 if (ConfigElement
) {
1541 FreePool (ConfigElement
);
1550 This helper function is to be called by drivers to map configuration strings
1551 to configurations stored in byte array ("block") formats such as UEFI Variables.
1553 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1555 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1557 @param Block A possibly null array of bytes representing the
1558 current block. Only bytes referenced in the
1559 ConfigResp string in the block are modified. If
1560 this parameter is null or if the *BlockSize
1561 parameter is (on input) shorter than required by
1562 the Configuration string, only the BlockSize
1563 parameter is updated and an appropriate status
1564 (see below) is returned.
1565 @param BlockSize The length of the Block in units of UINT8. On
1566 input, this is the size of the Block. On output,
1567 if successful, contains the index of the last
1568 modified byte in the Block.
1569 @param Progress On return, points to an element of the ConfigResp
1570 string filled in with the offset of the most
1571 recent '&' before the first failing name / value
1572 pair (or the beginning of the string if the
1573 failure is in the first name / value pair) or the
1574 terminating NULL if all was successful.
1576 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1577 terminator at the end of the ConfigResp string.
1578 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1579 points to the first character of ConfigResp.
1580 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1581 Block parameter would result in this type of
1582 error. Progress points to the first character of
1584 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1585 value pair. Block is left updated and
1586 Progress points at the '&' preceding the first
1593 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1594 IN CONST EFI_STRING ConfigResp
,
1595 IN OUT UINT8
*Block
,
1596 IN OUT UINTN
*BlockSize
,
1597 OUT EFI_STRING
*Progress
1600 HII_DATABASE_PRIVATE_DATA
*Private
;
1601 EFI_STRING StringPtr
;
1610 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1611 return EFI_INVALID_PARAMETER
;
1614 if (ConfigResp
== NULL
|| Block
== NULL
) {
1615 *Progress
= ConfigResp
;
1616 return EFI_INVALID_PARAMETER
;
1619 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1620 ASSERT (Private
!= NULL
);
1622 StringPtr
= ConfigResp
;
1623 BufferSize
= *BlockSize
;
1629 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1630 *Progress
= StringPtr
;
1631 Status
= EFI_INVALID_PARAMETER
;
1634 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1637 if (*StringPtr
== 0) {
1638 *Progress
= StringPtr
;
1639 Status
= EFI_INVALID_PARAMETER
;
1643 while (*StringPtr
!= L
'&' && *StringPtr
!= 0) {
1646 if (*StringPtr
== 0) {
1647 *Progress
= StringPtr
;
1648 Status
= EFI_INVALID_PARAMETER
;
1657 // Parse each <ConfigElement> if exists
1658 // Only <BlockConfig> format is supported by this help function.
1659 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1661 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1662 StringPtr
+= StrLen (L
"OFFSET=");
1666 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1667 if (Status
== EFI_OUT_OF_RESOURCES
) {
1668 *Progress
= ConfigResp
;
1675 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1677 FreePool (TmpBuffer
);
1679 StringPtr
+= Length
;
1680 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1681 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1682 Status
= EFI_INVALID_PARAMETER
;
1685 StringPtr
+= StrLen (L
"&WIDTH=");
1690 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1691 if (Status
== EFI_OUT_OF_RESOURCES
) {
1692 *Progress
= ConfigResp
;
1699 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1701 FreePool (TmpBuffer
);
1703 StringPtr
+= Length
;
1704 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1705 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1706 Status
= EFI_INVALID_PARAMETER
;
1709 StringPtr
+= StrLen (L
"&VALUE=");
1714 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1715 if (Status
== EFI_OUT_OF_RESOURCES
) {
1716 *Progress
= ConfigResp
;
1720 StringPtr
+= Length
;
1721 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1722 *Progress
= StringPtr
- Length
- 7;
1723 Status
= EFI_INVALID_PARAMETER
;
1728 // Update the Block with configuration info
1731 if (Offset
+ Width
> BufferSize
) {
1732 return EFI_DEVICE_ERROR
;
1735 CopyMem (Block
+ Offset
, Value
, Width
);
1736 *BlockSize
= Offset
+ Width
- 1;
1742 // If '\0', parsing is finished. Otherwise skip '&' to continue
1744 if (*StringPtr
== 0) {
1751 if (*StringPtr
!= 0) {
1752 *Progress
= StringPtr
- 1;
1753 Status
= EFI_INVALID_PARAMETER
;
1757 *Progress
= StringPtr
;
1762 if (Value
!= NULL
) {
1770 This helper function is to be called by drivers to extract portions of
1771 a larger configuration string.
1773 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1775 @param Configuration A null-terminated Unicode string in
1776 <MultiConfigAltResp> format.
1777 @param Guid A pointer to the GUID value to search for in the
1778 routing portion of the ConfigResp string when
1779 retrieving the requested data. If Guid is NULL,
1780 then all GUID values will be searched for.
1781 @param Name A pointer to the NAME value to search for in the
1782 routing portion of the ConfigResp string when
1783 retrieving the requested data. If Name is NULL,
1784 then all Name values will be searched for.
1785 @param DevicePath A pointer to the PATH value to search for in the
1786 routing portion of the ConfigResp string when
1787 retrieving the requested data. If DevicePath is
1788 NULL, then all DevicePath values will be searched
1790 @param AltCfgId A pointer to the ALTCFG value to search for in the
1791 routing portion of the ConfigResp string when
1792 retrieving the requested data. If this parameter
1793 is NULL, then the current setting will be
1795 @param AltCfgResp A pointer to a buffer which will be allocated by
1796 the function which contains the retrieved string
1797 as requested. This buffer is only allocated if
1798 the call was successful.
1800 @retval EFI_SUCCESS The request succeeded. The requested data was
1801 extracted and placed in the newly allocated
1803 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1804 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1805 @retval EFI_NOT_FOUND Target for the specified routing data was not
1812 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1813 IN CONST EFI_STRING Configuration
,
1814 IN CONST EFI_GUID
*Guid
,
1815 IN CONST EFI_STRING Name
,
1816 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1817 IN CONST UINT16
*AltCfgId
,
1818 OUT EFI_STRING
*AltCfgResp
1822 EFI_STRING StringPtr
;
1823 EFI_STRING HdrStart
;
1830 EFI_STRING AltIdStr
;
1837 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1838 // as FALSE. But this renders the system to not 100% compliant with
1839 // UEFI 2.1. Use this with caution.
1841 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1842 return EFI_UNSUPPORTED
;
1856 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1857 return EFI_INVALID_PARAMETER
;
1860 StringPtr
= Configuration
;
1861 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1862 return EFI_INVALID_PARAMETER
;
1866 // Generate the sub string for later matching.
1868 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1871 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1872 (VOID
*) DevicePath
,
1876 if (AltCfgId
!= NULL
) {
1877 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1880 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1882 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1885 while (*StringPtr
!= 0) {
1887 // Try to match the GUID
1890 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1891 if (TmpPtr
== NULL
) {
1892 Status
= EFI_NOT_FOUND
;
1898 // Jump to <NameHdr>
1901 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1903 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1904 if (StringPtr
== NULL
) {
1905 Status
= EFI_NOT_FOUND
;
1913 // Try to match the NAME
1915 if (GuidFlag
&& !NameFlag
) {
1916 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1920 // Jump to <PathHdr>
1923 StringPtr
+= StrLen (NameStr
);
1925 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1926 if (StringPtr
== NULL
) {
1927 Status
= EFI_NOT_FOUND
;
1936 // Try to match the DevicePath
1938 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1939 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1944 // Jump to '&' before <DescHdr> or <ConfigBody>
1946 if (DevicePath
!= NULL
) {
1947 StringPtr
+= StrLen (PathStr
);
1949 StringPtr
= StrStr (StringPtr
, L
"&");
1950 if (StringPtr
== NULL
) {
1951 Status
= EFI_NOT_FOUND
;
1956 HdrEnd
= ++StringPtr
;
1961 // Try to match the AltCfgId
1963 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1964 if (AltCfgId
== NULL
) {
1966 // Return Current Setting when AltCfgId is NULL.
1968 Status
= OutputConfigBody (StringPtr
, &Result
);
1972 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1974 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1979 Status
= OutputConfigBody (StringPtr
, &Result
);
1985 Status
= EFI_NOT_FOUND
;
1989 if (!EFI_ERROR (Status
)) {
1991 // Copy the <ConfigHdr> and <ConfigBody>
1993 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1994 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1995 if (*AltCfgResp
== NULL
) {
1996 Status
= EFI_OUT_OF_RESOURCES
;
1998 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1999 StrCat (*AltCfgResp
, Result
);
2000 Status
= EFI_SUCCESS
;
2004 if (GuidStr
!= NULL
) {
2007 if (NameStr
!= NULL
) {
2010 if (PathStr
!= NULL
) {
2013 if (AltIdStr
!= NULL
) {
2014 FreePool (AltIdStr
);
2016 if (Result
!= NULL
) {