]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
add parameter check logic to clean up Klocwork warning.
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3
4 Copyright (c) 2007 - 2008, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "HiiDatabase.h"
17
18 /**
19 Calculate the number of Unicode characters of the incoming Configuration string,
20 not including NULL terminator.
21
22 This is a internal function.
23
24 @param String String in <MultiConfigRequest> or
25 <MultiConfigResp> format.
26
27 @return The number of Unicode characters.
28
29 **/
30 UINTN
31 CalculateConfigStringLen (
32 IN EFI_STRING String
33 )
34 {
35 UINTN Length;
36
37 //
38 // "GUID=" should be the first element of incoming string.
39 //
40 ASSERT (String != NULL);
41 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
42
43 Length = StrLen (L"GUID=");
44 String += Length;
45
46 //
47 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
48 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
49 //
50 while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {
51 Length++;
52 String++;
53 }
54
55 return Length;
56 }
57
58
59 /**
60 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
61 from <PathHdr> of <ConfigHdr>.
62
63 This is a internal function.
64
65 @param String UEFI configuration string
66 @param DevicePath binary of a UEFI device path.
67
68 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
69 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
70 @retval EFI_SUCCESS The device path is retrieved and translated to
71 binary format.
72
73 **/
74 EFI_STATUS
75 GetDevicePath (
76 IN EFI_STRING String,
77 OUT UINT8 **DevicePath
78 )
79 {
80 UINTN Length;
81 EFI_STRING PathHdr;
82 EFI_STRING DevicePathString;
83
84 if (String == NULL || DevicePath == NULL) {
85 return EFI_INVALID_PARAMETER;
86 }
87
88 //
89 // Find the 'PATH=' of <PathHdr> and skip it.
90 //
91 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
92 if (*String == 0) {
93 return EFI_INVALID_PARAMETER;
94 }
95
96 String += StrLen (L"PATH=");
97 PathHdr = String;
98
99 //
100 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
101 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
102 // of UEFI device path.
103 //
104 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
105 DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
106 if (DevicePathString == NULL) {
107 return EFI_OUT_OF_RESOURCES;
108 }
109 StrnCpy (DevicePathString, PathHdr, Length);
110 *(DevicePathString + Length) = 0;
111
112 //
113 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
114 // as the device path resides in RAM memory.
115 // Translate the data into binary.
116 //
117 Length /= 2;
118 *DevicePath = (UINT8 *) AllocateZeroPool (Length);
119 if (*DevicePath == NULL) {
120 FreePool (DevicePathString);
121 return EFI_OUT_OF_RESOURCES;
122 }
123
124 HexStringToBufInReverseOrder (*DevicePath, &Length, DevicePathString);
125
126 FreePool (DevicePathString);
127
128 return EFI_SUCCESS;
129
130 }
131
132
133 /**
134 Generate a sub string then output it.
135
136 This is a internal function.
137
138 @param String A constant string which is the prefix of the to be
139 generated string, e.g. GUID=
140 @param BufferLen The length of the Buffer in bytes.
141 @param Buffer Points to a buffer which will be converted to be the
142 content of the generated string.
143 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
144 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
145 if 3, the buffer contains other data.
146 @param SubStr Points to the output string. It's caller's
147 responsibility to free this buffer.
148
149
150 **/
151 VOID
152 GenerateSubStr (
153 IN CONST EFI_STRING String,
154 IN UINTN BufferLen,
155 IN VOID *Buffer,
156 IN UINT8 Flag,
157 OUT EFI_STRING *SubStr
158 )
159 {
160 UINTN Length;
161 EFI_STRING Str;
162 EFI_STATUS Status;
163 EFI_STRING StringHeader;
164
165 ASSERT (String != NULL && SubStr != NULL);
166
167 if (Buffer == NULL) {
168 *SubStr = AllocateCopyPool (StrSize (String), String);
169 ASSERT (*SubStr != NULL);
170 return ;
171 }
172
173 Length = StrLen (String) + BufferLen * 2 + 1 + 1;
174 Str = AllocateZeroPool (Length * sizeof (CHAR16));
175 ASSERT (Str != NULL);
176
177 StrCpy (Str, String);
178 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
179
180 Status = EFI_SUCCESS;
181 StringHeader = Str + StrLen (String);
182
183 switch (Flag) {
184 case 1:
185 Status = BufInReverseOrderToHexString (StringHeader, (UINT8 *) Buffer, BufferLen);
186 break;
187 case 2:
188 Status = UnicodeToConfigString (StringHeader, &Length, (CHAR16 *) Buffer);
189 break;
190 case 3:
191 Status = BufToHexString (StringHeader, &Length, (UINT8 *) Buffer, BufferLen);
192 //
193 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
194 //
195 ToLower (StringHeader);
196 break;
197 default:
198 break;
199 }
200
201 ASSERT_EFI_ERROR (Status);
202 StrCat (Str, L"&");
203
204 *SubStr = Str;
205 }
206
207
208 /**
209 Retrieve the <ConfigBody> from String then output it.
210
211 This is a internal function.
212
213 @param String A sub string of a configuration string in
214 <MultiConfigAltResp> format.
215 @param ConfigBody Points to the output string. It's caller's
216 responsibility to free this buffer.
217
218 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
219 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
220 @retval EFI_SUCCESS All existing storage is exported.
221
222 **/
223 EFI_STATUS
224 OutputConfigBody (
225 IN EFI_STRING String,
226 OUT EFI_STRING *ConfigBody
227 )
228 {
229 EFI_STRING TmpPtr;
230 EFI_STRING Result;
231 UINTN Length;
232
233 if (String == NULL || ConfigBody == NULL) {
234 return EFI_INVALID_PARAMETER;
235 }
236
237 TmpPtr = StrStr (String, L"GUID=");
238 if (TmpPtr == NULL) {
239 //
240 // It is the last <ConfigResp> of the incoming configuration string.
241 //
242 Result = AllocateCopyPool (StrSize (String), String);
243 if (Result == NULL) {
244 return EFI_OUT_OF_RESOURCES;
245 } else {
246 *ConfigBody = Result;
247 return EFI_SUCCESS;
248 }
249 }
250
251 Length = TmpPtr - String;
252 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
253 if (Result == NULL) {
254 return EFI_OUT_OF_RESOURCES;
255 }
256
257 *(Result + Length - 1) = 0;
258 *ConfigBody = Result;
259 return EFI_SUCCESS;
260
261 }
262
263 /**
264 Append a string to a multi-string format.
265
266 This is a internal function.
267
268 @param MultiString String in <MultiConfigRequest>,
269 <MultiConfigAltResp>, or <MultiConfigResp>. On
270 input, the buffer length of this string is
271 MAX_STRING_LENGTH. On output, the buffer length
272 might be updated.
273 @param AppendString NULL-terminated Unicode string.
274
275 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
276 @retval EFI_SUCCESS AppendString is append to the end of MultiString
277
278 **/
279 EFI_STATUS
280 AppendToMultiString (
281 IN OUT EFI_STRING *MultiString,
282 IN EFI_STRING AppendString
283 )
284 {
285 UINTN AppendStringSize;
286 UINTN MultiStringSize;
287
288 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 AppendStringSize = StrSize (AppendString);
293 MultiStringSize = StrSize (*MultiString);
294
295 //
296 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
297 //
298 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
299 MultiStringSize > MAX_STRING_LENGTH) {
300 *MultiString = (EFI_STRING) ReallocatePool (
301 MultiStringSize,
302 MultiStringSize + AppendStringSize,
303 (VOID *) (*MultiString)
304 );
305 ASSERT (*MultiString != NULL);
306 }
307 //
308 // Append the incoming string
309 //
310 StrCat (*MultiString, AppendString);
311
312 return EFI_SUCCESS;
313 }
314
315
316 /**
317 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
318 or WIDTH or VALUE.
319 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
320
321 This is a internal function.
322
323 @param StringPtr String in <BlockConfig> format and points to the
324 first character of <Number>.
325 @param Number The output value. Caller takes the responsibility
326 to free memory.
327 @param Len Length of the <Number>, in characters.
328
329 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
330 structures.
331 @retval EFI_SUCCESS Value of <Number> is outputted in Number
332 successfully.
333
334 **/
335 EFI_STATUS
336 GetValueOfNumber (
337 IN EFI_STRING StringPtr,
338 OUT UINT8 **Number,
339 OUT UINTN *Len
340 )
341 {
342 EFI_STRING TmpPtr;
343 UINTN Length;
344 EFI_STRING Str;
345 UINT8 *Buf;
346 EFI_STATUS Status;
347
348 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
349 ASSERT (*StringPtr != 0);
350
351 Buf = NULL;
352
353 TmpPtr = StringPtr;
354 while (*StringPtr != 0 && *StringPtr != L'&') {
355 StringPtr++;
356 }
357 *Len = StringPtr - TmpPtr;
358 Length = *Len + 1;
359
360 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
361 if (Str == NULL) {
362 Status = EFI_OUT_OF_RESOURCES;
363 goto Exit;
364 }
365 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
366 *(Str + *Len) = 0;
367
368 Length = (Length + 1) / 2;
369 Buf = (UINT8 *) AllocateZeroPool (Length);
370 if (Buf == NULL) {
371 Status = EFI_OUT_OF_RESOURCES;
372 goto Exit;
373 }
374
375 Status = HexStringToBuf (Buf, &Length, Str, NULL);
376 if (EFI_ERROR (Status)) {
377 goto Exit;
378 }
379
380 *Number = Buf;
381 Status = EFI_SUCCESS;
382
383 Exit:
384 if (Str != NULL) {
385 FreePool (Str);
386 }
387 return Status;
388 }
389
390
391 /**
392 This function allows a caller to extract the current configuration
393 for one or more named elements from one or more drivers.
394
395 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
396 instance.
397 @param Request A null-terminated Unicode string in
398 <MultiConfigRequest> format.
399 @param Progress On return, points to a character in the Request
400 string. Points to the string's null terminator if
401 request was successful. Points to the most recent
402 & before the first failing name / value pair (or
403 the beginning of the string if the failure is in
404 the first name / value pair) if the request was
405 not successful.
406 @param Results Null-terminated Unicode string in
407 <MultiConfigAltResp> format which has all values
408 filled in for the names in the Request string.
409 String to be allocated by the called function.
410
411 @retval EFI_SUCCESS The Results string is filled with the values
412 corresponding to all requested names.
413 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
414 results that must be stored awaiting possible
415 future protocols.
416 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
417 Progress set to the "G" in "GUID" of the routing
418 header that doesn't match. Note: There is no
419 requirement that all routing data be validated
420 before any configuration extraction.
421 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
422 parameter would result in this type of error. The
423 Progress parameter is set to NULL.
424 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
425 before the error or the beginning of the string.
426 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
427 name in question.
428
429 **/
430 EFI_STATUS
431 EFIAPI
432 HiiConfigRoutingExtractConfig (
433 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
434 IN CONST EFI_STRING Request,
435 OUT EFI_STRING *Progress,
436 OUT EFI_STRING *Results
437 )
438 {
439 HII_DATABASE_PRIVATE_DATA *Private;
440 EFI_STRING StringPtr;
441 EFI_STRING ConfigRequest;
442 UINTN Length;
443 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
444 EFI_STATUS Status;
445 LIST_ENTRY *Link;
446 HII_DATABASE_RECORD *Database;
447 UINT8 *DevicePathPkg;
448 UINT8 *CurrentDevicePath;
449 EFI_HANDLE DriverHandle;
450 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
451 EFI_STRING AccessProgress;
452 EFI_STRING AccessResults;
453 BOOLEAN FirstElement;
454
455 //
456 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
457 // as FALSE. But this renders the system to not 100% compliant with
458 // UEFI 2.1. Use this with caution.
459 //
460 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
461 return EFI_UNSUPPORTED;
462 }
463
464 if (This == NULL || Progress == NULL || Results == NULL) {
465 return EFI_INVALID_PARAMETER;
466 }
467
468 if (Request == NULL) {
469 *Progress = NULL;
470 return EFI_INVALID_PARAMETER;
471 }
472
473 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
474 StringPtr = Request;
475 *Progress = StringPtr;
476
477 //
478 // The first element of <MultiConfigRequest> should be
479 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
480 //
481 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
482 return EFI_INVALID_PARAMETER;
483 }
484
485 FirstElement = TRUE;
486
487 //
488 // Allocate a fix length of memory to store Results. Reallocate memory for
489 // Results if this fix length is insufficient.
490 //
491 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
492 if (*Results == NULL) {
493 return EFI_OUT_OF_RESOURCES;
494 }
495
496 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
497 //
498 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
499 // or most recent & before the error.
500 //
501 if (StringPtr == Request) {
502 *Progress = StringPtr;
503 } else {
504 *Progress = StringPtr - 1;
505 }
506
507 //
508 // Process each <ConfigRequest> of <MultiConfigRequest>
509 //
510 Length = CalculateConfigStringLen (StringPtr);
511 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
512 if (ConfigRequest == NULL) {
513 return EFI_OUT_OF_RESOURCES;
514 }
515 *(ConfigRequest + Length) = 0;
516
517 //
518 // Get the UEFI device path
519 //
520 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
521 if (EFI_ERROR (Status)) {
522 FreePool (ConfigRequest);
523 return Status;
524 }
525
526 //
527 // Find driver which matches the routing data.
528 //
529 DriverHandle = NULL;
530 for (Link = Private->DatabaseList.ForwardLink;
531 Link != &Private->DatabaseList;
532 Link = Link->ForwardLink
533 ) {
534 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
535
536 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
537 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
538 if (CompareMem (
539 DevicePath,
540 CurrentDevicePath,
541 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
542 ) == 0) {
543 DriverHandle = Database->DriverHandle;
544 break;
545 }
546 }
547 }
548
549 FreePool (DevicePath);
550
551 if (DriverHandle == NULL) {
552 //
553 // Routing data does not match any known driver.
554 // Set Progress to the 'G' in "GUID" of the routing header.
555 //
556 *Progress = StringPtr;
557 FreePool (ConfigRequest);
558 return EFI_NOT_FOUND;
559 }
560
561 //
562 // Call corresponding ConfigAccess protocol to extract settings
563 //
564 Status = gBS->HandleProtocol (
565 DriverHandle,
566 &gEfiHiiConfigAccessProtocolGuid,
567 (VOID **) &ConfigAccess
568 );
569 ASSERT_EFI_ERROR (Status);
570
571 Status = ConfigAccess->ExtractConfig (
572 ConfigAccess,
573 ConfigRequest,
574 &AccessProgress,
575 &AccessResults
576 );
577 if (EFI_ERROR (Status)) {
578 //
579 // AccessProgress indicates the parsing progress on <ConfigRequest>.
580 // Map it to the progress on <MultiConfigRequest> then return it.
581 //
582 *Progress = StrStr (StringPtr, AccessProgress);
583 FreePool (ConfigRequest);
584 return Status;
585 }
586
587 //
588 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
589 // which seperates the first <ConfigAltResp> and the following ones.
590 //
591 ASSERT (*AccessProgress == 0);
592
593 if (!FirstElement) {
594 Status = AppendToMultiString (Results, L"&");
595 ASSERT_EFI_ERROR (Status);
596 }
597
598 Status = AppendToMultiString (Results, AccessResults);
599 ASSERT_EFI_ERROR (Status);
600
601 FirstElement = FALSE;
602
603 FreePool (AccessResults);
604 AccessResults = NULL;
605 FreePool (ConfigRequest);
606 ConfigRequest = NULL;
607
608 //
609 // Go to next <ConfigRequest> (skip '&').
610 //
611 StringPtr += Length;
612 if (*StringPtr == 0) {
613 *Progress = StringPtr;
614 break;
615 }
616
617 StringPtr++;
618
619 }
620
621 return EFI_SUCCESS;
622
623 }
624
625
626 /**
627 This function allows the caller to request the current configuration for the
628 entirety of the current HII database and returns the data in a
629 null-terminated Unicode string.
630
631 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
632 instance.
633 @param Results Null-terminated Unicode string in
634 <MultiConfigAltResp> format which has all values
635 filled in for the names in the Request string.
636 String to be allocated by the called function.
637 De-allocation is up to the caller.
638
639 @retval EFI_SUCCESS The Results string is filled with the values
640 corresponding to all requested names.
641 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
642 results that must be stored awaiting possible
643 future protocols.
644 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
645 parameter would result in this type of error.
646
647 **/
648 EFI_STATUS
649 EFIAPI
650 HiiConfigRoutingExportConfig (
651 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
652 OUT EFI_STRING *Results
653 )
654 {
655 EFI_STATUS Status;
656 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
657 EFI_STRING AccessResults;
658 UINTN Index;
659 EFI_HANDLE *ConfigAccessHandles;
660 UINTN NumberConfigAccessHandles;
661 BOOLEAN FirstElement;
662
663 //
664 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
665 // as FALSE. But this renders the system to not 100% compliant with
666 // UEFI 2.1. Use this with caution.
667 //
668 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
669 return EFI_UNSUPPORTED;
670 }
671
672 if (This == NULL || Results == NULL) {
673 return EFI_INVALID_PARAMETER;
674 }
675
676 //
677 // Allocate a fix length of memory to store Results. Reallocate memory for
678 // Results if this fix length is insufficient.
679 //
680 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
681 if (*Results == NULL) {
682 return EFI_OUT_OF_RESOURCES;
683 }
684
685 NumberConfigAccessHandles = 0;
686 Status = gBS->LocateHandleBuffer (
687 ByProtocol,
688 &gEfiHiiConfigAccessProtocolGuid,
689 NULL,
690 &NumberConfigAccessHandles,
691 &ConfigAccessHandles
692 );
693 if (EFI_ERROR (Status)) {
694 return Status;
695 }
696
697 FirstElement = TRUE;
698
699 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
700 Status = gBS->HandleProtocol (
701 ConfigAccessHandles[Index],
702 &gEfiHiiConfigAccessProtocolGuid,
703 (VOID **) &ConfigAccess
704 );
705 if (EFI_ERROR (Status)) {
706 continue;
707 }
708
709 Status = ConfigAccess->ExtractConfig (
710 ConfigAccess,
711 NULL,
712 NULL,
713 &AccessResults
714 );
715 if (!EFI_ERROR (Status)) {
716 //
717 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
718 // which seperates the first <ConfigAltResp> and the following ones.
719 //
720 if (!FirstElement) {
721 Status = AppendToMultiString (Results, L"&");
722 ASSERT_EFI_ERROR (Status);
723 }
724
725 Status = AppendToMultiString (Results, AccessResults);
726 ASSERT_EFI_ERROR (Status);
727
728 FirstElement = FALSE;
729
730 FreePool (AccessResults);
731 AccessResults = NULL;
732 }
733 }
734 FreePool (ConfigAccessHandles);
735
736 return EFI_SUCCESS;
737 }
738
739
740 /**
741 This function processes the results of processing forms and routes it to the
742 appropriate handlers or storage.
743
744 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
745 instance.
746 @param Configuration A null-terminated Unicode string in
747 <MulltiConfigResp> format.
748 @param Progress A pointer to a string filled in with the offset of
749 the most recent & before the first failing name /
750 value pair (or the beginning of the string if the
751 failure is in the first name / value pair) or the
752 terminating NULL if all was successful.
753
754 @retval EFI_SUCCESS The results have been distributed or are awaiting
755 distribution.
756 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
757 results that must be stored awaiting possible
758 future protocols.
759 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
760 would result in this type of error.
761 @retval EFI_NOT_FOUND Target for the specified routing data was not
762 found.
763
764 **/
765 EFI_STATUS
766 EFIAPI
767 HiiConfigRoutingRouteConfig (
768 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
769 IN CONST EFI_STRING Configuration,
770 OUT EFI_STRING *Progress
771 )
772 {
773 HII_DATABASE_PRIVATE_DATA *Private;
774 EFI_STRING StringPtr;
775 EFI_STRING ConfigResp;
776 UINTN Length;
777 EFI_STATUS Status;
778 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
779 LIST_ENTRY *Link;
780 HII_DATABASE_RECORD *Database;
781 UINT8 *DevicePathPkg;
782 UINT8 *CurrentDevicePath;
783 EFI_HANDLE DriverHandle;
784 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
785 EFI_STRING AccessProgress;
786
787 //
788 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
789 // as FALSE. But this renders the system to not 100% compliant with
790 // UEFI 2.1. Use this with caution.
791 //
792 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
793 return EFI_UNSUPPORTED;
794 }
795
796 if (This == NULL || Progress == NULL) {
797 return EFI_INVALID_PARAMETER;
798 }
799
800 if (Configuration == NULL) {
801 *Progress = NULL;
802 return EFI_INVALID_PARAMETER;
803 }
804
805 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
806 StringPtr = Configuration;
807 *Progress = StringPtr;
808
809 //
810 // The first element of <MultiConfigResp> should be
811 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
812 //
813 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
814 return EFI_INVALID_PARAMETER;
815 }
816
817 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
818 //
819 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
820 // or most recent & before the error.
821 //
822 if (StringPtr == Configuration) {
823 *Progress = StringPtr;
824 } else {
825 *Progress = StringPtr - 1;
826 }
827
828 //
829 // Process each <ConfigResp> of <MultiConfigResp>
830 //
831 Length = CalculateConfigStringLen (StringPtr);
832 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
833 if (ConfigResp == NULL) {
834 return EFI_OUT_OF_RESOURCES;
835 }
836 //
837 // Append '\0' to the end of ConfigRequest
838 //
839 *(ConfigResp + Length) = 0;
840
841 //
842 // Get the UEFI device path
843 //
844 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
845 if (EFI_ERROR (Status)) {
846 FreePool (ConfigResp);
847 return Status;
848 }
849
850 //
851 // Find driver which matches the routing data.
852 //
853 DriverHandle = NULL;
854 for (Link = Private->DatabaseList.ForwardLink;
855 Link != &Private->DatabaseList;
856 Link = Link->ForwardLink
857 ) {
858 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
859
860 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
861 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
862 if (CompareMem (
863 DevicePath,
864 CurrentDevicePath,
865 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
866 ) == 0) {
867 DriverHandle = Database->DriverHandle;
868 break;
869 }
870 }
871 }
872
873 FreePool (DevicePath);
874
875 if (DriverHandle == NULL) {
876 //
877 // Routing data does not match any known driver.
878 // Set Progress to the 'G' in "GUID" of the routing header.
879 //
880 *Progress = StringPtr;
881 FreePool (ConfigResp);
882 return EFI_NOT_FOUND;
883 }
884
885 //
886 // Call corresponding ConfigAccess protocol to route settings
887 //
888 Status = gBS->HandleProtocol (
889 DriverHandle,
890 &gEfiHiiConfigAccessProtocolGuid,
891 (VOID **) &ConfigAccess
892 );
893 ASSERT_EFI_ERROR (Status);
894
895 Status = ConfigAccess->RouteConfig (
896 ConfigAccess,
897 ConfigResp,
898 &AccessProgress
899 );
900
901 if (EFI_ERROR (Status)) {
902 //
903 // AccessProgress indicates the parsing progress on <ConfigResp>.
904 // Map it to the progress on <MultiConfigResp> then return it.
905 //
906 *Progress = StrStr (StringPtr, AccessProgress);
907
908 FreePool (ConfigResp);
909 return Status;
910 }
911
912 FreePool (ConfigResp);
913 ConfigResp = NULL;
914
915 //
916 // Go to next <ConfigResp> (skip '&').
917 //
918 StringPtr += Length;
919 if (*StringPtr == 0) {
920 *Progress = StringPtr;
921 break;
922 }
923
924 StringPtr++;
925
926 }
927
928 return EFI_SUCCESS;
929 }
930
931
932 /**
933 This helper function is to be called by drivers to map configuration data
934 stored in byte array ("block") formats such as UEFI Variables into current
935 configuration strings.
936
937 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
938 instance.
939 @param ConfigRequest A null-terminated Unicode string in
940 <ConfigRequest> format.
941 @param Block Array of bytes defining the block's configuration.
942 @param BlockSize Length in bytes of Block.
943 @param Config Filled-in configuration string. String allocated
944 by the function. Returned only if call is
945 successful.
946 @param Progress A pointer to a string filled in with the offset of
947 the most recent & before the first failing
948 name/value pair (or the beginning of the string if
949 the failure is in the first name / value pair) or
950 the terminating NULL if all was successful.
951
952 @retval EFI_SUCCESS The request succeeded. Progress points to the null
953 terminator at the end of the ConfigRequest
954 string.
955 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
956 points to the first character of ConfigRequest.
957 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
958 Block parameter would result in this type of
959 error. Progress points to the first character of
960 ConfigRequest.
961 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
962 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
963 Block is left updated and Progress points at
964 the "&" preceding the first non-<BlockName>.
965
966 **/
967 EFI_STATUS
968 EFIAPI
969 HiiBlockToConfig (
970 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
971 IN CONST EFI_STRING ConfigRequest,
972 IN CONST UINT8 *Block,
973 IN CONST UINTN BlockSize,
974 OUT EFI_STRING *Config,
975 OUT EFI_STRING *Progress
976 )
977 {
978 HII_DATABASE_PRIVATE_DATA *Private;
979 EFI_STRING StringPtr;
980 UINTN Length;
981 EFI_STATUS Status;
982 EFI_STRING TmpPtr;
983 UINT8 *TmpBuffer;
984 UINTN Offset;
985 UINTN Width;
986 UINT8 *Value;
987 EFI_STRING ValueStr;
988 EFI_STRING ConfigElement;
989
990 if (This == NULL || Progress == NULL || Config == NULL) {
991 return EFI_INVALID_PARAMETER;
992 }
993
994 if (Block == NULL || ConfigRequest == NULL) {
995 *Progress = ConfigRequest;
996 return EFI_INVALID_PARAMETER;
997 }
998
999
1000 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1001 ASSERT (Private != NULL);
1002
1003 StringPtr = ConfigRequest;
1004 ValueStr = NULL;
1005 Value = NULL;
1006 ConfigElement = NULL;
1007
1008 //
1009 // Allocate a fix length of memory to store Results. Reallocate memory for
1010 // Results if this fix length is insufficient.
1011 //
1012 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
1013 if (*Config == NULL) {
1014 return EFI_OUT_OF_RESOURCES;
1015 }
1016
1017 //
1018 // Jump <ConfigHdr>
1019 //
1020 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1021 *Progress = StringPtr;
1022 Status = EFI_INVALID_PARAMETER;
1023 goto Exit;
1024 }
1025 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1026 StringPtr++;
1027 }
1028 if (*StringPtr == 0) {
1029 *Progress = StringPtr;
1030 Status = EFI_INVALID_PARAMETER;
1031 goto Exit;
1032 }
1033
1034 while (*StringPtr != L'&' && *StringPtr != 0) {
1035 StringPtr++;
1036 }
1037 if (*StringPtr == 0) {
1038 *Progress = StringPtr;
1039 Status = EFI_INVALID_PARAMETER;
1040 goto Exit;
1041 }
1042 //
1043 // Skip '&'
1044 //
1045 StringPtr++;
1046
1047 //
1048 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1049 //
1050 Length = StringPtr - ConfigRequest;
1051 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
1052
1053 //
1054 // Parse each <RequestElement> if exists
1055 // Only <BlockName> format is supported by this help function.
1056 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1057 //
1058 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1059 //
1060 // Back up the header of one <BlockName>
1061 //
1062 TmpPtr = StringPtr;
1063
1064 StringPtr += StrLen (L"OFFSET=");
1065 //
1066 // Get Offset
1067 //
1068 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1069 if (Status == EFI_OUT_OF_RESOURCES) {
1070 *Progress = ConfigRequest;
1071 goto Exit;
1072 }
1073 Offset = 0;
1074 CopyMem (
1075 &Offset,
1076 TmpBuffer,
1077 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1078 );
1079 FreePool (TmpBuffer);
1080
1081 StringPtr += Length;
1082 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1083 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1084 Status = EFI_INVALID_PARAMETER;
1085 goto Exit;
1086 }
1087 StringPtr += StrLen (L"&WIDTH=");
1088
1089 //
1090 // Get Width
1091 //
1092 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1093 if (Status == EFI_OUT_OF_RESOURCES) {
1094 *Progress = ConfigRequest;
1095 goto Exit;
1096 }
1097 Width = 0;
1098 CopyMem (
1099 &Width,
1100 TmpBuffer,
1101 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1102 );
1103 FreePool (TmpBuffer);
1104
1105 StringPtr += Length;
1106 if (*StringPtr != 0 && *StringPtr != L'&') {
1107 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1108 Status = EFI_INVALID_PARAMETER;
1109 goto Exit;
1110 }
1111
1112 //
1113 // Calculate Value and convert it to hex string.
1114 //
1115 if (Offset + Width > BlockSize) {
1116 *Progress = StringPtr;
1117 Status = EFI_DEVICE_ERROR;
1118 goto Exit;
1119 }
1120
1121 Value = (UINT8 *) AllocateZeroPool (Width);
1122 if (Value == NULL) {
1123 *Progress = ConfigRequest;
1124 Status = EFI_OUT_OF_RESOURCES;
1125 goto Exit;
1126 }
1127
1128 CopyMem (Value, (UINT8 *) Block + Offset, Width);
1129
1130 Length = Width * 2 + 1;
1131 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1132 if (ValueStr == NULL) {
1133 *Progress = ConfigRequest;
1134 Status = EFI_OUT_OF_RESOURCES;
1135 goto Exit;
1136 }
1137
1138 Status = BufToHexString (ValueStr, &Length, Value, Width);
1139 ASSERT_EFI_ERROR (Status);
1140 ToLower (ValueStr);
1141
1142 FreePool (Value);
1143 Value = NULL;
1144
1145 //
1146 // Build a ConfigElement
1147 //
1148 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
1149 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1150 if (ConfigElement == NULL) {
1151 Status = EFI_OUT_OF_RESOURCES;
1152 goto Exit;
1153 }
1154 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
1155 if (*StringPtr == 0) {
1156 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
1157 }
1158 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
1159 StrCat (ConfigElement, L"VALUE=");
1160 StrCat (ConfigElement, ValueStr);
1161
1162 AppendToMultiString (Config, ConfigElement);
1163
1164 FreePool (ConfigElement);
1165 FreePool (ValueStr);
1166 ConfigElement = NULL;
1167 ValueStr = NULL;
1168
1169 //
1170 // If '\0', parsing is finished. Otherwise skip '&' to continue
1171 //
1172 if (*StringPtr == 0) {
1173 break;
1174 }
1175 AppendToMultiString (Config, L"&");
1176 StringPtr++;
1177
1178 }
1179
1180 if (*StringPtr != 0) {
1181 *Progress = StringPtr - 1;
1182 Status = EFI_INVALID_PARAMETER;
1183 goto Exit;
1184 }
1185
1186 *Progress = StringPtr;
1187 return EFI_SUCCESS;
1188
1189 Exit:
1190 FreePool (*Config);
1191 if (ValueStr != NULL) {
1192 FreePool (ValueStr);
1193 }
1194 if (Value != NULL) {
1195 FreePool (Value);
1196 }
1197 if (ConfigElement != NULL) {
1198 FreePool (ConfigElement);
1199 }
1200
1201 return Status;
1202
1203 }
1204
1205
1206 /**
1207 This helper function is to be called by drivers to map configuration strings
1208 to configurations stored in byte array ("block") formats such as UEFI Variables.
1209
1210 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1211 instance.
1212 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1213 format.
1214 @param Block A possibly null array of bytes representing the
1215 current block. Only bytes referenced in the
1216 ConfigResp string in the block are modified. If
1217 this parameter is null or if the *BlockSize
1218 parameter is (on input) shorter than required by
1219 the Configuration string, only the BlockSize
1220 parameter is updated and an appropriate status
1221 (see below) is returned.
1222 @param BlockSize The length of the Block in units of UINT8. On
1223 input, this is the size of the Block. On output,
1224 if successful, contains the index of the last
1225 modified byte in the Block.
1226 @param Progress On return, points to an element of the ConfigResp
1227 string filled in with the offset of the most
1228 recent '&' before the first failing name / value
1229 pair (or the beginning of the string if the
1230 failure is in the first name / value pair) or the
1231 terminating NULL if all was successful.
1232
1233 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1234 terminator at the end of the ConfigResp string.
1235 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1236 points to the first character of ConfigResp.
1237 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1238 Block parameter would result in this type of
1239 error. Progress points to the first character of
1240 ConfigResp.
1241 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1242 value pair. Block is left updated and
1243 Progress points at the '&' preceding the first
1244 non-<BlockName>.
1245
1246 **/
1247 EFI_STATUS
1248 EFIAPI
1249 HiiConfigToBlock (
1250 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1251 IN CONST EFI_STRING ConfigResp,
1252 IN OUT UINT8 *Block,
1253 IN OUT UINTN *BlockSize,
1254 OUT EFI_STRING *Progress
1255 )
1256 {
1257 HII_DATABASE_PRIVATE_DATA *Private;
1258 EFI_STRING StringPtr;
1259 UINTN Length;
1260 EFI_STATUS Status;
1261 UINT8 *TmpBuffer;
1262 UINTN Offset;
1263 UINTN Width;
1264 UINT8 *Value;
1265 UINTN BufferSize;
1266
1267 if (This == NULL || BlockSize == NULL || Progress == NULL) {
1268 return EFI_INVALID_PARAMETER;
1269 }
1270
1271 if (ConfigResp == NULL || Block == NULL) {
1272 *Progress = ConfigResp;
1273 return EFI_INVALID_PARAMETER;
1274 }
1275
1276 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1277 ASSERT (Private != NULL);
1278
1279 StringPtr = ConfigResp;
1280 BufferSize = *BlockSize;
1281 Value = NULL;
1282
1283 //
1284 // Jump <ConfigHdr>
1285 //
1286 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1287 *Progress = StringPtr;
1288 Status = EFI_INVALID_PARAMETER;
1289 goto Exit;
1290 }
1291 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1292 StringPtr++;
1293 }
1294 if (*StringPtr == 0) {
1295 *Progress = StringPtr;
1296 Status = EFI_INVALID_PARAMETER;
1297 goto Exit;
1298 }
1299
1300 while (*StringPtr != L'&' && *StringPtr != 0) {
1301 StringPtr++;
1302 }
1303 if (*StringPtr == 0) {
1304 *Progress = StringPtr;
1305 Status = EFI_INVALID_PARAMETER;
1306 goto Exit;
1307 }
1308 //
1309 // Skip '&'
1310 //
1311 StringPtr++;
1312
1313 //
1314 // Parse each <ConfigElement> if exists
1315 // Only <BlockConfig> format is supported by this help function.
1316 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1317 //
1318 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1319 StringPtr += StrLen (L"OFFSET=");
1320 //
1321 // Get Offset
1322 //
1323 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1324 if (Status == EFI_OUT_OF_RESOURCES) {
1325 *Progress = ConfigResp;
1326 goto Exit;
1327 }
1328 Offset = 0;
1329 CopyMem (
1330 &Offset,
1331 TmpBuffer,
1332 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1333 );
1334 FreePool (TmpBuffer);
1335
1336 StringPtr += Length;
1337 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1338 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1339 Status = EFI_INVALID_PARAMETER;
1340 goto Exit;
1341 }
1342 StringPtr += StrLen (L"&WIDTH=");
1343
1344 //
1345 // Get Width
1346 //
1347 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1348 if (Status == EFI_OUT_OF_RESOURCES) {
1349 *Progress = ConfigResp;
1350 goto Exit;
1351 }
1352 Width = 0;
1353 CopyMem (
1354 &Width,
1355 TmpBuffer,
1356 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1357 );
1358 FreePool (TmpBuffer);
1359
1360 StringPtr += Length;
1361 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1362 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1363 Status = EFI_INVALID_PARAMETER;
1364 goto Exit;
1365 }
1366 StringPtr += StrLen (L"&VALUE=");
1367
1368 //
1369 // Get Value
1370 //
1371 Status = GetValueOfNumber (StringPtr, &Value, &Length);
1372 if (Status == EFI_OUT_OF_RESOURCES) {
1373 *Progress = ConfigResp;
1374 goto Exit;
1375 }
1376
1377 StringPtr += Length;
1378 if (*StringPtr != 0 && *StringPtr != L'&') {
1379 *Progress = StringPtr - Length - 7;
1380 Status = EFI_INVALID_PARAMETER;
1381 goto Exit;
1382 }
1383
1384 //
1385 // Update the Block with configuration info
1386 //
1387
1388 if (Offset + Width > BufferSize) {
1389 return EFI_DEVICE_ERROR;
1390 }
1391
1392 CopyMem (Block + Offset, Value, Width);
1393 *BlockSize = Offset + Width - 1;
1394
1395 FreePool (Value);
1396 Value = NULL;
1397
1398 //
1399 // If '\0', parsing is finished. Otherwise skip '&' to continue
1400 //
1401 if (*StringPtr == 0) {
1402 break;
1403 }
1404
1405 StringPtr++;
1406 }
1407
1408 if (*StringPtr != 0) {
1409 *Progress = StringPtr - 1;
1410 Status = EFI_INVALID_PARAMETER;
1411 goto Exit;
1412 }
1413
1414 *Progress = StringPtr;
1415 return EFI_SUCCESS;
1416
1417 Exit:
1418
1419 if (Value != NULL) {
1420 FreePool (Value);
1421 }
1422 return Status;
1423 }
1424
1425
1426 /**
1427 This helper function is to be called by drivers to extract portions of
1428 a larger configuration string.
1429
1430 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1431 instance.
1432 @param Configuration A null-terminated Unicode string in
1433 <MultiConfigAltResp> format.
1434 @param Guid A pointer to the GUID value to search for in the
1435 routing portion of the ConfigResp string when
1436 retrieving the requested data. If Guid is NULL,
1437 then all GUID values will be searched for.
1438 @param Name A pointer to the NAME value to search for in the
1439 routing portion of the ConfigResp string when
1440 retrieving the requested data. If Name is NULL,
1441 then all Name values will be searched for.
1442 @param DevicePath A pointer to the PATH value to search for in the
1443 routing portion of the ConfigResp string when
1444 retrieving the requested data. If DevicePath is
1445 NULL, then all DevicePath values will be searched
1446 for.
1447 @param AltCfgId A pointer to the ALTCFG value to search for in the
1448 routing portion of the ConfigResp string when
1449 retrieving the requested data. If this parameter
1450 is NULL, then the current setting will be
1451 retrieved.
1452 @param AltCfgResp A pointer to a buffer which will be allocated by
1453 the function which contains the retrieved string
1454 as requested. This buffer is only allocated if
1455 the call was successful.
1456
1457 @retval EFI_SUCCESS The request succeeded. The requested data was
1458 extracted and placed in the newly allocated
1459 AltCfgResp buffer.
1460 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1461 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1462 @retval EFI_NOT_FOUND Target for the specified routing data was not
1463 found.
1464
1465 **/
1466 EFI_STATUS
1467 EFIAPI
1468 HiiGetAltCfg (
1469 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1470 IN CONST EFI_STRING Configuration,
1471 IN CONST EFI_GUID *Guid,
1472 IN CONST EFI_STRING Name,
1473 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1474 IN CONST UINT16 *AltCfgId,
1475 OUT EFI_STRING *AltCfgResp
1476 )
1477 {
1478 EFI_STATUS Status;
1479 EFI_STRING StringPtr;
1480 EFI_STRING HdrStart;
1481 EFI_STRING HdrEnd;
1482 EFI_STRING TmpPtr;
1483 UINTN Length;
1484 EFI_STRING GuidStr;
1485 EFI_STRING NameStr;
1486 EFI_STRING PathStr;
1487 EFI_STRING AltIdStr;
1488 EFI_STRING Result;
1489 BOOLEAN GuidFlag;
1490 BOOLEAN NameFlag;
1491 BOOLEAN PathFlag;
1492
1493 //
1494 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1495 // as FALSE. But this renders the system to not 100% compliant with
1496 // UEFI 2.1. Use this with caution.
1497 //
1498 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
1499 return EFI_UNSUPPORTED;
1500 }
1501
1502 HdrStart = NULL;
1503 HdrEnd = NULL;
1504 GuidStr = NULL;
1505 NameStr = NULL;
1506 PathStr = NULL;
1507 AltIdStr = NULL;
1508 Result = NULL;
1509 GuidFlag = FALSE;
1510 NameFlag = FALSE;
1511 PathFlag = FALSE;
1512
1513 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
1514 return EFI_INVALID_PARAMETER;
1515 }
1516
1517 StringPtr = Configuration;
1518 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1519 return EFI_INVALID_PARAMETER;
1520 }
1521
1522 //
1523 // Generate the sub string for later matching.
1524 //
1525 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
1526 GenerateSubStr (
1527 L"PATH=",
1528 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1529 (VOID *) DevicePath,
1530 1,
1531 &PathStr
1532 );
1533 if (AltCfgId != NULL) {
1534 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
1535 }
1536 if (Name != NULL) {
1537 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1538 } else {
1539 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1540 }
1541
1542 while (*StringPtr != 0) {
1543 //
1544 // Try to match the GUID
1545 //
1546 if (!GuidFlag) {
1547 TmpPtr = StrStr (StringPtr, GuidStr);
1548 if (TmpPtr == NULL) {
1549 Status = EFI_NOT_FOUND;
1550 goto Exit;
1551 }
1552 HdrStart = TmpPtr;
1553
1554 //
1555 // Jump to <NameHdr>
1556 //
1557 if (Guid != NULL) {
1558 StringPtr = TmpPtr + StrLen (GuidStr);
1559 } else {
1560 StringPtr = StrStr (TmpPtr, L"NAME=");
1561 if (StringPtr == NULL) {
1562 Status = EFI_NOT_FOUND;
1563 goto Exit;
1564 }
1565 }
1566 GuidFlag = TRUE;
1567 }
1568
1569 //
1570 // Try to match the NAME
1571 //
1572 if (GuidFlag && !NameFlag) {
1573 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
1574 GuidFlag = FALSE;
1575 } else {
1576 //
1577 // Jump to <PathHdr>
1578 //
1579 if (Name != NULL) {
1580 StringPtr += StrLen (NameStr);
1581 } else {
1582 StringPtr = StrStr (StringPtr, L"PATH=");
1583 if (StringPtr == NULL) {
1584 Status = EFI_NOT_FOUND;
1585 goto Exit;
1586 }
1587 }
1588 NameFlag = TRUE;
1589 }
1590 }
1591
1592 //
1593 // Try to match the DevicePath
1594 //
1595 if (GuidFlag && NameFlag && !PathFlag) {
1596 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
1597 GuidFlag = FALSE;
1598 NameFlag = FALSE;
1599 } else {
1600 //
1601 // Jump to '&' before <DescHdr> or <ConfigBody>
1602 //
1603 if (DevicePath != NULL) {
1604 StringPtr += StrLen (PathStr);
1605 } else {
1606 StringPtr = StrStr (StringPtr, L"&");
1607 if (StringPtr == NULL) {
1608 Status = EFI_NOT_FOUND;
1609 goto Exit;
1610 }
1611 }
1612 PathFlag = TRUE;
1613 HdrEnd = ++StringPtr;
1614 }
1615 }
1616
1617 //
1618 // Try to match the AltCfgId
1619 //
1620 if (GuidFlag && NameFlag && PathFlag) {
1621 if (AltCfgId == NULL) {
1622 //
1623 // Return Current Setting when AltCfgId is NULL.
1624 //
1625 Status = OutputConfigBody (StringPtr, &Result);
1626 goto Exit;
1627 }
1628 //
1629 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1630 //
1631 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
1632 GuidFlag = FALSE;
1633 NameFlag = FALSE;
1634 PathFlag = FALSE;
1635 } else {
1636 Status = OutputConfigBody (StringPtr, &Result);
1637 goto Exit;
1638 }
1639 }
1640 }
1641
1642 Status = EFI_NOT_FOUND;
1643
1644 Exit:
1645
1646 if (!EFI_ERROR (Status)) {
1647 //
1648 // Copy the <ConfigHdr> and <ConfigBody>
1649 //
1650 Length = HdrEnd - HdrStart + StrLen (Result);
1651 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
1652 if (*AltCfgResp == NULL) {
1653 Status = EFI_OUT_OF_RESOURCES;
1654 } else {
1655 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
1656 StrCat (*AltCfgResp, Result);
1657 Status = EFI_SUCCESS;
1658 }
1659 }
1660
1661 if (GuidStr != NULL) {
1662 FreePool (GuidStr);
1663 }
1664 if (NameStr != NULL) {
1665 FreePool (NameStr);
1666 }
1667 if (PathStr != NULL) {
1668 FreePool (PathStr);
1669 }
1670 if (AltIdStr != NULL) {
1671 FreePool (AltIdStr);
1672 }
1673 if (Result != NULL) {
1674 FreePool (Result);
1675 }
1676
1677 return Status;
1678
1679 }
1680
1681