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