]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
aed93be1f03f7e2c0db37f5e9025d5d9aee27c76
[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 FreePool (DevicePathString);
131 return EFI_OUT_OF_RESOURCES;
132 }
133
134 HexStringToBufInReverseOrder (*DevicePath, &Length, DevicePathString);
135
136 FreePool (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 if (HandleBuffer != NULL) {
206 FreePool (HandleBuffer);
207 }
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 FreePool (HandleBuffer);
225 FreePool (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 FreePool (HandleBuffer);
276 FreePool (HiiPackageList);
277 FreePool (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 FreePool (HiiPackageList);
311 }
312
313 FreePool (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 = BufInReverseOrderToHexString (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 /**
451 Adjusts the size of a previously allocated buffer.
452
453
454 @param OldPool A pointer to the buffer whose size is being adjusted.
455 @param OldSize The size of the current buffer.
456 @param NewSize The size of the new buffer.
457
458 @return The new buffer allocated.
459
460 **/
461 VOID *
462 ReallocatePool (
463 IN VOID *OldPool,
464 IN UINTN OldSize,
465 IN UINTN NewSize
466 )
467 {
468 VOID *NewPool;
469
470 NewPool = NULL;
471 if (NewSize != 0) {
472 NewPool = AllocateZeroPool (NewSize);
473 }
474
475 if (OldPool != NULL) {
476 if (NewPool != NULL) {
477 CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
478 }
479
480 gBS->FreePool (OldPool);
481 }
482
483 return NewPool;
484 }
485
486
487 /**
488 Append a string to a multi-string format.
489
490 This is a internal function.
491
492 @param MultiString String in <MultiConfigRequest>,
493 <MultiConfigAltResp>, or <MultiConfigResp>. On
494 input, the buffer length of this string is
495 MAX_STRING_LENGTH. On output, the buffer length
496 might be updated.
497 @param AppendString NULL-terminated Unicode string.
498
499 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
500 @retval EFI_SUCCESS AppendString is append to the end of MultiString
501
502 **/
503 EFI_STATUS
504 AppendToMultiString (
505 IN OUT EFI_STRING *MultiString,
506 IN EFI_STRING AppendString
507 )
508 {
509 UINTN AppendStringSize;
510 UINTN MultiStringSize;
511
512 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
513 return EFI_INVALID_PARAMETER;
514 }
515
516 AppendStringSize = StrSize (AppendString);
517 MultiStringSize = StrSize (*MultiString);
518
519 //
520 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
521 //
522 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
523 MultiStringSize > MAX_STRING_LENGTH) {
524 *MultiString = (EFI_STRING) ReallocatePool (
525 (VOID *) (*MultiString),
526 MultiStringSize,
527 MultiStringSize + AppendStringSize
528 );
529 }
530
531 //
532 // Append the incoming string
533 //
534 StrCat (*MultiString, AppendString);
535
536 return EFI_SUCCESS;
537 }
538
539
540 /**
541 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
542 or WIDTH or VALUE.
543 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
544
545 This is a internal function.
546
547 @param StringPtr String in <BlockConfig> format and points to the
548 first character of <Number>.
549 @param Number The output value. Caller takes the responsibility
550 to free memory.
551 @param Len Length of the <Number>, in characters.
552
553 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
554 structures.
555 @retval EFI_SUCCESS Value of <Number> is outputted in Number
556 successfully.
557
558 **/
559 EFI_STATUS
560 GetValueOfNumber (
561 IN EFI_STRING StringPtr,
562 OUT UINT8 **Number,
563 OUT UINTN *Len
564 )
565 {
566 EFI_STRING TmpPtr;
567 UINTN Length;
568 EFI_STRING Str;
569 UINT8 *Buf;
570 EFI_STATUS Status;
571
572 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
573 ASSERT (*StringPtr != 0);
574
575 Buf = NULL;
576
577 TmpPtr = StringPtr;
578 while (*StringPtr != 0 && *StringPtr != L'&') {
579 StringPtr++;
580 }
581 *Len = StringPtr - TmpPtr;
582 Length = *Len + 1;
583
584 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (EFI_STRING));
585 if (Str == NULL) {
586 Status = EFI_OUT_OF_RESOURCES;
587 goto Exit;
588 }
589 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
590 *(Str + *Len) = 0;
591
592 Length = (Length + 1) / 2;
593 Buf = (UINT8 *) AllocateZeroPool (Length);
594 if (Buf == NULL) {
595 Status = EFI_OUT_OF_RESOURCES;
596 goto Exit;
597 }
598
599 Status = HexStringToBuf (Buf, &Length, Str, NULL);
600 if (EFI_ERROR (Status)) {
601 goto Exit;
602 }
603
604 *Number = Buf;
605 Status = EFI_SUCCESS;
606
607 Exit:
608 if (Str != NULL) {
609 FreePool (Str);
610 }
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 HII_DATABASE_PRIVATE_DATA *Private;
664 EFI_STRING StringPtr;
665 EFI_STRING ConfigRequest;
666 UINTN Length;
667 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
668 EFI_STATUS Status;
669 LIST_ENTRY *Link;
670 HII_DATABASE_RECORD *Database;
671 UINT8 *DevicePathPkg;
672 UINT8 *CurrentDevicePath;
673 EFI_HANDLE DriverHandle;
674 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
675 EFI_STRING AccessProgress;
676 EFI_STRING AccessResults;
677 UINTN RemainSize;
678 EFI_STRING TmpPtr;
679
680 //
681 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
682 // as FALSE. But this renders the system to not 100% compliant with
683 // UEFI 2.1. Use this with caution.
684 //
685 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
686 return EFI_UNSUPPORTED;
687 }
688
689 if (This == NULL || Progress == NULL || Results == NULL) {
690 return EFI_INVALID_PARAMETER;
691 }
692
693 if (Request == NULL) {
694 *Progress = NULL;
695 return EFI_INVALID_PARAMETER;
696 }
697
698 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
699 StringPtr = Request;
700 *Progress = StringPtr;
701
702 //
703 // The first element of <MultiConfigRequest> should be
704 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
705 //
706 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
707 return EFI_INVALID_PARAMETER;
708 }
709
710 //
711 // Allocate a fix length of memory to store Results. Reallocate memory for
712 // Results if this fix length is insufficient.
713 //
714 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
715 if (*Results == NULL) {
716 return EFI_OUT_OF_RESOURCES;
717 }
718
719 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
720 //
721 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
722 // or most recent & before the error.
723 //
724 if (StringPtr == Request) {
725 *Progress = StringPtr;
726 } else {
727 *Progress = StringPtr - 1;
728 }
729
730 //
731 // Process each <ConfigRequest> of <MultiConfigRequest>
732 //
733 Length = CalculateConfigStringLen (StringPtr);
734 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
735 if (ConfigRequest == NULL) {
736 return EFI_OUT_OF_RESOURCES;
737 }
738 *(ConfigRequest + Length) = 0;
739
740 //
741 // Get the UEFI device path
742 //
743 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
744 if (EFI_ERROR (Status)) {
745 FreePool (ConfigRequest);
746 return Status;
747 }
748
749 //
750 // Find driver which matches the routing data.
751 //
752 DriverHandle = NULL;
753 for (Link = Private->DatabaseList.ForwardLink;
754 Link != &Private->DatabaseList;
755 Link = Link->ForwardLink
756 ) {
757 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
758
759 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
760 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
761 if (CompareMem (
762 DevicePath,
763 CurrentDevicePath,
764 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
765 ) == 0) {
766 DriverHandle = Database->DriverHandle;
767 break;
768 }
769 }
770 }
771
772 FreePool (DevicePath);
773
774 if (DriverHandle == NULL) {
775 //
776 // Routing data does not match any known driver.
777 // Set Progress to the 'G' in "GUID" of the routing header.
778 //
779 *Progress = StringPtr;
780 FreePool (ConfigRequest);
781 return EFI_NOT_FOUND;
782 }
783
784 //
785 // Call corresponding ConfigAccess protocol to extract settings
786 //
787 Status = gBS->HandleProtocol (
788 DriverHandle,
789 &gEfiHiiConfigAccessProtocolGuid,
790 (VOID **) &ConfigAccess
791 );
792 ASSERT_EFI_ERROR (Status);
793
794 Status = ConfigAccess->ExtractConfig (
795 ConfigAccess,
796 ConfigRequest,
797 &AccessProgress,
798 &AccessResults
799 );
800 if (EFI_ERROR (Status)) {
801 //
802 // AccessProgress indicates the parsing progress on <ConfigRequest>.
803 // Map it to the progress on <MultiConfigRequest> then return it.
804 //
805 RemainSize = StrSize (AccessProgress);
806 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
807 *Progress = TmpPtr;
808
809 FreePool (ConfigRequest);
810 return Status;
811 }
812
813 //
814 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
815 //
816 ASSERT (*AccessProgress == 0);
817 Status = AppendToMultiString (Results, AccessResults);
818 ASSERT_EFI_ERROR (Status);
819 FreePool (AccessResults);
820 AccessResults = NULL;
821 FreePool (ConfigRequest);
822 ConfigRequest = NULL;
823
824 //
825 // Go to next <ConfigRequest> (skip '&').
826 //
827 StringPtr += Length;
828 if (*StringPtr == 0) {
829 *Progress = StringPtr;
830 break;
831 }
832
833 StringPtr++;
834
835 }
836
837 return EFI_SUCCESS;
838
839 }
840
841
842 /**
843 This function allows the caller to request the current configuration for the
844 entirety of the current HII database and returns the data in a
845 null-terminated Unicode string.
846
847 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
848 instance.
849 @param Results Null-terminated Unicode string in
850 <MultiConfigAltResp> format which has all values
851 filled in for the names in the Request string.
852 String to be allocated by the called function.
853 De-allocation is up to the caller.
854
855 @retval EFI_SUCCESS The Results string is filled with the values
856 corresponding to all requested names.
857 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
858 results that must be stored awaiting possible
859 future protocols.
860 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
861 parameter would result in this type of error.
862
863 **/
864 EFI_STATUS
865 EFIAPI
866 HiiConfigRoutingExportConfig (
867 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
868 OUT EFI_STRING *Results
869 )
870 {
871 EFI_STATUS Status;
872 HII_DATABASE_PRIVATE_DATA *Private;
873 LIST_ENTRY StorageListHdr;
874 HII_FORMSET_STORAGE *Storage;
875 LIST_ENTRY *Link;
876 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
877 UINTN Length;
878 EFI_STRING PathHdr;
879 UINTN PathHdrSize;
880 EFI_STRING ConfigRequest;
881 UINTN RequestSize;
882 EFI_STRING StringPtr;
883 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
884 EFI_STRING AccessProgress;
885 EFI_STRING AccessResults;
886
887 //
888 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
889 // as FALSE. But this renders the system to not 100% compliant with
890 // UEFI 2.1. Use this with caution.
891 //
892 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
893 return EFI_UNSUPPORTED;
894 }
895
896 if (This == NULL || Results == NULL) {
897 return EFI_INVALID_PARAMETER;
898 }
899
900 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
901
902 InitializeListHead (&StorageListHdr);
903
904 Status = ExportAllStorage (&Private->HiiDatabase, &StorageListHdr);
905 if (EFI_ERROR (Status)) {
906 return Status;
907 }
908
909 //
910 // Allocate a fix length of memory to store Results. Reallocate memory for
911 // Results if this fix length is insufficient.
912 //
913 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
914 if (*Results == NULL) {
915 return EFI_OUT_OF_RESOURCES;
916 }
917
918 //
919 // Parsing all formset storages.
920 //
921 for (Link = StorageListHdr.ForwardLink; Link != &StorageListHdr; Link = Link->ForwardLink) {
922 Storage = CR (Link, HII_FORMSET_STORAGE, Entry, HII_FORMSET_STORAGE_SIGNATURE);
923 //
924 // Find the corresponding device path instance
925 //
926 Status = gBS->HandleProtocol (
927 Storage->DriverHandle,
928 &gEfiDevicePathProtocolGuid,
929 (VOID **) &DevicePath
930 );
931 if (EFI_ERROR (Status)) {
932 return Status;
933 }
934 //
935 // Convert the device path binary to hex UNICODE %02x bytes in the same order
936 // as the device path resides in RAM memory.
937 //
938 Length = GetDevicePathSize (DevicePath);
939 PathHdrSize = (Length * 2 + 1) * sizeof (CHAR16);
940 PathHdr = (EFI_STRING) AllocateZeroPool (PathHdrSize);
941 if (PathHdr == NULL) {
942 return EFI_OUT_OF_RESOURCES;
943 }
944 Status = BufInReverseOrderToHexString (PathHdr, (UINT8 *) DevicePath, Length);
945 ASSERT_EFI_ERROR (Status);
946
947 //
948 // Generate a <ConfigRequest> with one <ConfigHdr> and zero <RequestElement>.
949 // It means extract all possible configurations from this specific driver.
950 //
951 RequestSize = (StrLen (L"GUID=&NAME=&PATH=") + 32) * sizeof (CHAR16) + PathHdrSize;
952 if (Storage->Name != NULL) {
953 RequestSize += StrLen (Storage->Name) * 4 * sizeof (CHAR16);
954 }
955
956 ConfigRequest = (EFI_STRING) AllocateZeroPool (RequestSize);
957 if (ConfigRequest == NULL) {
958 FreePool (PathHdr);
959 return EFI_OUT_OF_RESOURCES;
960 }
961
962 //
963 // Add <GuidHdr>
964 // <GuidHdr> ::= 'GUID='<Guid>
965 // Convert <Guid> in the same order as it resides in RAM memory.
966 //
967 StringPtr = ConfigRequest;
968 StrnCpy (StringPtr, L"GUID=", StrLen (L"GUID="));
969 StringPtr += StrLen (L"GUID=");
970
971 Status = BufInReverseOrderToHexString (StringPtr, (UINT8 *) (&Storage->Guid), sizeof (EFI_GUID));
972 ASSERT_EFI_ERROR (Status);
973
974 StringPtr += 32;
975 ASSERT (*StringPtr == 0);
976 *StringPtr = L'&';
977 StringPtr++;
978
979 //
980 // Add <NameHdr>
981 // <NameHdr> ::= 'NAME='<String>
982 //
983 StrnCpy (StringPtr, L"NAME=", StrLen (L"NAME="));
984 StringPtr += StrLen (L"NAME=");
985
986 if (Storage->Name != NULL) {
987 Length = (StrLen (Storage->Name) * 4 + 1) * sizeof (CHAR16);
988 Status = UnicodeToConfigString (StringPtr, &Length, Storage->Name);
989 ASSERT_EFI_ERROR (Status);
990 StringPtr += StrLen (Storage->Name) * 4;
991 }
992
993 *StringPtr = L'&';
994 StringPtr++;
995
996 //
997 // Add <PathHdr>
998 // <PathHdr> ::= '<PATH=>'<UEFI binary represented as hex UNICODE %02x>
999 //
1000 StrnCpy (StringPtr, L"PATH=", StrLen (L"PATH="));
1001 StringPtr += StrLen (L"PATH=");
1002 StrCpy (StringPtr, PathHdr);
1003
1004 FreePool (PathHdr);
1005 PathHdr = NULL;
1006
1007 //
1008 // BUGBUG: The "Implementation note" of ExportConfig() in UEFI spec makes the
1009 // code somewhat complex. Let's TBD here whether a <ConfigRequest> or a <ConfigHdr>
1010 // is required to call ConfigAccess.ExtractConfig().
1011 //
1012 // Here we use <ConfigHdr> to call ConfigAccess instance. It requires ConfigAccess
1013 // to handle such kind of "ConfigRequest". It is not supported till now.
1014 //
1015 // Either the ExportConfig will be updated or the ConfigAccess.ExtractConfig()
1016 // will be updated as soon as the decision is made.
1017
1018 //
1019 // Route the request to corresponding ConfigAccess protocol to extract settings.
1020 //
1021 Status = gBS->HandleProtocol (
1022 Storage->DriverHandle,
1023 &gEfiHiiConfigAccessProtocolGuid,
1024 (VOID **) &ConfigAccess
1025 );
1026 ASSERT_EFI_ERROR (Status);
1027
1028 AccessProgress = NULL;
1029 AccessResults = NULL;
1030 Status = ConfigAccess->ExtractConfig (
1031 ConfigAccess,
1032 ConfigRequest,
1033 &AccessProgress,
1034 &AccessResults
1035 );
1036 if (EFI_ERROR (Status)) {
1037 FreePool (ConfigRequest);
1038 if (AccessProgress != NULL) {
1039 FreePool (AccessProgress);
1040 }
1041 if (AccessResults != NULL) {
1042 FreePool (AccessResults);
1043 }
1044 return EFI_INVALID_PARAMETER;
1045 }
1046
1047 //
1048 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>
1049 //
1050 ASSERT (*AccessProgress == 0);
1051 Status = AppendToMultiString (Results, AccessResults);
1052 ASSERT_EFI_ERROR (Status);
1053 FreePool (AccessResults);
1054 AccessResults = NULL;
1055 FreePool (ConfigRequest);
1056 ConfigRequest = NULL;
1057
1058 }
1059
1060 //
1061 // Free the exported storage resource
1062 //
1063 while (!IsListEmpty (&StorageListHdr)) {
1064 Storage = CR (
1065 StorageListHdr.ForwardLink,
1066 HII_FORMSET_STORAGE,
1067 Entry,
1068 HII_FORMSET_STORAGE_SIGNATURE
1069 );
1070 RemoveEntryList (&Storage->Entry);
1071 FreePool (Storage->Name);
1072 FreePool (Storage);
1073 }
1074
1075 return EFI_SUCCESS;
1076 }
1077
1078
1079 /**
1080 This function processes the results of processing forms and routes it to the
1081 appropriate handlers or storage.
1082
1083 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1084 instance.
1085 @param Configuration A null-terminated Unicode string in
1086 <MulltiConfigResp> format.
1087 @param Progress A pointer to a string filled in with the offset of
1088 the most recent & before the first failing name /
1089 value pair (or the beginning of the string if the
1090 failure is in the first name / value pair) or the
1091 terminating NULL if all was successful.
1092
1093 @retval EFI_SUCCESS The results have been distributed or are awaiting
1094 distribution.
1095 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
1096 results that must be stored awaiting possible
1097 future protocols.
1098 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
1099 would result in this type of error.
1100 @retval EFI_NOT_FOUND Target for the specified routing data was not
1101 found.
1102
1103 **/
1104 EFI_STATUS
1105 EFIAPI
1106 HiiConfigRoutingRouteConfig (
1107 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1108 IN CONST EFI_STRING Configuration,
1109 OUT EFI_STRING *Progress
1110 )
1111 {
1112 HII_DATABASE_PRIVATE_DATA *Private;
1113 EFI_STRING StringPtr;
1114 EFI_STRING ConfigResp;
1115 UINTN Length;
1116 EFI_STATUS Status;
1117 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1118 LIST_ENTRY *Link;
1119 HII_DATABASE_RECORD *Database;
1120 UINT8 *DevicePathPkg;
1121 UINT8 *CurrentDevicePath;
1122 EFI_HANDLE DriverHandle;
1123 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
1124 EFI_STRING AccessProgress;
1125 UINTN RemainSize;
1126 EFI_STRING TmpPtr;
1127
1128 //
1129 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1130 // as FALSE. But this renders the system to not 100% compliant with
1131 // UEFI 2.1. Use this with caution.
1132 //
1133 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
1134 return EFI_UNSUPPORTED;
1135 }
1136
1137 if (This == NULL || Progress == NULL) {
1138 return EFI_INVALID_PARAMETER;
1139 }
1140
1141 if (Configuration == NULL) {
1142 *Progress = NULL;
1143 return EFI_INVALID_PARAMETER;
1144 }
1145
1146 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1147 StringPtr = Configuration;
1148 *Progress = StringPtr;
1149
1150 //
1151 // The first element of <MultiConfigResp> should be
1152 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
1153 //
1154 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1155 return EFI_INVALID_PARAMETER;
1156 }
1157
1158 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
1159 //
1160 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
1161 // or most recent & before the error.
1162 //
1163 if (StringPtr == Configuration) {
1164 *Progress = StringPtr;
1165 } else {
1166 *Progress = StringPtr - 1;
1167 }
1168
1169 //
1170 // Process each <ConfigResp> of <MultiConfigResp>
1171 //
1172 Length = CalculateConfigStringLen (StringPtr);
1173 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
1174 if (ConfigResp == NULL) {
1175 return EFI_OUT_OF_RESOURCES;
1176 }
1177 //
1178 // Append '\0' to the end of ConfigRequest
1179 //
1180 *(ConfigResp + Length) = 0;
1181
1182 //
1183 // Get the UEFI device path
1184 //
1185 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
1186 if (EFI_ERROR (Status)) {
1187 FreePool (ConfigResp);
1188 return Status;
1189 }
1190
1191 //
1192 // Find driver which matches the routing data.
1193 //
1194 DriverHandle = NULL;
1195 for (Link = Private->DatabaseList.ForwardLink;
1196 Link != &Private->DatabaseList;
1197 Link = Link->ForwardLink
1198 ) {
1199 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
1200
1201 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
1202 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
1203 if (CompareMem (
1204 DevicePath,
1205 CurrentDevicePath,
1206 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
1207 ) == 0) {
1208 DriverHandle = Database->DriverHandle;
1209 break;
1210 }
1211 }
1212 }
1213
1214 FreePool (DevicePath);
1215
1216 if (DriverHandle == NULL) {
1217 //
1218 // Routing data does not match any known driver.
1219 // Set Progress to the 'G' in "GUID" of the routing header.
1220 //
1221 *Progress = StringPtr;
1222 FreePool (ConfigResp);
1223 return EFI_NOT_FOUND;
1224 }
1225
1226 //
1227 // Call corresponding ConfigAccess protocol to route settings
1228 //
1229 Status = gBS->HandleProtocol (
1230 DriverHandle,
1231 &gEfiHiiConfigAccessProtocolGuid,
1232 (VOID **) &ConfigAccess
1233 );
1234 ASSERT_EFI_ERROR (Status);
1235
1236 Status = ConfigAccess->RouteConfig (
1237 ConfigAccess,
1238 ConfigResp,
1239 &AccessProgress
1240 );
1241
1242 if (EFI_ERROR (Status)) {
1243 //
1244 // AccessProgress indicates the parsing progress on <ConfigResp>.
1245 // Map it to the progress on <MultiConfigResp> then return it.
1246 //
1247 RemainSize = StrSize (AccessProgress);
1248 for (TmpPtr = StringPtr; CompareMem (TmpPtr, AccessProgress, RemainSize) != 0; TmpPtr++);
1249 *Progress = TmpPtr;
1250
1251 FreePool (ConfigResp);
1252 return Status;
1253 }
1254
1255 FreePool (ConfigResp);
1256 ConfigResp = NULL;
1257
1258 //
1259 // Go to next <ConfigResp> (skip '&').
1260 //
1261 StringPtr += Length;
1262 if (*StringPtr == 0) {
1263 *Progress = StringPtr;
1264 break;
1265 }
1266
1267 StringPtr++;
1268
1269 }
1270
1271 return EFI_SUCCESS;
1272 }
1273
1274
1275 /**
1276 This helper function is to be called by drivers to map configuration data
1277 stored in byte array ("block") formats such as UEFI Variables into current
1278 configuration strings.
1279
1280 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1281 instance.
1282 @param ConfigRequest A null-terminated Unicode string in
1283 <ConfigRequest> format.
1284 @param Block Array of bytes defining the block's configuration.
1285 @param BlockSize Length in bytes of Block.
1286 @param Config Filled-in configuration string. String allocated
1287 by the function. Returned only if call is
1288 successful.
1289 @param Progress A pointer to a string filled in with the offset of
1290 the most recent & before the first failing
1291 name/value pair (or the beginning of the string if
1292 the failure is in the first name / value pair) or
1293 the terminating NULL if all was successful.
1294
1295 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1296 terminator at the end of the ConfigRequest
1297 string.
1298 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1299 points to the first character of ConfigRequest.
1300 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
1301 Block parameter would result in this type of
1302 error. Progress points to the first character of
1303 ConfigRequest.
1304 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
1305 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
1306 Block is left updated and Progress points at
1307 the "&" preceding the first non-<BlockName>.
1308
1309 **/
1310 EFI_STATUS
1311 EFIAPI
1312 HiiBlockToConfig (
1313 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1314 IN CONST EFI_STRING ConfigRequest,
1315 IN CONST UINT8 *Block,
1316 IN CONST UINTN BlockSize,
1317 OUT EFI_STRING *Config,
1318 OUT EFI_STRING *Progress
1319 )
1320 {
1321 HII_DATABASE_PRIVATE_DATA *Private;
1322 EFI_STRING StringPtr;
1323 UINTN Length;
1324 EFI_STATUS Status;
1325 EFI_STRING TmpPtr;
1326 UINT8 *TmpBuffer;
1327 UINTN Offset;
1328 UINTN Width;
1329 UINT8 *Value;
1330 EFI_STRING ValueStr;
1331 EFI_STRING ConfigElement;
1332
1333 if (This == NULL || Progress == NULL || Config == NULL) {
1334 return EFI_INVALID_PARAMETER;
1335 }
1336
1337 if (Block == NULL || ConfigRequest == NULL) {
1338 *Progress = ConfigRequest;
1339 return EFI_INVALID_PARAMETER;
1340 }
1341
1342
1343 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1344 ASSERT (Private != NULL);
1345
1346 StringPtr = ConfigRequest;
1347 ValueStr = NULL;
1348 Value = NULL;
1349 ConfigElement = NULL;
1350
1351 //
1352 // Allocate a fix length of memory to store Results. Reallocate memory for
1353 // Results if this fix length is insufficient.
1354 //
1355 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
1356 if (*Config == NULL) {
1357 return EFI_OUT_OF_RESOURCES;
1358 }
1359
1360 //
1361 // Jump <ConfigHdr>
1362 //
1363 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1364 *Progress = StringPtr;
1365 Status = EFI_INVALID_PARAMETER;
1366 goto Exit;
1367 }
1368 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1369 StringPtr++;
1370 }
1371 if (*StringPtr == 0) {
1372 *Progress = StringPtr;
1373 Status = EFI_INVALID_PARAMETER;
1374 goto Exit;
1375 }
1376
1377 while (*StringPtr != L'&' && *StringPtr != 0) {
1378 StringPtr++;
1379 }
1380 if (*StringPtr == 0) {
1381 *Progress = StringPtr;
1382 Status = EFI_INVALID_PARAMETER;
1383 goto Exit;
1384 }
1385 //
1386 // Skip '&'
1387 //
1388 StringPtr++;
1389
1390 //
1391 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
1392 //
1393 Length = StringPtr - ConfigRequest;
1394 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
1395
1396 //
1397 // Parse each <RequestElement> if exists
1398 // Only <BlockName> format is supported by this help function.
1399 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
1400 //
1401 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1402 //
1403 // Back up the header of one <BlockName>
1404 //
1405 TmpPtr = StringPtr;
1406
1407 StringPtr += StrLen (L"OFFSET=");
1408 //
1409 // Get Offset
1410 //
1411 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1412 if (Status == EFI_OUT_OF_RESOURCES) {
1413 *Progress = ConfigRequest;
1414 goto Exit;
1415 }
1416 Offset = 0;
1417 CopyMem (
1418 &Offset,
1419 TmpBuffer,
1420 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1421 );
1422 FreePool (TmpBuffer);
1423
1424 StringPtr += Length;
1425 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1426 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1427 Status = EFI_INVALID_PARAMETER;
1428 goto Exit;
1429 }
1430 StringPtr += StrLen (L"&WIDTH=");
1431
1432 //
1433 // Get Width
1434 //
1435 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1436 if (Status == EFI_OUT_OF_RESOURCES) {
1437 *Progress = ConfigRequest;
1438 goto Exit;
1439 }
1440 Width = 0;
1441 CopyMem (
1442 &Width,
1443 TmpBuffer,
1444 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1445 );
1446 FreePool (TmpBuffer);
1447
1448 StringPtr += Length;
1449 if (*StringPtr != 0 && *StringPtr != L'&') {
1450 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1451 Status = EFI_INVALID_PARAMETER;
1452 goto Exit;
1453 }
1454
1455 //
1456 // Calculate Value and convert it to hex string.
1457 //
1458 if (Offset + Width > BlockSize) {
1459 *Progress = StringPtr;
1460 Status = EFI_DEVICE_ERROR;
1461 goto Exit;
1462 }
1463
1464 Value = (UINT8 *) AllocateZeroPool (Width);
1465 if (Value == NULL) {
1466 *Progress = ConfigRequest;
1467 Status = EFI_OUT_OF_RESOURCES;
1468 goto Exit;
1469 }
1470
1471 CopyMem (Value, (UINT8 *) Block + Offset, Width);
1472
1473 Length = Width * 2 + 1;
1474 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1475 if (ValueStr == NULL) {
1476 *Progress = ConfigRequest;
1477 Status = EFI_OUT_OF_RESOURCES;
1478 goto Exit;
1479 }
1480
1481 Status = BufToHexString (ValueStr, &Length, Value, Width);
1482 ASSERT_EFI_ERROR (Status);
1483 ToLower (ValueStr);
1484
1485 FreePool (Value);
1486 Value = NULL;
1487
1488 //
1489 // Build a ConfigElement
1490 //
1491 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
1492 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
1493 if (ConfigElement == NULL) {
1494 Status = EFI_OUT_OF_RESOURCES;
1495 goto Exit;
1496 }
1497 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
1498 if (*StringPtr == 0) {
1499 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
1500 }
1501 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
1502 StrCat (ConfigElement, L"VALUE=");
1503 StrCat (ConfigElement, ValueStr);
1504
1505 AppendToMultiString (Config, ConfigElement);
1506
1507 FreePool (ConfigElement);
1508 FreePool (ValueStr);
1509 ConfigElement = NULL;
1510 ValueStr = NULL;
1511
1512 //
1513 // If '\0', parsing is finished. Otherwise skip '&' to continue
1514 //
1515 if (*StringPtr == 0) {
1516 break;
1517 }
1518 AppendToMultiString (Config, L"&");
1519 StringPtr++;
1520
1521 }
1522
1523 if (*StringPtr != 0) {
1524 *Progress = StringPtr - 1;
1525 Status = EFI_INVALID_PARAMETER;
1526 goto Exit;
1527 }
1528
1529 *Progress = StringPtr;
1530 return EFI_SUCCESS;
1531
1532 Exit:
1533 FreePool (*Config);
1534 if (ValueStr != NULL) {
1535 FreePool (ValueStr);
1536 }
1537 if (Value != NULL) {
1538 FreePool (Value);
1539 }
1540 if (ConfigElement) {
1541 FreePool (ConfigElement);
1542 }
1543
1544 return Status;
1545
1546 }
1547
1548
1549 /**
1550 This helper function is to be called by drivers to map configuration strings
1551 to configurations stored in byte array ("block") formats such as UEFI Variables.
1552
1553 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1554 instance.
1555 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
1556 format.
1557 @param Block A possibly null array of bytes representing the
1558 current block. Only bytes referenced in the
1559 ConfigResp string in the block are modified. If
1560 this parameter is null or if the *BlockSize
1561 parameter is (on input) shorter than required by
1562 the Configuration string, only the BlockSize
1563 parameter is updated and an appropriate status
1564 (see below) is returned.
1565 @param BlockSize The length of the Block in units of UINT8. On
1566 input, this is the size of the Block. On output,
1567 if successful, contains the index of the last
1568 modified byte in the Block.
1569 @param Progress On return, points to an element of the ConfigResp
1570 string filled in with the offset of the most
1571 recent '&' before the first failing name / value
1572 pair (or the beginning of the string if the
1573 failure is in the first name / value pair) or the
1574 terminating NULL if all was successful.
1575
1576 @retval EFI_SUCCESS The request succeeded. Progress points to the null
1577 terminator at the end of the ConfigResp string.
1578 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
1579 points to the first character of ConfigResp.
1580 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
1581 Block parameter would result in this type of
1582 error. Progress points to the first character of
1583 ConfigResp.
1584 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
1585 value pair. Block is left updated and
1586 Progress points at the '&' preceding the first
1587 non-<BlockName>.
1588
1589 **/
1590 EFI_STATUS
1591 EFIAPI
1592 HiiConfigToBlock (
1593 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1594 IN CONST EFI_STRING ConfigResp,
1595 IN OUT UINT8 *Block,
1596 IN OUT UINTN *BlockSize,
1597 OUT EFI_STRING *Progress
1598 )
1599 {
1600 HII_DATABASE_PRIVATE_DATA *Private;
1601 EFI_STRING StringPtr;
1602 UINTN Length;
1603 EFI_STATUS Status;
1604 UINT8 *TmpBuffer;
1605 UINTN Offset;
1606 UINTN Width;
1607 UINT8 *Value;
1608 UINTN BufferSize;
1609
1610 if (This == NULL || BlockSize == NULL || Progress == NULL) {
1611 return EFI_INVALID_PARAMETER;
1612 }
1613
1614 if (ConfigResp == NULL || Block == NULL) {
1615 *Progress = ConfigResp;
1616 return EFI_INVALID_PARAMETER;
1617 }
1618
1619 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
1620 ASSERT (Private != NULL);
1621
1622 StringPtr = ConfigResp;
1623 BufferSize = *BlockSize;
1624 Value = NULL;
1625
1626 //
1627 // Jump <ConfigHdr>
1628 //
1629 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1630 *Progress = StringPtr;
1631 Status = EFI_INVALID_PARAMETER;
1632 goto Exit;
1633 }
1634 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
1635 StringPtr++;
1636 }
1637 if (*StringPtr == 0) {
1638 *Progress = StringPtr;
1639 Status = EFI_INVALID_PARAMETER;
1640 goto Exit;
1641 }
1642
1643 while (*StringPtr != L'&' && *StringPtr != 0) {
1644 StringPtr++;
1645 }
1646 if (*StringPtr == 0) {
1647 *Progress = StringPtr;
1648 Status = EFI_INVALID_PARAMETER;
1649 goto Exit;
1650 }
1651 //
1652 // Skip '&'
1653 //
1654 StringPtr++;
1655
1656 //
1657 // Parse each <ConfigElement> if exists
1658 // Only <BlockConfig> format is supported by this help function.
1659 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
1660 //
1661 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
1662 StringPtr += StrLen (L"OFFSET=");
1663 //
1664 // Get Offset
1665 //
1666 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1667 if (Status == EFI_OUT_OF_RESOURCES) {
1668 *Progress = ConfigResp;
1669 goto Exit;
1670 }
1671 Offset = 0;
1672 CopyMem (
1673 &Offset,
1674 TmpBuffer,
1675 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1676 );
1677 FreePool (TmpBuffer);
1678
1679 StringPtr += Length;
1680 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1681 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
1682 Status = EFI_INVALID_PARAMETER;
1683 goto Exit;
1684 }
1685 StringPtr += StrLen (L"&WIDTH=");
1686
1687 //
1688 // Get Width
1689 //
1690 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1691 if (Status == EFI_OUT_OF_RESOURCES) {
1692 *Progress = ConfigResp;
1693 goto Exit;
1694 }
1695 Width = 0;
1696 CopyMem (
1697 &Width,
1698 TmpBuffer,
1699 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
1700 );
1701 FreePool (TmpBuffer);
1702
1703 StringPtr += Length;
1704 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
1705 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
1706 Status = EFI_INVALID_PARAMETER;
1707 goto Exit;
1708 }
1709 StringPtr += StrLen (L"&VALUE=");
1710
1711 //
1712 // Get Value
1713 //
1714 Status = GetValueOfNumber (StringPtr, &Value, &Length);
1715 if (Status == EFI_OUT_OF_RESOURCES) {
1716 *Progress = ConfigResp;
1717 goto Exit;
1718 }
1719
1720 StringPtr += Length;
1721 if (*StringPtr != 0 && *StringPtr != L'&') {
1722 *Progress = StringPtr - Length - 7;
1723 Status = EFI_INVALID_PARAMETER;
1724 goto Exit;
1725 }
1726
1727 //
1728 // Update the Block with configuration info
1729 //
1730
1731 if (Offset + Width > BufferSize) {
1732 return EFI_DEVICE_ERROR;
1733 }
1734
1735 CopyMem (Block + Offset, Value, Width);
1736 *BlockSize = Offset + Width - 1;
1737
1738 FreePool (Value);
1739 Value = NULL;
1740
1741 //
1742 // If '\0', parsing is finished. Otherwise skip '&' to continue
1743 //
1744 if (*StringPtr == 0) {
1745 break;
1746 }
1747
1748 StringPtr++;
1749 }
1750
1751 if (*StringPtr != 0) {
1752 *Progress = StringPtr - 1;
1753 Status = EFI_INVALID_PARAMETER;
1754 goto Exit;
1755 }
1756
1757 *Progress = StringPtr;
1758 return EFI_SUCCESS;
1759
1760 Exit:
1761
1762 if (Value != NULL) {
1763 FreePool (Value);
1764 }
1765 return Status;
1766 }
1767
1768
1769 /**
1770 This helper function is to be called by drivers to extract portions of
1771 a larger configuration string.
1772
1773 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
1774 instance.
1775 @param Configuration A null-terminated Unicode string in
1776 <MultiConfigAltResp> format.
1777 @param Guid A pointer to the GUID value to search for in the
1778 routing portion of the ConfigResp string when
1779 retrieving the requested data. If Guid is NULL,
1780 then all GUID values will be searched for.
1781 @param Name A pointer to the NAME value to search for in the
1782 routing portion of the ConfigResp string when
1783 retrieving the requested data. If Name is NULL,
1784 then all Name values will be searched for.
1785 @param DevicePath A pointer to the PATH value to search for in the
1786 routing portion of the ConfigResp string when
1787 retrieving the requested data. If DevicePath is
1788 NULL, then all DevicePath values will be searched
1789 for.
1790 @param AltCfgId A pointer to the ALTCFG value to search for in the
1791 routing portion of the ConfigResp string when
1792 retrieving the requested data. If this parameter
1793 is NULL, then the current setting will be
1794 retrieved.
1795 @param AltCfgResp A pointer to a buffer which will be allocated by
1796 the function which contains the retrieved string
1797 as requested. This buffer is only allocated if
1798 the call was successful.
1799
1800 @retval EFI_SUCCESS The request succeeded. The requested data was
1801 extracted and placed in the newly allocated
1802 AltCfgResp buffer.
1803 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
1804 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
1805 @retval EFI_NOT_FOUND Target for the specified routing data was not
1806 found.
1807
1808 **/
1809 EFI_STATUS
1810 EFIAPI
1811 HiiGetAltCfg (
1812 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
1813 IN CONST EFI_STRING Configuration,
1814 IN CONST EFI_GUID *Guid,
1815 IN CONST EFI_STRING Name,
1816 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1817 IN CONST UINT16 *AltCfgId,
1818 OUT EFI_STRING *AltCfgResp
1819 )
1820 {
1821 EFI_STATUS Status;
1822 EFI_STRING StringPtr;
1823 EFI_STRING HdrStart;
1824 EFI_STRING HdrEnd;
1825 EFI_STRING TmpPtr;
1826 UINTN Length;
1827 EFI_STRING GuidStr;
1828 EFI_STRING NameStr;
1829 EFI_STRING PathStr;
1830 EFI_STRING AltIdStr;
1831 EFI_STRING Result;
1832 BOOLEAN GuidFlag;
1833 BOOLEAN NameFlag;
1834 BOOLEAN PathFlag;
1835
1836 //
1837 // For size reduction, please define PcdSupportFullConfigRoutingProtocol
1838 // as FALSE. But this renders the system to not 100% compliant with
1839 // UEFI 2.1. Use this with caution.
1840 //
1841 if (!FeaturePcdGet (PcdSupportFullConfigRoutingProtocol)) {
1842 return EFI_UNSUPPORTED;
1843 }
1844
1845 HdrStart = NULL;
1846 HdrEnd = NULL;
1847 GuidStr = NULL;
1848 NameStr = NULL;
1849 PathStr = NULL;
1850 AltIdStr = NULL;
1851 Result = NULL;
1852 GuidFlag = FALSE;
1853 NameFlag = FALSE;
1854 PathFlag = FALSE;
1855
1856 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
1857 return EFI_INVALID_PARAMETER;
1858 }
1859
1860 StringPtr = Configuration;
1861 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1862 return EFI_INVALID_PARAMETER;
1863 }
1864
1865 //
1866 // Generate the sub string for later matching.
1867 //
1868 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
1869 GenerateSubStr (
1870 L"PATH=",
1871 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1872 (VOID *) DevicePath,
1873 1,
1874 &PathStr
1875 );
1876 if (AltCfgId != NULL) {
1877 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
1878 }
1879 if (Name != NULL) {
1880 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
1881 } else {
1882 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1883 }
1884
1885 while (*StringPtr != 0) {
1886 //
1887 // Try to match the GUID
1888 //
1889 if (!GuidFlag) {
1890 TmpPtr = StrStr (StringPtr, GuidStr);
1891 if (TmpPtr == NULL) {
1892 Status = EFI_NOT_FOUND;
1893 goto Exit;
1894 }
1895 HdrStart = TmpPtr;
1896
1897 //
1898 // Jump to <NameHdr>
1899 //
1900 if (Guid != NULL) {
1901 StringPtr = TmpPtr + StrLen (GuidStr);
1902 } else {
1903 StringPtr = StrStr (TmpPtr, L"NAME=");
1904 if (StringPtr == NULL) {
1905 Status = EFI_NOT_FOUND;
1906 goto Exit;
1907 }
1908 }
1909 GuidFlag = TRUE;
1910 }
1911
1912 //
1913 // Try to match the NAME
1914 //
1915 if (GuidFlag && !NameFlag) {
1916 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
1917 GuidFlag = FALSE;
1918 } else {
1919 //
1920 // Jump to <PathHdr>
1921 //
1922 if (Name != NULL) {
1923 StringPtr += StrLen (NameStr);
1924 } else {
1925 StringPtr = StrStr (StringPtr, L"PATH=");
1926 if (StringPtr == NULL) {
1927 Status = EFI_NOT_FOUND;
1928 goto Exit;
1929 }
1930 }
1931 NameFlag = TRUE;
1932 }
1933 }
1934
1935 //
1936 // Try to match the DevicePath
1937 //
1938 if (GuidFlag && NameFlag && !PathFlag) {
1939 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
1940 GuidFlag = FALSE;
1941 NameFlag = FALSE;
1942 } else {
1943 //
1944 // Jump to '&' before <DescHdr> or <ConfigBody>
1945 //
1946 if (DevicePath != NULL) {
1947 StringPtr += StrLen (PathStr);
1948 } else {
1949 StringPtr = StrStr (StringPtr, L"&");
1950 if (StringPtr == NULL) {
1951 Status = EFI_NOT_FOUND;
1952 goto Exit;
1953 }
1954 }
1955 PathFlag = TRUE;
1956 HdrEnd = ++StringPtr;
1957 }
1958 }
1959
1960 //
1961 // Try to match the AltCfgId
1962 //
1963 if (GuidFlag && NameFlag && PathFlag) {
1964 if (AltCfgId == NULL) {
1965 //
1966 // Return Current Setting when AltCfgId is NULL.
1967 //
1968 Status = OutputConfigBody (StringPtr, &Result);
1969 goto Exit;
1970 }
1971 //
1972 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
1973 //
1974 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
1975 GuidFlag = FALSE;
1976 NameFlag = FALSE;
1977 PathFlag = FALSE;
1978 } else {
1979 Status = OutputConfigBody (StringPtr, &Result);
1980 goto Exit;
1981 }
1982 }
1983 }
1984
1985 Status = EFI_NOT_FOUND;
1986
1987 Exit:
1988
1989 if (!EFI_ERROR (Status)) {
1990 //
1991 // Copy the <ConfigHdr> and <ConfigBody>
1992 //
1993 Length = HdrEnd - HdrStart + StrLen (Result);
1994 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
1995 if (*AltCfgResp == NULL) {
1996 Status = EFI_OUT_OF_RESOURCES;
1997 } else {
1998 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
1999 StrCat (*AltCfgResp, Result);
2000 Status = EFI_SUCCESS;
2001 }
2002 }
2003
2004 if (GuidStr != NULL) {
2005 FreePool (GuidStr);
2006 }
2007 if (NameStr != NULL) {
2008 FreePool (NameStr);
2009 }
2010 if (PathStr != NULL) {
2011 FreePool (PathStr);
2012 }
2013 if (AltIdStr != NULL) {
2014 FreePool (AltIdStr);
2015 }
2016 if (Result != NULL) {
2017 FreePool (Result);
2018 }
2019
2020 return Status;
2021
2022 }
2023
2024