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