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 SafeFreePool (DevicePathString
);
131 return EFI_OUT_OF_RESOURCES
;
134 HexStringToBuffer (*DevicePath
, &Length
, DevicePathString
);
136 SafeFreePool (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 SafeFreePool (HandleBuffer
);
209 HandleCount
= BufferSize
/ sizeof (EFI_HII_HANDLE
);
210 for (Index
= 0; Index
< HandleCount
; Index
++) {
211 HiiHandle
= HandleBuffer
[Index
];
214 HiiPackageList
= NULL
;
215 Status
= HiiExportPackageLists (HiiDatabase
, HiiHandle
, &BufferSize
, HiiPackageList
);
216 if (Status
== EFI_BUFFER_TOO_SMALL
) {
217 HiiPackageList
= AllocateZeroPool (BufferSize
);
218 ASSERT (HiiPackageList
!= NULL
);
219 Status
= HiiExportPackageLists (HiiDatabase
, HiiHandle
, &BufferSize
, HiiPackageList
);
221 if (EFI_ERROR (Status
)) {
222 SafeFreePool (HandleBuffer
);
223 SafeFreePool (HiiPackageList
);
228 // Get Form package from this HII package List
230 Offset
= sizeof (EFI_HII_PACKAGE_LIST_HEADER
);
231 CopyMem (&PackageListLength
, &HiiPackageList
->PackageLength
, sizeof (UINT32
));
233 ZeroMem (&PackageHeader
, sizeof (EFI_HII_PACKAGE_HEADER
));
235 while (Offset
< PackageListLength
) {
236 Package
= (EFI_HII_PACKAGE_HEADER
*) (((UINT8
*) HiiPackageList
) + Offset
);
237 CopyMem (&PackageHeader
, Package
, sizeof (EFI_HII_PACKAGE_HEADER
));
238 if (PackageHeader
.Type
== EFI_HII_PACKAGE_FORM
) {
241 Offset
+= PackageHeader
.Length
;
243 if (Offset
>= PackageListLength
) {
245 // Error here: No Form package found in this Package List
251 // Search Storage definition in this Form package
253 Offset
= sizeof (EFI_HII_PACKAGE_HEADER
);
254 while (Offset
< PackageHeader
.Length
) {
255 OpCodeData
= ((UINT8
*) Package
) + Offset
;
256 Offset
+= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->Length
;
258 Operand
= ((EFI_IFR_OP_HEADER
*) OpCodeData
)->OpCode
;
260 if ((Operand
== EFI_IFR_VARSTORE_OP
) ||
261 (Operand
== EFI_IFR_VARSTORE_NAME_VALUE_OP
) ||
262 (Operand
== EFI_IFR_VARSTORE_EFI_OP
)) {
264 Storage
= AllocateZeroPool (sizeof (HII_FORMSET_STORAGE
));
265 ASSERT (Storage
!= NULL
);
266 InsertTailList (StorageListHead
, &Storage
->Entry
);
268 Storage
->Signature
= HII_FORMSET_STORAGE_SIGNATURE
;
269 Storage
->HiiHandle
= HiiHandle
;
271 Status
= HiiGetPackageListHandle (HiiDatabase
, HiiHandle
, &DriverHandle
);
272 if (EFI_ERROR (Status
)) {
273 SafeFreePool (HandleBuffer
);
274 SafeFreePool (HiiPackageList
);
275 SafeFreePool (Storage
);
278 Storage
->DriverHandle
= DriverHandle
;
280 if (Operand
== EFI_IFR_VARSTORE_OP
) {
281 Storage
->Type
= EFI_HII_VARSTORE_BUFFER
;
283 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
284 CopyMem (&Storage
->Size
, &((EFI_IFR_VARSTORE
*) OpCodeData
)->Size
, sizeof (UINT16
));
286 AsciiString
= (CHAR8
*) ((EFI_IFR_VARSTORE
*) OpCodeData
)->Name
;
287 Storage
->Name
= AllocateZeroPool (AsciiStrSize (AsciiString
) * 2);
288 ASSERT (Storage
->Name
!= NULL
);
289 for (Index2
= 0; AsciiString
[Index2
] != 0; Index2
++) {
290 Storage
->Name
[Index2
] = (CHAR16
) AsciiString
[Index2
];
293 // Append '\0' to the end of the unicode string.
295 Storage
->Name
[Index2
] = 0;
296 } else if (Operand
== EFI_IFR_VARSTORE_NAME_VALUE_OP
) {
297 Storage
->Type
= EFI_HII_VARSTORE_NAME_VALUE
;
299 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE_NAME_VALUE
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
300 } else if (Operand
== EFI_IFR_VARSTORE_EFI_OP
) {
301 Storage
->Type
= EFI_HII_VARSTORE_EFI_VARIABLE
;
303 CopyMem (&Storage
->Guid
, &((EFI_IFR_VARSTORE_EFI
*) OpCodeData
)->Guid
, sizeof (EFI_GUID
));
308 SafeFreePool (HiiPackageList
);
311 SafeFreePool (HandleBuffer
);
318 Generate a sub string then output it.
320 This is a internal function.
322 @param String A constant string which is the prefix of the to be
323 generated string, e.g. GUID=
324 @param BufferLen The length of the Buffer in bytes.
325 @param Buffer Points to a buffer which will be converted to be the
326 content of the generated string.
327 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
328 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
329 if 3, the buffer contains other data.
330 @param SubStr Points to the output string. It's caller's
331 responsibility to free this buffer.
337 IN CONST EFI_STRING String
,
341 OUT EFI_STRING
*SubStr
347 EFI_STRING StringHeader
;
349 ASSERT (String
!= NULL
&& SubStr
!= NULL
);
351 if (Buffer
== NULL
) {
352 *SubStr
= AllocateCopyPool (StrSize (String
), String
);
353 ASSERT (*SubStr
!= NULL
);
357 Length
= StrLen (String
) + BufferLen
* 2 + 1 + 1;
358 Str
= AllocateZeroPool (Length
* sizeof (CHAR16
));
359 ASSERT (Str
!= NULL
);
361 StrCpy (Str
, String
);
362 Length
= (BufferLen
* 2 + 1) * sizeof (CHAR16
);
364 Status
= EFI_SUCCESS
;
365 StringHeader
= Str
+ StrLen (String
);
369 Status
= BufferToHexString (StringHeader
, (UINT8
*) Buffer
, BufferLen
);
372 Status
= UnicodeToConfigString (StringHeader
, &Length
, (CHAR16
*) Buffer
);
375 Status
= BufToHexString (StringHeader
, &Length
, (UINT8
*) Buffer
, BufferLen
);
377 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
379 ToLower (StringHeader
);
385 ASSERT_EFI_ERROR (Status
);
393 Retrieve the <ConfigBody> from String then output it.
395 This is a internal function.
397 @param String A sub string of a configuration string in
398 <MultiConfigAltResp> format.
399 @param ConfigBody Points to the output string. It's caller's
400 responsibility to free this buffer.
402 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
403 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
404 @retval EFI_SUCCESS All existing storage is exported.
409 IN EFI_STRING String
,
410 OUT EFI_STRING
*ConfigBody
417 if (String
== NULL
|| ConfigBody
== NULL
) {
418 return EFI_INVALID_PARAMETER
;
421 TmpPtr
= StrStr (String
, L
"GUID=");
422 if (TmpPtr
== NULL
) {
424 // It is the last <ConfigResp> of the incoming configuration string.
426 Result
= AllocateCopyPool (StrSize (String
), String
);
427 if (Result
== NULL
) {
428 return EFI_OUT_OF_RESOURCES
;
430 *ConfigBody
= Result
;
435 Length
= TmpPtr
- String
;
436 Result
= AllocateCopyPool (Length
* sizeof (CHAR16
), String
);
437 if (Result
== NULL
) {
438 return EFI_OUT_OF_RESOURCES
;
441 *(Result
+ Length
- 1) = 0;
442 *ConfigBody
= Result
;
449 Adjusts the size of a previously allocated buffer.
452 @param OldPool A pointer to the buffer whose size is being adjusted.
453 @param OldSize The size of the current buffer.
454 @param NewSize The size of the new buffer.
456 @return The new buffer allocated.
470 NewPool
= AllocateZeroPool (NewSize
);
473 if (OldPool
!= NULL
) {
474 if (NewPool
!= NULL
) {
475 CopyMem (NewPool
, OldPool
, OldSize
< NewSize
? OldSize
: NewSize
);
478 gBS
->FreePool (OldPool
);
486 Append a string to a multi-string format.
488 This is a internal function.
490 @param MultiString String in <MultiConfigRequest>,
491 <MultiConfigAltResp>, or <MultiConfigResp>. On
492 input, the buffer length of this string is
493 MAX_STRING_LENGTH. On output, the buffer length
495 @param AppendString NULL-terminated Unicode string.
497 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
498 @retval EFI_SUCCESS AppendString is append to the end of MultiString
502 AppendToMultiString (
503 IN OUT EFI_STRING
*MultiString
,
504 IN EFI_STRING AppendString
507 UINTN AppendStringSize
;
508 UINTN MultiStringSize
;
510 if (MultiString
== NULL
|| *MultiString
== NULL
|| AppendString
== NULL
) {
511 return EFI_INVALID_PARAMETER
;
514 AppendStringSize
= StrSize (AppendString
);
515 MultiStringSize
= StrSize (*MultiString
);
518 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
520 if (MultiStringSize
+ AppendStringSize
> MAX_STRING_LENGTH
||
521 MultiStringSize
> MAX_STRING_LENGTH
) {
522 *MultiString
= (EFI_STRING
) ReallocatePool (
523 (VOID
*) (*MultiString
),
525 MultiStringSize
+ AppendStringSize
530 // Append the incoming string
532 StrCat (*MultiString
, AppendString
);
539 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
541 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
543 This is a internal function.
545 @param StringPtr String in <BlockConfig> format and points to the
546 first character of <Number>.
547 @param Number The output value. Caller takes the responsibility
549 @param Len Length of the <Number>, in characters.
551 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
553 @retval EFI_SUCCESS Value of <Number> is outputted in Number
559 IN EFI_STRING StringPtr
,
570 ASSERT (StringPtr
!= NULL
&& Number
!= NULL
&& Len
!= NULL
);
571 ASSERT (*StringPtr
!= 0);
576 while (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
579 *Len
= StringPtr
- TmpPtr
;
582 Str
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (EFI_STRING
));
584 Status
= EFI_OUT_OF_RESOURCES
;
587 CopyMem (Str
, TmpPtr
, *Len
* sizeof (CHAR16
));
590 Length
= (Length
+ 1) / 2;
591 Buf
= (UINT8
*) AllocateZeroPool (Length
);
593 Status
= EFI_OUT_OF_RESOURCES
;
597 Status
= HexStringToBuf (Buf
, &Length
, Str
, NULL
);
598 if (EFI_ERROR (Status
)) {
603 Status
= EFI_SUCCESS
;
612 This function allows a caller to extract the current configuration
613 for one or more named elements from one or more drivers.
615 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
617 @param Request A null-terminated Unicode string in
618 <MultiConfigRequest> format.
619 @param Progress On return, points to a character in the Request
620 string. Points to the string's null terminator if
621 request was successful. Points to the most recent
622 & before the first failing name / value pair (or
623 the beginning of the string if the failure is in
624 the first name / value pair) if the request was
626 @param Results Null-terminated Unicode string in
627 <MultiConfigAltResp> format which has all values
628 filled in for the names in the Request string.
629 String to be allocated by the called function.
631 @retval EFI_SUCCESS The Results string is filled with the values
632 corresponding to all requested names.
633 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
634 results that must be stored awaiting possible
636 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
637 Progress set to the "G" in "GUID" of the routing
638 header that doesn't match. Note: There is no
639 requirement that all routing data be validated
640 before any configuration extraction.
641 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
642 parameter would result in this type of error. The
643 Progress parameter is set to NULL.
644 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
645 before the error or the beginning of the string.
646 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
652 HiiConfigRoutingExtractConfig (
653 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
654 IN CONST EFI_STRING Request
,
655 OUT EFI_STRING
*Progress
,
656 OUT EFI_STRING
*Results
659 HII_DATABASE_PRIVATE_DATA
*Private
;
660 EFI_STRING StringPtr
;
661 EFI_STRING ConfigRequest
;
663 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
666 HII_DATABASE_RECORD
*Database
;
667 UINT8
*CurrentDevicePath
;
668 EFI_HANDLE DriverHandle
;
669 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
670 EFI_STRING AccessProgress
;
671 EFI_STRING AccessResults
;
676 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
677 // as FALSE. But this renders the system to not 100% compliant with
678 // UEFI 2.1. Use this with caution.
680 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
681 return EFI_UNSUPPORTED
;
684 if (This
== NULL
|| Progress
== NULL
|| Results
== NULL
) {
685 return EFI_INVALID_PARAMETER
;
688 if (Request
== NULL
) {
690 return EFI_INVALID_PARAMETER
;
693 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
695 *Progress
= StringPtr
;
698 // The first element of <MultiConfigRequest> should be
699 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
701 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
702 return EFI_INVALID_PARAMETER
;
706 // Allocate a fix length of memory to store Results. Reallocate memory for
707 // Results if this fix length is insufficient.
709 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
710 if (*Results
== NULL
) {
711 return EFI_OUT_OF_RESOURCES
;
714 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
716 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
717 // or most recent & before the error.
719 if (StringPtr
== Request
) {
720 *Progress
= StringPtr
;
722 *Progress
= StringPtr
- 1;
726 // Process each <ConfigRequest> of <MultiConfigRequest>
728 Length
= CalculateConfigStringLen (StringPtr
);
729 ConfigRequest
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
730 if (ConfigRequest
== NULL
) {
731 return EFI_OUT_OF_RESOURCES
;
733 *(ConfigRequest
+ Length
) = 0;
736 // Get the UEFI device path
738 Status
= GetDevicePath (ConfigRequest
, (UINT8
**) &DevicePath
);
739 if (EFI_ERROR (Status
)) {
740 SafeFreePool (ConfigRequest
);
745 // Find driver which matches the routing data.
748 for (Link
= Private
->DatabaseList
.ForwardLink
;
749 Link
!= &Private
->DatabaseList
;
750 Link
= Link
->ForwardLink
752 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
753 CurrentDevicePath
= Database
->PackageList
->DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
754 if (CurrentDevicePath
!= NULL
) {
758 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
760 DriverHandle
= Database
->DriverHandle
;
766 SafeFreePool (DevicePath
);
768 if (DriverHandle
== NULL
) {
770 // Routing data does not match any known driver.
771 // Set Progress to the 'G' in "GUID" of the routing header.
773 *Progress
= StringPtr
;
774 SafeFreePool (ConfigRequest
);
775 return EFI_NOT_FOUND
;
779 // Call corresponding ConfigAccess protocol to extract settings
781 Status
= gBS
->HandleProtocol (
783 &gEfiHiiConfigAccessProtocolGuid
,
784 (VOID
**) &ConfigAccess
786 ASSERT_EFI_ERROR (Status
);
788 Status
= ConfigAccess
->ExtractConfig (
794 if (EFI_ERROR (Status
)) {
796 // AccessProgress indicates the parsing progress on <ConfigRequest>.
797 // Map it to the progress on <MultiConfigRequest> then return it.
799 RemainSize
= StrSize (AccessProgress
);
800 for (TmpPtr
= StringPtr
; CompareMem (TmpPtr
, AccessProgress
, RemainSize
) != 0; TmpPtr
++);
803 SafeFreePool (ConfigRequest
);
808 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
810 ASSERT (*AccessProgress
== 0);
811 Status
= AppendToMultiString (Results
, AccessResults
);
812 ASSERT_EFI_ERROR (Status
);
813 SafeFreePool (AccessResults
);
814 AccessResults
= NULL
;
815 SafeFreePool (ConfigRequest
);
816 ConfigRequest
= NULL
;
819 // Go to next <ConfigRequest> (skip '&').
822 if (*StringPtr
== 0) {
823 *Progress
= StringPtr
;
837 This function allows the caller to request the current configuration for the
838 entirety of the current HII database and returns the data in a
839 null-terminated Unicode string.
841 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
843 @param Results Null-terminated Unicode string in
844 <MultiConfigAltResp> format which has all values
845 filled in for the names in the Request string.
846 String to be allocated by the called function.
847 De-allocation is up to the caller.
849 @retval EFI_SUCCESS The Results string is filled with the values
850 corresponding to all requested names.
851 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
852 results that must be stored awaiting possible
854 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
855 parameter would result in this type of error.
860 HiiConfigRoutingExportConfig (
861 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
862 OUT EFI_STRING
*Results
866 HII_DATABASE_PRIVATE_DATA
*Private
;
867 LIST_ENTRY StorageListHdr
;
868 HII_FORMSET_STORAGE
*Storage
;
870 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
874 EFI_STRING ConfigRequest
;
876 EFI_STRING StringPtr
;
877 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
878 EFI_STRING AccessProgress
;
879 EFI_STRING AccessResults
;
883 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
884 // as FALSE. But this renders the system to not 100% compliant with
885 // UEFI 2.1. Use this with caution.
887 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
888 return EFI_UNSUPPORTED
;
891 if (This
== NULL
|| Results
== NULL
) {
892 return EFI_INVALID_PARAMETER
;
895 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
897 InitializeListHead (&StorageListHdr
);
899 Status
= ExportAllStorage (&Private
->HiiDatabase
, &StorageListHdr
);
900 if (EFI_ERROR (Status
)) {
905 // Allocate a fix length of memory to store Results. Reallocate memory for
906 // Results if this fix length is insufficient.
908 *Results
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
909 if (*Results
== NULL
) {
910 return EFI_OUT_OF_RESOURCES
;
914 // Parsing all formset storages.
916 for (Link
= StorageListHdr
.ForwardLink
; Link
!= &StorageListHdr
; Link
= Link
->ForwardLink
) {
917 Storage
= CR (Link
, HII_FORMSET_STORAGE
, Entry
, HII_FORMSET_STORAGE_SIGNATURE
);
919 // Find the corresponding device path instance
921 Status
= gBS
->HandleProtocol (
922 Storage
->DriverHandle
,
923 &gEfiDevicePathProtocolGuid
,
924 (VOID
**) &DevicePath
926 if (EFI_ERROR (Status
)) {
930 // Convert the device path binary to hex UNICODE %02x bytes in the same order
931 // as the device path resides in RAM memory.
933 Length
= GetDevicePathSize (DevicePath
);
934 PathHdrSize
= (Length
* 2 + 1) * sizeof (CHAR16
);
935 PathHdr
= (EFI_STRING
) AllocateZeroPool (PathHdrSize
);
936 if (PathHdr
== NULL
) {
937 return EFI_OUT_OF_RESOURCES
;
939 Status
= BufferToHexString (PathHdr
, (UINT8
*) DevicePath
, Length
);
940 ASSERT_EFI_ERROR (Status
);
943 // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
944 // It means extract all possible configurations from this specific driver.
946 TmpSize
= StrLen (L
"GUID=&NAME=&PATH=");
947 RequestSize
= (TmpSize
+ 32 + StrLen (Storage
->Name
) * 4)
948 * sizeof (CHAR16
) + PathHdrSize
;
949 ConfigRequest
= (EFI_STRING
) AllocateZeroPool (RequestSize
);
950 if (ConfigRequest
== NULL
) {
951 SafeFreePool (PathHdr
);
952 return EFI_OUT_OF_RESOURCES
;
957 // <GuidHdr> ::= 'GUID='<Guid>
958 // Convert <Guid> in the same order as it resides in RAM memory.
960 StringPtr
= ConfigRequest
;
961 StrnCpy (StringPtr
, L
"GUID=", StrLen (L
"GUID="));
962 StringPtr
+= StrLen (L
"GUID=");
964 Status
= BufferToHexString (StringPtr
, (UINT8
*) (&Storage
->Guid
), sizeof (EFI_GUID
));
965 ASSERT_EFI_ERROR (Status
);
968 ASSERT (*StringPtr
== 0);
974 // <NameHdr> ::= 'NAME='<String>
976 StrnCpy (StringPtr
, L
"NAME=", StrLen (L
"NAME="));
977 StringPtr
+= StrLen (L
"NAME=");
979 Length
= (StrLen (Storage
->Name
) * 4 + 1) * sizeof (CHAR16
);
980 Status
= UnicodeToConfigString (StringPtr
, &Length
, Storage
->Name
);
981 ASSERT_EFI_ERROR (Status
);
982 StringPtr
+= StrLen (Storage
->Name
) * 4;
989 // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
991 StrnCpy (StringPtr
, L
"PATH=", StrLen (L
"PATH="));
992 StringPtr
+= StrLen (L
"PATH=");
993 StrCpy (StringPtr
, PathHdr
);
995 SafeFreePool (PathHdr
);
999 // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
1000 // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
1001 // is required to call ConfigAccess.ExtractConfig().
1003 // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
1004 // to handle such kind of "ConfigRequest". It is not supported till now.
1006 // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
1007 // will be updated as soon as the decision is made.
1010 // Route the request to corresponding ConfigAccess protocol to extract settings.
1012 Status
= gBS
->HandleProtocol (
1013 Storage
->DriverHandle
,
1014 &gEfiHiiConfigAccessProtocolGuid
,
1015 (VOID
**) &ConfigAccess
1017 ASSERT_EFI_ERROR (Status
);
1019 Status
= ConfigAccess
->ExtractConfig (
1025 if (EFI_ERROR (Status
)) {
1026 SafeFreePool (ConfigRequest
);
1027 SafeFreePool (AccessResults
);
1028 return EFI_INVALID_PARAMETER
;
1032 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
1034 ASSERT (*AccessProgress
== 0);
1035 Status
= AppendToMultiString (Results
, AccessResults
);
1036 ASSERT_EFI_ERROR (Status
);
1037 SafeFreePool (AccessResults
);
1038 AccessResults
= NULL
;
1039 SafeFreePool (ConfigRequest
);
1040 ConfigRequest
= NULL
;
1045 // Free the exported storage resource
1047 while (!IsListEmpty (&StorageListHdr
)) {
1049 StorageListHdr
.ForwardLink
,
1050 HII_FORMSET_STORAGE
,
1052 HII_FORMSET_STORAGE_SIGNATURE
1054 RemoveEntryList (&Storage
->Entry
);
1055 SafeFreePool (Storage
->Name
);
1056 SafeFreePool (Storage
);
1064 This function processes the results of processing forms and routes it to the
1065 appropriate handlers or storage.
1067 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1069 @param Configuration A null-terminated Unicode string in
1070 <MulltiConfigResp> format.
1071 @param Progress A pointer to a string filled in with the offset of
1072 the most recent & before the first failing name /
1073 value pair (or the beginning of the string if the
1074 failure is in the first name / value pair) or the
1075 terminating NULL if all was successful.
1077 @retval EFI_SUCCESS The results have been distributed or are awaiting
1079 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
1080 results that must be stored awaiting possible
1082 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
1083 would result in this type of error.
1084 @retval EFI_NOT_FOUND Target for the specified routing data was not
1090 HiiConfigRoutingRouteConfig (
1091 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1092 IN CONST EFI_STRING Configuration
,
1093 OUT EFI_STRING
*Progress
1096 HII_DATABASE_PRIVATE_DATA
*Private
;
1097 EFI_STRING StringPtr
;
1098 EFI_STRING ConfigResp
;
1101 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1103 HII_DATABASE_RECORD
*Database
;
1104 UINT8
*CurrentDevicePath
;
1105 EFI_HANDLE DriverHandle
;
1106 EFI_HII_CONFIG_ACCESS_PROTOCOL
*ConfigAccess
;
1107 EFI_STRING AccessProgress
;
1112 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1113 // as FALSE. But this renders the system to not 100% compliant with
1114 // UEFI 2.1. Use this with caution.
1116 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1117 return EFI_UNSUPPORTED
;
1120 if (This
== NULL
|| Progress
== NULL
) {
1121 return EFI_INVALID_PARAMETER
;
1124 if (Configuration
== NULL
) {
1126 return EFI_INVALID_PARAMETER
;
1129 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1130 StringPtr
= Configuration
;
1131 *Progress
= StringPtr
;
1134 // The first element of <MultiConfigResp> should be
1135 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
1137 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1138 return EFI_INVALID_PARAMETER
;
1141 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) == 0) {
1143 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
1144 // or most recent & before the error.
1146 if (StringPtr
== Configuration
) {
1147 *Progress
= StringPtr
;
1149 *Progress
= StringPtr
- 1;
1153 // Process each <ConfigResp> of <MultiConfigResp>
1155 Length
= CalculateConfigStringLen (StringPtr
);
1156 ConfigResp
= AllocateCopyPool ((Length
+ 1) * sizeof (CHAR16
), StringPtr
);
1157 if (ConfigResp
== NULL
) {
1158 return EFI_OUT_OF_RESOURCES
;
1161 // Append '\0' to the end of ConfigRequest
1163 *(ConfigResp
+ Length
) = 0;
1166 // Get the UEFI device path
1168 Status
= GetDevicePath (ConfigResp
, (UINT8
**) &DevicePath
);
1169 if (EFI_ERROR (Status
)) {
1170 SafeFreePool (ConfigResp
);
1175 // Find driver which matches the routing data.
1177 DriverHandle
= NULL
;
1178 for (Link
= Private
->DatabaseList
.ForwardLink
;
1179 Link
!= &Private
->DatabaseList
;
1180 Link
= Link
->ForwardLink
1182 Database
= CR (Link
, HII_DATABASE_RECORD
, DatabaseEntry
, HII_DATABASE_RECORD_SIGNATURE
);
1183 CurrentDevicePath
= Database
->PackageList
->DevicePathPkg
+ sizeof (EFI_HII_PACKAGE_HEADER
);
1184 if (CurrentDevicePath
!= NULL
) {
1188 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) CurrentDevicePath
)
1190 DriverHandle
= Database
->DriverHandle
;
1196 SafeFreePool (DevicePath
);
1198 if (DriverHandle
== NULL
) {
1200 // Routing data does not match any known driver.
1201 // Set Progress to the 'G' in "GUID" of the routing header.
1203 *Progress
= StringPtr
;
1204 SafeFreePool (ConfigResp
);
1205 return EFI_NOT_FOUND
;
1209 // Call corresponding ConfigAccess protocol to route settings
1211 Status
= gBS
->HandleProtocol (
1213 &gEfiHiiConfigAccessProtocolGuid
,
1214 (VOID
**) &ConfigAccess
1216 ASSERT_EFI_ERROR (Status
);
1218 Status
= ConfigAccess
->RouteConfig (
1224 if (EFI_ERROR (Status
)) {
1226 // AccessProgress indicates the parsing progress on <ConfigResp>.
1227 // Map it to the progress on <MultiConfigResp> then return it.
1229 RemainSize
= StrSize (AccessProgress
);
1230 for (TmpPtr
= StringPtr
; CompareMem (TmpPtr
, AccessProgress
, RemainSize
) != 0; TmpPtr
++);
1233 SafeFreePool (ConfigResp
);
1237 SafeFreePool (ConfigResp
);
1241 // Go to next <ConfigResp> (skip '&').
1243 StringPtr
+= Length
;
1244 if (*StringPtr
== 0) {
1245 *Progress
= StringPtr
;
1258 This helper function is to be called by drivers to map configuration data
1259 stored in byte array ("block") formats such as UEFI Variables into current
1260 configuration strings.
1262 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1264 @param ConfigRequest A null-terminated Unicode string in
1265 <ConfigRequest> format.
1266 @param Block Array of bytes defining the block's configuration.
1267 @param BlockSize Length in bytes of Block.
1268 @param Config Filled-in configuration string. String allocated
1269 by the function. Returned only if call is
1271 @param Progress A pointer to a string filled in with the offset of
1272 the most recent & before the first failing
1273 name/value pair (or the beginning of the string if
1274 the failure is in the first name / value pair) or
1275 the terminating NULL if all was successful.
1277 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1278 terminator at the end of the ConfigRequest
1280 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1281 points to the first character of ConfigRequest.
1282 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1283 Block parameter would result in this type of
1284 error. Progress points to the first character of
1286 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1287 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1288 Block is left updated and Progress points at
1289 the "&" preceding the first non-<BlockName>.
1295 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1296 IN CONST EFI_STRING ConfigRequest
,
1297 IN CONST UINT8
*Block
,
1298 IN CONST UINTN BlockSize
,
1299 OUT EFI_STRING
*Config
,
1300 OUT EFI_STRING
*Progress
1303 HII_DATABASE_PRIVATE_DATA
*Private
;
1304 EFI_STRING StringPtr
;
1312 EFI_STRING ValueStr
;
1313 EFI_STRING ConfigElement
;
1315 if (This
== NULL
|| Progress
== NULL
|| Config
== NULL
) {
1316 return EFI_INVALID_PARAMETER
;
1319 if (Block
== NULL
|| ConfigRequest
== NULL
) {
1320 *Progress
= ConfigRequest
;
1321 return EFI_INVALID_PARAMETER
;
1325 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1326 ASSERT (Private
!= NULL
);
1328 StringPtr
= ConfigRequest
;
1331 ConfigElement
= NULL
;
1334 // Allocate a fix length of memory to store Results. Reallocate memory for
1335 // Results if this fix length is insufficient.
1337 *Config
= (EFI_STRING
) AllocateZeroPool (MAX_STRING_LENGTH
);
1338 if (*Config
== NULL
) {
1339 return EFI_OUT_OF_RESOURCES
;
1345 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1346 *Progress
= StringPtr
;
1347 Status
= EFI_INVALID_PARAMETER
;
1350 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1353 if (*StringPtr
== 0) {
1354 *Progress
= StringPtr
;
1355 Status
= EFI_INVALID_PARAMETER
;
1358 while (*StringPtr
++ != L
'&');
1361 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1363 Length
= StringPtr
- ConfigRequest
;
1364 CopyMem (*Config
, ConfigRequest
, Length
* sizeof (CHAR16
));
1367 // Parse each <RequestElement> if exists
1368 // Only <BlockName> format is supported by this help function.
1369 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1371 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1373 // Back up the header of one <BlockName>
1377 StringPtr
+= StrLen (L
"OFFSET=");
1381 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1382 if (Status
== EFI_OUT_OF_RESOURCES
) {
1383 *Progress
= ConfigRequest
;
1390 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1392 SafeFreePool (TmpBuffer
);
1394 StringPtr
+= Length
;
1395 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1396 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1397 Status
= EFI_INVALID_PARAMETER
;
1400 StringPtr
+= StrLen (L
"&WIDTH=");
1405 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1406 if (Status
== EFI_OUT_OF_RESOURCES
) {
1407 *Progress
= ConfigRequest
;
1414 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1416 SafeFreePool (TmpBuffer
);
1418 StringPtr
+= Length
;
1419 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1420 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1421 Status
= EFI_INVALID_PARAMETER
;
1426 // Calculate Value and convert it to hex string.
1428 if (Offset
+ Width
> BlockSize
) {
1429 *Progress
= StringPtr
;
1430 Status
= EFI_DEVICE_ERROR
;
1434 Value
= (UINT8
*) AllocateZeroPool (Width
);
1435 if (Value
== NULL
) {
1436 *Progress
= ConfigRequest
;
1437 Status
= EFI_OUT_OF_RESOURCES
;
1441 CopyMem (Value
, (UINT8
*) Block
+ Offset
, Width
);
1443 Length
= Width
* 2 + 1;
1444 ValueStr
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1445 if (ValueStr
== NULL
) {
1446 *Progress
= ConfigRequest
;
1447 Status
= EFI_OUT_OF_RESOURCES
;
1451 Status
= BufToHexString (ValueStr
, &Length
, Value
, Width
);
1452 ASSERT_EFI_ERROR (Status
);
1455 SafeFreePool (Value
);
1459 // Build a ConfigElement
1461 Length
+= StringPtr
- TmpPtr
+ 1 + StrLen (L
"VALUE=");
1462 ConfigElement
= (EFI_STRING
) AllocateZeroPool (Length
* sizeof (CHAR16
));
1463 if (ConfigElement
== NULL
) {
1464 Status
= EFI_OUT_OF_RESOURCES
;
1467 CopyMem (ConfigElement
, TmpPtr
, (StringPtr
- TmpPtr
+ 1) * sizeof (CHAR16
));
1468 if (*StringPtr
== 0) {
1469 *(ConfigElement
+ (StringPtr
- TmpPtr
)) = L
'&';
1471 *(ConfigElement
+ (StringPtr
- TmpPtr
) + 1) = 0;
1472 StrCat (ConfigElement
, L
"VALUE=");
1473 StrCat (ConfigElement
, ValueStr
);
1475 AppendToMultiString (Config
, ConfigElement
);
1477 SafeFreePool (ConfigElement
);
1478 SafeFreePool (ValueStr
);
1479 ConfigElement
= NULL
;
1483 // If '\0', parsing is finished. Otherwise skip '&' to continue
1485 if (*StringPtr
== 0) {
1488 AppendToMultiString (Config
, L
"&");
1493 if (*StringPtr
!= 0) {
1494 *Progress
= StringPtr
- 1;
1495 Status
= EFI_INVALID_PARAMETER
;
1499 *Progress
= StringPtr
;
1504 SafeFreePool (*Config
);
1505 SafeFreePool (ValueStr
);
1506 SafeFreePool (Value
);
1507 SafeFreePool (ConfigElement
);
1515 This helper function is to be called by drivers to map configuration strings
1516 to configurations stored in byte array ("block") formats such as UEFI Variables.
1518 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1520 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1522 @param Block A possibly null array of bytes representing the
1523 current block. Only bytes referenced in the
1524 ConfigResp string in the block are modified. If
1525 this parameter is null or if the *BlockSize
1526 parameter is (on input) shorter than required by
1527 the Configuration string, only the BlockSize
1528 parameter is updated and an appropriate status
1529 (see below) is returned.
1530 @param BlockSize The length of the Block in units of UINT8. On
1531 input, this is the size of the Block. On output,
1532 if successful, contains the index of the last
1533 modified byte in the Block.
1534 @param Progress On return, points to an element of the ConfigResp
1535 string filled in with the offset of the most
1536 recent '&' before the first failing name / value
1537 pair (or the beginning of the string if the
1538 failure is in the first name / value pair) or the
1539 terminating NULL if all was successful.
1541 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1542 terminator at the end of the ConfigResp string.
1543 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1544 points to the first character of ConfigResp.
1545 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1546 Block parameter would result in this type of
1547 error. Progress points to the first character of
1549 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1550 value pair. Block is left updated and
1551 Progress points at the '&' preceding the first
1558 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1559 IN CONST EFI_STRING ConfigResp
,
1560 IN OUT UINT8
*Block
,
1561 IN OUT UINTN
*BlockSize
,
1562 OUT EFI_STRING
*Progress
1565 HII_DATABASE_PRIVATE_DATA
*Private
;
1566 EFI_STRING StringPtr
;
1575 if (This
== NULL
|| BlockSize
== NULL
|| Progress
== NULL
) {
1576 return EFI_INVALID_PARAMETER
;
1579 if (ConfigResp
== NULL
|| Block
== NULL
) {
1580 *Progress
= ConfigResp
;
1581 return EFI_INVALID_PARAMETER
;
1584 Private
= CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This
);
1585 ASSERT (Private
!= NULL
);
1587 StringPtr
= ConfigResp
;
1588 BufferSize
= *BlockSize
;
1594 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1595 *Progress
= StringPtr
;
1596 Status
= EFI_INVALID_PARAMETER
;
1599 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"PATH=", StrLen (L
"PATH=")) != 0) {
1602 if (*StringPtr
== 0) {
1603 *Progress
= StringPtr
;
1604 Status
= EFI_INVALID_PARAMETER
;
1607 while (*StringPtr
++ != L
'&');
1610 // Parse each <ConfigElement> if exists
1611 // Only <BlockConfig> format is supported by this help function.
1612 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1614 while (*StringPtr
!= 0 && StrnCmp (StringPtr
, L
"OFFSET=", StrLen (L
"OFFSET=")) == 0) {
1615 StringPtr
+= StrLen (L
"OFFSET=");
1619 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1620 if (Status
== EFI_OUT_OF_RESOURCES
) {
1621 *Progress
= ConfigResp
;
1628 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1630 SafeFreePool (TmpBuffer
);
1632 StringPtr
+= Length
;
1633 if (StrnCmp (StringPtr
, L
"&WIDTH=", StrLen (L
"&WIDTH=")) != 0) {
1634 *Progress
= StringPtr
- Length
- StrLen (L
"OFFSET=") - 1;
1635 Status
= EFI_INVALID_PARAMETER
;
1638 StringPtr
+= StrLen (L
"&WIDTH=");
1643 Status
= GetValueOfNumber (StringPtr
, &TmpBuffer
, &Length
);
1644 if (Status
== EFI_OUT_OF_RESOURCES
) {
1645 *Progress
= ConfigResp
;
1652 (((Length
+ 1) / 2) < sizeof (UINTN
)) ? ((Length
+ 1) / 2) : sizeof (UINTN
)
1654 SafeFreePool (TmpBuffer
);
1656 StringPtr
+= Length
;
1657 if (StrnCmp (StringPtr
, L
"&VALUE=", StrLen (L
"&VALUE=")) != 0) {
1658 *Progress
= StringPtr
- Length
- StrLen (L
"&WIDTH=");
1659 Status
= EFI_INVALID_PARAMETER
;
1662 StringPtr
+= StrLen (L
"&VALUE=");
1667 Status
= GetValueOfNumber (StringPtr
, &Value
, &Length
);
1668 if (Status
== EFI_OUT_OF_RESOURCES
) {
1669 *Progress
= ConfigResp
;
1673 StringPtr
+= Length
;
1674 if (*StringPtr
!= 0 && *StringPtr
!= L
'&') {
1675 *Progress
= StringPtr
- Length
- 7;
1676 Status
= EFI_INVALID_PARAMETER
;
1681 // Update the Block with configuration info
1684 if (Offset
+ Width
> BufferSize
) {
1685 return EFI_DEVICE_ERROR
;
1688 CopyMem (Block
+ Offset
, Value
, Width
);
1689 *BlockSize
= Offset
+ Width
- 1;
1691 SafeFreePool (Value
);
1695 // If '\0', parsing is finished. Otherwise skip '&' to continue
1697 if (*StringPtr
== 0) {
1704 if (*StringPtr
!= 0) {
1705 *Progress
= StringPtr
- 1;
1706 Status
= EFI_INVALID_PARAMETER
;
1710 *Progress
= StringPtr
;
1715 SafeFreePool (Value
);
1721 This helper function is to be called by drivers to extract portions of
1722 a larger configuration string.
1724 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1726 @param Configuration A null-terminated Unicode string in
1727 <MultiConfigAltResp> format.
1728 @param Guid A pointer to the GUID value to search for in the
1729 routing portion of the ConfigResp string when
1730 retrieving the requested data. If Guid is NULL,
1731 then all GUID values will be searched for.
1732 @param Name A pointer to the NAME value to search for in the
1733 routing portion of the ConfigResp string when
1734 retrieving the requested data. If Name is NULL,
1735 then all Name values will be searched for.
1736 @param DevicePath A pointer to the PATH value to search for in the
1737 routing portion of the ConfigResp string when
1738 retrieving the requested data. If DevicePath is
1739 NULL, then all DevicePath values will be searched
1741 @param AltCfgId A pointer to the ALTCFG value to search for in the
1742 routing portion of the ConfigResp string when
1743 retrieving the requested data. If this parameter
1744 is NULL, then the current setting will be
1746 @param AltCfgResp A pointer to a buffer which will be allocated by
1747 the function which contains the retrieved string
1748 as requested. This buffer is only allocated if
1749 the call was successful.
1751 @retval EFI_SUCCESS The request succeeded. The requested data was
1752 extracted and placed in the newly allocated
1754 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1755 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1756 @retval EFI_NOT_FOUND Target for the specified routing data was not
1763 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL
*This
,
1764 IN CONST EFI_STRING Configuration
,
1765 IN CONST EFI_GUID
*Guid
,
1766 IN CONST EFI_STRING Name
,
1767 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1768 IN CONST UINT16
*AltCfgId
,
1769 OUT EFI_STRING
*AltCfgResp
1773 EFI_STRING StringPtr
;
1774 EFI_STRING HdrStart
;
1781 EFI_STRING AltIdStr
;
1788 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1789 // as FALSE. But this renders the system to not 100% compliant with
1790 // UEFI 2.1. Use this with caution.
1792 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol
)) {
1793 return EFI_UNSUPPORTED
;
1807 if (This
== NULL
|| Configuration
== NULL
|| AltCfgResp
== NULL
) {
1808 return EFI_INVALID_PARAMETER
;
1811 StringPtr
= Configuration
;
1812 if (StrnCmp (StringPtr
, L
"GUID=", StrLen (L
"GUID=")) != 0) {
1813 return EFI_INVALID_PARAMETER
;
1817 // Generate the sub string for later matching.
1819 GenerateSubStr (L
"GUID=", sizeof (EFI_GUID
), (VOID
*) Guid
, 1, &GuidStr
);
1822 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL
*) DevicePath
),
1823 (VOID
*) DevicePath
,
1827 if (AltCfgId
!= NULL
) {
1828 GenerateSubStr (L
"ALTCFG=", sizeof (UINT16
), (VOID
*) AltCfgId
, 3, &AltIdStr
);
1831 GenerateSubStr (L
"NAME=", StrLen (Name
) * sizeof (CHAR16
), (VOID
*) Name
, 2, &NameStr
);
1833 GenerateSubStr (L
"NAME=", 0, NULL
, 2, &NameStr
);
1836 while (*StringPtr
!= 0) {
1838 // Try to match the GUID
1841 TmpPtr
= StrStr (StringPtr
, GuidStr
);
1842 if (TmpPtr
== NULL
) {
1843 Status
= EFI_NOT_FOUND
;
1849 // Jump to <NameHdr>
1852 StringPtr
= TmpPtr
+ StrLen (GuidStr
);
1854 StringPtr
= StrStr (TmpPtr
, L
"NAME=");
1855 if (StringPtr
== NULL
) {
1856 Status
= EFI_NOT_FOUND
;
1864 // Try to match the NAME
1866 if (GuidFlag
&& !NameFlag
) {
1867 if (StrnCmp (StringPtr
, NameStr
, StrLen (NameStr
)) != 0) {
1871 // Jump to <PathHdr>
1874 StringPtr
+= StrLen (NameStr
);
1876 StringPtr
= StrStr (StringPtr
, L
"PATH=");
1877 if (StringPtr
== NULL
) {
1878 Status
= EFI_NOT_FOUND
;
1887 // Try to match the DevicePath
1889 if (GuidFlag
&& NameFlag
&& !PathFlag
) {
1890 if (StrnCmp (StringPtr
, PathStr
, StrLen (PathStr
)) != 0) {
1895 // Jump to '&' before <DescHdr> or <ConfigBody>
1897 if (DevicePath
!= NULL
) {
1898 StringPtr
+= StrLen (PathStr
);
1900 StringPtr
= StrStr (StringPtr
, L
"&");
1901 if (StringPtr
== NULL
) {
1902 Status
= EFI_NOT_FOUND
;
1907 HdrEnd
= ++StringPtr
;
1912 // Try to match the AltCfgId
1914 if (GuidFlag
&& NameFlag
&& PathFlag
) {
1915 if (AltCfgId
== NULL
) {
1917 // Return Current Setting when AltCfgId is NULL.
1919 Status
= OutputConfigBody (StringPtr
, &Result
);
1923 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1925 if (StrnCmp (StringPtr
, AltIdStr
, StrLen (AltIdStr
)) != 0) {
1930 Status
= OutputConfigBody (StringPtr
, &Result
);
1936 Status
= EFI_NOT_FOUND
;
1940 if (!EFI_ERROR (Status
)) {
1942 // Copy the <ConfigHdr> and <ConfigBody>
1944 Length
= HdrEnd
- HdrStart
+ StrLen (Result
);
1945 *AltCfgResp
= AllocateZeroPool (Length
* sizeof (CHAR16
));
1946 if (*AltCfgResp
== NULL
) {
1947 Status
= EFI_OUT_OF_RESOURCES
;
1949 StrnCpy (*AltCfgResp
, HdrStart
, HdrEnd
- HdrStart
);
1950 StrCat (*AltCfgResp
, Result
);
1951 Status
= EFI_SUCCESS
;
1955 SafeFreePool (GuidStr
);
1956 SafeFreePool (NameStr
);
1957 SafeFreePool (PathStr
);
1958 SafeFreePool (AltIdStr
);
1959 SafeFreePool (Result
);