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