]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
Fix error when replace HexStringToBuf
[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 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 HII_DATABASE_PRIVATE_DATA *Private;
510 EFI_STRING StringPtr;
511 EFI_STRING ConfigRequest;
512 UINTN Length;
513 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
514 EFI_STATUS Status;
515 LIST_ENTRY *Link;
516 HII_DATABASE_RECORD *Database;
517 UINT8 *DevicePathPkg;
518 UINT8 *CurrentDevicePath;
519 EFI_HANDLE DriverHandle;
520 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
521 EFI_STRING AccessProgress;
522 EFI_STRING AccessResults;
523 BOOLEAN FirstElement;
524
525 if (This == NULL || Progress == NULL || Results == NULL) {
526 return EFI_INVALID_PARAMETER;
527 }
528
529 if (Request == NULL) {
530 *Progress = NULL;
531 return EFI_INVALID_PARAMETER;
532 }
533
534 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
535 StringPtr = Request;
536 *Progress = StringPtr;
537
538 //
539 // The first element of <MultiConfigRequest> should be
540 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
541 //
542 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
543 return EFI_INVALID_PARAMETER;
544 }
545
546 FirstElement = TRUE;
547
548 //
549 // Allocate a fix length of memory to store Results. Reallocate memory for
550 // Results if this fix length is insufficient.
551 //
552 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
553 if (*Results == NULL) {
554 return EFI_OUT_OF_RESOURCES;
555 }
556
557 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
558 //
559 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
560 // or most recent & before the error.
561 //
562 if (StringPtr == Request) {
563 *Progress = StringPtr;
564 } else {
565 *Progress = StringPtr - 1;
566 }
567
568 //
569 // Process each <ConfigRequest> of <MultiConfigRequest>
570 //
571 Length = CalculateConfigStringLen (StringPtr);
572 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
573 if (ConfigRequest == NULL) {
574 return EFI_OUT_OF_RESOURCES;
575 }
576 *(ConfigRequest + Length) = 0;
577
578 //
579 // Get the UEFI device path
580 //
581 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
582 if (EFI_ERROR (Status)) {
583 FreePool (ConfigRequest);
584 return Status;
585 }
586
587 //
588 // Find driver which matches the routing data.
589 //
590 DriverHandle = NULL;
591 for (Link = Private->DatabaseList.ForwardLink;
592 Link != &Private->DatabaseList;
593 Link = Link->ForwardLink
594 ) {
595 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
596
597 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
598 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
599 if (CompareMem (
600 DevicePath,
601 CurrentDevicePath,
602 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
603 ) == 0) {
604 DriverHandle = Database->DriverHandle;
605 break;
606 }
607 }
608 }
609
610 FreePool (DevicePath);
611
612 if (DriverHandle == NULL) {
613 //
614 // Routing data does not match any known driver.
615 // Set Progress to the 'G' in "GUID" of the routing header.
616 //
617 *Progress = StringPtr;
618 FreePool (ConfigRequest);
619 return EFI_NOT_FOUND;
620 }
621
622 //
623 // Call corresponding ConfigAccess protocol to extract settings
624 //
625 Status = gBS->HandleProtocol (
626 DriverHandle,
627 &gEfiHiiConfigAccessProtocolGuid,
628 (VOID **) &ConfigAccess
629 );
630 ASSERT_EFI_ERROR (Status);
631
632 Status = ConfigAccess->ExtractConfig (
633 ConfigAccess,
634 ConfigRequest,
635 &AccessProgress,
636 &AccessResults
637 );
638 if (EFI_ERROR (Status)) {
639 //
640 // AccessProgress indicates the parsing progress on <ConfigRequest>.
641 // Map it to the progress on <MultiConfigRequest> then return it.
642 //
643 *Progress = StrStr (StringPtr, AccessProgress);
644 FreePool (ConfigRequest);
645 return Status;
646 }
647
648 //
649 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
650 // which seperates the first <ConfigAltResp> and the following ones.
651 //
652 ASSERT (*AccessProgress == 0);
653
654 if (!FirstElement) {
655 Status = AppendToMultiString (Results, L"&");
656 ASSERT_EFI_ERROR (Status);
657 }
658
659 Status = AppendToMultiString (Results, AccessResults);
660 ASSERT_EFI_ERROR (Status);
661
662 FirstElement = FALSE;
663
664 FreePool (AccessResults);
665 AccessResults = NULL;
666 FreePool (ConfigRequest);
667 ConfigRequest = NULL;
668
669 //
670 // Go to next <ConfigRequest> (skip '&').
671 //
672 StringPtr += Length;
673 if (*StringPtr == 0) {
674 *Progress = StringPtr;
675 break;
676 }
677
678 StringPtr++;
679
680 }
681
682 return EFI_SUCCESS;
683
684 }
685
686
687 /**
688 This function allows the caller to request the current configuration for the
689 entirety of the current HII database and returns the data in a
690 null-terminated Unicode string.
691
692 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
693 instance.
694 @param Results Null-terminated Unicode string in
695 <MultiConfigAltResp> format which has all values
696 filled in for the names in the Request string.
697 String to be allocated by the called function.
698 De-allocation is up to the caller.
699
700 @retval EFI_SUCCESS The Results string is filled with the values
701 corresponding to all requested names.
702 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
703 results that must be stored awaiting possible
704 future protocols.
705 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
706 parameter would result in this type of error.
707
708 **/
709 EFI_STATUS
710 EFIAPI
711 HiiConfigRoutingExportConfig (
712 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
713 OUT EFI_STRING *Results
714 )
715 {
716 EFI_STATUS Status;
717 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
718 EFI_STRING AccessResults;
719 UINTN Index;
720 EFI_HANDLE *ConfigAccessHandles;
721 UINTN NumberConfigAccessHandles;
722 BOOLEAN FirstElement;
723
724 if (This == NULL || Results == NULL) {
725 return EFI_INVALID_PARAMETER;
726 }
727
728 //
729 // Allocate a fix length of memory to store Results. Reallocate memory for
730 // Results if this fix length is insufficient.
731 //
732 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
733 if (*Results == NULL) {
734 return EFI_OUT_OF_RESOURCES;
735 }
736
737 NumberConfigAccessHandles = 0;
738 Status = gBS->LocateHandleBuffer (
739 ByProtocol,
740 &gEfiHiiConfigAccessProtocolGuid,
741 NULL,
742 &NumberConfigAccessHandles,
743 &ConfigAccessHandles
744 );
745 if (EFI_ERROR (Status)) {
746 return Status;
747 }
748
749 FirstElement = TRUE;
750
751 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
752 Status = gBS->HandleProtocol (
753 ConfigAccessHandles[Index],
754 &gEfiHiiConfigAccessProtocolGuid,
755 (VOID **) &ConfigAccess
756 );
757 if (EFI_ERROR (Status)) {
758 continue;
759 }
760
761 Status = ConfigAccess->ExtractConfig (
762 ConfigAccess,
763 NULL,
764 NULL,
765 &AccessResults
766 );
767 if (!EFI_ERROR (Status)) {
768 //
769 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
770 // which seperates the first <ConfigAltResp> and the following ones.
771 //
772 if (!FirstElement) {
773 Status = AppendToMultiString (Results, L"&");
774 ASSERT_EFI_ERROR (Status);
775 }
776
777 Status = AppendToMultiString (Results, AccessResults);
778 ASSERT_EFI_ERROR (Status);
779
780 FirstElement = FALSE;
781
782 FreePool (AccessResults);
783 AccessResults = NULL;
784 }
785 }
786 FreePool (ConfigAccessHandles);
787
788 return EFI_SUCCESS;
789 }
790
791
792 /**
793 This function processes the results of processing forms and routes it to the
794 appropriate handlers or storage.
795
796 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
797 instance.
798 @param Configuration A null-terminated Unicode string in
799 <MulltiConfigResp> format.
800 @param Progress A pointer to a string filled in with the offset of
801 the most recent & before the first failing name /
802 value pair (or the beginning of the string if the
803 failure is in the first name / value pair) or the
804 terminating NULL if all was successful.
805
806 @retval EFI_SUCCESS The results have been distributed or are awaiting
807 distribution.
808 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
809 results that must be stored awaiting possible
810 future protocols.
811 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
812 would result in this type of error.
813 @retval EFI_NOT_FOUND Target for the specified routing data was not
814 found.
815
816 **/
817 EFI_STATUS
818 EFIAPI
819 HiiConfigRoutingRouteConfig (
820 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
821 IN CONST EFI_STRING Configuration,
822 OUT EFI_STRING *Progress
823 )
824 {
825 HII_DATABASE_PRIVATE_DATA *Private;
826 EFI_STRING StringPtr;
827 EFI_STRING ConfigResp;
828 UINTN Length;
829 EFI_STATUS Status;
830 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
831 LIST_ENTRY *Link;
832 HII_DATABASE_RECORD *Database;
833 UINT8 *DevicePathPkg;
834 UINT8 *CurrentDevicePath;
835 EFI_HANDLE DriverHandle;
836 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
837 EFI_STRING AccessProgress;
838
839 if (This == NULL || Progress == NULL) {
840 return EFI_INVALID_PARAMETER;
841 }
842
843 if (Configuration == NULL) {
844 *Progress = NULL;
845 return EFI_INVALID_PARAMETER;
846 }
847
848 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
849 StringPtr = Configuration;
850 *Progress = StringPtr;
851
852 //
853 // The first element of <MultiConfigResp> should be
854 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
855 //
856 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
857 return EFI_INVALID_PARAMETER;
858 }
859
860 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
861 //
862 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
863 // or most recent & before the error.
864 //
865 if (StringPtr == Configuration) {
866 *Progress = StringPtr;
867 } else {
868 *Progress = StringPtr - 1;
869 }
870
871 //
872 // Process each <ConfigResp> of <MultiConfigResp>
873 //
874 Length = CalculateConfigStringLen (StringPtr);
875 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
876 if (ConfigResp == NULL) {
877 return EFI_OUT_OF_RESOURCES;
878 }
879 //
880 // Append '\0' to the end of ConfigRequest
881 //
882 *(ConfigResp + Length) = 0;
883
884 //
885 // Get the UEFI device path
886 //
887 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
888 if (EFI_ERROR (Status)) {
889 FreePool (ConfigResp);
890 return Status;
891 }
892
893 //
894 // Find driver which matches the routing data.
895 //
896 DriverHandle = NULL;
897 for (Link = Private->DatabaseList.ForwardLink;
898 Link != &Private->DatabaseList;
899 Link = Link->ForwardLink
900 ) {
901 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
902
903 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
904 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
905 if (CompareMem (
906 DevicePath,
907 CurrentDevicePath,
908 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
909 ) == 0) {
910 DriverHandle = Database->DriverHandle;
911 break;
912 }
913 }
914 }
915
916 FreePool (DevicePath);
917
918 if (DriverHandle == NULL) {
919 //
920 // Routing data does not match any known driver.
921 // Set Progress to the 'G' in "GUID" of the routing header.
922 //
923 *Progress = StringPtr;
924 FreePool (ConfigResp);
925 return EFI_NOT_FOUND;
926 }
927
928 //
929 // Call corresponding ConfigAccess protocol to route settings
930 //
931 Status = gBS->HandleProtocol (
932 DriverHandle,
933 &gEfiHiiConfigAccessProtocolGuid,
934 (VOID **) &ConfigAccess
935 );
936 ASSERT_EFI_ERROR (Status);
937
938 Status = ConfigAccess->RouteConfig (
939 ConfigAccess,
940 ConfigResp,
941 &AccessProgress
942 );
943
944 if (EFI_ERROR (Status)) {
945 //
946 // AccessProgress indicates the parsing progress on <ConfigResp>.
947 // Map it to the progress on <MultiConfigResp> then return it.
948 //
949 *Progress = StrStr (StringPtr, AccessProgress);
950
951 FreePool (ConfigResp);
952 return Status;
953 }
954
955 FreePool (ConfigResp);
956 ConfigResp = NULL;
957
958 //
959 // Go to next <ConfigResp> (skip '&').
960 //
961 StringPtr += Length;
962 if (*StringPtr == 0) {
963 *Progress = StringPtr;
964 break;
965 }
966
967 StringPtr++;
968
969 }
970
971 return EFI_SUCCESS;
972 }
973
974
975 /**
976 This helper function is to be called by drivers to map configuration data
977 stored in byte array ("block") formats such as UEFI Variables into current
978 configuration strings.
979
980 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
981 instance.
982 @param ConfigRequest A null-terminated Unicode string in
983 <ConfigRequest> format.
984 @param Block Array of bytes defining the block's configuration.
985 @param BlockSize Length in bytes of Block.
986 @param Config Filled-in configuration string. String allocated
987 by the function. Returned only if call is
988 successful.
989 @param Progress A pointer to a string filled in with the offset of
990 the most recent & before the first failing
991 name/value pair (or the beginning of the string if
992 the failure is in the first name / value pair) or
993 the terminating NULL if all was successful.
994
995 @retval EFI_SUCCESS The request succeeded. Progress points to the null
996 terminator at the end of the ConfigRequest
997 string.
998 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
999 points to the first character of ConfigRequest.
1000 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1001 Block parameter would result in this type of
1002 error. Progress points to the first character of
1003 ConfigRequest.
1004 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1005 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1006 Block is left updated and Progress points at
1007 the "&" preceding the first non-<BlockName>.
1008
1009 **/
1010 EFI_STATUS
1011 EFIAPI
1012 HiiBlockToConfig (
1013 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1014 IN CONST EFI_STRING ConfigRequest,
1015 IN CONST UINT8 *Block,
1016 IN CONST UINTN BlockSize,
1017 OUT EFI_STRING *Config,
1018 OUT EFI_STRING *Progress
1019 )
1020 {
1021 HII_DATABASE_PRIVATE_DATA *Private;
1022 EFI_STRING StringPtr;
1023 UINTN Length;
1024 EFI_STATUS Status;
1025 EFI_STRING TmpPtr;
1026 UINT8 *TmpBuffer;
1027 UINTN Offset;
1028 UINTN Width;
1029 UINT8 *Value;
1030 EFI_STRING ValueStr;
1031 EFI_STRING ConfigElement;
1032 UINTN Index;
1033 UINT8 *TemBuffer;
1034 CHAR16 *TemString;
1035
1036 if (This == NULL || Progress == NULL || Config == NULL) {
1037 return EFI_INVALID_PARAMETER;
1038 }
1039
1040 if (Block == NULL || ConfigRequest == NULL) {
1041 *Progress = ConfigRequest;
1042 return EFI_INVALID_PARAMETER;
1043 }
1044
1045
1046 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1047 ASSERT (Private != NULL);
1048
1049 StringPtr = ConfigRequest;
1050 ValueStr = NULL;
1051 Value = NULL;
1052 ConfigElement = NULL;
1053
1054 //
1055 // Allocate a fix length of memory to store Results. Reallocate memory for
1056 // Results if this fix length is insufficient.
1057 //
1058 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
1059 if (*Config == NULL) {
1060 return EFI_OUT_OF_RESOURCES;
1061 }
1062
1063 //
1064 // Jump <ConfigHdr>
1065 //
1066 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1067 *Progress = StringPtr;
1068 Status = EFI_INVALID_PARAMETER;
1069 goto Exit;
1070 }
1071 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1072 StringPtr++;
1073 }
1074 if (*StringPtr == 0) {
1075 *Progress = StringPtr;
1076 Status = EFI_INVALID_PARAMETER;
1077 goto Exit;
1078 }
1079
1080 while (*StringPtr != L'&' && *StringPtr != 0) {
1081 StringPtr++;
1082 }
1083 if (*StringPtr == 0) {
1084 *Progress = StringPtr;
1085 Status = EFI_INVALID_PARAMETER;
1086 goto Exit;
1087 }
1088 //
1089 // Skip '&'
1090 //
1091 StringPtr++;
1092
1093 //
1094 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1095 //
1096 Length = StringPtr - ConfigRequest;
1097 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
1098
1099 //
1100 // Parse each <RequestElement> if exists
1101 // Only <BlockName> format is supported by this help function.
1102 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1103 //
1104 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1105 //
1106 // Back up the header of one <BlockName>
1107 //
1108 TmpPtr = StringPtr;
1109
1110 StringPtr += StrLen (L"OFFSET=");
1111 //
1112 // Get Offset
1113 //
1114 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1115 if (Status == EFI_OUT_OF_RESOURCES) {
1116 *Progress = ConfigRequest;
1117 goto Exit;
1118 }
1119 Offset = 0;
1120 CopyMem (
1121 &Offset,
1122 TmpBuffer,
1123 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1124 );
1125 FreePool (TmpBuffer);
1126
1127 StringPtr += Length;
1128 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1129 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1130 Status = EFI_INVALID_PARAMETER;
1131 goto Exit;
1132 }
1133 StringPtr += StrLen (L"&WIDTH=");
1134
1135 //
1136 // Get Width
1137 //
1138 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1139 if (Status == EFI_OUT_OF_RESOURCES) {
1140 *Progress = ConfigRequest;
1141 goto Exit;
1142 }
1143 Width = 0;
1144 CopyMem (
1145 &Width,
1146 TmpBuffer,
1147 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1148 );
1149 FreePool (TmpBuffer);
1150
1151 StringPtr += Length;
1152 if (*StringPtr != 0 && *StringPtr != L'&') {
1153 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1154 Status = EFI_INVALID_PARAMETER;
1155 goto Exit;
1156 }
1157
1158 //
1159 // Calculate Value and convert it to hex string.
1160 //
1161 if (Offset + Width > BlockSize) {
1162 *Progress = StringPtr;
1163 Status = EFI_DEVICE_ERROR;
1164 goto Exit;
1165 }
1166
1167 Value = (UINT8 *) AllocateZeroPool (Width);
1168 if (Value == NULL) {
1169 *Progress = ConfigRequest;
1170 Status = EFI_OUT_OF_RESOURCES;
1171 goto Exit;
1172 }
1173
1174 CopyMem (Value, (UINT8 *) Block + Offset, Width);
1175
1176 Length = Width * 2 + 1;
1177 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1178 if (ValueStr == NULL) {
1179 *Progress = ConfigRequest;
1180 Status = EFI_OUT_OF_RESOURCES;
1181 goto Exit;
1182 }
1183
1184 TemString = ValueStr;
1185 TemBuffer = Value + Width - 1;
1186 for (Index = 0; Index < Width; Index ++, TemBuffer --) {
1187 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
1188 }
1189 HiiToLower (ValueStr);
1190
1191 FreePool (Value);
1192 Value = NULL;
1193
1194 //
1195 // Build a ConfigElement
1196 //
1197 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
1198 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1199 if (ConfigElement == NULL) {
1200 Status = EFI_OUT_OF_RESOURCES;
1201 goto Exit;
1202 }
1203 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
1204 if (*StringPtr == 0) {
1205 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
1206 }
1207 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
1208 StrCat (ConfigElement, L"VALUE=");
1209 StrCat (ConfigElement, ValueStr);
1210
1211 AppendToMultiString (Config, ConfigElement);
1212
1213 FreePool (ConfigElement);
1214 FreePool (ValueStr);
1215 ConfigElement = NULL;
1216 ValueStr = NULL;
1217
1218 //
1219 // If '\0', parsing is finished. Otherwise skip '&' to continue
1220 //
1221 if (*StringPtr == 0) {
1222 break;
1223 }
1224 AppendToMultiString (Config, L"&");
1225 StringPtr++;
1226
1227 }
1228
1229 if (*StringPtr != 0) {
1230 *Progress = StringPtr - 1;
1231 Status = EFI_INVALID_PARAMETER;
1232 goto Exit;
1233 }
1234
1235 *Progress = StringPtr;
1236 return EFI_SUCCESS;
1237
1238 Exit:
1239 FreePool (*Config);
1240 if (ValueStr != NULL) {
1241 FreePool (ValueStr);
1242 }
1243 if (Value != NULL) {
1244 FreePool (Value);
1245 }
1246 if (ConfigElement != NULL) {
1247 FreePool (ConfigElement);
1248 }
1249
1250 return Status;
1251
1252 }
1253
1254
1255 /**
1256 This helper function is to be called by drivers to map configuration strings
1257 to configurations stored in byte array ("block") formats such as UEFI Variables.
1258
1259 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1260 instance.
1261 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1262 format.
1263 @param Block A possibly null array of bytes representing the
1264 current block. Only bytes referenced in the
1265 ConfigResp string in the block are modified. If
1266 this parameter is null or if the *BlockSize
1267 parameter is (on input) shorter than required by
1268 the Configuration string, only the BlockSize
1269 parameter is updated and an appropriate status
1270 (see below) is returned.
1271 @param BlockSize The length of the Block in units of UINT8. On
1272 input, this is the size of the Block. On output,
1273 if successful, contains the index of the last
1274 modified byte in the Block.
1275 @param Progress On return, points to an element of the ConfigResp
1276 string filled in with the offset of the most
1277 recent '&' before the first failing name / value
1278 pair (or the beginning of the string if the
1279 failure is in the first name / value pair) or the
1280 terminating NULL if all was successful.
1281
1282 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1283 terminator at the end of the ConfigResp string.
1284 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1285 points to the first character of ConfigResp.
1286 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1287 Block parameter would result in this type of
1288 error. Progress points to the first character of
1289 ConfigResp.
1290 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1291 value pair. Block is left updated and
1292 Progress points at the '&' preceding the first
1293 non-<BlockName>.
1294
1295 **/
1296 EFI_STATUS
1297 EFIAPI
1298 HiiConfigToBlock (
1299 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1300 IN CONST EFI_STRING ConfigResp,
1301 IN OUT UINT8 *Block,
1302 IN OUT UINTN *BlockSize,
1303 OUT EFI_STRING *Progress
1304 )
1305 {
1306 HII_DATABASE_PRIVATE_DATA *Private;
1307 EFI_STRING StringPtr;
1308 UINTN Length;
1309 EFI_STATUS Status;
1310 UINT8 *TmpBuffer;
1311 UINTN Offset;
1312 UINTN Width;
1313 UINT8 *Value;
1314 UINTN BufferSize;
1315
1316 if (This == NULL || BlockSize == NULL || Progress == NULL) {
1317 return EFI_INVALID_PARAMETER;
1318 }
1319
1320 if (ConfigResp == NULL || Block == NULL) {
1321 *Progress = ConfigResp;
1322 return EFI_INVALID_PARAMETER;
1323 }
1324
1325 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1326 ASSERT (Private != NULL);
1327
1328 StringPtr = ConfigResp;
1329 BufferSize = *BlockSize;
1330 Value = NULL;
1331
1332 //
1333 // Jump <ConfigHdr>
1334 //
1335 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1336 *Progress = StringPtr;
1337 Status = EFI_INVALID_PARAMETER;
1338 goto Exit;
1339 }
1340 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1341 StringPtr++;
1342 }
1343 if (*StringPtr == 0) {
1344 *Progress = StringPtr;
1345 Status = EFI_INVALID_PARAMETER;
1346 goto Exit;
1347 }
1348
1349 while (*StringPtr != L'&' && *StringPtr != 0) {
1350 StringPtr++;
1351 }
1352 if (*StringPtr == 0) {
1353 *Progress = StringPtr;
1354 Status = EFI_INVALID_PARAMETER;
1355 goto Exit;
1356 }
1357 //
1358 // Skip '&'
1359 //
1360 StringPtr++;
1361
1362 //
1363 // Parse each <ConfigElement> if exists
1364 // Only <BlockConfig> format is supported by this help function.
1365 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1366 //
1367 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1368 StringPtr += StrLen (L"OFFSET=");
1369 //
1370 // Get Offset
1371 //
1372 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1373 if (EFI_ERROR (Status)) {
1374 *Progress = ConfigResp;
1375 goto Exit;
1376 }
1377 Offset = 0;
1378 CopyMem (
1379 &Offset,
1380 TmpBuffer,
1381 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1382 );
1383 FreePool (TmpBuffer);
1384
1385 StringPtr += Length;
1386 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1387 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1388 Status = EFI_INVALID_PARAMETER;
1389 goto Exit;
1390 }
1391 StringPtr += StrLen (L"&WIDTH=");
1392
1393 //
1394 // Get Width
1395 //
1396 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1397 if (Status == EFI_OUT_OF_RESOURCES) {
1398 *Progress = ConfigResp;
1399 goto Exit;
1400 }
1401 Width = 0;
1402 CopyMem (
1403 &Width,
1404 TmpBuffer,
1405 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1406 );
1407 FreePool (TmpBuffer);
1408
1409 StringPtr += Length;
1410 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1411 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1412 Status = EFI_INVALID_PARAMETER;
1413 goto Exit;
1414 }
1415 StringPtr += StrLen (L"&VALUE=");
1416
1417 //
1418 // Get Value
1419 //
1420 Status = GetValueOfNumber (StringPtr, &Value, &Length);
1421 if (EFI_ERROR (Status)) {
1422 *Progress = ConfigResp;
1423 goto Exit;
1424 }
1425
1426 StringPtr += Length;
1427 if (*StringPtr != 0 && *StringPtr != L'&') {
1428 *Progress = StringPtr - Length - 7;
1429 Status = EFI_INVALID_PARAMETER;
1430 goto Exit;
1431 }
1432
1433 //
1434 // Update the Block with configuration info
1435 //
1436
1437 if (Offset + Width > BufferSize) {
1438 return EFI_DEVICE_ERROR;
1439 }
1440
1441 CopyMem (Block + Offset, Value, Width);
1442 *BlockSize = Offset + Width - 1;
1443
1444 FreePool (Value);
1445 Value = NULL;
1446
1447 //
1448 // If '\0', parsing is finished. Otherwise skip '&' to continue
1449 //
1450 if (*StringPtr == 0) {
1451 break;
1452 }
1453
1454 StringPtr++;
1455 }
1456
1457 if (*StringPtr != 0) {
1458 *Progress = StringPtr - 1;
1459 Status = EFI_INVALID_PARAMETER;
1460 goto Exit;
1461 }
1462
1463 *Progress = StringPtr;
1464 return EFI_SUCCESS;
1465
1466 Exit:
1467
1468 if (Value != NULL) {
1469 FreePool (Value);
1470 }
1471 return Status;
1472 }
1473
1474
1475 /**
1476 This helper function is to be called by drivers to extract portions of
1477 a larger configuration string.
1478
1479 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1480 instance.
1481 @param Configuration A null-terminated Unicode string in
1482 <MultiConfigAltResp> format.
1483 @param Guid A pointer to the GUID value to search for in the
1484 routing portion of the ConfigResp string when
1485 retrieving the requested data. If Guid is NULL,
1486 then all GUID values will be searched for.
1487 @param Name A pointer to the NAME value to search for in the
1488 routing portion of the ConfigResp string when
1489 retrieving the requested data. If Name is NULL,
1490 then all Name values will be searched for.
1491 @param DevicePath A pointer to the PATH value to search for in the
1492 routing portion of the ConfigResp string when
1493 retrieving the requested data. If DevicePath is
1494 NULL, then all DevicePath values will be searched
1495 for.
1496 @param AltCfgId A pointer to the ALTCFG value to search for in the
1497 routing portion of the ConfigResp string when
1498 retrieving the requested data. If this parameter
1499 is NULL, then the current setting will be
1500 retrieved.
1501 @param AltCfgResp A pointer to a buffer which will be allocated by
1502 the function which contains the retrieved string
1503 as requested. This buffer is only allocated if
1504 the call was successful.
1505
1506 @retval EFI_SUCCESS The request succeeded. The requested data was
1507 extracted and placed in the newly allocated
1508 AltCfgResp buffer.
1509 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1510 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1511 @retval EFI_NOT_FOUND Target for the specified routing data was not
1512 found.
1513
1514 **/
1515 EFI_STATUS
1516 EFIAPI
1517 HiiGetAltCfg (
1518 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1519 IN CONST EFI_STRING Configuration,
1520 IN CONST EFI_GUID *Guid,
1521 IN CONST EFI_STRING Name,
1522 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1523 IN CONST UINT16 *AltCfgId,
1524 OUT EFI_STRING *AltCfgResp
1525 )
1526 {
1527 EFI_STATUS Status;
1528 EFI_STRING StringPtr;
1529 EFI_STRING HdrStart;
1530 EFI_STRING HdrEnd;
1531 EFI_STRING TmpPtr;
1532 UINTN Length;
1533 EFI_STRING GuidStr;
1534 EFI_STRING NameStr;
1535 EFI_STRING PathStr;
1536 EFI_STRING AltIdStr;
1537 EFI_STRING Result;
1538 BOOLEAN GuidFlag;
1539 BOOLEAN NameFlag;
1540 BOOLEAN PathFlag;
1541
1542 HdrStart = NULL;
1543 HdrEnd = NULL;
1544 GuidStr = NULL;
1545 NameStr = NULL;
1546 PathStr = NULL;
1547 AltIdStr = NULL;
1548 Result = NULL;
1549 GuidFlag = FALSE;
1550 NameFlag = FALSE;
1551 PathFlag = FALSE;
1552
1553 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
1554 return EFI_INVALID_PARAMETER;
1555 }
1556
1557 StringPtr = Configuration;
1558 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1559 return EFI_INVALID_PARAMETER;
1560 }
1561
1562 //
1563 // Generate the sub string for later matching.
1564 //
1565 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
1566 GenerateSubStr (
1567 L"PATH=",
1568 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1569 (VOID *) DevicePath,
1570 1,
1571 &PathStr
1572 );
1573 if (AltCfgId != NULL) {
1574 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
1575 }
1576 if (Name != NULL) {
1577 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1578 } else {
1579 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1580 }
1581
1582 while (*StringPtr != 0) {
1583 //
1584 // Try to match the GUID
1585 //
1586 if (!GuidFlag) {
1587 TmpPtr = StrStr (StringPtr, GuidStr);
1588 if (TmpPtr == NULL) {
1589 Status = EFI_NOT_FOUND;
1590 goto Exit;
1591 }
1592 HdrStart = TmpPtr;
1593
1594 //
1595 // Jump to <NameHdr>
1596 //
1597 if (Guid != NULL) {
1598 StringPtr = TmpPtr + StrLen (GuidStr);
1599 } else {
1600 StringPtr = StrStr (TmpPtr, L"NAME=");
1601 if (StringPtr == NULL) {
1602 Status = EFI_NOT_FOUND;
1603 goto Exit;
1604 }
1605 }
1606 GuidFlag = TRUE;
1607 }
1608
1609 //
1610 // Try to match the NAME
1611 //
1612 if (GuidFlag && !NameFlag) {
1613 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
1614 GuidFlag = FALSE;
1615 } else {
1616 //
1617 // Jump to <PathHdr>
1618 //
1619 if (Name != NULL) {
1620 StringPtr += StrLen (NameStr);
1621 } else {
1622 StringPtr = StrStr (StringPtr, L"PATH=");
1623 if (StringPtr == NULL) {
1624 Status = EFI_NOT_FOUND;
1625 goto Exit;
1626 }
1627 }
1628 NameFlag = TRUE;
1629 }
1630 }
1631
1632 //
1633 // Try to match the DevicePath
1634 //
1635 if (GuidFlag && NameFlag && !PathFlag) {
1636 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
1637 GuidFlag = FALSE;
1638 NameFlag = FALSE;
1639 } else {
1640 //
1641 // Jump to '&' before <DescHdr> or <ConfigBody>
1642 //
1643 if (DevicePath != NULL) {
1644 StringPtr += StrLen (PathStr);
1645 } else {
1646 StringPtr = StrStr (StringPtr, L"&");
1647 if (StringPtr == NULL) {
1648 Status = EFI_NOT_FOUND;
1649 goto Exit;
1650 }
1651 }
1652 PathFlag = TRUE;
1653 HdrEnd = ++StringPtr;
1654 }
1655 }
1656
1657 //
1658 // Try to match the AltCfgId
1659 //
1660 if (GuidFlag && NameFlag && PathFlag) {
1661 if (AltCfgId == NULL) {
1662 //
1663 // Return Current Setting when AltCfgId is NULL.
1664 //
1665 Status = OutputConfigBody (StringPtr, &Result);
1666 goto Exit;
1667 }
1668 //
1669 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1670 //
1671 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
1672 GuidFlag = FALSE;
1673 NameFlag = FALSE;
1674 PathFlag = FALSE;
1675 } else {
1676 Status = OutputConfigBody (StringPtr, &Result);
1677 goto Exit;
1678 }
1679 }
1680 }
1681
1682 Status = EFI_NOT_FOUND;
1683
1684 Exit:
1685
1686 if (!EFI_ERROR (Status) && (Result != NULL)) {
1687 //
1688 // Copy the <ConfigHdr> and <ConfigBody>
1689 //
1690 Length = HdrEnd - HdrStart + StrLen (Result);
1691 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
1692 if (*AltCfgResp == NULL) {
1693 Status = EFI_OUT_OF_RESOURCES;
1694 } else {
1695 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
1696 StrCat (*AltCfgResp, Result);
1697 Status = EFI_SUCCESS;
1698 }
1699 }
1700
1701 if (GuidStr != NULL) {
1702 FreePool (GuidStr);
1703 }
1704 if (NameStr != NULL) {
1705 FreePool (NameStr);
1706 }
1707 if (PathStr != NULL) {
1708 FreePool (PathStr);
1709 }
1710 if (AltIdStr != NULL) {
1711 FreePool (AltIdStr);
1712 }
1713 if (Result != NULL) {
1714 FreePool (Result);
1715 }
1716
1717 return Status;
1718
1719 }
1720
1721