]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
1) Add BufToHexString, HexStringToBuf and IsHexDigit to BaseLib.
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file
2
3 Copyright (c) 2007 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 ConfigRouting.c
15
16 Abstract:
17
18 Implementation for EFI_HII_CONFIG_ROUTING_PROTOCOL.
19
20 Revision History
21
22
23 **/
24
25
26 #include "HiiDatabase.h"
27
28 #ifndef DISABLE_UNUSED_HII_PROTOCOLS
29
30 STATIC
31 CHAR16
32 NibbleToHexCharPrivate (
33 IN UINT8 Nibble
34 )
35 /*++
36
37 Routine Description:
38 Converts the low nibble of a byte to hex unicode character.
39
40 Arguments:
41 Nibble - lower nibble of a byte.
42
43 Returns:
44 Hex unicode character between L'0' to L'f'.
45
46 --*/
47 {
48 Nibble &= 0x0F;
49
50 if (Nibble <= 0x9) {
51 return (CHAR16)(Nibble + L'0');
52 }
53
54 return (CHAR16)(Nibble - 0xA + L'a');
55 }
56
57
58 /**
59 Converts Unicode string to binary buffer.
60 The conversion may be partial.
61 The first character in the string that is not hex digit stops the conversion.
62 At a minimum, any blob of data could be represented as a hex string.
63
64 @param Buf Pointer to buffer that receives the data.
65 @param Len Length in bytes of the buffer to hold converted
66 data. If routine return with EFI_SUCCESS,
67 containing length of converted data. If routine
68 return with EFI_BUFFER_TOO_SMALL, containg length
69 of buffer desired.
70 @param Str String to be converted from.
71 @param ConvertedStrLen Length of the Hex String consumed.
72
73 @retval EFI_SUCCESS Routine Success.
74 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold converted data.
75
76 **/
77 STATIC
78 EFI_STATUS
79 HexStringToBufPrivate (
80 IN OUT UINT8 *Buf,
81 IN OUT UINTN *Len,
82 IN CHAR16 *Str,
83 OUT UINTN *ConvertedStrLen OPTIONAL
84 )
85 {
86 UINTN HexCnt;
87 UINTN Idx;
88 UINTN BufferLength;
89 UINT8 Digit;
90 UINT8 Byte;
91
92 //
93 // Find out how many hex characters the string has.
94 //
95 for (Idx = 0, HexCnt = 0; IsHexDigit (&Digit, Str[Idx]); Idx++, HexCnt++);
96
97 if (HexCnt == 0) {
98 *Len = 0;
99 return EFI_SUCCESS;
100 }
101 //
102 // Two Unicode characters make up 1 buffer byte. Round up.
103 //
104 BufferLength = (HexCnt + 1) / 2;
105
106 //
107 // Test if buffer is passed enough.
108 //
109 if (BufferLength > (*Len)) {
110 *Len = BufferLength;
111 return EFI_BUFFER_TOO_SMALL;
112 }
113
114 *Len = BufferLength;
115
116 for (Idx = 0; Idx < HexCnt; Idx++) {
117
118 IsHexDigit (&Digit, Str[Idx]);
119
120 //
121 // For odd charaters, write the lower nibble for each buffer byte,
122 // and for even characters, the upper nibble.
123 //
124 if ((Idx & 1) == 0) {
125 Byte = (UINT8) (Digit << 4);
126 } else {
127 Byte = Buf[Idx / 2];
128 Byte &= 0xF0;
129 Byte = (UINT8) (Byte | Digit);
130 }
131
132 Buf[Idx / 2] = Byte;
133 }
134
135 if (ConvertedStrLen != NULL) {
136 *ConvertedStrLen = HexCnt;
137 }
138
139 return EFI_SUCCESS;
140 }
141
142
143 /**
144 Converts binary buffer to Unicode string.
145 At a minimum, any blob of data could be represented as a hex string.
146
147 @param Str Pointer to the string.
148 @param HexStringBufferLength Length in bytes of buffer to hold the hex string.
149 Includes tailing '\0' character. If routine return
150 with EFI_SUCCESS, containing length of hex string
151 buffer. If routine return with
152 EFI_BUFFER_TOO_SMALL, containg length of hex
153 string buffer desired.
154 @param Buf Buffer to be converted from.
155 @param Len Length in bytes of the buffer to be converted.
156 @param Flag If TRUE, encode the data in the same order as the
157 it resides in the Buf. Else encode it in the
158 reverse direction.
159
160 @retval EFI_SUCCESS Routine success.
161 @retval EFI_BUFFER_TOO_SMALL The hex string buffer is too small.
162
163 **/
164 STATIC
165 EFI_STATUS
166 BufToHexStringPrivate (
167 IN OUT CHAR16 *Str,
168 IN OUT UINTN *HexStringBufferLength,
169 IN UINT8 *Buf,
170 IN UINTN Len,
171 IN BOOLEAN Flag
172 )
173 {
174 UINTN Idx;
175 UINT8 Byte;
176 UINTN StrLen;
177
178 //
179 // Make sure string is either passed or allocate enough.
180 // It takes 2 Unicode characters (4 bytes) to represent 1 byte of the binary buffer.
181 // Plus the Unicode termination character.
182 //
183 StrLen = Len * 2;
184 if ((*HexStringBufferLength) < (StrLen + 1) * sizeof (CHAR16)) {
185 *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
186 return EFI_BUFFER_TOO_SMALL;
187 }
188
189 *HexStringBufferLength = (StrLen + 1) * sizeof (CHAR16);
190
191 //
192 // Ends the string.
193 //
194 Str[StrLen] = 0;
195
196 for (Idx = 0; Idx < Len; Idx++) {
197
198 Byte = Buf[Idx];
199 if (Flag) {
200 Str[Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
201 Str[Idx * 2 + 1] = NibbleToHexCharPrivate (Byte);
202 } else {
203 Str[StrLen - 1 - Idx * 2] = NibbleToHexCharPrivate (Byte);
204 Str[StrLen - 2 - Idx * 2] = NibbleToHexCharPrivate ((UINT8)(Byte >> 4));
205 }
206 }
207
208 return EFI_SUCCESS;
209 }
210
211
212
213 /**
214 Calculate the number of Unicode characters of the incoming Configuration string,
215 not including NULL terminator.
216
217 @param String String in <MultiConfigRequest> or
218 <MultiConfigResp> format.
219
220 @return The number of Unicode characters.
221
222 **/
223 STATIC
224 UINTN
225 CalculateConfigStringLen (
226 IN EFI_STRING String
227 )
228 {
229 UINTN Length;
230
231 //
232 // "GUID=" should be the first element of incoming string.
233 //
234 ASSERT (String != NULL);
235 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
236
237 Length = StrLen (L"GUID=");
238 String += Length;
239
240 //
241 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
242 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
243 //
244 while (*String != 0 && StrnCmp (String, L"&GUID=", StrLen (L"&GUID=")) != 0) {
245 Length++;
246 String++;
247 }
248
249 return Length;
250 }
251
252
253 /**
254 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
255 from <PathHdr> of <ConfigHdr>.
256
257 @param String UEFI configuration string
258 @param DevicePath binary of a UEFI device path.
259
260 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
261 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
262 @retval EFI_SUCCESS The device path is retrieved and translated to
263 binary format.
264
265 **/
266 STATIC
267 EFI_STATUS
268 GetDevicePath (
269 IN EFI_STRING String,
270 OUT UINT8 **DevicePath
271 )
272 {
273 UINTN Length;
274 EFI_STRING PathHdr;
275 EFI_STRING DevicePathString;
276
277 if (String == NULL || DevicePath == NULL) {
278 return EFI_INVALID_PARAMETER;
279 }
280
281 //
282 // Find the 'PATH=' of <PathHdr> and skip it.
283 //
284 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
285 if (*String == 0) {
286 return EFI_INVALID_PARAMETER;
287 }
288
289 String += StrLen (L"PATH=");
290 PathHdr = String;
291
292 //
293 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
294 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
295 // of UEFI device path.
296 //
297 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
298 DevicePathString = (EFI_STRING) AllocateZeroPool ((Length + 1) * sizeof (CHAR16));
299 if (DevicePathString == NULL) {
300 return EFI_OUT_OF_RESOURCES;
301 }
302 StrnCpy (DevicePathString, PathHdr, Length);
303 *(DevicePathString + Length) = 0;
304
305 //
306 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
307 // as the device path resides in RAM memory.
308 // Translate the data into binary.
309 // Two Unicode characters make up 1 buffer byte.
310 //
311 Length /= 2;
312 *DevicePath = (UINT8 *) AllocateZeroPool (Length);
313 if (*DevicePath == NULL) {
314 SafeFreePool (DevicePathString);
315 return EFI_OUT_OF_RESOURCES;
316 }
317
318 HexStringToBufPrivate (*DevicePath, &Length, DevicePathString, NULL);
319
320 SafeFreePool (DevicePathString);
321
322 return EFI_SUCCESS;
323
324 }
325
326
327 /**
328 Extract Storage from all Form Packages in current hii database.
329
330 @param HiiDatabase EFI_HII_DATABASE_PROTOCOL instance.
331 @param StorageListHead Storage link List head.
332
333 @retval EFI_NOT_FOUND There is no form package in current hii database.
334 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
335 @retval EFI_SUCCESS All existing storage is exported.
336
337 **/
338 STATIC
339 EFI_STATUS
340 ExportAllStorage (
341 IN EFI_HII_DATABASE_PROTOCOL *HiiDatabase,
342 IN OUT LIST_ENTRY *StorageListHead
343 )
344 {
345 EFI_STATUS Status;
346 UINTN BufferSize;
347 UINTN HandleCount;
348 EFI_HII_HANDLE *HandleBuffer;
349 UINTN Index;
350 UINTN Index2;
351 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
352 EFI_HII_PACKAGE_HEADER *Package;
353 UINT8 *OpCodeData;
354 UINT8 Operand;
355 UINT32 Offset;
356 HII_FORMSET_STORAGE *Storage;
357 EFI_HII_HANDLE HiiHandle;
358 EFI_HANDLE DriverHandle;
359 CHAR8 *AsciiString;
360 UINT32 PackageListLength;
361 EFI_HII_PACKAGE_HEADER PackageHeader;
362
363 //
364 // Find the package list which contains Form package.
365 //
366 BufferSize = 0;
367 HandleBuffer = NULL;
368 Status = HiiListPackageLists (
369 HiiDatabase,
370 EFI_HII_PACKAGE_FORM,
371 NULL,
372 &BufferSize,
373 HandleBuffer
374 );
375 if (Status == EFI_BUFFER_TOO_SMALL) {
376 HandleBuffer = AllocateZeroPool (BufferSize);
377 ASSERT (HandleBuffer != NULL);
378
379 Status = HiiListPackageLists (
380 HiiDatabase,
381 EFI_HII_PACKAGE_FORM,
382 NULL,
383 &BufferSize,
384 HandleBuffer
385 );
386 }
387 if (EFI_ERROR (Status)) {
388 SafeFreePool (HandleBuffer);
389 return Status;
390 }
391
392 HandleCount = BufferSize / sizeof (EFI_HII_HANDLE);
393 for (Index = 0; Index < HandleCount; Index++) {
394 HiiHandle = HandleBuffer[Index];
395
396 BufferSize = 0;
397 HiiPackageList = NULL;
398 Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
399 if (Status == EFI_BUFFER_TOO_SMALL) {
400 HiiPackageList = AllocateZeroPool (BufferSize);
401 ASSERT (HiiPackageList != NULL);
402 Status = HiiExportPackageLists (HiiDatabase, HiiHandle, &BufferSize, HiiPackageList);
403 }
404 if (EFI_ERROR (Status)) {
405 SafeFreePool (HandleBuffer);
406 SafeFreePool (HiiPackageList);
407 return Status;
408 }
409
410 //
411 // Get Form package from this HII package List
412 //
413 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
414 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));
415 Package = NULL;
416 ZeroMem (&PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));
417
418 while (Offset < PackageListLength) {
419 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);
420 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
421 if (PackageHeader.Type == EFI_HII_PACKAGE_FORM) {
422 break;
423 }
424 Offset += PackageHeader.Length;
425 }
426 if (Offset >= PackageListLength) {
427 //
428 // Error here: No Form package found in this Package List
429 //
430 ASSERT (FALSE);
431 }
432
433 //
434 // Search Storage definition in this Form package
435 //
436 Offset = sizeof (EFI_HII_PACKAGE_HEADER);
437 while (Offset < PackageHeader.Length) {
438 OpCodeData = ((UINT8 *) Package) + Offset;
439 Offset += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
440
441 Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;
442
443 if ((Operand == EFI_IFR_VARSTORE_OP) ||
444 (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) ||
445 (Operand == EFI_IFR_VARSTORE_EFI_OP)) {
446
447 Storage = AllocateZeroPool (sizeof (HII_FORMSET_STORAGE));
448 ASSERT (Storage != NULL);
449 InsertTailList (StorageListHead, &Storage->Entry);
450
451 Storage->Signature = HII_FORMSET_STORAGE_SIGNATURE;
452 Storage->HiiHandle = HiiHandle;
453
454 Status = HiiGetPackageListHandle (HiiDatabase, HiiHandle, &DriverHandle);
455 if (EFI_ERROR (Status)) {
456 SafeFreePool (HandleBuffer);
457 SafeFreePool (HiiPackageList);
458 SafeFreePool (Storage);
459 return Status;
460 }
461 Storage->DriverHandle = DriverHandle;
462
463 if (Operand == EFI_IFR_VARSTORE_OP) {
464 Storage->Type = EFI_HII_VARSTORE_BUFFER;
465
466 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE *) OpCodeData)->Guid, sizeof (EFI_GUID));
467 CopyMem (&Storage->Size, &((EFI_IFR_VARSTORE *) OpCodeData)->Size, sizeof (UINT16));
468
469 AsciiString = (CHAR8 *) ((EFI_IFR_VARSTORE *) OpCodeData)->Name;
470 Storage->Name = AllocateZeroPool (AsciiStrSize (AsciiString) * 2);
471 ASSERT (Storage->Name != NULL);
472 for (Index2 = 0; AsciiString[Index2] != 0; Index2++) {
473 Storage->Name[Index2] = (CHAR16) AsciiString[Index2];
474 }
475 //
476 // Append '\0' to the end of the unicode string.
477 //
478 Storage->Name[Index2] = 0;
479 } else if (Operand == EFI_IFR_VARSTORE_NAME_VALUE_OP) {
480 Storage->Type = EFI_HII_VARSTORE_NAME_VALUE;
481
482 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_NAME_VALUE *) OpCodeData)->Guid, sizeof (EFI_GUID));
483 } else if (Operand == EFI_IFR_VARSTORE_EFI_OP) {
484 Storage->Type = EFI_HII_VARSTORE_EFI_VARIABLE;
485
486 CopyMem (&Storage->Guid, &((EFI_IFR_VARSTORE_EFI *) OpCodeData)->Guid, sizeof (EFI_GUID));
487 }
488 }
489 }
490
491 SafeFreePool (HiiPackageList);
492 }
493
494 SafeFreePool (HandleBuffer);
495
496 return EFI_SUCCESS;
497 }
498
499
500 /**
501 Generate a sub string then output it.
502
503 @param String A constant string which is the prefix of the to be
504 generated string, e.g. GUID=
505 @param BufferLen The length of the Buffer in bytes.
506 @param Buffer Points to a buffer which will be converted to hex
507 string and to be the content of the generated
508 string.
509 @param Flag If TRUE, convert the buffer data in the same order
510 as the it resides in the Buffer. Else convert it
511 in the reverse direction.
512 @param SubStr Points to the output string. It's caller's
513 responsibility to free this buffer.
514
515
516 **/
517 STATIC
518 VOID
519 GenerateSubStr (
520 IN CONST EFI_STRING String,
521 IN UINTN BufferLen,
522 IN UINT8 *Buffer,
523 IN BOOLEAN Flag,
524 OUT EFI_STRING *SubStr
525 )
526 {
527 UINTN Length;
528 EFI_STRING Str;
529 EFI_STATUS Status;
530
531 ASSERT (String != NULL && SubStr != NULL);
532
533 if (Buffer == NULL) {
534 *SubStr = AllocateCopyPool (StrSize (String), String);
535 ASSERT (*SubStr != NULL);
536 return ;
537 }
538
539 Length = BufferLen * 2 + 1 + StrLen (String) + 1;
540 Str = AllocateZeroPool (Length * sizeof (CHAR16));
541 ASSERT (Str != NULL);
542
543 StrCpy (Str, String);
544 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
545
546 Status = BufToHexStringPrivate (
547 Str + StrLen (String),
548 &Length,
549 Buffer,
550 BufferLen,
551 Flag
552 );
553
554 ASSERT_EFI_ERROR (Status);
555 StrCat (Str, L"&");
556
557 *SubStr = Str;
558 }
559
560
561 /**
562 Retrieve the <ConfigBody> from String then output it.
563
564 @param String A sub string of a configuration string in
565 <MultiConfigAltResp> format.
566 @param ConfigBody Points to the output string. It's caller's
567 responsibility to free this buffer.
568
569 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
570 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
571 @retval EFI_SUCCESS All existing storage is exported.
572
573 **/
574 STATIC
575 EFI_STATUS
576 OutputConfigBody (
577 IN EFI_STRING String,
578 OUT EFI_STRING *ConfigBody
579 )
580 {
581 EFI_STRING TmpPtr;
582 EFI_STRING Result;
583 UINTN Length;
584
585 if (String == NULL || ConfigBody == NULL) {
586 return EFI_INVALID_PARAMETER;
587 }
588
589 TmpPtr = StrStr (String, L"GUID=");
590 if (TmpPtr == NULL) {
591 //
592 // It is the last <ConfigResp> of the incoming configuration string.
593 //
594 Result = AllocateCopyPool (StrSize (String), String);
595 if (Result == NULL) {
596 return EFI_OUT_OF_RESOURCES;
597 } else {
598 *ConfigBody = Result;
599 return EFI_SUCCESS;
600 }
601 }
602
603 Length = TmpPtr - String;
604 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
605 if (Result == NULL) {
606 return EFI_OUT_OF_RESOURCES;
607 }
608
609 *(Result + Length - 1) = 0;
610 *ConfigBody = Result;
611 return EFI_SUCCESS;
612
613 }
614
615
616 #endif
617
618 VOID *
619 ReallocatePool (
620 IN VOID *OldPool,
621 IN UINTN OldSize,
622 IN UINTN NewSize
623 )
624 /*++
625
626 Routine Description:
627 Adjusts the size of a previously allocated buffer.
628
629 Arguments:
630 OldPool - A pointer to the buffer whose size is being adjusted.
631 OldSize - The size of the current buffer.
632 NewSize - The size of the new buffer.
633
634 Returns:
635 Points to the new buffer
636
637 --*/
638 {
639 VOID *NewPool;
640
641 NewPool = NULL;
642 if (NewSize) {
643 NewPool = AllocateZeroPool (NewSize);
644 }
645
646 if (OldPool) {
647 if (NewPool) {
648 CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
649 }
650
651 gBS->FreePool (OldPool);
652 }
653
654 return NewPool;
655 }
656
657
658 /**
659 Append a string to a multi-string format.
660
661 @param MultiString String in <MultiConfigRequest>,
662 <MultiConfigAltResp>, or <MultiConfigResp>. On
663 input, the buffer length of this string is
664 MAX_STRING_LENGTH. On output, the buffer length
665 might be updated.
666 @param AppendString NULL-terminated Unicode string.
667
668 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
669 @retval EFI_SUCCESS AppendString is append to the end of MultiString
670
671 **/
672 STATIC
673 EFI_STATUS
674 AppendToMultiString (
675 IN OUT EFI_STRING *MultiString,
676 IN EFI_STRING AppendString
677 )
678 {
679 UINTN AppendStringSize;
680 UINTN MultiStringSize;
681
682 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
683 return EFI_INVALID_PARAMETER;
684 }
685
686 AppendStringSize = StrSize (AppendString);
687 MultiStringSize = StrSize (*MultiString);
688
689 //
690 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
691 //
692 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
693 MultiStringSize > MAX_STRING_LENGTH) {
694 *MultiString = (EFI_STRING) ReallocatePool (
695 (VOID *) (*MultiString),
696 MultiStringSize,
697 MultiStringSize + AppendStringSize
698 );
699 }
700
701 //
702 // Append the incoming string
703 //
704 StrCat (*MultiString, AppendString);
705
706 return EFI_SUCCESS;
707 }
708
709
710 /**
711 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
712 or WIDTH or VALUE.
713 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
714
715 @param StringPtr String in <BlockConfig> format and points to the
716 first character of <Number>.
717 @param Number The output value. Caller takes the responsibility
718 to free memory.
719 @param Len Length of the <Number>, in characters.
720
721 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
722 structures.
723 @retval EFI_SUCCESS Value of <Number> is outputted in Number
724 successfully.
725
726 **/
727 STATIC
728 EFI_STATUS
729 GetValueOfNumber (
730 IN EFI_STRING StringPtr,
731 OUT UINT8 **Number,
732 OUT UINTN *Len
733 )
734 {
735 EFI_STRING TmpPtr;
736 UINTN Length;
737 EFI_STRING Str;
738 UINT8 *Buf;
739 EFI_STATUS Status;
740
741 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
742 ASSERT (*StringPtr != 0);
743
744 Buf = NULL;
745
746 TmpPtr = StringPtr;
747 while (*StringPtr != 0 && *StringPtr != L'&') {
748 StringPtr++;
749 }
750 *Len = StringPtr - TmpPtr;
751 Length = *Len + 1;
752
753 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
754 if (Str == NULL) {
755 Status = EFI_OUT_OF_RESOURCES;
756 goto Exit;
757 }
758 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
759 *(Str + *Len) = 0;
760
761 Length = (Length + 1) / 2;
762 Buf = (UINT8 *) AllocateZeroPool (Length);
763 if (Buf == NULL) {
764 Status = EFI_OUT_OF_RESOURCES;
765 goto Exit;
766 }
767
768 Status = HexStringToBuf (Buf, &Length, Str, NULL);
769 if (EFI_ERROR (Status)) {
770 goto Exit;
771 }
772
773 *Number = Buf;
774 Status = EFI_SUCCESS;
775
776 Exit:
777 SafeFreePool (Str);
778 return Status;
779 }
780
781
782 /**
783 This function allows a caller to extract the current configuration
784 for one or more named elements from one or more drivers.
785
786 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
787 instance.
788 @param Request A null-terminated Unicode string in
789 <MultiConfigRequest> format.
790 @param Progress On return, points to a character in the Request
791 string. Points to the string's null terminator if
792 request was successful. Points to the most recent
793 & before the first failing name / value pair (or
794 the beginning of the string if the failure is in
795 the first name / value pair) if the request was
796 not successful.
797 @param Results Null-terminated Unicode string in
798 <MultiConfigAltResp> format which has all values
799 filled in for the names in the Request string.
800 String to be allocated by the called function.
801
802 @retval EFI_SUCCESS The Results string is filled with the values
803 corresponding to all requested names.
804 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
805 results that must be stored awaiting possible
806 future protocols.
807 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
808 Progress set to the "G" in "GUID" of the routing
809 header that doesn't match. Note: There is no
810 requirement that all routing data be validated
811 before any configuration extraction.
812 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
813 parameter would result in this type of error. The
814 Progress parameter is set to NULL.
815 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
816 before the error or the beginning of the string.
817 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
818 name in question.
819
820 **/
821 EFI_STATUS
822 EFIAPI
823 HiiConfigRoutingExtractConfig (
824 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
825 IN CONST EFI_STRING Request,
826 OUT EFI_STRING *Progress,
827 OUT EFI_STRING *Results
828 )
829 {
830 #ifndef DISABLE_UNUSED_HII_PROTOCOLS
831
832 HII_DATABASE_PRIVATE_DATA *Private;
833 EFI_STRING StringPtr;
834 EFI_STRING ConfigRequest;
835 UINTN Length;
836 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
837 EFI_STATUS Status;
838 LIST_ENTRY *Link;
839 HII_DATABASE_RECORD *Database;
840 UINT8 *CurrentDevicePath;
841 EFI_HANDLE DriverHandle;
842 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
843 EFI_STRING AccessProgress;
844 EFI_STRING AccessResults;
845 UINTN RemainSize;
846 EFI_STRING TmpPtr;
847
848 if (This == NULL || Progress == NULL || Results == NULL) {
849 return EFI_INVALID_PARAMETER;
850 }
851
852 if (Request == NULL) {
853 *Progress = NULL;
854 return EFI_INVALID_PARAMETER;
855 }
856
857 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
858 StringPtr = Request;
859 *Progress = StringPtr;
860
861 //
862 // The first element of <MultiConfigRequest> should be
863 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
864 //
865 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
866 return EFI_INVALID_PARAMETER;
867 }
868
869 //
870 // Allocate a fix length of memory to store Results. Reallocate memory for
871 // Results if this fix length is insufficient.
872 //
873 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
874 if (*Results == NULL) {
875 return EFI_OUT_OF_RESOURCES;
876 }
877
878 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
879 //
880 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
881 // or most recent & before the error.
882 //
883 if (StringPtr == Request) {
884 *Progress = StringPtr;
885 } else {
886 *Progress = StringPtr - 1;
887 }
888
889 //
890 // Process each <ConfigRequest> of <MultiConfigRequest>
891 //
892 Length = CalculateConfigStringLen (StringPtr);
893 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
894 if (ConfigRequest == NULL) {
895 return EFI_OUT_OF_RESOURCES;
896 }
897 *(ConfigRequest + Length) = 0;
898
899 //
900 // Get the UEFI device path
901 //
902 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
903 if (EFI_ERROR (Status)) {
904 SafeFreePool (ConfigRequest);
905 return Status;
906 }
907
908 //
909 // Find driver which matches the routing data.
910 //
911 DriverHandle = NULL;
912 for (Link = Private->DatabaseList.ForwardLink;
913 Link != &Private->DatabaseList;
914 Link = Link->ForwardLink
915 ) {
916 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
917 CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
918 if (CurrentDevicePath != NULL) {
919 if (CompareMem (
920 DevicePath,
921 CurrentDevicePath,
922 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
923 ) == 0) {
924 DriverHandle = Database->DriverHandle;
925 break;
926 }
927 }
928 }
929
930 SafeFreePool (DevicePath);
931
932 if (DriverHandle == NULL) {
933 //
934 // Routing data does not match any known driver.
935 // Set Progress to the 'G' in "GUID" of the routing header.
936 //
937 *Progress = StringPtr;
938 SafeFreePool (ConfigRequest);
939 return EFI_NOT_FOUND;
940 }
941
942 //
943 // Call corresponding ConfigAccess protocol to extract settings
944 //
945 Status = gBS->HandleProtocol (
946 DriverHandle,
947 &gEfiHiiConfigAccessProtocolGuid,
948 (VOID **) &ConfigAccess
949 );
950 ASSERT_EFI_ERROR (Status);
951
952 Status = ConfigAccess->ExtractConfig (
953 ConfigAccess,
954 ConfigRequest,
955 &AccessProgress,
956 &AccessResults
957 );
958 if (EFI_ERROR (Status)) {
959 //
960 // AccessProgress indicates the parsing progress on <ConfigRequest>.
961 // Map it to the progress on <MultiConfigRequest> then return it.
962 //
963 RemainSize = StrSize (AccessProgress);
964 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
965 *Progress = TmpPtr;
966
967 SafeFreePool (ConfigRequest);
968 return Status;
969 }
970
971 //
972 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
973 //
974 ASSERT (*AccessProgress == 0);
975 Status = AppendToMultiString (Results, AccessResults);
976 ASSERT_EFI_ERROR (Status);
977 SafeFreePool (AccessResults);
978 AccessResults = NULL;
979 SafeFreePool (ConfigRequest);
980 ConfigRequest = NULL;
981
982 //
983 // Go to next <ConfigRequest> (skip '&').
984 //
985 StringPtr += Length;
986 if (*StringPtr == 0) {
987 *Progress = StringPtr;
988 break;
989 }
990
991 StringPtr++;
992
993 }
994
995 return EFI_SUCCESS;
996 #else
997 return EFI_UNSUPPORTED;
998 #endif
999
1000 }
1001
1002
1003 /**
1004 This function allows the caller to request the current configuration for the
1005 entirety of the current HII database and returns the data in a
1006 null-terminated Unicode string.
1007
1008 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1009 instance.
1010 @param Results Null-terminated Unicode string in
1011 <MultiConfigAltResp> format which has all values
1012 filled in for the names in the Request string.
1013 String to be allocated by the called function.
1014 De-allocation is up to the caller.
1015
1016 @retval EFI_SUCCESS The Results string is filled with the values
1017 corresponding to all requested names.
1018 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
1019 results that must be stored awaiting possible
1020 future protocols.
1021 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
1022 parameter would result in this type of error.
1023
1024 **/
1025 EFI_STATUS
1026 EFIAPI
1027 HiiConfigRoutingExportConfig (
1028 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1029 OUT EFI_STRING *Results
1030 )
1031 {
1032 #ifndef DISABLE_UNUSED_HII_PROTOCOLS
1033
1034 EFI_STATUS Status;
1035 HII_DATABASE_PRIVATE_DATA *Private;
1036 LIST_ENTRY StorageListHdr;
1037 HII_FORMSET_STORAGE *Storage;
1038 LIST_ENTRY *Link;
1039 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1040 UINTN Length;
1041 EFI_STRING PathHdr;
1042 UINTN PathHdrSize;
1043 EFI_STRING ConfigRequest;
1044 UINTN RequestSize;
1045 EFI_STRING StringPtr;
1046 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1047 EFI_STRING AccessProgress;
1048 EFI_STRING AccessResults;
1049 UINTN TmpSize;
1050
1051 if (This == NULL || Results == NULL) {
1052 return EFI_INVALID_PARAMETER;
1053 }
1054
1055 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1056
1057 InitializeListHead (&StorageListHdr);
1058
1059 Status = ExportAllStorage (&Private->HiiDatabase, &StorageListHdr);
1060 if (EFI_ERROR (Status)) {
1061 return Status;
1062 }
1063
1064 //
1065 // Allocate a fix length of memory to store Results. Reallocate memory for
1066 // Results if this fix length is insufficient.
1067 //
1068 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
1069 if (*Results == NULL) {
1070 return EFI_OUT_OF_RESOURCES;
1071 }
1072
1073 //
1074 // Parsing all formset storages.
1075 //
1076 for (Link = StorageListHdr.ForwardLink; Link != &StorageListHdr; Link = Link->ForwardLink) {
1077 Storage = CR (Link, HII_FORMSET_STORAGE, Entry, HII_FORMSET_STORAGE_SIGNATURE);
1078 //
1079 // Find the corresponding device path instance
1080 //
1081 Status = gBS->HandleProtocol (
1082 Storage->DriverHandle,
1083 &gEfiDevicePathProtocolGuid,
1084 (VOID **) &DevicePath
1085 );
1086 if (EFI_ERROR (Status)) {
1087 return Status;
1088 }
1089 //
1090 // Convert the device path binary to hex UNICODE %02x bytes in the same order
1091 // as the device path resides in RAM memory.
1092 //
1093 Length = GetDevicePathSize (DevicePath);
1094 PathHdrSize = (Length * 2 + 1) * sizeof (CHAR16);
1095 PathHdr = (EFI_STRING) AllocateZeroPool (PathHdrSize);
1096 if (PathHdr == NULL) {
1097 return EFI_OUT_OF_RESOURCES;
1098 }
1099 Status = BufToHexStringPrivate (PathHdr, &PathHdrSize, (UINT8 *) DevicePath, Length, TRUE);
1100 ASSERT_EFI_ERROR (Status);
1101
1102 //
1103 // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
1104 // It means extract all possible configurations from this specific driver.
1105 //
1106 TmpSize = StrLen (L"GUID=&NAME=&PATH=");
1107 RequestSize = (TmpSize + sizeof (EFI_GUID) * 2 + StrLen (Storage->Name))
1108 * sizeof (CHAR16) + PathHdrSize;
1109 ConfigRequest = (EFI_STRING) AllocateZeroPool (RequestSize);
1110 if (ConfigRequest == NULL) {
1111 SafeFreePool (PathHdr);
1112 return EFI_OUT_OF_RESOURCES;
1113 }
1114
1115 //
1116 // Add <GuidHdr>
1117 // <GuidHdr> ::= 'GUID='<Guid>
1118 //
1119 StringPtr = ConfigRequest;
1120 StrnCpy (StringPtr, L"GUID=", StrLen (L"GUID="));
1121 StringPtr += StrLen (L"GUID=");
1122
1123 Status = BufToHexStringPrivate (
1124 StringPtr,
1125 &RequestSize,
1126 (UINT8 *) (&Storage->Guid),
1127 sizeof (EFI_GUID),
1128 FALSE
1129 );
1130 ASSERT_EFI_ERROR (Status);
1131 StringPtr += RequestSize / 2 - 1;
1132 ASSERT (*StringPtr == 0);
1133 *StringPtr = L'&';
1134 StringPtr++;
1135
1136 //
1137 // Add <NameHdr>
1138 // <NameHdr> ::= 'NAME='<String>
1139 //
1140 StrnCpy (StringPtr, L"NAME=", StrLen (L"NAME="));
1141 StringPtr += StrLen (L"NAME=");
1142 StrnCpy (StringPtr, Storage->Name, StrLen (Storage->Name));
1143 StringPtr += StrLen (Storage->Name);
1144 *StringPtr = L'&';
1145 StringPtr++;
1146
1147 //
1148 // Add <PathHdr>
1149 // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
1150 //
1151 StrnCpy (StringPtr, L"PATH=", StrLen (L"PATH="));
1152 StringPtr += StrLen (L"PATH=");
1153 StrCpy (StringPtr, PathHdr);
1154
1155 SafeFreePool (PathHdr);
1156 PathHdr = NULL;
1157
1158 //
1159 // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
1160 // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
1161 // is required to call ConfigAccess.ExtractConfig().
1162 //
1163 // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
1164 // to handle such kind of "ConfigRequest". It is not supported till now.
1165 //
1166 // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
1167 // will be updated as soon as the decision is made.
1168
1169 //
1170 // Route the request to corresponding ConfigAccess protocol to extract settings.
1171 //
1172 Status = gBS->HandleProtocol (
1173 Storage->DriverHandle,
1174 &gEfiHiiConfigAccessProtocolGuid,
1175 (VOID **) &ConfigAccess
1176 );
1177 ASSERT_EFI_ERROR (Status);
1178
1179 Status = ConfigAccess->ExtractConfig (
1180 ConfigAccess,
1181 ConfigRequest,
1182 &AccessProgress,
1183 &AccessResults
1184 );
1185 if (EFI_ERROR (Status)) {
1186 SafeFreePool (ConfigRequest);
1187 SafeFreePool (AccessResults);
1188 return EFI_INVALID_PARAMETER;
1189 }
1190
1191 //
1192 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
1193 //
1194 ASSERT (*AccessProgress == 0);
1195 Status = AppendToMultiString (Results, AccessResults);
1196 ASSERT_EFI_ERROR (Status);
1197 SafeFreePool (AccessResults);
1198 AccessResults = NULL;
1199 SafeFreePool (ConfigRequest);
1200 ConfigRequest = NULL;
1201
1202 }
1203
1204 //
1205 // Free the exported storage resource
1206 //
1207 while (!IsListEmpty (&StorageListHdr)) {
1208 Storage = CR (
1209 StorageListHdr.ForwardLink,
1210 HII_FORMSET_STORAGE,
1211 Entry,
1212 HII_FORMSET_STORAGE_SIGNATURE
1213 );
1214 RemoveEntryList (&Storage->Entry);
1215 SafeFreePool (Storage->Name);
1216 SafeFreePool (Storage);
1217 }
1218
1219 return EFI_SUCCESS;
1220 #else
1221 return EFI_UNSUPPORTED;
1222 #endif
1223 }
1224
1225
1226 /**
1227 This function processes the results of processing forms and routes it to the
1228 appropriate handlers or storage.
1229
1230 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1231 instance.
1232 @param Configuration A null-terminated Unicode string in
1233 <MulltiConfigResp> format.
1234 @param Progress A pointer to a string filled in with the offset of
1235 the most recent & before the first failing name /
1236 value pair (or the beginning of the string if the
1237 failure is in the first name / value pair) or the
1238 terminating NULL if all was successful.
1239
1240 @retval EFI_SUCCESS The results have been distributed or are awaiting
1241 distribution.
1242 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
1243 results that must be stored awaiting possible
1244 future protocols.
1245 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
1246 would result in this type of error.
1247 @retval EFI_NOT_FOUND Target for the specified routing data was not
1248 found.
1249
1250 **/
1251 EFI_STATUS
1252 EFIAPI
1253 HiiConfigRoutingRoutConfig (
1254 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1255 IN CONST EFI_STRING Configuration,
1256 OUT EFI_STRING *Progress
1257 )
1258 {
1259 #ifndef DISABLE_UNUSED_HII_PROTOCOLS
1260
1261 HII_DATABASE_PRIVATE_DATA *Private;
1262 EFI_STRING StringPtr;
1263 EFI_STRING ConfigResp;
1264 UINTN Length;
1265 EFI_STATUS Status;
1266 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1267 LIST_ENTRY *Link;
1268 HII_DATABASE_RECORD *Database;
1269 UINT8 *CurrentDevicePath;
1270 EFI_HANDLE DriverHandle;
1271 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1272 EFI_STRING AccessProgress;
1273 UINTN RemainSize;
1274 EFI_STRING TmpPtr;
1275
1276 if (This == NULL || Progress == NULL) {
1277 return EFI_INVALID_PARAMETER;
1278 }
1279
1280 if (Configuration == NULL) {
1281 *Progress = NULL;
1282 return EFI_INVALID_PARAMETER;
1283 }
1284
1285 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1286 StringPtr = Configuration;
1287 *Progress = StringPtr;
1288
1289 //
1290 // The first element of <MultiConfigResp> should be
1291 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
1292 //
1293 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1294 return EFI_INVALID_PARAMETER;
1295 }
1296
1297 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
1298 //
1299 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
1300 // or most recent & before the error.
1301 //
1302 if (StringPtr == Configuration) {
1303 *Progress = StringPtr;
1304 } else {
1305 *Progress = StringPtr - 1;
1306 }
1307
1308 //
1309 // Process each <ConfigResp> of <MultiConfigResp>
1310 //
1311 Length = CalculateConfigStringLen (StringPtr);
1312 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
1313 if (ConfigResp == NULL) {
1314 return EFI_OUT_OF_RESOURCES;
1315 }
1316 //
1317 // Append '\0' to the end of ConfigRequest
1318 //
1319 *(ConfigResp + Length) = 0;
1320
1321 //
1322 // Get the UEFI device path
1323 //
1324 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
1325 if (EFI_ERROR (Status)) {
1326 SafeFreePool (ConfigResp);
1327 return Status;
1328 }
1329
1330 //
1331 // Find driver which matches the routing data.
1332 //
1333 DriverHandle = NULL;
1334 for (Link = Private->DatabaseList.ForwardLink;
1335 Link != &Private->DatabaseList;
1336 Link = Link->ForwardLink
1337 ) {
1338 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
1339 CurrentDevicePath = Database->PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
1340 if (CurrentDevicePath != NULL) {
1341 if (CompareMem (
1342 DevicePath,
1343 CurrentDevicePath,
1344 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
1345 ) == 0) {
1346 DriverHandle = Database->DriverHandle;
1347 break;
1348 }
1349 }
1350 }
1351
1352 SafeFreePool (DevicePath);
1353
1354 if (DriverHandle == NULL) {
1355 //
1356 // Routing data does not match any known driver.
1357 // Set Progress to the 'G' in "GUID" of the routing header.
1358 //
1359 *Progress = StringPtr;
1360 SafeFreePool (ConfigResp);
1361 return EFI_NOT_FOUND;
1362 }
1363
1364 //
1365 // Call corresponding ConfigAccess protocol to route settings
1366 //
1367 Status = gBS->HandleProtocol (
1368 DriverHandle,
1369 &gEfiHiiConfigAccessProtocolGuid,
1370 (VOID **) &ConfigAccess
1371 );
1372 ASSERT_EFI_ERROR (Status);
1373
1374 Status = ConfigAccess->RouteConfig (
1375 ConfigAccess,
1376 ConfigResp,
1377 &AccessProgress
1378 );
1379
1380 if (EFI_ERROR (Status)) {
1381 //
1382 // AccessProgress indicates the parsing progress on <ConfigResp>.
1383 // Map it to the progress on <MultiConfigResp> then return it.
1384 //
1385 RemainSize = StrSize (AccessProgress);
1386 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
1387 *Progress = TmpPtr;
1388
1389 SafeFreePool (ConfigResp);
1390 return Status;
1391 }
1392
1393 SafeFreePool (ConfigResp);
1394 ConfigResp = NULL;
1395
1396 //
1397 // Go to next <ConfigResp> (skip '&').
1398 //
1399 StringPtr += Length;
1400 if (*StringPtr == 0) {
1401 *Progress = StringPtr;
1402 break;
1403 }
1404
1405 StringPtr++;
1406
1407 }
1408
1409 return EFI_SUCCESS;
1410 #else
1411 return EFI_UNSUPPORTED;
1412 #endif
1413 }
1414
1415
1416 /**
1417 This helper function is to be called by drivers to map configuration data
1418 stored in byte array ("block") formats such as UEFI Variables into current
1419 configuration strings.
1420
1421 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1422 instance.
1423 @param ConfigRequest A null-terminated Unicode string in
1424 <ConfigRequest> format.
1425 @param Block Array of bytes defining the block's configuration.
1426 @param BlockSize Length in bytes of Block.
1427 @param Config Filled-in configuration string. String allocated
1428 by the function. Returned only if call is
1429 successful.
1430 @param Progress A pointer to a string filled in with the offset of
1431 the most recent & before the first failing
1432 name/value pair (or the beginning of the string if
1433 the failure is in the first name / value pair) or
1434 the terminating NULL if all was successful.
1435
1436 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1437 terminator at the end of the ConfigRequest
1438 string.
1439 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1440 points to the first character of ConfigRequest.
1441 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1442 Block parameter would result in this type of
1443 error. Progress points to the first character of
1444 ConfigRequest.
1445 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1446 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1447 Block is left updated and Progress points at
1448 the "&" preceding the first non-<BlockName>.
1449
1450 **/
1451 EFI_STATUS
1452 EFIAPI
1453 HiiBlockToConfig (
1454 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1455 IN CONST EFI_STRING ConfigRequest,
1456 IN CONST UINT8 *Block,
1457 IN CONST UINTN BlockSize,
1458 OUT EFI_STRING *Config,
1459 OUT EFI_STRING *Progress
1460 )
1461 {
1462 HII_DATABASE_PRIVATE_DATA *Private;
1463 EFI_STRING StringPtr;
1464 UINTN Length;
1465 EFI_STATUS Status;
1466 EFI_STRING TmpPtr;
1467 UINT8 *TmpBuffer;
1468 UINTN Offset;
1469 UINTN Width;
1470 UINT8 *Value;
1471 EFI_STRING ValueStr;
1472 EFI_STRING ConfigElement;
1473
1474 if (This == NULL || Progress == NULL || Config == NULL) {
1475 return EFI_INVALID_PARAMETER;
1476 }
1477
1478 if (Block == NULL || ConfigRequest == NULL) {
1479 *Progress = ConfigRequest;
1480 return EFI_INVALID_PARAMETER;
1481 }
1482
1483
1484 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1485 ASSERT (Private != NULL);
1486
1487 StringPtr = ConfigRequest;
1488 ValueStr = NULL;
1489 Value = NULL;
1490 ConfigElement = NULL;
1491
1492 //
1493 // Allocate a fix length of memory to store Results. Reallocate memory for
1494 // Results if this fix length is insufficient.
1495 //
1496 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
1497 if (*Config == NULL) {
1498 return EFI_OUT_OF_RESOURCES;
1499 }
1500
1501 //
1502 // Jump <ConfigHdr>
1503 //
1504 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1505 *Progress = StringPtr;
1506 Status = EFI_INVALID_PARAMETER;
1507 goto Exit;
1508 }
1509 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1510 StringPtr++;
1511 }
1512 if (*StringPtr == 0) {
1513 *Progress = StringPtr;
1514 Status = EFI_INVALID_PARAMETER;
1515 goto Exit;
1516 }
1517 while (*StringPtr++ != L'&');
1518
1519 //
1520 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1521 //
1522 Length = StringPtr - ConfigRequest;
1523 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
1524
1525 //
1526 // Parse each <RequestElement> if exists
1527 // Only <BlockName> format is supported by this help function.
1528 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1529 //
1530 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1531 //
1532 // Back up the header of one <BlockName>
1533 //
1534 TmpPtr = StringPtr;
1535
1536 StringPtr += StrLen (L"OFFSET=");
1537 //
1538 // Get Offset
1539 //
1540 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1541 if (Status == EFI_OUT_OF_RESOURCES) {
1542 *Progress = ConfigRequest;
1543 goto Exit;
1544 }
1545 Offset = 0;
1546 CopyMem (
1547 &Offset,
1548 TmpBuffer,
1549 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1550 );
1551 SafeFreePool (TmpBuffer);
1552
1553 StringPtr += Length;
1554 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1555 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1556 Status = EFI_INVALID_PARAMETER;
1557 goto Exit;
1558 }
1559 StringPtr += StrLen (L"&WIDTH=");
1560
1561 //
1562 // Get Width
1563 //
1564 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1565 if (Status == EFI_OUT_OF_RESOURCES) {
1566 *Progress = ConfigRequest;
1567 goto Exit;
1568 }
1569 Width = 0;
1570 CopyMem (
1571 &Width,
1572 TmpBuffer,
1573 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1574 );
1575 SafeFreePool (TmpBuffer);
1576
1577 StringPtr += Length;
1578 if (*StringPtr != 0 && *StringPtr != L'&') {
1579 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1580 Status = EFI_INVALID_PARAMETER;
1581 goto Exit;
1582 }
1583
1584 //
1585 // Calculate Value and convert it to hex string.
1586 //
1587 if (Offset + Width > BlockSize) {
1588 *Progress = StringPtr;
1589 Status = EFI_DEVICE_ERROR;
1590 goto Exit;
1591 }
1592
1593 Value = (UINT8 *) AllocateZeroPool (Width);
1594 if (Value == NULL) {
1595 *Progress = ConfigRequest;
1596 Status = EFI_OUT_OF_RESOURCES;
1597 goto Exit;
1598 }
1599
1600 CopyMem (Value, (UINT8 *) Block + Offset, Width);
1601
1602 Length = Width * 2 + 1;
1603 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1604 if (ValueStr == NULL) {
1605 *Progress = ConfigRequest;
1606 Status = EFI_OUT_OF_RESOURCES;
1607 goto Exit;
1608 }
1609
1610 Status = BufToHexString (ValueStr, &Length, Value, Width);
1611 ASSERT_EFI_ERROR (Status);
1612 SafeFreePool (Value);
1613 Value = NULL;
1614
1615 //
1616 // Build a ConfigElement
1617 //
1618 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
1619 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1620 if (ConfigElement == NULL) {
1621 Status = EFI_OUT_OF_RESOURCES;
1622 goto Exit;
1623 }
1624 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
1625 if (*StringPtr == 0) {
1626 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
1627 }
1628 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
1629 StrCat (ConfigElement, L"VALUE=");
1630 StrCat (ConfigElement, ValueStr);
1631
1632 AppendToMultiString (Config, ConfigElement);
1633
1634 SafeFreePool (ConfigElement);
1635 SafeFreePool (ValueStr);
1636 ConfigElement = NULL;
1637 ValueStr = NULL;
1638
1639 //
1640 // If '\0', parsing is finished. Otherwise skip '&' to continue
1641 //
1642 if (*StringPtr == 0) {
1643 break;
1644 }
1645 AppendToMultiString (Config, L"&");
1646 StringPtr++;
1647
1648 }
1649
1650 if (*StringPtr != 0) {
1651 *Progress = StringPtr - 1;
1652 Status = EFI_INVALID_PARAMETER;
1653 goto Exit;
1654 }
1655
1656 *Progress = StringPtr;
1657 return EFI_SUCCESS;
1658
1659 Exit:
1660
1661 SafeFreePool (*Config);
1662 SafeFreePool (ValueStr);
1663 SafeFreePool (Value);
1664 SafeFreePool (ConfigElement);
1665
1666 return Status;
1667
1668 }
1669
1670
1671 /**
1672 This helper function is to be called by drivers to map configuration strings
1673 to configurations stored in byte array ("block") formats such as UEFI Variables.
1674
1675 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1676 instance.
1677 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1678 format.
1679 @param Block A possibly null array of bytes representing the
1680 current block. Only bytes referenced in the
1681 ConfigResp string in the block are modified. If
1682 this parameter is null or if the *BlockSize
1683 parameter is (on input) shorter than required by
1684 the Configuration string, only the BlockSize
1685 parameter is updated and an appropriate status
1686 (see below) is returned.
1687 @param BlockSize The length of the Block in units of UINT8. On
1688 input, this is the size of the Block. On output,
1689 if successful, contains the index of the last
1690 modified byte in the Block.
1691 @param Progress On return, points to an element of the ConfigResp
1692 string filled in with the offset of the most
1693 recent '&' before the first failing name / value
1694 pair (or the beginning of the string if the
1695 failure is in the first name / value pair) or the
1696 terminating NULL if all was successful.
1697
1698 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1699 terminator at the end of the ConfigResp string.
1700 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1701 points to the first character of ConfigResp.
1702 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1703 Block parameter would result in this type of
1704 error. Progress points to the first character of
1705 ConfigResp.
1706 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1707 value pair. Block is left updated and
1708 Progress points at the '&' preceding the first
1709 non-<BlockName>.
1710
1711 **/
1712 EFI_STATUS
1713 EFIAPI
1714 HiiConfigToBlock (
1715 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1716 IN CONST EFI_STRING ConfigResp,
1717 IN OUT UINT8 *Block,
1718 IN OUT UINTN *BlockSize,
1719 OUT EFI_STRING *Progress
1720 )
1721 {
1722 HII_DATABASE_PRIVATE_DATA *Private;
1723 EFI_STRING StringPtr;
1724 UINTN Length;
1725 EFI_STATUS Status;
1726 UINT8 *TmpBuffer;
1727 UINTN Offset;
1728 UINTN Width;
1729 UINT8 *Value;
1730 UINTN BufferSize;
1731
1732 if (This == NULL || BlockSize == NULL || Progress == NULL) {
1733 return EFI_INVALID_PARAMETER;
1734 }
1735
1736 if (ConfigResp == NULL || Block == NULL) {
1737 *Progress = ConfigResp;
1738 return EFI_INVALID_PARAMETER;
1739 }
1740
1741 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1742 ASSERT (Private != NULL);
1743
1744 StringPtr = ConfigResp;
1745 BufferSize = *BlockSize;
1746 Value = NULL;
1747
1748 //
1749 // Jump <ConfigHdr>
1750 //
1751 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1752 *Progress = StringPtr;
1753 Status = EFI_INVALID_PARAMETER;
1754 goto Exit;
1755 }
1756 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1757 StringPtr++;
1758 }
1759 if (*StringPtr == 0) {
1760 *Progress = StringPtr;
1761 Status = EFI_INVALID_PARAMETER;
1762 goto Exit;
1763 }
1764 while (*StringPtr++ != L'&');
1765
1766 //
1767 // Parse each <ConfigElement> if exists
1768 // Only <BlockConfig> format is supported by this help function.
1769 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1770 //
1771 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1772 StringPtr += StrLen (L"OFFSET=");
1773 //
1774 // Get Offset
1775 //
1776 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1777 if (Status == EFI_OUT_OF_RESOURCES) {
1778 *Progress = ConfigResp;
1779 goto Exit;
1780 }
1781 Offset = 0;
1782 CopyMem (
1783 &Offset,
1784 TmpBuffer,
1785 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1786 );
1787 SafeFreePool (TmpBuffer);
1788
1789 StringPtr += Length;
1790 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1791 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1792 Status = EFI_INVALID_PARAMETER;
1793 goto Exit;
1794 }
1795 StringPtr += StrLen (L"&WIDTH=");
1796
1797 //
1798 // Get Width
1799 //
1800 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1801 if (Status == EFI_OUT_OF_RESOURCES) {
1802 *Progress = ConfigResp;
1803 goto Exit;
1804 }
1805 Width = 0;
1806 CopyMem (
1807 &Width,
1808 TmpBuffer,
1809 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1810 );
1811 SafeFreePool (TmpBuffer);
1812
1813 StringPtr += Length;
1814 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1815 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1816 Status = EFI_INVALID_PARAMETER;
1817 goto Exit;
1818 }
1819 StringPtr += StrLen (L"&VALUE=");
1820
1821 //
1822 // Get Value
1823 //
1824 Status = GetValueOfNumber (StringPtr, &Value, &Length);
1825 if (Status == EFI_OUT_OF_RESOURCES) {
1826 *Progress = ConfigResp;
1827 goto Exit;
1828 }
1829
1830 StringPtr += Length;
1831 if (*StringPtr != 0 && *StringPtr != L'&') {
1832 *Progress = StringPtr - Length - 7;
1833 Status = EFI_INVALID_PARAMETER;
1834 goto Exit;
1835 }
1836
1837 //
1838 // Update the Block with configuration info
1839 //
1840
1841 if (Offset + Width > BufferSize) {
1842 return EFI_DEVICE_ERROR;
1843 }
1844
1845 CopyMem (Block + Offset, Value, Width);
1846 *BlockSize = Offset + Width - 1;
1847
1848 SafeFreePool (Value);
1849 Value = NULL;
1850
1851 //
1852 // If '\0', parsing is finished. Otherwise skip '&' to continue
1853 //
1854 if (*StringPtr == 0) {
1855 break;
1856 }
1857
1858 StringPtr++;
1859 }
1860
1861 if (*StringPtr != 0) {
1862 *Progress = StringPtr - 1;
1863 Status = EFI_INVALID_PARAMETER;
1864 goto Exit;
1865 }
1866
1867 *Progress = StringPtr;
1868 return EFI_SUCCESS;
1869
1870 Exit:
1871
1872 SafeFreePool (Value);
1873 return Status;
1874 }
1875
1876
1877 /**
1878 This helper function is to be called by drivers to extract portions of
1879 a larger configuration string.
1880
1881 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1882 instance.
1883 @param Configuration A null-terminated Unicode string in
1884 <MultiConfigAltResp> format.
1885 @param Guid A pointer to the GUID value to search for in the
1886 routing portion of the ConfigResp string when
1887 retrieving the requested data. If Guid is NULL,
1888 then all GUID values will be searched for.
1889 @param Name A pointer to the NAME value to search for in the
1890 routing portion of the ConfigResp string when
1891 retrieving the requested data. If Name is NULL,
1892 then all Name values will be searched for.
1893 @param DevicePath A pointer to the PATH value to search for in the
1894 routing portion of the ConfigResp string when
1895 retrieving the requested data. If DevicePath is
1896 NULL, then all DevicePath values will be searched
1897 for.
1898 @param AltCfgId A pointer to the ALTCFG value to search for in the
1899 routing portion of the ConfigResp string when
1900 retrieving the requested data. If this parameter
1901 is NULL, then the current setting will be
1902 retrieved.
1903 @param AltCfgResp A pointer to a buffer which will be allocated by
1904 the function which contains the retrieved string
1905 as requested. This buffer is only allocated if
1906 the call was successful.
1907
1908 @retval EFI_SUCCESS The request succeeded. The requested data was
1909 extracted and placed in the newly allocated
1910 AltCfgResp buffer.
1911 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1912 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1913 @retval EFI_NOT_FOUND Target for the specified routing data was not
1914 found.
1915
1916 **/
1917 EFI_STATUS
1918 EFIAPI
1919 HiiGetAltCfg (
1920 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1921 IN CONST EFI_STRING Configuration,
1922 IN CONST EFI_GUID *Guid,
1923 IN CONST EFI_STRING Name,
1924 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1925 IN CONST UINT16 *AltCfgId,
1926 OUT EFI_STRING *AltCfgResp
1927 )
1928 {
1929 #ifndef DISABLE_UNUSED_HII_PROTOCOLS
1930
1931 EFI_STATUS Status;
1932 EFI_STRING StringPtr;
1933 EFI_STRING HdrStart = NULL;
1934 EFI_STRING HdrEnd = NULL;
1935 EFI_STRING TmpPtr;
1936 UINTN Length;
1937 EFI_STRING GuidStr = NULL;
1938 EFI_STRING NameStr = NULL;
1939 EFI_STRING PathStr = NULL;
1940 EFI_STRING AltIdStr = NULL;
1941 EFI_STRING Result = NULL;
1942 BOOLEAN GuidFlag = FALSE;
1943 BOOLEAN NameFlag = FALSE;
1944 BOOLEAN PathFlag = FALSE;
1945
1946 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
1947 return EFI_INVALID_PARAMETER;
1948 }
1949
1950 StringPtr = Configuration;
1951 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1952 return EFI_INVALID_PARAMETER;
1953 }
1954
1955 //
1956 // Generate the sub string for later matching.
1957 //
1958 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (UINT8 *) Guid, FALSE, &GuidStr);
1959 GenerateSubStr (
1960 L"PATH=",
1961 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1962 (UINT8 *) DevicePath,
1963 TRUE,
1964 &PathStr
1965 );
1966 if (AltCfgId != NULL) {
1967 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (UINT8 *) AltCfgId, FALSE, &AltIdStr);
1968 }
1969 if (Name != NULL) {
1970 Length = StrLen (Name);
1971 Length += StrLen (L"NAME=&") + 1;
1972 NameStr = AllocateZeroPool (Length * sizeof (CHAR16));
1973 if (NameStr == NULL) {
1974 Status = EFI_OUT_OF_RESOURCES;
1975 goto Exit;
1976 }
1977 StrCpy (NameStr, L"NAME=");
1978 StrCat (NameStr, Name);
1979 StrCat (NameStr, L"&");
1980 } else {
1981 GenerateSubStr (L"NAME=", 0, NULL, FALSE, &NameStr);
1982 }
1983
1984 while (*StringPtr != 0) {
1985 //
1986 // Try to match the GUID
1987 //
1988 if (!GuidFlag) {
1989 TmpPtr = StrStr (StringPtr, GuidStr);
1990 if (TmpPtr == NULL) {
1991 Status = EFI_NOT_FOUND;
1992 goto Exit;
1993 }
1994 HdrStart = TmpPtr;
1995
1996 //
1997 // Jump to <NameHdr>
1998 //
1999 if (Guid != NULL) {
2000 StringPtr = TmpPtr + StrLen (GuidStr);
2001 } else {
2002 StringPtr = StrStr (TmpPtr, L"NAME=");
2003 if (StringPtr == NULL) {
2004 Status = EFI_NOT_FOUND;
2005 goto Exit;
2006 }
2007 }
2008 GuidFlag = TRUE;
2009 }
2010
2011 //
2012 // Try to match the NAME
2013 //
2014 if (GuidFlag && !NameFlag) {
2015 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
2016 GuidFlag = FALSE;
2017 } else {
2018 //
2019 // Jump to <PathHdr>
2020 //
2021 if (Name != NULL) {
2022 StringPtr += StrLen (NameStr);
2023 } else {
2024 StringPtr = StrStr (StringPtr, L"PATH=");
2025 if (StringPtr == NULL) {
2026 Status = EFI_NOT_FOUND;
2027 goto Exit;
2028 }
2029 }
2030 NameFlag = TRUE;
2031 }
2032 }
2033
2034 //
2035 // Try to match the DevicePath
2036 //
2037 if (GuidFlag && NameFlag && !PathFlag) {
2038 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
2039 GuidFlag = FALSE;
2040 NameFlag = FALSE;
2041 } else {
2042 //
2043 // Jump to '&' before <DescHdr> or <ConfigBody>
2044 //
2045 if (DevicePath != NULL) {
2046 StringPtr += StrLen (PathStr);
2047 } else {
2048 StringPtr = StrStr (StringPtr, L"&");
2049 if (StringPtr == NULL) {
2050 Status = EFI_NOT_FOUND;
2051 goto Exit;
2052 }
2053 }
2054 PathFlag = TRUE;
2055 HdrEnd = ++StringPtr;
2056 }
2057 }
2058
2059 //
2060 // Try to match the AltCfgId
2061 //
2062 if (GuidFlag && NameFlag && PathFlag) {
2063 if (AltCfgId == NULL) {
2064 //
2065 // Return Current Setting when AltCfgId is NULL.
2066 //
2067 Status = OutputConfigBody (StringPtr, &Result);
2068 goto Exit;
2069 }
2070 //
2071 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
2072 //
2073 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
2074 GuidFlag = FALSE;
2075 NameFlag = FALSE;
2076 PathFlag = FALSE;
2077 } else {
2078 Status = OutputConfigBody (StringPtr, &Result);
2079 goto Exit;
2080 }
2081 }
2082 }
2083
2084 Status = EFI_NOT_FOUND;
2085
2086 Exit:
2087
2088 if (!EFI_ERROR (Status)) {
2089 //
2090 // Copy the <ConfigHdr> and <ConfigBody>
2091 //
2092 Length = HdrEnd - HdrStart + StrLen (Result);
2093 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2094 if (*AltCfgResp == NULL) {
2095 Status = EFI_OUT_OF_RESOURCES;
2096 } else {
2097 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
2098 StrCat (*AltCfgResp, Result);
2099 Status = EFI_SUCCESS;
2100 }
2101 }
2102
2103 SafeFreePool (GuidStr);
2104 SafeFreePool (NameStr);
2105 SafeFreePool (PathStr);
2106 SafeFreePool (AltIdStr);
2107 SafeFreePool (Result);
2108
2109 return Status;
2110
2111 #else
2112 return EFI_UNSUPPORTED;
2113 #endif
2114
2115 }
2116
2117