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