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