]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
e51de1371ad520762870b7b559f66c9baa2fffad
[mirror_edk2.git] / MdeModulePkg / Universal / HiiDatabaseDxe / ConfigRouting.c
1 /** @file
2 Implementation of interfaces function for EFI_HII_CONFIG_ROUTING_PROTOCOL.
3
4 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "HiiDatabase.h"
17 extern HII_DATABASE_PRIVATE_DATA mPrivate;
18
19 /**
20 Calculate the number of Unicode characters of the incoming Configuration string,
21 not including NULL terminator.
22
23 This is a internal function.
24
25 @param String String in <MultiConfigRequest> or
26 <MultiConfigResp> format.
27
28 @return The number of Unicode characters.
29
30 **/
31 UINTN
32 CalculateConfigStringLen (
33 IN EFI_STRING String
34 )
35 {
36 EFI_STRING TmpPtr;
37
38 //
39 // "GUID=" should be the first element of incoming string.
40 //
41 ASSERT (String != NULL);
42 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
43
44 //
45 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
46 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
47 //
48 TmpPtr = StrStr (String, L"&GUID=");
49 if (TmpPtr == NULL) {
50 return StrLen (String);
51 }
52
53 return (TmpPtr - String);
54 }
55
56
57 /**
58 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
59 from <PathHdr> of <ConfigHdr>.
60
61 This is a internal function.
62
63 @param String UEFI configuration string
64 @param DevicePathData Binary of a UEFI device path.
65
66 @retval EFI_NOT_FOUND The device path is not invalid.
67 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
68 @retval EFI_OUT_OF_RESOURCES Lake of resources to store neccesary structures.
69 @retval EFI_SUCCESS The device path is retrieved and translated to
70 binary format.
71
72 **/
73 EFI_STATUS
74 GetDevicePath (
75 IN EFI_STRING String,
76 OUT UINT8 **DevicePathData
77 )
78 {
79 UINTN Length;
80 EFI_STRING PathHdr;
81 UINT8 *DevicePathBuffer;
82 CHAR16 TemStr[2];
83 UINTN Index;
84 UINT8 DigitUint8;
85 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
86
87
88 if (String == NULL || DevicePathData == NULL) {
89 return EFI_INVALID_PARAMETER;
90 }
91
92 //
93 // Find the 'PATH=' of <PathHdr> and skip it.
94 //
95 for (; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++);
96 if (*String == 0) {
97 return EFI_INVALID_PARAMETER;
98 }
99 //
100 // Check whether path data does exist.
101 //
102 String += StrLen (L"PATH=");
103 if (*String == 0) {
104 return EFI_INVALID_PARAMETER;
105 }
106 PathHdr = String;
107
108 //
109 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
110 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
111 // of UEFI device path.
112 //
113 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++);
114 //
115 // Check DevicePath Length
116 //
117 if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
118 return EFI_NOT_FOUND;
119 }
120
121 //
122 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
123 // as the device path resides in RAM memory.
124 // Translate the data into binary.
125 //
126 DevicePathBuffer = (UINT8 *) AllocateZeroPool ((Length + 1) / 2);
127 if (DevicePathBuffer == NULL) {
128 return EFI_OUT_OF_RESOURCES;
129 }
130
131 //
132 // Convert DevicePath
133 //
134 ZeroMem (TemStr, sizeof (TemStr));
135 for (Index = 0; Index < Length; Index ++) {
136 TemStr[0] = PathHdr[Index];
137 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
138 if ((Index & 1) == 0) {
139 DevicePathBuffer [Index/2] = DigitUint8;
140 } else {
141 DevicePathBuffer [Index/2] = (UINT8) ((DevicePathBuffer [Index/2] << 4) + DigitUint8);
142 }
143 }
144
145 //
146 // Validate DevicePath
147 //
148 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) DevicePathBuffer;
149 while (!IsDevicePathEnd (DevicePath)) {
150 if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
151 //
152 // Invalid device path
153 //
154 FreePool (DevicePathBuffer);
155 return EFI_NOT_FOUND;
156 }
157 DevicePath = NextDevicePathNode (DevicePath);
158 }
159
160 //
161 // return the device path
162 //
163 *DevicePathData = DevicePathBuffer;
164 return EFI_SUCCESS;
165 }
166
167 /**
168 Converts the unicode character of the string from uppercase to lowercase.
169 This is a internal function.
170
171 @param ConfigString String to be converted
172
173 **/
174 VOID
175 EFIAPI
176 HiiToLower (
177 IN EFI_STRING ConfigString
178 )
179 {
180 EFI_STRING String;
181 BOOLEAN Lower;
182
183 ASSERT (ConfigString != NULL);
184
185 //
186 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
187 //
188 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
189 if (*String == L'=') {
190 Lower = TRUE;
191 } else if (*String == L'&') {
192 Lower = FALSE;
193 } else if (Lower && *String >= L'A' && *String <= L'F') {
194 *String = (CHAR16) (*String - L'A' + L'a');
195 }
196 }
197
198 return;
199 }
200
201 /**
202 Generate a sub string then output it.
203
204 This is a internal function.
205
206 @param String A constant string which is the prefix of the to be
207 generated string, e.g. GUID=
208
209 @param BufferLen The length of the Buffer in bytes.
210
211 @param Buffer Points to a buffer which will be converted to be the
212 content of the generated string.
213
214 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
215 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
216 if 3, the buffer contains other data.
217
218 @param SubStr Points to the output string. It's caller's
219 responsibility to free this buffer.
220
221
222 **/
223 VOID
224 GenerateSubStr (
225 IN CONST EFI_STRING String,
226 IN UINTN BufferLen,
227 IN VOID *Buffer,
228 IN UINT8 Flag,
229 OUT EFI_STRING *SubStr
230 )
231 {
232 UINTN Length;
233 EFI_STRING Str;
234 EFI_STRING StringHeader;
235 CHAR16 *TemString;
236 CHAR16 *TemName;
237 UINT8 *TemBuffer;
238 UINTN Index;
239
240 ASSERT (String != NULL && SubStr != NULL);
241
242 if (Buffer == NULL) {
243 *SubStr = AllocateCopyPool (StrSize (String), String);
244 ASSERT (*SubStr != NULL);
245 return ;
246 }
247
248 //
249 // Header + Data + '&' + '\0'
250 //
251 Length = StrLen (String) + BufferLen * 2 + 1 + 1;
252 Str = AllocateZeroPool (Length * sizeof (CHAR16));
253 ASSERT (Str != NULL);
254
255 StrCpy (Str, String);
256 Length = (BufferLen * 2 + 1) * sizeof (CHAR16);
257
258 StringHeader = Str + StrLen (String);
259 TemString = (CHAR16 *) StringHeader;
260
261 switch (Flag) {
262 case 1:
263 //
264 // Convert Buffer to Hex String in reverse order
265 //
266 TemBuffer = ((UINT8 *) Buffer);
267 for (Index = 0; Index < BufferLen; Index ++, TemBuffer ++) {
268 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
269 }
270 break;
271 case 2:
272 //
273 // Check buffer is enough
274 //
275 TemName = (CHAR16 *) Buffer;
276 ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));
277 //
278 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
279 //
280 for (; *TemName != L'\0'; TemName++) {
281 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemName, 4);
282 }
283 break;
284 case 3:
285 //
286 // Convert Buffer to Hex String
287 //
288 TemBuffer = ((UINT8 *) Buffer) + BufferLen - 1;
289 for (Index = 0; Index < BufferLen; Index ++, TemBuffer --) {
290 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
291 }
292 break;
293 default:
294 break;
295 }
296
297 //
298 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
299 //
300 StrCat (Str, L"&");
301 HiiToLower (Str);
302
303 *SubStr = Str;
304 }
305
306
307 /**
308 Retrieve the <ConfigBody> from String then output it.
309
310 This is a internal function.
311
312 @param String A sub string of a configuration string in
313 <MultiConfigAltResp> format.
314 @param ConfigBody Points to the output string. It's caller's
315 responsibility to free this buffer.
316
317 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
318 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
319 @retval EFI_SUCCESS All existing storage is exported.
320
321 **/
322 EFI_STATUS
323 OutputConfigBody (
324 IN EFI_STRING String,
325 OUT EFI_STRING *ConfigBody
326 )
327 {
328 EFI_STRING TmpPtr;
329 EFI_STRING Result;
330 UINTN Length;
331
332 if (String == NULL || ConfigBody == NULL) {
333 return EFI_INVALID_PARAMETER;
334 }
335
336 //
337 // The setting information should start OFFSET, not ALTCFG.
338 //
339 if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {
340 return EFI_INVALID_PARAMETER;
341 }
342
343 TmpPtr = StrStr (String, L"GUID=");
344 if (TmpPtr == NULL) {
345 //
346 // It is the last <ConfigResp> of the incoming configuration string.
347 //
348 Result = AllocateCopyPool (StrSize (String), String);
349 if (Result == NULL) {
350 return EFI_OUT_OF_RESOURCES;
351 } else {
352 *ConfigBody = Result;
353 return EFI_SUCCESS;
354 }
355 }
356
357 Length = TmpPtr - String;
358 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
359 if (Result == NULL) {
360 return EFI_OUT_OF_RESOURCES;
361 }
362
363 *(Result + Length - 1) = 0;
364 *ConfigBody = Result;
365 return EFI_SUCCESS;
366 }
367
368 /**
369 Append a string to a multi-string format.
370
371 This is a internal function.
372
373 @param MultiString String in <MultiConfigRequest>,
374 <MultiConfigAltResp>, or <MultiConfigResp>. On
375 input, the buffer length of this string is
376 MAX_STRING_LENGTH. On output, the buffer length
377 might be updated.
378 @param AppendString NULL-terminated Unicode string.
379
380 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
381 @retval EFI_SUCCESS AppendString is append to the end of MultiString
382
383 **/
384 EFI_STATUS
385 AppendToMultiString (
386 IN OUT EFI_STRING *MultiString,
387 IN EFI_STRING AppendString
388 )
389 {
390 UINTN AppendStringSize;
391 UINTN MultiStringSize;
392
393 if (MultiString == NULL || *MultiString == NULL || AppendString == NULL) {
394 return EFI_INVALID_PARAMETER;
395 }
396
397 AppendStringSize = StrSize (AppendString);
398 MultiStringSize = StrSize (*MultiString);
399
400 //
401 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
402 //
403 if (MultiStringSize + AppendStringSize > MAX_STRING_LENGTH ||
404 MultiStringSize > MAX_STRING_LENGTH) {
405 *MultiString = (EFI_STRING) ReallocatePool (
406 MultiStringSize,
407 MultiStringSize + AppendStringSize,
408 (VOID *) (*MultiString)
409 );
410 ASSERT (*MultiString != NULL);
411 }
412 //
413 // Append the incoming string
414 //
415 StrCat (*MultiString, AppendString);
416
417 return EFI_SUCCESS;
418 }
419
420
421 /**
422 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
423 or WIDTH or VALUE.
424 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
425
426 This is a internal function.
427
428 @param StringPtr String in <BlockConfig> format and points to the
429 first character of <Number>.
430 @param Number The output value. Caller takes the responsibility
431 to free memory.
432 @param Len Length of the <Number>, in characters.
433
434 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store neccessary
435 structures.
436 @retval EFI_SUCCESS Value of <Number> is outputted in Number
437 successfully.
438
439 **/
440 EFI_STATUS
441 GetValueOfNumber (
442 IN EFI_STRING StringPtr,
443 OUT UINT8 **Number,
444 OUT UINTN *Len
445 )
446 {
447 EFI_STRING TmpPtr;
448 UINTN Length;
449 EFI_STRING Str;
450 UINT8 *Buf;
451 EFI_STATUS Status;
452 UINT8 DigitUint8;
453 UINTN Index;
454 CHAR16 TemStr[2];
455
456 ASSERT (StringPtr != NULL && Number != NULL && Len != NULL);
457 ASSERT (*StringPtr != L'\0');
458
459 Buf = NULL;
460
461 TmpPtr = StringPtr;
462 while (*StringPtr != L'\0' && *StringPtr != L'&') {
463 StringPtr++;
464 }
465 *Len = StringPtr - TmpPtr;
466 Length = *Len + 1;
467
468 Str = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
469 if (Str == NULL) {
470 Status = EFI_OUT_OF_RESOURCES;
471 goto Exit;
472 }
473 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
474 *(Str + *Len) = L'\0';
475
476 Length = (Length + 1) / 2;
477 Buf = (UINT8 *) AllocateZeroPool (Length);
478 if (Buf == NULL) {
479 Status = EFI_OUT_OF_RESOURCES;
480 goto Exit;
481 }
482
483 Length = *Len;
484 ZeroMem (TemStr, sizeof (TemStr));
485 for (Index = 0; Index < Length; Index ++) {
486 TemStr[0] = Str[Length - Index - 1];
487 DigitUint8 = (UINT8) StrHexToUint64 (TemStr);
488 if ((Index & 1) == 0) {
489 Buf [Index/2] = DigitUint8;
490 } else {
491 Buf [Index/2] = (UINT8) ((DigitUint8 << 4) + Buf [Index/2]);
492 }
493 }
494
495 *Number = Buf;
496 Status = EFI_SUCCESS;
497
498 Exit:
499 if (Str != NULL) {
500 FreePool (Str);
501 }
502
503 return Status;
504 }
505
506 /**
507 This function merges DefaultAltCfgResp string into AltCfgResp string for
508 the missing AltCfgId in AltCfgResq.
509
510 @param AltCfgResp Pointer to a null-terminated Unicode string in
511 <ConfigAltResp> format. The default value string
512 will be merged into it.
513 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
514 <MultiConfigAltResp> format. The default value
515 string may contain more than one ConfigAltResp
516 string for the different varstore buffer.
517
518 @retval EFI_SUCCESS The merged string returns.
519 @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
520 **/
521 EFI_STATUS
522 EFIAPI
523 MergeDefaultString (
524 IN OUT EFI_STRING *AltCfgResp,
525 IN EFI_STRING DefaultAltCfgResp
526 )
527 {
528 EFI_STRING StringPtrDefault;
529 EFI_STRING StringPtrEnd;
530 CHAR16 TempChar;
531 EFI_STRING StringPtr;
532 EFI_STRING AltConfigHdr;
533 UINTN HeaderLength;
534 UINTN SizeAltCfgResp;
535
536 if (*AltCfgResp == NULL) {
537 return EFI_INVALID_PARAMETER;
538 }
539
540 //
541 // Get the requestr ConfigHdr
542 //
543 SizeAltCfgResp = 0;
544 StringPtr = *AltCfgResp;
545
546 //
547 // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
548 //
549 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
550 return EFI_INVALID_PARAMETER;
551 }
552 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
553 StringPtr++;
554 }
555 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
556 StringPtr++;
557 }
558 if (*StringPtr == L'\0') {
559 return EFI_INVALID_PARAMETER;
560 }
561 StringPtr += StrLen (L"&PATH=");
562 while (*StringPtr != L'\0' && *StringPtr != L'&') {
563 StringPtr ++;
564 }
565 HeaderLength = StringPtr - *AltCfgResp;
566
567 //
568 // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
569 // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
570 //
571 AltConfigHdr = AllocateZeroPool ((1 + HeaderLength + 8 + 4 + 1) * sizeof (CHAR16));
572 if (AltConfigHdr == NULL) {
573 return EFI_OUT_OF_RESOURCES;
574 }
575 StrCpy (AltConfigHdr, L"&");
576 StrnCat (AltConfigHdr, *AltCfgResp, HeaderLength);
577 StrCat (AltConfigHdr, L"&ALTCFG=");
578 HeaderLength = StrLen (AltConfigHdr);
579
580 StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
581 while (StringPtrDefault != NULL) {
582 //
583 // Get AltCfg Name
584 //
585 StrnCat (AltConfigHdr, StringPtrDefault + HeaderLength, 4);
586 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
587
588 //
589 // Append the found default value string to the input AltCfgResp
590 //
591 if (StringPtr == NULL) {
592 StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
593 SizeAltCfgResp = StrSize (*AltCfgResp);
594 if (StringPtrEnd == NULL) {
595 //
596 // No more default string is found.
597 //
598 *AltCfgResp = (EFI_STRING) ReallocatePool (
599 SizeAltCfgResp,
600 SizeAltCfgResp + StrSize (StringPtrDefault),
601 (VOID *) (*AltCfgResp)
602 );
603 if (*AltCfgResp == NULL) {
604 FreePool (AltConfigHdr);
605 return EFI_OUT_OF_RESOURCES;
606 }
607 StrCat (*AltCfgResp, StringPtrDefault);
608 break;
609 } else {
610 TempChar = *StringPtrEnd;
611 *StringPtrEnd = L'\0';
612 *AltCfgResp = (EFI_STRING) ReallocatePool (
613 SizeAltCfgResp,
614 SizeAltCfgResp + StrSize (StringPtrDefault),
615 (VOID *) (*AltCfgResp)
616 );
617 if (*AltCfgResp == NULL) {
618 FreePool (AltConfigHdr);
619 return EFI_OUT_OF_RESOURCES;
620 }
621 StrCat (*AltCfgResp, StringPtrDefault);
622 *StringPtrEnd = TempChar;
623 }
624 }
625
626 //
627 // Find next AltCfg String
628 //
629 *(AltConfigHdr + HeaderLength) = L'\0';
630 StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
631 }
632
633 FreePool (AltConfigHdr);
634 return EFI_SUCCESS;
635 }
636
637 /**
638 This function finds the matched DefaultName for the input DefaultId
639
640 @param DefaultIdArray Array stores the map table between DefaultId and DefaultName.
641 @param VarDefaultId Default Id
642 @param VarDefaultName Default Name string ID for the input default ID.
643
644 @retval EFI_SUCCESS The mapped default name string ID is found.
645 @retval EFI_NOT_FOUND The mapped default name string ID is not found.
646 **/
647 EFI_STATUS
648 FindDefaultName (
649 IN IFR_DEFAULT_DATA *DefaultIdArray,
650 IN UINT16 VarDefaultId,
651 OUT EFI_STRING_ID *VarDefaultName
652 )
653 {
654 LIST_ENTRY *Link;
655 IFR_DEFAULT_DATA *DefaultData;
656
657 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
658 DefaultData = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
659 if (DefaultData->DefaultId == VarDefaultId) {
660 *VarDefaultName = DefaultData->DefaultName;
661 return EFI_SUCCESS;
662 }
663 }
664
665 return EFI_NOT_FOUND;
666 }
667
668 /**
669 This function inserts new DefaultValueData into the BlockData DefaultValue array.
670
671 @param BlockData The BlockData is updated to add new default value.
672 @param DefaultValueData The DefaultValue is added.
673
674 **/
675 VOID
676 InsertDefaultValue (
677 IN IFR_BLOCK_DATA *BlockData,
678 IN IFR_DEFAULT_DATA *DefaultValueData
679 )
680 {
681 LIST_ENTRY *Link;
682 IFR_DEFAULT_DATA *DefaultValueArray;
683
684 for (Link = BlockData->DefaultValueEntry.ForwardLink; Link != &BlockData->DefaultValueEntry; Link = Link->ForwardLink) {
685 DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
686 if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
687 if (DefaultValueData->OpCode == EFI_IFR_DEFAULT_OP) {
688 //
689 // Update the default value array in BlockData.
690 //
691 DefaultValueArray->Value = DefaultValueData->Value;
692 } else if (DefaultValueArray->OpCode != EFI_IFR_DEFAULT_OP) {
693 //
694 // Update the default value array in BlockData.
695 //
696 DefaultValueArray->Value = DefaultValueData->Value;
697 }
698 FreePool (DefaultValueData);
699 return;
700 } else if (DefaultValueArray->DefaultId > DefaultValueData->DefaultId) {
701 //
702 // Insert new default value data in the front of this default value array.
703 //
704 InsertTailList (Link, &DefaultValueData->Entry);
705 return;
706 }
707 }
708
709 //
710 // Insert new default value data in tail.
711 //
712 InsertTailList (Link, &DefaultValueData->Entry);
713 return;
714 }
715
716 /**
717 This function inserts new BlockData into the block link
718
719 @param BlockLink The list entry points to block array.
720 @param BlockData The point to BlockData is added.
721
722 **/
723 VOID
724 InsertBlockData (
725 IN LIST_ENTRY *BlockLink,
726 IN IFR_BLOCK_DATA **BlockData
727 )
728 {
729 LIST_ENTRY *Link;
730 IFR_BLOCK_DATA *BlockArray;
731 IFR_BLOCK_DATA *BlockSingleData;
732
733 BlockSingleData = *BlockData;
734
735 //
736 // Insert block data in its Offset and Width order.
737 //
738 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
739 BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
740 if (BlockArray->Offset == BlockSingleData->Offset) {
741 if (BlockArray->Width > BlockSingleData->Width) {
742 //
743 // Insert this block data in the front of block array
744 //
745 InsertTailList (Link, &BlockSingleData->Entry);
746 return;
747 }
748
749 if (BlockArray->Width == BlockSingleData->Width) {
750 //
751 // The same block array has been added.
752 //
753 FreePool (BlockSingleData);
754 *BlockData = BlockArray;
755 return;
756 }
757 } else if (BlockArray->Offset > BlockSingleData->Offset) {
758 //
759 // Insert new block data in the front of block array
760 //
761 InsertTailList (Link, &BlockSingleData->Entry);
762 return;
763 }
764 }
765
766 //
767 // Add new block data into the tail.
768 //
769 InsertTailList (Link, &BlockSingleData->Entry);
770 return;
771 }
772
773 /**
774 This function checks VarOffset and VarWidth is in the block range.
775
776 @param RequestBlockArray The block array is to be checked.
777 @param VarOffset Offset of var to the structure
778 @param VarWidth Width of var.
779
780 @retval TRUE This Var is in the block range.
781 @retval FALSE This Var is not in the block range.
782 **/
783 BOOLEAN
784 BlockArrayCheck (
785 IN IFR_BLOCK_DATA *RequestBlockArray,
786 IN UINT16 VarOffset,
787 IN UINT16 VarWidth
788 )
789 {
790 LIST_ENTRY *Link;
791 IFR_BLOCK_DATA *BlockData;
792
793 //
794 // No Request Block array, all vars are got.
795 //
796 if (RequestBlockArray == NULL) {
797 return TRUE;
798 }
799
800 //
801 // Check the input var is in the request block range.
802 //
803 for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
804 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
805 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
806 return TRUE;
807 }
808 }
809
810 return FALSE;
811 }
812
813 /**
814 This function parses Form Package to get the block array and the default
815 value array according to the request ConfigHdr.
816
817 @param Package Pointer to the form package data.
818 @param PackageLength Length of the pacakge.
819 @param ConfigHdr Request string ConfigHdr. If it is NULL,
820 the first found varstore will be as ConfigHdr.
821 @param RequestBlockArray The block array is retrieved from the request string.
822 @param VarStorageData VarStorage structure contains the got block and default value.
823 @param PIfrDefaultIdArray Point to the got default id and default name array.
824
825 @retval EFI_SUCCESS The block array and the default value array are got.
826 @retval EFI_INVALID_PARAMETER The varstore defintion in the differnt form pacakges
827 are conflicted.
828 @retval EFI_OUT_OF_RESOURCES No enough memory.
829 **/
830 EFI_STATUS
831 EFIAPI
832 ParseIfrData (
833 IN UINT8 *Package,
834 IN UINT32 PackageLength,
835 IN EFI_STRING ConfigHdr,
836 IN IFR_BLOCK_DATA *RequestBlockArray,
837 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
838 OUT IFR_DEFAULT_DATA *DefaultIdArray
839 )
840 {
841 EFI_STATUS Status;
842 UINTN IfrOffset;
843 EFI_IFR_VARSTORE *IfrVarStore;
844 EFI_IFR_OP_HEADER *IfrOpHdr;
845 EFI_IFR_ONE_OF *IfrOneOf;
846 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
847 EFI_IFR_DEFAULT *IfrDefault;
848 EFI_IFR_ORDERED_LIST *IfrOrderedList;
849 EFI_IFR_CHECKBOX *IfrCheckBox;
850 EFI_IFR_PASSWORD *IfrPassword;
851 EFI_IFR_STRING *IfrString;
852 IFR_DEFAULT_DATA *DefaultData;
853 IFR_BLOCK_DATA *BlockData;
854 CHAR16 *VarStoreName;
855 UINT16 VarOffset;
856 UINT16 VarWidth;
857 EFI_STRING_ID VarDefaultName;
858 UINT16 VarDefaultId;
859 EFI_STRING GuidStr;
860 EFI_STRING NameStr;
861 EFI_STRING TempStr;
862 UINTN LengthString;
863 BOOLEAN FirstOneOfOption;
864
865 LengthString = 0;
866 Status = EFI_SUCCESS;
867 GuidStr = NULL;
868 NameStr = NULL;
869 TempStr = NULL;
870 BlockData = NULL;
871 DefaultData = NULL;
872 VarDefaultName = 0;
873 FirstOneOfOption = FALSE;
874
875 //
876 // Go through the form package to parse OpCode one by one.
877 //
878 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
879 while (IfrOffset < PackageLength) {
880 IfrOpHdr = (EFI_IFR_OP_HEADER *) (Package + IfrOffset);
881
882 switch (IfrOpHdr->OpCode) {
883 case EFI_IFR_VARSTORE_OP:
884 //
885 // VarStore is found. Don't need to search any more.
886 //
887 if (VarStorageData->Size != 0) {
888 break;
889 }
890
891 //
892 // Get the requied varstore information
893 // Add varstore by Guid and Name in ConfigHdr
894 // Make sure Offset is in varstore size and varstoreid
895 //
896 IfrVarStore = (EFI_IFR_VARSTORE *) IfrOpHdr;
897 VarStoreName = AllocateZeroPool (AsciiStrSize ((CHAR8 *)IfrVarStore->Name) * sizeof (CHAR16));
898 if (VarStoreName == NULL) {
899 Status = EFI_OUT_OF_RESOURCES;
900 goto Done;
901 }
902 AsciiStrToUnicodeStr ((CHAR8 *) IfrVarStore->Name, VarStoreName);
903
904 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &IfrVarStore->Guid, 1, &GuidStr);
905 GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *) VarStoreName, 2, &NameStr);
906 LengthString = StrLen (GuidStr);
907 LengthString = LengthString + StrLen (NameStr) + 1;
908 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
909 if (TempStr == NULL) {
910 FreePool (GuidStr);
911 FreePool (NameStr);
912 FreePool (VarStoreName);
913 Status = EFI_OUT_OF_RESOURCES;
914 goto Done;
915 }
916 StrCpy (TempStr, GuidStr);
917 StrCat (TempStr, NameStr);
918 if (ConfigHdr == NULL || StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0) {
919 //
920 // Find the matched VarStore
921 //
922 CopyGuid (&VarStorageData->Guid, (EFI_GUID *) (VOID *) &IfrVarStore->Guid);
923 VarStorageData->VarStoreId = IfrVarStore->VarStoreId;
924 VarStorageData->Size = IfrVarStore->Size;
925 VarStorageData->Name = VarStoreName;
926 } else {
927 //
928 // No found, free the allocated memory
929 //
930 FreePool (VarStoreName);
931 }
932 //
933 // Free alllocated temp string.
934 //
935 FreePool (GuidStr);
936 FreePool (NameStr);
937 FreePool (TempStr);
938 break;
939
940 case EFI_IFR_DEFAULTSTORE_OP:
941 //
942 // Add new the map between default id and default name.
943 //
944 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
945 if (DefaultData == NULL) {
946 Status = EFI_OUT_OF_RESOURCES;
947 goto Done;
948 }
949 DefaultData->DefaultId = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId;
950 DefaultData->DefaultName = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultName;
951 InsertTailList (&DefaultIdArray->Entry, &DefaultData->Entry);
952 DefaultData = NULL;
953 break;
954
955 case EFI_IFR_FORM_OP:
956 case EFI_IFR_FORM_MAP_OP:
957 //
958 // No matched varstore is found and directly return.
959 //
960 if (VarStorageData->Size == 0) {
961 Status = EFI_SUCCESS;
962 goto Done;
963 }
964 break;
965
966 case EFI_IFR_ONE_OF_OP:
967 case EFI_IFR_NUMERIC_OP:
968 //
969 // Numeric and OneOf has the same opcode structure.
970 //
971
972 //
973 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
974 //
975 if (VarStorageData->Size == 0) {
976 Status = EFI_INVALID_PARAMETER;
977 goto Done;
978 }
979 //
980 // Check whether this question is for the requested varstore.
981 //
982 IfrOneOf = (EFI_IFR_ONE_OF *) IfrOpHdr;
983 if (IfrOneOf->Question.VarStoreId != VarStorageData->VarStoreId) {
984 break;
985 }
986
987 //
988 // Get Offset/Width by Question header and OneOf Flags
989 //
990 VarOffset = IfrOneOf->Question.VarStoreInfo.VarOffset;
991 VarWidth = (UINT16) (1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
992 //
993 // Check whether this question is in requested block array.
994 //
995 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
996 //
997 // This question is not in the requested string. Skip it.
998 //
999 break;
1000 }
1001
1002 //
1003 // Check this var question is in the var storage
1004 //
1005 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1006 Status = EFI_INVALID_PARAMETER;
1007 goto Done;
1008 }
1009
1010 //
1011 // Set Block Data
1012 //
1013 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1014 if (BlockData == NULL) {
1015 Status = EFI_OUT_OF_RESOURCES;
1016 goto Done;
1017 }
1018 BlockData->Offset = VarOffset;
1019 BlockData->Width = VarWidth;
1020 BlockData->QuestionId = IfrOneOf->Question.QuestionId;
1021 BlockData->OpCode = IfrOpHdr->OpCode;
1022 BlockData->Scope = IfrOpHdr->Scope;
1023 InitializeListHead (&BlockData->DefaultValueEntry);
1024 //
1025 // Add Block Data into VarStorageData BlockEntry
1026 //
1027 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1028
1029 if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
1030 //
1031 // Set this flag to TRUE for the first oneof option.
1032 //
1033 FirstOneOfOption = TRUE;
1034 } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
1035 //
1036 // Numeric minimum value will be used as default value when no default is specified.
1037 //
1038
1039 //
1040 // Set standard ID and Get DefaultName String ID
1041 //
1042 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1043 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1044 if (EFI_ERROR (Status)) {
1045 goto Done;
1046 }
1047 //
1048 // Prepare new DefaultValue
1049 //
1050 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1051 if (DefaultData == NULL) {
1052 Status = EFI_OUT_OF_RESOURCES;
1053 goto Done;
1054 }
1055 DefaultData->OpCode = IfrOpHdr->OpCode;
1056 DefaultData->DefaultId = VarDefaultId;
1057 DefaultData->DefaultName = VarDefaultName;
1058
1059 switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
1060 case EFI_IFR_NUMERIC_SIZE_1:
1061 DefaultData->Value = (UINT64) IfrOneOf->data.u8.MinValue;
1062 break;
1063
1064 case EFI_IFR_NUMERIC_SIZE_2:
1065 CopyMem (&DefaultData->Value, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
1066 break;
1067
1068 case EFI_IFR_NUMERIC_SIZE_4:
1069 CopyMem (&DefaultData->Value, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
1070 break;
1071
1072 case EFI_IFR_NUMERIC_SIZE_8:
1073 CopyMem (&DefaultData->Value, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
1074 break;
1075 }
1076 //
1077 // Add DefaultValue into current BlockData
1078 //
1079 InsertDefaultValue (BlockData, DefaultData);
1080 }
1081 break;
1082
1083 case EFI_IFR_ORDERED_LIST_OP:
1084 //
1085 // offset by question header
1086 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
1087 // no default value and default id, how to define its default value?
1088 //
1089
1090 //
1091 // OrderedList question is not in IFR Form. This IFR form is not valid.
1092 //
1093 if (VarStorageData->Size == 0) {
1094 Status = EFI_INVALID_PARAMETER;
1095 goto Done;
1096 }
1097 //
1098 // Check whether this question is for the requested varstore.
1099 //
1100 IfrOrderedList = (EFI_IFR_ORDERED_LIST *) IfrOpHdr;
1101 if (IfrOrderedList->Question.VarStoreId != VarStorageData->VarStoreId) {
1102 BlockData = NULL;
1103 break;
1104 }
1105
1106 //
1107 // Get Offset/Width by Question header and OneOf Flags
1108 //
1109 VarOffset = IfrOrderedList->Question.VarStoreInfo.VarOffset;
1110 VarWidth = IfrOrderedList->MaxContainers;
1111
1112 //
1113 // Set Block Data
1114 //
1115 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1116 if (BlockData == NULL) {
1117 Status = EFI_OUT_OF_RESOURCES;
1118 goto Done;
1119 }
1120 BlockData->Offset = VarOffset;
1121 BlockData->Width = VarWidth;
1122 BlockData->QuestionId = IfrOrderedList->Question.QuestionId;
1123 BlockData->OpCode = IfrOpHdr->OpCode;
1124 BlockData->Scope = IfrOpHdr->Scope;
1125 InitializeListHead (&BlockData->DefaultValueEntry);
1126 break;
1127
1128 case EFI_IFR_CHECKBOX_OP:
1129 //
1130 // EFI_IFR_DEFAULT_OP
1131 // offset by question header
1132 // width is 1 sizeof (BOOLEAN)
1133 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
1134 // value by DefaultOption
1135 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
1136 //
1137
1138 //
1139 // CheckBox question is not in IFR Form. This IFR form is not valid.
1140 //
1141 if (VarStorageData->Size == 0) {
1142 Status = EFI_INVALID_PARAMETER;
1143 goto Done;
1144 }
1145 //
1146 // Check whether this question is for the requested varstore.
1147 //
1148 IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr;
1149 if (IfrCheckBox->Question.VarStoreId != VarStorageData->VarStoreId) {
1150 break;
1151 }
1152
1153 //
1154 // Get Offset/Width by Question header and OneOf Flags
1155 //
1156 VarOffset = IfrCheckBox->Question.VarStoreInfo.VarOffset;
1157 VarWidth = (UINT16) sizeof (BOOLEAN);
1158
1159 //
1160 // Check whether this question is in requested block array.
1161 //
1162 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1163 //
1164 // This question is not in the requested string. Skip it.
1165 //
1166 break;
1167 }
1168
1169 //
1170 // Check this var question is in the var storage
1171 //
1172 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1173 Status = EFI_INVALID_PARAMETER;
1174 goto Done;
1175 }
1176
1177 //
1178 // Set Block Data
1179 //
1180 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1181 if (BlockData == NULL) {
1182 Status = EFI_OUT_OF_RESOURCES;
1183 goto Done;
1184 }
1185 BlockData->Offset = VarOffset;
1186 BlockData->Width = VarWidth;
1187 BlockData->QuestionId = IfrCheckBox->Question.QuestionId;
1188 BlockData->OpCode = IfrOpHdr->OpCode;
1189 BlockData->Scope = IfrOpHdr->Scope;
1190 InitializeListHead (&BlockData->DefaultValueEntry);
1191 //
1192 // Add Block Data into VarStorageData BlockEntry
1193 //
1194 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1195
1196 //
1197 // Add default value by CheckBox Flags
1198 //
1199 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
1200 //
1201 // Set standard ID to Manufacture ID and Get DefaultName String ID
1202 //
1203 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1204 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1205 if (EFI_ERROR (Status)) {
1206 goto Done;
1207 }
1208 //
1209 // Prepare new DefaultValue
1210 //
1211 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1212 if (DefaultData == NULL) {
1213 Status = EFI_OUT_OF_RESOURCES;
1214 goto Done;
1215 }
1216 DefaultData->OpCode = IfrOpHdr->OpCode;
1217 DefaultData->DefaultId = VarDefaultId;
1218 DefaultData->DefaultName = VarDefaultName;
1219 DefaultData->Value = 1;
1220 //
1221 // Add DefaultValue into current BlockData
1222 //
1223 InsertDefaultValue (BlockData, DefaultData);
1224 }
1225
1226 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
1227 //
1228 // Set standard ID to Manufacture ID and Get DefaultName String ID
1229 //
1230 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1231 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1232 if (EFI_ERROR (Status)) {
1233 goto Done;
1234 }
1235 //
1236 // Prepare new DefaultValue
1237 //
1238 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1239 if (DefaultData == NULL) {
1240 Status = EFI_OUT_OF_RESOURCES;
1241 goto Done;
1242 }
1243 DefaultData->OpCode = IfrOpHdr->OpCode;
1244 DefaultData->DefaultId = VarDefaultId;
1245 DefaultData->DefaultName = VarDefaultName;
1246 DefaultData->Value = 1;
1247 //
1248 // Add DefaultValue into current BlockData
1249 //
1250 InsertDefaultValue (BlockData, DefaultData);
1251 }
1252 break;
1253
1254 case EFI_IFR_STRING_OP:
1255 //
1256 // offset by question header
1257 // width MaxSize * sizeof (CHAR16)
1258 // no default value, only block array
1259 //
1260
1261 //
1262 // String question is not in IFR Form. This IFR form is not valid.
1263 //
1264 if (VarStorageData->Size == 0) {
1265 Status = EFI_INVALID_PARAMETER;
1266 goto Done;
1267 }
1268 //
1269 // Check whether this question is for the requested varstore.
1270 //
1271 IfrString = (EFI_IFR_STRING *) IfrOpHdr;
1272 if (IfrString->Question.VarStoreId != VarStorageData->VarStoreId) {
1273 break;
1274 }
1275
1276 //
1277 // Get Offset/Width by Question header and OneOf Flags
1278 //
1279 VarOffset = IfrString->Question.VarStoreInfo.VarOffset;
1280 VarWidth = (UINT16) (IfrString->MaxSize * sizeof (UINT16));
1281
1282 //
1283 // Check whether this question is in requested block array.
1284 //
1285 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1286 //
1287 // This question is not in the requested string. Skip it.
1288 //
1289 break;
1290 }
1291
1292 //
1293 // Check this var question is in the var storage
1294 //
1295 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1296 Status = EFI_INVALID_PARAMETER;
1297 goto Done;
1298 }
1299
1300 //
1301 // Set Block Data
1302 //
1303 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1304 if (BlockData == NULL) {
1305 Status = EFI_OUT_OF_RESOURCES;
1306 goto Done;
1307 }
1308 BlockData->Offset = VarOffset;
1309 BlockData->Width = VarWidth;
1310 BlockData->QuestionId = IfrString->Question.QuestionId;
1311 BlockData->OpCode = IfrOpHdr->OpCode;
1312 InitializeListHead (&BlockData->DefaultValueEntry);
1313
1314 //
1315 // Add Block Data into VarStorageData BlockEntry
1316 //
1317 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1318
1319 //
1320 // No default value for string.
1321 //
1322 BlockData = NULL;
1323 break;
1324
1325 case EFI_IFR_PASSWORD_OP:
1326 //
1327 // offset by question header
1328 // width MaxSize * sizeof (CHAR16)
1329 // no default value, only block array
1330 //
1331
1332 //
1333 // Password question is not in IFR Form. This IFR form is not valid.
1334 //
1335 if (VarStorageData->Size == 0) {
1336 Status = EFI_INVALID_PARAMETER;
1337 goto Done;
1338 }
1339 //
1340 // Check whether this question is for the requested varstore.
1341 //
1342 IfrPassword = (EFI_IFR_PASSWORD *) IfrOpHdr;
1343 if (IfrPassword->Question.VarStoreId != VarStorageData->VarStoreId) {
1344 break;
1345 }
1346
1347 //
1348 // Get Offset/Width by Question header and OneOf Flags
1349 //
1350 VarOffset = IfrPassword->Question.VarStoreInfo.VarOffset;
1351 VarWidth = (UINT16) (IfrPassword->MaxSize * sizeof (UINT16));
1352
1353 //
1354 // Check whether this question is in requested block array.
1355 //
1356 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth)) {
1357 //
1358 // This question is not in the requested string. Skip it.
1359 //
1360 break;
1361 }
1362
1363 //
1364 // Check this var question is in the var storage
1365 //
1366 if ((VarOffset + VarWidth) > VarStorageData->Size) {
1367 Status = EFI_INVALID_PARAMETER;
1368 goto Done;
1369 }
1370
1371 //
1372 // Set Block Data
1373 //
1374 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1375 if (BlockData == NULL) {
1376 Status = EFI_OUT_OF_RESOURCES;
1377 goto Done;
1378 }
1379 BlockData->Offset = VarOffset;
1380 BlockData->Width = VarWidth;
1381 BlockData->QuestionId = IfrPassword->Question.QuestionId;
1382 BlockData->OpCode = IfrOpHdr->OpCode;
1383 InitializeListHead (&BlockData->DefaultValueEntry);
1384
1385 //
1386 // Add Block Data into VarStorageData BlockEntry
1387 //
1388 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1389
1390 //
1391 // No default value for string.
1392 //
1393 BlockData = NULL;
1394 break;
1395
1396 case EFI_IFR_ONE_OF_OPTION_OP:
1397 //
1398 // No matched block data is ignored.
1399 //
1400 if (BlockData == NULL || BlockData->Scope == 0) {
1401 break;
1402 }
1403
1404 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr;
1405 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1406 //
1407 // Get ordered list option data type.
1408 //
1409 if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN) {
1410 VarWidth = 1;
1411 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
1412 VarWidth = 2;
1413 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
1414 VarWidth = 4;
1415 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
1416 VarWidth = 8;
1417 } else {
1418 //
1419 // Invalid ordered list option data type.
1420 //
1421 Status = EFI_INVALID_PARAMETER;
1422 FreePool (BlockData);
1423 goto Done;
1424 }
1425
1426 //
1427 // Calculate Ordered list QuestionId width.
1428 //
1429 BlockData->Width = (UINT16) (BlockData->Width * VarWidth);
1430 //
1431 // Check whether this question is in requested block array.
1432 //
1433 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width)) {
1434 //
1435 // This question is not in the requested string. Skip it.
1436 //
1437 FreePool (BlockData);
1438 BlockData = NULL;
1439 break;
1440 }
1441 //
1442 // Check this var question is in the var storage
1443 //
1444 if ((BlockData->Offset + BlockData->Width) > VarStorageData->Size) {
1445 Status = EFI_INVALID_PARAMETER;
1446 FreePool (BlockData);
1447 goto Done;
1448 }
1449 //
1450 // Add Block Data into VarStorageData BlockEntry
1451 //
1452 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
1453 //
1454 // No default data for OrderedList.
1455 //
1456 BlockData = NULL;
1457 break;
1458 }
1459
1460 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
1461 (BlockData->OpCode == EFI_IFR_ONE_OF_OP && FirstOneOfOption)) {
1462 //
1463 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
1464 // The first oneof option value will be used as default value when no default value is specified.
1465 //
1466 FirstOneOfOption = FALSE;
1467 //
1468 // Set standard ID to Manufacture ID and Get DefaultName String ID
1469 //
1470 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
1471 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1472 if (EFI_ERROR (Status)) {
1473 goto Done;
1474 }
1475 //
1476 // Prepare new DefaultValue
1477 //
1478 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1479 if (DefaultData == NULL) {
1480 Status = EFI_OUT_OF_RESOURCES;
1481 goto Done;
1482 }
1483 DefaultData->OpCode = IfrOpHdr->OpCode;
1484 DefaultData->DefaultId = VarDefaultId;
1485 DefaultData->DefaultName = VarDefaultName;
1486 DefaultData->Value = IfrOneOfOption->Value.u64;
1487 //
1488 // Add DefaultValue into current BlockData
1489 //
1490 InsertDefaultValue (BlockData, DefaultData);
1491 }
1492
1493 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
1494 //
1495 // Set default ID to Manufacture ID and Get DefaultName String ID
1496 //
1497 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
1498 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1499 if (EFI_ERROR (Status)) {
1500 goto Done;
1501 }
1502 //
1503 // Prepare new DefaultValue
1504 //
1505 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1506 if (DefaultData == NULL) {
1507 Status = EFI_OUT_OF_RESOURCES;
1508 goto Done;
1509 }
1510 DefaultData->OpCode = IfrOpHdr->OpCode;
1511 DefaultData->DefaultId = VarDefaultId;
1512 DefaultData->DefaultName = VarDefaultName;
1513 DefaultData->Value = IfrOneOfOption->Value.u64;
1514 //
1515 // Add DefaultValue into current BlockData
1516 //
1517 InsertDefaultValue (BlockData, DefaultData);
1518 }
1519 break;
1520
1521 case EFI_IFR_DEFAULT_OP:
1522 //
1523 // Update Current BlockData to the default value.
1524 //
1525 if (BlockData == NULL || BlockData->Scope == 0) {
1526 //
1527 // No matched block data is ignored.
1528 //
1529 break;
1530 }
1531
1532 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
1533 //
1534 // OrderedList Opcode is no default value.
1535 //
1536 break;
1537 }
1538 //
1539 // Get the DefaultId and DefaultName String ID
1540 //
1541 IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr;
1542 VarDefaultId = IfrDefault->DefaultId;
1543 Status = FindDefaultName (DefaultIdArray, VarDefaultId, &VarDefaultName);
1544 if (EFI_ERROR (Status)) {
1545 goto Done;
1546 }
1547 //
1548 // Prepare new DefaultValue
1549 //
1550 DefaultData = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1551 if (DefaultData == NULL) {
1552 Status = EFI_OUT_OF_RESOURCES;
1553 goto Done;
1554 }
1555 DefaultData->OpCode = IfrOpHdr->OpCode;
1556 DefaultData->DefaultId = VarDefaultId;
1557 DefaultData->DefaultName = VarDefaultName;
1558 DefaultData->Value = IfrDefault->Value.u64;
1559 //
1560 // Add DefaultValue into current BlockData
1561 //
1562 InsertDefaultValue (BlockData, DefaultData);
1563 break;
1564 case EFI_IFR_END_OP:
1565 //
1566 // End Opcode is for Var question.
1567 //
1568 if (BlockData != NULL && BlockData->Scope > 0) {
1569 BlockData->Scope--;
1570 }
1571 break;
1572 default:
1573 if (BlockData != NULL && BlockData->Scope > 0) {
1574 BlockData->Scope = (UINT8) (BlockData->Scope + IfrOpHdr->Scope);
1575 }
1576 break;
1577 }
1578
1579 IfrOffset += IfrOpHdr->Length;
1580 }
1581
1582 Done:
1583 return Status;
1584 }
1585
1586 /**
1587 This function gets the full request string and full default value string by
1588 parsing IFR data in HII form packages.
1589
1590 When Request points to NULL string, the request string and default value string
1591 for each varstore in form package will return.
1592
1593 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1594 @param DevicePath Device Path which Hii Config Access Protocol is registered.
1595 @param Request Pointer to a null-terminated Unicode string in
1596 <ConfigRequest> format. When it doesn't contain
1597 any RequestElement, it will be updated to return
1598 the full RequestElement retrieved from IFR data.
1599 If it points to NULL, the request string for the first
1600 varstore in form package will be merged into a
1601 <MultiConfigRequest> format string and return.
1602 @param AltCfgResp Pointer to a null-terminated Unicode string in
1603 <ConfigAltResp> format. When the pointer is to NULL,
1604 the full default value string retrieved from IFR data
1605 will return. When the pinter is to a string, the
1606 full default value string retrieved from IFR data
1607 will be merged into the input string and return.
1608 When Request points to NULL, the default value string
1609 for each varstore in form package will be merged into
1610 a <MultiConfigAltResp> format string and return.
1611 @param PointerProgress Optional parameter, it can be be NULL.
1612 When it is not NULL, if Request is NULL, it returns NULL.
1613 On return, points to a character in the Request
1614 string. Points to the string's null terminator if
1615 request was successful. Points to the most recent
1616 & before the first failing name / value pair (or
1617 the beginning of the string if the failure is in
1618 the first name / value pair) if the request was
1619 not successful.
1620 @retval EFI_SUCCESS The Results string is set to the full request string.
1621 And AltCfgResp contains all default value string.
1622 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
1623 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
1624 can't be found in Form package.
1625 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
1626 @retval EFI_INVALID_PARAMETER Request points to NULL.
1627
1628 **/
1629 EFI_STATUS
1630 EFIAPI
1631 GetFullStringFromHiiFormPackages (
1632 IN HII_DATABASE_RECORD *DataBaseRecord,
1633 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1634 IN OUT EFI_STRING *Request,
1635 IN OUT EFI_STRING *AltCfgResp,
1636 OUT EFI_STRING *PointerProgress OPTIONAL
1637 )
1638 {
1639 EFI_STATUS Status;
1640 UINT8 *HiiFormPackage;
1641 UINTN PackageSize;
1642 UINTN ResultSize;
1643 IFR_BLOCK_DATA *RequestBlockArray;
1644 IFR_BLOCK_DATA *BlockData;
1645 IFR_BLOCK_DATA *NextBlockData;
1646 IFR_DEFAULT_DATA *DefaultValueData;
1647 IFR_DEFAULT_DATA *DefaultId;
1648 IFR_DEFAULT_DATA *DefaultIdArray;
1649 IFR_VARSTORAGE_DATA *VarStorageData;
1650 EFI_STRING DefaultAltCfgResp;
1651 EFI_STRING FullConfigRequest;
1652 EFI_STRING ConfigHdr;
1653 EFI_STRING GuidStr;
1654 EFI_STRING NameStr;
1655 EFI_STRING PathStr;
1656 EFI_STRING StringPtr;
1657 EFI_STRING Progress;
1658 UINTN Length;
1659 UINT8 *TmpBuffer;
1660 UINT16 Offset;
1661 UINT16 Width;
1662 LIST_ENTRY *Link;
1663 LIST_ENTRY *LinkData;
1664 LIST_ENTRY *LinkDefault;
1665 BOOLEAN DataExist;
1666
1667 if (DataBaseRecord == NULL || DevicePath == NULL || Request == NULL || AltCfgResp == NULL) {
1668 return EFI_INVALID_PARAMETER;
1669 }
1670
1671 //
1672 // Initialize the local variables.
1673 //
1674 RequestBlockArray = NULL;
1675 DefaultIdArray = NULL;
1676 VarStorageData = NULL;
1677 DefaultAltCfgResp = NULL;
1678 FullConfigRequest = NULL;
1679 ConfigHdr = NULL;
1680 GuidStr = NULL;
1681 NameStr = NULL;
1682 PathStr = NULL;
1683 HiiFormPackage = NULL;
1684 ResultSize = 0;
1685 PackageSize = 0;
1686 DataExist = FALSE;
1687 Progress = *Request;
1688
1689 //
1690 // 0. Get Hii Form Package by HiiHandle
1691 //
1692 Status = ExportFormPackages (
1693 &mPrivate,
1694 DataBaseRecord->Handle,
1695 DataBaseRecord->PackageList,
1696 0,
1697 PackageSize,
1698 HiiFormPackage,
1699 &ResultSize
1700 );
1701 if (EFI_ERROR (Status)) {
1702 return Status;
1703 }
1704
1705 HiiFormPackage = AllocatePool (ResultSize);
1706 if (HiiFormPackage == NULL) {
1707 Status = EFI_OUT_OF_RESOURCES;
1708 goto Done;
1709 }
1710
1711 //
1712 // Get HiiFormPackage by HiiHandle
1713 //
1714 PackageSize = ResultSize;
1715 ResultSize = 0;
1716 Status = ExportFormPackages (
1717 &mPrivate,
1718 DataBaseRecord->Handle,
1719 DataBaseRecord->PackageList,
1720 0,
1721 PackageSize,
1722 HiiFormPackage,
1723 &ResultSize
1724 );
1725 if (EFI_ERROR (Status)) {
1726 goto Done;
1727 }
1728
1729 //
1730 // 1. Get the request block array by Request String when Request string containts the block array.
1731 //
1732 StringPtr = NULL;
1733 if (*Request != NULL) {
1734 StringPtr = *Request;
1735 //
1736 // Jump <ConfigHdr>
1737 //
1738 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1739 Status = EFI_INVALID_PARAMETER;
1740 goto Done;
1741 }
1742 StringPtr += StrLen (L"GUID=");
1743 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1744 StringPtr++;
1745 }
1746 if (*StringPtr == L'\0') {
1747 Status = EFI_INVALID_PARAMETER;
1748 goto Done;
1749 }
1750 StringPtr += StrLen (L"&NAME=");
1751 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1752 StringPtr++;
1753 }
1754 if (*StringPtr == L'\0') {
1755 Status = EFI_INVALID_PARAMETER;
1756 goto Done;
1757 }
1758 StringPtr += StrLen (L"&PATH=");
1759 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1760 StringPtr ++;
1761 }
1762 //
1763 // Check the following string &OFFSET=
1764 //
1765 if (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
1766 Progress = StringPtr;
1767 Status = EFI_INVALID_PARAMETER;
1768 goto Done;
1769 } else if (*StringPtr == L'\0') {
1770 //
1771 // No request block is found.
1772 //
1773 StringPtr = NULL;
1774 }
1775 }
1776 if (StringPtr != NULL) {
1777 //
1778 // Init RequestBlockArray
1779 //
1780 RequestBlockArray = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1781 if (RequestBlockArray == NULL) {
1782 Status = EFI_OUT_OF_RESOURCES;
1783 goto Done;
1784 }
1785 InitializeListHead (&RequestBlockArray->Entry);
1786
1787 //
1788 // Get the request Block array from the request string
1789 // Offset and Width
1790 //
1791
1792 //
1793 // Parse each <RequestElement> if exists
1794 // Only <BlockName> format is supported by this help function.
1795 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
1796 //
1797 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
1798 //
1799 // Skip the OFFSET string
1800 //
1801 Progress = StringPtr;
1802 StringPtr += StrLen (L"&OFFSET=");
1803 //
1804 // Get Offset
1805 //
1806 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1807 if (EFI_ERROR (Status)) {
1808 goto Done;
1809 }
1810 Offset = 0;
1811 CopyMem (
1812 &Offset,
1813 TmpBuffer,
1814 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1815 );
1816 FreePool (TmpBuffer);
1817
1818 StringPtr += Length;
1819 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
1820 Status = EFI_INVALID_PARAMETER;
1821 goto Done;
1822 }
1823 StringPtr += StrLen (L"&WIDTH=");
1824
1825 //
1826 // Get Width
1827 //
1828 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1829 if (EFI_ERROR (Status)) {
1830 goto Done;
1831 }
1832 Width = 0;
1833 CopyMem (
1834 &Width,
1835 TmpBuffer,
1836 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
1837 );
1838 FreePool (TmpBuffer);
1839
1840 StringPtr += Length;
1841 if (*StringPtr != 0 && *StringPtr != L'&') {
1842 Status = EFI_INVALID_PARAMETER;
1843 goto Done;
1844 }
1845
1846 //
1847 // Set Block Data
1848 //
1849 BlockData = (IFR_BLOCK_DATA *) AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
1850 if (BlockData == NULL) {
1851 Status = EFI_OUT_OF_RESOURCES;
1852 goto Done;
1853 }
1854 BlockData->Offset = Offset;
1855 BlockData->Width = Width;
1856 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
1857
1858 //
1859 // Skip &VALUE string if &VALUE does exists.
1860 //
1861 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
1862 StringPtr += StrLen (L"&VALUE=");
1863
1864 //
1865 // Get Value
1866 //
1867 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
1868 if (EFI_ERROR (Status)) {
1869 Status = EFI_INVALID_PARAMETER;
1870 goto Done;
1871 }
1872
1873 StringPtr += Length;
1874 if (*StringPtr != 0 && *StringPtr != L'&') {
1875 Status = EFI_INVALID_PARAMETER;
1876 goto Done;
1877 }
1878 }
1879 //
1880 // If '\0', parsing is finished.
1881 //
1882 if (*StringPtr == 0) {
1883 break;
1884 }
1885 }
1886
1887 //
1888 // Merge the requested block data.
1889 //
1890 Link = RequestBlockArray->Entry.ForwardLink;
1891 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
1892 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1893 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
1894 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
1895 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
1896 BlockData->Width = (UINT16) (NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
1897 }
1898 RemoveEntryList (Link->ForwardLink);
1899 FreePool (NextBlockData);
1900 continue;
1901 }
1902 Link = Link->ForwardLink;
1903 }
1904 }
1905
1906 //
1907 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
1908 //
1909
1910 //
1911 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
1912 //
1913 DefaultIdArray = (IFR_DEFAULT_DATA *) AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1914 if (DefaultIdArray == NULL) {
1915 Status = EFI_OUT_OF_RESOURCES;
1916 goto Done;
1917 }
1918 InitializeListHead (&DefaultIdArray->Entry);
1919
1920 //
1921 // Initialize VarStorageData to store the var store Block and Default value information.
1922 //
1923 VarStorageData = (IFR_VARSTORAGE_DATA *) AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
1924 if (VarStorageData == NULL) {
1925 Status = EFI_OUT_OF_RESOURCES;
1926 goto Done;
1927 }
1928 InitializeListHead (&VarStorageData->Entry);
1929 InitializeListHead (&VarStorageData->BlockEntry);
1930
1931 //
1932 // Parse the opcode in form pacakge to get the default setting.
1933 //
1934 Status = ParseIfrData (HiiFormPackage, (UINT32) PackageSize, *Request, RequestBlockArray, VarStorageData, DefaultIdArray);
1935 if (EFI_ERROR (Status)) {
1936 goto Done;
1937 }
1938
1939 //
1940 // No requested varstore in IFR data and directly return
1941 //
1942 if (VarStorageData->Size == 0) {
1943 Status = EFI_SUCCESS;
1944 goto Done;
1945 }
1946
1947 //
1948 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
1949 //
1950
1951 //
1952 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
1953 //
1954 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) &VarStorageData->Guid, 1, &GuidStr);
1955 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *) VarStorageData->Name, 2, &NameStr);
1956 GenerateSubStr (
1957 L"PATH=",
1958 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
1959 (VOID *) DevicePath,
1960 1,
1961 &PathStr
1962 );
1963 Length = StrLen (GuidStr);
1964 Length = Length + StrLen (NameStr);
1965 Length = Length + StrLen (PathStr) + 1;
1966 ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
1967 if (ConfigHdr == NULL) {
1968 Status = EFI_OUT_OF_RESOURCES;
1969 goto Done;
1970 }
1971 StrCpy (ConfigHdr, GuidStr);
1972 StrCat (ConfigHdr, NameStr);
1973 StrCat (ConfigHdr, PathStr);
1974
1975 //
1976 // Remove the last character L'&'
1977 //
1978 *(ConfigHdr + StrLen (ConfigHdr) - 1) = L'\0';
1979
1980 if (RequestBlockArray == NULL) {
1981 //
1982 // Append VarStorageData BlockEntry into *Request string
1983 // Now support only one varstore in a form package.
1984 //
1985
1986 //
1987 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
1988 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
1989 //
1990
1991 //
1992 // Compute the length of the entire request starting with <ConfigHdr> and a
1993 // Null-terminator
1994 //
1995 DataExist = FALSE;
1996 Length = StrLen (ConfigHdr) + 1;
1997
1998 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
1999 //
2000 // Add <BlockName> length for each Offset/Width pair
2001 //
2002 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
2003 // | 8 | 4 | 7 | 4 |
2004 //
2005 DataExist = TRUE;
2006 Length = Length + (8 + 4 + 7 + 4);
2007 }
2008
2009 //
2010 // No any request block data is found. The request string can't be constructed.
2011 //
2012 if (!DataExist) {
2013 Status = EFI_SUCCESS;
2014 goto Done;
2015 }
2016
2017 //
2018 // Allocate buffer for the entire <ConfigRequest>
2019 //
2020 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
2021 if (FullConfigRequest == NULL) {
2022 Status = EFI_OUT_OF_RESOURCES;
2023 goto Done;
2024 }
2025 StringPtr = FullConfigRequest;
2026
2027 //
2028 // Start with <ConfigHdr>
2029 //
2030 StrCpy (StringPtr, ConfigHdr);
2031 StringPtr += StrLen (StringPtr);
2032
2033 //
2034 // Loop through all the Offset/Width pairs and append them to ConfigRequest
2035 //
2036 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
2037 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
2038 //
2039 // Append &OFFSET=XXXX&WIDTH=YYYY\0
2040 //
2041 UnicodeSPrint (
2042 StringPtr,
2043 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
2044 L"&OFFSET=%04X&WIDTH=%04X",
2045 BlockData->Offset,
2046 BlockData->Width
2047 );
2048 StringPtr += StrLen (StringPtr);
2049 }
2050 //
2051 // Set to the got full request string.
2052 //
2053 HiiToLower (FullConfigRequest);
2054 if (*Request != NULL) {
2055 FreePool (*Request);
2056 }
2057 *Request = FullConfigRequest;
2058 }
2059
2060 //
2061 // 4. Construct Default Value string in AltResp according to request element.
2062 // Go through all VarStorageData Entry and get the DefaultId array for each one
2063 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
2064 //
2065 DataExist = FALSE;
2066 //
2067 // Add length for <ConfigHdr> + '\0'
2068 //
2069 Length = StrLen (ConfigHdr) + 1;
2070
2071 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2072 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2073 //
2074 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
2075 // |1| StrLen (ConfigHdr) | 8 | 4 |
2076 //
2077 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
2078
2079 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2080 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2081 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2082 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2083 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2084 //
2085 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
2086 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
2087 //
2088 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
2089 DataExist = TRUE;
2090 }
2091 }
2092 }
2093 }
2094
2095 //
2096 // No default value is found. The default string doesn't exist.
2097 //
2098 if (!DataExist) {
2099 Status = EFI_SUCCESS;
2100 goto Done;
2101 }
2102
2103 //
2104 // Allocate buffer for the entire <DefaultAltCfgResp>
2105 //
2106 DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
2107 if (DefaultAltCfgResp == NULL) {
2108 Status = EFI_OUT_OF_RESOURCES;
2109 goto Done;
2110 }
2111 StringPtr = DefaultAltCfgResp;
2112
2113 //
2114 // Start with <ConfigHdr>
2115 //
2116 StrCpy (StringPtr, ConfigHdr);
2117 StringPtr += StrLen (StringPtr);
2118
2119 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
2120 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
2121 //
2122 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
2123 // |1| StrLen (ConfigHdr) | 8 | 4 |
2124 //
2125 UnicodeSPrint (
2126 StringPtr,
2127 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
2128 L"&%s&ALTCFG=%04X",
2129 ConfigHdr,
2130 DefaultId->DefaultName
2131 );
2132 StringPtr += StrLen (StringPtr);
2133
2134 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
2135 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
2136 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; LinkDefault = LinkDefault->ForwardLink) {
2137 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
2138 if (DefaultValueData->DefaultId == DefaultId->DefaultId) {
2139 //
2140 // Add <BlockConfig>
2141 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
2142 //
2143 UnicodeSPrint (
2144 StringPtr,
2145 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
2146 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
2147 BlockData->Offset,
2148 BlockData->Width
2149 );
2150 StringPtr += StrLen (StringPtr);
2151
2152 //
2153 // Convert Value to a hex string in "%x" format
2154 // NOTE: This is in the opposite byte that GUID and PATH use
2155 //
2156 Width = BlockData->Width;
2157 TmpBuffer = (UINT8 *) &(DefaultValueData->Value);
2158 for (; Width > 0; Width--) {
2159 StringPtr += UnicodeValueToString (StringPtr, PREFIX_ZERO | RADIX_HEX, TmpBuffer[Width - 1], 2);
2160 }
2161 }
2162 }
2163 }
2164 }
2165 HiiToLower (DefaultAltCfgResp);
2166
2167 //
2168 // 5. Merge string into the input AltCfgResp if the iput *AltCfgResp is not NULL.
2169 //
2170 if (*AltCfgResp != NULL && DefaultAltCfgResp != NULL) {
2171 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
2172 FreePool (DefaultAltCfgResp);
2173 } else if (*AltCfgResp == NULL) {
2174 *AltCfgResp = DefaultAltCfgResp;
2175 }
2176
2177 Done:
2178 if (RequestBlockArray != NULL) {
2179 //
2180 // Free Link Array RequestBlockArray
2181 //
2182 while (!IsListEmpty (&RequestBlockArray->Entry)) {
2183 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
2184 RemoveEntryList (&BlockData->Entry);
2185 FreePool (BlockData);
2186 }
2187
2188 FreePool (RequestBlockArray);
2189 }
2190
2191 if (VarStorageData != NULL) {
2192 //
2193 // Free link array VarStorageData
2194 //
2195 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
2196 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
2197 RemoveEntryList (&BlockData->Entry);
2198 //
2199 // Free default value link array
2200 //
2201 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
2202 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2203 RemoveEntryList (&DefaultValueData->Entry);
2204 FreePool (DefaultValueData);
2205 }
2206 FreePool (BlockData);
2207 }
2208 FreePool (VarStorageData);
2209 }
2210
2211 if (DefaultIdArray != NULL) {
2212 //
2213 // Free DefaultId Array
2214 //
2215 while (!IsListEmpty (&DefaultIdArray->Entry)) {
2216 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
2217 RemoveEntryList (&DefaultId->Entry);
2218 FreePool (DefaultId);
2219 }
2220 FreePool (DefaultIdArray);
2221 }
2222
2223 //
2224 // Free the allocated string
2225 //
2226 if (GuidStr != NULL) {
2227 FreePool (GuidStr);
2228 }
2229 if (NameStr != NULL) {
2230 FreePool (NameStr);
2231 }
2232 if (PathStr != NULL) {
2233 FreePool (PathStr);
2234 }
2235 if (ConfigHdr != NULL) {
2236 FreePool (ConfigHdr);
2237 }
2238
2239 //
2240 // Free Pacakge data
2241 //
2242 if (HiiFormPackage != NULL) {
2243 FreePool (HiiFormPackage);
2244 }
2245
2246 if (PointerProgress != NULL) {
2247 if (*Request == NULL) {
2248 *PointerProgress = NULL;
2249 } else if (EFI_ERROR (Status)) {
2250 *PointerProgress = Progress;
2251 } else {
2252 *PointerProgress = *Request + StrLen (*Request);
2253 }
2254 }
2255
2256 return Status;
2257 }
2258
2259 /**
2260 This function allows a caller to extract the current configuration
2261 for one or more named elements from one or more drivers.
2262
2263 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2264 instance.
2265 @param Request A null-terminated Unicode string in
2266 <MultiConfigRequest> format.
2267 @param Progress On return, points to a character in the Request
2268 string. Points to the string's null terminator if
2269 request was successful. Points to the most recent
2270 & before the first failing name / value pair (or
2271 the beginning of the string if the failure is in
2272 the first name / value pair) if the request was
2273 not successful.
2274 @param Results Null-terminated Unicode string in
2275 <MultiConfigAltResp> format which has all values
2276 filled in for the names in the Request string.
2277 String to be allocated by the called function.
2278
2279 @retval EFI_SUCCESS The Results string is filled with the values
2280 corresponding to all requested names.
2281 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2282 results that must be stored awaiting possible
2283 future protocols.
2284 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
2285 Progress set to the "G" in "GUID" of the routing
2286 header that doesn't match. Note: There is no
2287 requirement that all routing data be validated
2288 before any configuration extraction.
2289 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
2290 parameter would result in this type of error. The
2291 Progress parameter is set to NULL.
2292 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
2293 before the error or the beginning of the string.
2294 @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the
2295 name in question.
2296
2297 **/
2298 EFI_STATUS
2299 EFIAPI
2300 HiiConfigRoutingExtractConfig (
2301 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2302 IN CONST EFI_STRING Request,
2303 OUT EFI_STRING *Progress,
2304 OUT EFI_STRING *Results
2305 )
2306 {
2307 HII_DATABASE_PRIVATE_DATA *Private;
2308 EFI_STRING StringPtr;
2309 EFI_STRING ConfigRequest;
2310 UINTN Length;
2311 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2312 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2313 EFI_STATUS Status;
2314 LIST_ENTRY *Link;
2315 HII_DATABASE_RECORD *Database;
2316 UINT8 *DevicePathPkg;
2317 UINT8 *CurrentDevicePath;
2318 EFI_HANDLE DriverHandle;
2319 EFI_HII_HANDLE HiiHandle;
2320 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2321 EFI_STRING AccessProgress;
2322 EFI_STRING AccessResults;
2323 EFI_STRING DefaultResults;
2324 BOOLEAN FirstElement;
2325 BOOLEAN IfrDataParsedFlag;
2326
2327 if (This == NULL || Progress == NULL || Results == NULL) {
2328 return EFI_INVALID_PARAMETER;
2329 }
2330
2331 if (Request == NULL) {
2332 *Progress = NULL;
2333 return EFI_INVALID_PARAMETER;
2334 }
2335
2336 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2337 StringPtr = Request;
2338 *Progress = StringPtr;
2339 DefaultResults = NULL;
2340 ConfigRequest = NULL;
2341 Status = EFI_SUCCESS;
2342 AccessResults = NULL;
2343 DevicePath = NULL;
2344 IfrDataParsedFlag = FALSE;
2345
2346 //
2347 // The first element of <MultiConfigRequest> should be
2348 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2349 //
2350 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2351 return EFI_INVALID_PARAMETER;
2352 }
2353
2354 FirstElement = TRUE;
2355
2356 //
2357 // Allocate a fix length of memory to store Results. Reallocate memory for
2358 // Results if this fix length is insufficient.
2359 //
2360 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2361 if (*Results == NULL) {
2362 return EFI_OUT_OF_RESOURCES;
2363 }
2364
2365 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2366 //
2367 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
2368 // or most recent & before the error.
2369 //
2370 if (StringPtr == Request) {
2371 *Progress = StringPtr;
2372 } else {
2373 *Progress = StringPtr - 1;
2374 }
2375
2376 //
2377 // Process each <ConfigRequest> of <MultiConfigRequest>
2378 //
2379 Length = CalculateConfigStringLen (StringPtr);
2380 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2381 if (ConfigRequest == NULL) {
2382 Status = EFI_OUT_OF_RESOURCES;
2383 goto Done;
2384 }
2385 *(ConfigRequest + Length) = 0;
2386
2387 //
2388 // Get the UEFI device path
2389 //
2390 Status = GetDevicePath (ConfigRequest, (UINT8 **) &DevicePath);
2391 if (EFI_ERROR (Status)) {
2392 goto Done;
2393 }
2394
2395 //
2396 // Find driver which matches the routing data.
2397 //
2398 DriverHandle = NULL;
2399 HiiHandle = NULL;
2400 Database = NULL;
2401 for (Link = Private->DatabaseList.ForwardLink;
2402 Link != &Private->DatabaseList;
2403 Link = Link->ForwardLink
2404 ) {
2405 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2406 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2407 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2408 if (CompareMem (
2409 DevicePath,
2410 CurrentDevicePath,
2411 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2412 ) == 0) {
2413 DriverHandle = Database->DriverHandle;
2414 HiiHandle = Database->Handle;
2415 break;
2416 }
2417 }
2418 }
2419
2420 //
2421 // Try to find driver handle by device path.
2422 //
2423 if (DriverHandle == NULL) {
2424 TempDevicePath = DevicePath;
2425 Status = gBS->LocateDevicePath (
2426 &gEfiDevicePathProtocolGuid,
2427 &TempDevicePath,
2428 &DriverHandle
2429 );
2430 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2431 //
2432 // Routing data does not match any known driver.
2433 // Set Progress to the 'G' in "GUID" of the routing header.
2434 //
2435 *Progress = StringPtr;
2436 Status = EFI_NOT_FOUND;
2437 goto Done;
2438 }
2439 }
2440
2441 //
2442 // Check whether ConfigRequest contains request string OFFSET/WIDTH
2443 //
2444 IfrDataParsedFlag = FALSE;
2445 if ((HiiHandle != NULL) && (StrStr (ConfigRequest, L"&OFFSET=") == NULL)) {
2446 //
2447 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
2448 //
2449 IfrDataParsedFlag = TRUE;
2450 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
2451 if (EFI_ERROR (Status)) {
2452 //
2453 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2454 // Map it to the progress on <MultiConfigRequest> then return it.
2455 //
2456 *Progress = StrStr (StringPtr, AccessProgress);
2457 goto Done;
2458 }
2459 //
2460 // Not any request block is found.
2461 //
2462 if (StrStr (ConfigRequest, L"&OFFSET=") == NULL) {
2463 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
2464 goto NextConfigString;
2465 }
2466 }
2467
2468 //
2469 // Call corresponding ConfigAccess protocol to extract settings
2470 //
2471 Status = gBS->HandleProtocol (
2472 DriverHandle,
2473 &gEfiHiiConfigAccessProtocolGuid,
2474 (VOID **) &ConfigAccess
2475 );
2476 ASSERT_EFI_ERROR (Status);
2477
2478 Status = ConfigAccess->ExtractConfig (
2479 ConfigAccess,
2480 ConfigRequest,
2481 &AccessProgress,
2482 &AccessResults
2483 );
2484 if (EFI_ERROR (Status)) {
2485 //
2486 // AccessProgress indicates the parsing progress on <ConfigRequest>.
2487 // Map it to the progress on <MultiConfigRequest> then return it.
2488 //
2489 *Progress = StrStr (StringPtr, AccessProgress);
2490 goto Done;
2491 }
2492
2493 //
2494 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2495 // which seperates the first <ConfigAltResp> and the following ones.
2496 //
2497 ASSERT (*AccessProgress == 0);
2498
2499 //
2500 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2501 //
2502 if (!IfrDataParsedFlag && HiiHandle != NULL) {
2503 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2504 ASSERT_EFI_ERROR (Status);
2505 }
2506
2507 FreePool (DevicePath);
2508 DevicePath = NULL;
2509
2510 if (DefaultResults != NULL) {
2511 Status = MergeDefaultString (&AccessResults, DefaultResults);
2512 ASSERT_EFI_ERROR (Status);
2513 FreePool (DefaultResults);
2514 DefaultResults = NULL;
2515 }
2516
2517 NextConfigString:
2518 if (!FirstElement) {
2519 Status = AppendToMultiString (Results, L"&");
2520 ASSERT_EFI_ERROR (Status);
2521 }
2522
2523 Status = AppendToMultiString (Results, AccessResults);
2524 ASSERT_EFI_ERROR (Status);
2525
2526 FirstElement = FALSE;
2527
2528 FreePool (AccessResults);
2529 AccessResults = NULL;
2530 FreePool (ConfigRequest);
2531 ConfigRequest = NULL;
2532
2533 //
2534 // Go to next <ConfigRequest> (skip '&').
2535 //
2536 StringPtr += Length;
2537 if (*StringPtr == 0) {
2538 *Progress = StringPtr;
2539 break;
2540 }
2541
2542 StringPtr++;
2543 }
2544
2545 Done:
2546 if (EFI_ERROR (Status)) {
2547 FreePool (*Results);
2548 *Results = NULL;
2549 }
2550
2551 if (ConfigRequest != NULL) {
2552 FreePool (ConfigRequest);
2553 }
2554
2555 if (AccessResults != NULL) {
2556 FreePool (AccessResults);
2557 }
2558
2559 if (DefaultResults != NULL) {
2560 FreePool (DefaultResults);
2561 }
2562
2563 if (DevicePath != NULL) {
2564 FreePool (DevicePath);
2565 }
2566
2567 return Status;
2568 }
2569
2570
2571 /**
2572 This function allows the caller to request the current configuration for the
2573 entirety of the current HII database and returns the data in a
2574 null-terminated Unicode string.
2575
2576 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2577 instance.
2578 @param Results Null-terminated Unicode string in
2579 <MultiConfigAltResp> format which has all values
2580 filled in for the names in the Request string.
2581 String to be allocated by the called function.
2582 De-allocation is up to the caller.
2583
2584 @retval EFI_SUCCESS The Results string is filled with the values
2585 corresponding to all requested names.
2586 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2587 results that must be stored awaiting possible
2588 future protocols.
2589 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
2590 parameter would result in this type of error.
2591
2592 **/
2593 EFI_STATUS
2594 EFIAPI
2595 HiiConfigRoutingExportConfig (
2596 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2597 OUT EFI_STRING *Results
2598 )
2599 {
2600 EFI_STATUS Status;
2601 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2602 EFI_STRING AccessResults;
2603 EFI_STRING Progress;
2604 EFI_STRING StringPtr;
2605 EFI_STRING ConfigRequest;
2606 UINTN Index;
2607 EFI_HANDLE *ConfigAccessHandles;
2608 UINTN NumberConfigAccessHandles;
2609 BOOLEAN FirstElement;
2610 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2611 EFI_HII_HANDLE HiiHandle;
2612 EFI_STRING DefaultResults;
2613 HII_DATABASE_PRIVATE_DATA *Private;
2614 LIST_ENTRY *Link;
2615 HII_DATABASE_RECORD *Database;
2616 UINT8 *DevicePathPkg;
2617 UINT8 *CurrentDevicePath;
2618 BOOLEAN IfrDataParsedFlag;
2619
2620 if (This == NULL || Results == NULL) {
2621 return EFI_INVALID_PARAMETER;
2622 }
2623
2624 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2625
2626 //
2627 // Allocate a fix length of memory to store Results. Reallocate memory for
2628 // Results if this fix length is insufficient.
2629 //
2630 *Results = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
2631 if (*Results == NULL) {
2632 return EFI_OUT_OF_RESOURCES;
2633 }
2634
2635 NumberConfigAccessHandles = 0;
2636 Status = gBS->LocateHandleBuffer (
2637 ByProtocol,
2638 &gEfiHiiConfigAccessProtocolGuid,
2639 NULL,
2640 &NumberConfigAccessHandles,
2641 &ConfigAccessHandles
2642 );
2643 if (EFI_ERROR (Status)) {
2644 return Status;
2645 }
2646
2647 FirstElement = TRUE;
2648
2649 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
2650 Status = gBS->HandleProtocol (
2651 ConfigAccessHandles[Index],
2652 &gEfiHiiConfigAccessProtocolGuid,
2653 (VOID **) &ConfigAccess
2654 );
2655 if (EFI_ERROR (Status)) {
2656 continue;
2657 }
2658
2659 //
2660 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
2661 //
2662 IfrDataParsedFlag = FALSE;
2663 Progress = NULL;
2664 HiiHandle = NULL;
2665 DefaultResults = NULL;
2666 Database = NULL;
2667 ConfigRequest = NULL;
2668 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
2669 if (DevicePath != NULL) {
2670 for (Link = Private->DatabaseList.ForwardLink;
2671 Link != &Private->DatabaseList;
2672 Link = Link->ForwardLink
2673 ) {
2674 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2675 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2676 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2677 if (CompareMem (
2678 DevicePath,
2679 CurrentDevicePath,
2680 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2681 ) == 0) {
2682 HiiHandle = Database->Handle;
2683 break;
2684 }
2685 }
2686 }
2687 }
2688
2689 Status = ConfigAccess->ExtractConfig (
2690 ConfigAccess,
2691 NULL,
2692 &Progress,
2693 &AccessResults
2694 );
2695 if (EFI_ERROR (Status)) {
2696 //
2697 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2698 //
2699 if (HiiHandle != NULL && DevicePath != NULL) {
2700 IfrDataParsedFlag = TRUE;
2701 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
2702 //
2703 // Get the full request string to get the Current setting again.
2704 //
2705 if (!EFI_ERROR (Status) && ConfigRequest != NULL) {
2706 Status = ConfigAccess->ExtractConfig (
2707 ConfigAccess,
2708 ConfigRequest,
2709 &Progress,
2710 &AccessResults
2711 );
2712 FreePool (ConfigRequest);
2713 } else {
2714 Status = EFI_NOT_FOUND;
2715 }
2716 }
2717 }
2718
2719 if (!EFI_ERROR (Status)) {
2720 //
2721 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
2722 //
2723 if (!IfrDataParsedFlag && HiiHandle != NULL && DevicePath != NULL) {
2724 StringPtr = StrStr (AccessResults, L"&GUID=");
2725 if (StringPtr != NULL) {
2726 *StringPtr = 0;
2727 }
2728 if (StrStr (AccessResults, L"&OFFSET=") != NULL) {
2729 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
2730 ASSERT_EFI_ERROR (Status);
2731 }
2732 if (StringPtr != NULL) {
2733 *StringPtr = L'&';
2734 }
2735 }
2736 //
2737 // Merge the default sting from IFR code into the got setting from driver.
2738 //
2739 if (DefaultResults != NULL) {
2740 Status = MergeDefaultString (&AccessResults, DefaultResults);
2741 ASSERT_EFI_ERROR (Status);
2742 FreePool (DefaultResults);
2743 DefaultResults = NULL;
2744 }
2745
2746 //
2747 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
2748 // which seperates the first <ConfigAltResp> and the following ones.
2749 //
2750 if (!FirstElement) {
2751 Status = AppendToMultiString (Results, L"&");
2752 ASSERT_EFI_ERROR (Status);
2753 }
2754
2755 Status = AppendToMultiString (Results, AccessResults);
2756 ASSERT_EFI_ERROR (Status);
2757
2758 FirstElement = FALSE;
2759
2760 FreePool (AccessResults);
2761 AccessResults = NULL;
2762 }
2763 }
2764 FreePool (ConfigAccessHandles);
2765
2766 return EFI_SUCCESS;
2767 }
2768
2769
2770 /**
2771 This function processes the results of processing forms and routes it to the
2772 appropriate handlers or storage.
2773
2774 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2775 instance.
2776 @param Configuration A null-terminated Unicode string in
2777 <MulltiConfigResp> format.
2778 @param Progress A pointer to a string filled in with the offset of
2779 the most recent & before the first failing name /
2780 value pair (or the beginning of the string if the
2781 failure is in the first name / value pair) or the
2782 terminating NULL if all was successful.
2783
2784 @retval EFI_SUCCESS The results have been distributed or are awaiting
2785 distribution.
2786 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
2787 results that must be stored awaiting possible
2788 future protocols.
2789 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
2790 would result in this type of error.
2791 @retval EFI_NOT_FOUND Target for the specified routing data was not
2792 found.
2793
2794 **/
2795 EFI_STATUS
2796 EFIAPI
2797 HiiConfigRoutingRouteConfig (
2798 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
2799 IN CONST EFI_STRING Configuration,
2800 OUT EFI_STRING *Progress
2801 )
2802 {
2803 HII_DATABASE_PRIVATE_DATA *Private;
2804 EFI_STRING StringPtr;
2805 EFI_STRING ConfigResp;
2806 UINTN Length;
2807 EFI_STATUS Status;
2808 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
2809 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
2810 LIST_ENTRY *Link;
2811 HII_DATABASE_RECORD *Database;
2812 UINT8 *DevicePathPkg;
2813 UINT8 *CurrentDevicePath;
2814 EFI_HANDLE DriverHandle;
2815 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
2816 EFI_STRING AccessProgress;
2817
2818 if (This == NULL || Progress == NULL) {
2819 return EFI_INVALID_PARAMETER;
2820 }
2821
2822 if (Configuration == NULL) {
2823 *Progress = NULL;
2824 return EFI_INVALID_PARAMETER;
2825 }
2826
2827 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
2828 StringPtr = Configuration;
2829 *Progress = StringPtr;
2830
2831 //
2832 // The first element of <MultiConfigResp> should be
2833 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
2834 //
2835 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
2836 return EFI_INVALID_PARAMETER;
2837 }
2838
2839 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
2840 //
2841 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
2842 // or most recent & before the error.
2843 //
2844 if (StringPtr == Configuration) {
2845 *Progress = StringPtr;
2846 } else {
2847 *Progress = StringPtr - 1;
2848 }
2849
2850 //
2851 // Process each <ConfigResp> of <MultiConfigResp>
2852 //
2853 Length = CalculateConfigStringLen (StringPtr);
2854 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
2855 if (ConfigResp == NULL) {
2856 return EFI_OUT_OF_RESOURCES;
2857 }
2858 //
2859 // Append '\0' to the end of ConfigRequest
2860 //
2861 *(ConfigResp + Length) = 0;
2862
2863 //
2864 // Get the UEFI device path
2865 //
2866 Status = GetDevicePath (ConfigResp, (UINT8 **) &DevicePath);
2867 if (EFI_ERROR (Status)) {
2868 FreePool (ConfigResp);
2869 return Status;
2870 }
2871
2872 //
2873 // Find driver which matches the routing data.
2874 //
2875 DriverHandle = NULL;
2876 for (Link = Private->DatabaseList.ForwardLink;
2877 Link != &Private->DatabaseList;
2878 Link = Link->ForwardLink
2879 ) {
2880 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
2881
2882 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
2883 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
2884 if (CompareMem (
2885 DevicePath,
2886 CurrentDevicePath,
2887 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) CurrentDevicePath)
2888 ) == 0) {
2889 DriverHandle = Database->DriverHandle;
2890 break;
2891 }
2892 }
2893 }
2894
2895 //
2896 // Try to find driver handle by device path.
2897 //
2898 if (DriverHandle == NULL) {
2899 TempDevicePath = DevicePath;
2900 Status = gBS->LocateDevicePath (
2901 &gEfiDevicePathProtocolGuid,
2902 &TempDevicePath,
2903 &DriverHandle
2904 );
2905 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
2906 //
2907 // Routing data does not match any known driver.
2908 // Set Progress to the 'G' in "GUID" of the routing header.
2909 //
2910 FreePool (DevicePath);
2911 *Progress = StringPtr;
2912 FreePool (ConfigResp);
2913 return EFI_NOT_FOUND;
2914 }
2915 }
2916
2917 FreePool (DevicePath);
2918
2919 //
2920 // Call corresponding ConfigAccess protocol to route settings
2921 //
2922 Status = gBS->HandleProtocol (
2923 DriverHandle,
2924 &gEfiHiiConfigAccessProtocolGuid,
2925 (VOID **) &ConfigAccess
2926 );
2927 ASSERT_EFI_ERROR (Status);
2928
2929 Status = ConfigAccess->RouteConfig (
2930 ConfigAccess,
2931 ConfigResp,
2932 &AccessProgress
2933 );
2934
2935 if (EFI_ERROR (Status)) {
2936 //
2937 // AccessProgress indicates the parsing progress on <ConfigResp>.
2938 // Map it to the progress on <MultiConfigResp> then return it.
2939 //
2940 *Progress = StrStr (StringPtr, AccessProgress);
2941
2942 FreePool (ConfigResp);
2943 return Status;
2944 }
2945
2946 FreePool (ConfigResp);
2947 ConfigResp = NULL;
2948
2949 //
2950 // Go to next <ConfigResp> (skip '&').
2951 //
2952 StringPtr += Length;
2953 if (*StringPtr == 0) {
2954 *Progress = StringPtr;
2955 break;
2956 }
2957
2958 StringPtr++;
2959
2960 }
2961
2962 return EFI_SUCCESS;
2963 }
2964
2965
2966 /**
2967 This helper function is to be called by drivers to map configuration data
2968 stored in byte array ("block") formats such as UEFI Variables into current
2969 configuration strings.
2970
2971 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
2972 instance.
2973 @param ConfigRequest A null-terminated Unicode string in
2974 <ConfigRequest> format.
2975 @param Block Array of bytes defining the block's configuration.
2976 @param BlockSize Length in bytes of Block.
2977 @param Config Filled-in configuration string. String allocated
2978 by the function. Returned only if call is
2979 successful. It is <ConfigResp> string format.
2980 @param Progress A pointer to a string filled in with the offset of
2981 the most recent & before the first failing
2982 name/value pair (or the beginning of the string if
2983 the failure is in the first name / value pair) or
2984 the terminating NULL if all was successful.
2985
2986 @retval EFI_SUCCESS The request succeeded. Progress points to the null
2987 terminator at the end of the ConfigRequest
2988 string.
2989 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
2990 points to the first character of ConfigRequest.
2991 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
2992 Block parameter would result in this type of
2993 error. Progress points to the first character of
2994 ConfigRequest.
2995 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
2996 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
2997 Block is left updated and Progress points at
2998 the "&" preceding the first non-<BlockName>.
2999
3000 **/
3001 EFI_STATUS
3002 EFIAPI
3003 HiiBlockToConfig (
3004 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3005 IN CONST EFI_STRING ConfigRequest,
3006 IN CONST UINT8 *Block,
3007 IN CONST UINTN BlockSize,
3008 OUT EFI_STRING *Config,
3009 OUT EFI_STRING *Progress
3010 )
3011 {
3012 HII_DATABASE_PRIVATE_DATA *Private;
3013 EFI_STRING StringPtr;
3014 UINTN Length;
3015 EFI_STATUS Status;
3016 EFI_STRING TmpPtr;
3017 UINT8 *TmpBuffer;
3018 UINTN Offset;
3019 UINTN Width;
3020 UINT8 *Value;
3021 EFI_STRING ValueStr;
3022 EFI_STRING ConfigElement;
3023 UINTN Index;
3024 UINT8 *TemBuffer;
3025 CHAR16 *TemString;
3026
3027 if (This == NULL || Progress == NULL || Config == NULL) {
3028 return EFI_INVALID_PARAMETER;
3029 }
3030
3031 if (Block == NULL || ConfigRequest == NULL) {
3032 *Progress = ConfigRequest;
3033 return EFI_INVALID_PARAMETER;
3034 }
3035
3036
3037 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3038 ASSERT (Private != NULL);
3039
3040 StringPtr = ConfigRequest;
3041 ValueStr = NULL;
3042 Value = NULL;
3043 ConfigElement = NULL;
3044
3045 //
3046 // Allocate a fix length of memory to store Results. Reallocate memory for
3047 // Results if this fix length is insufficient.
3048 //
3049 *Config = (EFI_STRING) AllocateZeroPool (MAX_STRING_LENGTH);
3050 if (*Config == NULL) {
3051 return EFI_OUT_OF_RESOURCES;
3052 }
3053
3054 //
3055 // Jump <ConfigHdr>
3056 //
3057 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3058 *Progress = StringPtr;
3059 Status = EFI_INVALID_PARAMETER;
3060 goto Exit;
3061 }
3062 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3063 StringPtr++;
3064 }
3065 if (*StringPtr == 0) {
3066 *Progress = StringPtr - 1;
3067 Status = EFI_INVALID_PARAMETER;
3068 goto Exit;
3069 }
3070
3071 while (*StringPtr != L'&' && *StringPtr != 0) {
3072 StringPtr++;
3073 }
3074 if (*StringPtr == 0) {
3075 *Progress = StringPtr - 1;
3076 Status = EFI_INVALID_PARAMETER;
3077 goto Exit;
3078 }
3079 //
3080 // Skip '&'
3081 //
3082 StringPtr++;
3083
3084 //
3085 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
3086 //
3087 Length = StringPtr - ConfigRequest;
3088 CopyMem (*Config, ConfigRequest, Length * sizeof (CHAR16));
3089
3090 //
3091 // Parse each <RequestElement> if exists
3092 // Only <BlockName> format is supported by this help function.
3093 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
3094 //
3095 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3096 //
3097 // Back up the header of one <BlockName>
3098 //
3099 TmpPtr = StringPtr;
3100
3101 StringPtr += StrLen (L"OFFSET=");
3102 //
3103 // Get Offset
3104 //
3105 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3106 if (Status == EFI_OUT_OF_RESOURCES) {
3107 *Progress = ConfigRequest;
3108 goto Exit;
3109 }
3110 Offset = 0;
3111 CopyMem (
3112 &Offset,
3113 TmpBuffer,
3114 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3115 );
3116 FreePool (TmpBuffer);
3117
3118 StringPtr += Length;
3119 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3120 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3121 Status = EFI_INVALID_PARAMETER;
3122 goto Exit;
3123 }
3124 StringPtr += StrLen (L"&WIDTH=");
3125
3126 //
3127 // Get Width
3128 //
3129 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3130 if (Status == EFI_OUT_OF_RESOURCES) {
3131 *Progress = ConfigRequest;
3132 goto Exit;
3133 }
3134 Width = 0;
3135 CopyMem (
3136 &Width,
3137 TmpBuffer,
3138 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3139 );
3140 FreePool (TmpBuffer);
3141
3142 StringPtr += Length;
3143 if (*StringPtr != 0 && *StringPtr != L'&') {
3144 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3145 Status = EFI_INVALID_PARAMETER;
3146 goto Exit;
3147 }
3148
3149 //
3150 // Calculate Value and convert it to hex string.
3151 //
3152 if (Offset + Width > BlockSize) {
3153 *Progress = StringPtr;
3154 Status = EFI_DEVICE_ERROR;
3155 goto Exit;
3156 }
3157
3158 Value = (UINT8 *) AllocateZeroPool (Width);
3159 if (Value == NULL) {
3160 *Progress = ConfigRequest;
3161 Status = EFI_OUT_OF_RESOURCES;
3162 goto Exit;
3163 }
3164
3165 CopyMem (Value, (UINT8 *) Block + Offset, Width);
3166
3167 Length = Width * 2 + 1;
3168 ValueStr = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3169 if (ValueStr == NULL) {
3170 *Progress = ConfigRequest;
3171 Status = EFI_OUT_OF_RESOURCES;
3172 goto Exit;
3173 }
3174
3175 TemString = ValueStr;
3176 TemBuffer = Value + Width - 1;
3177 for (Index = 0; Index < Width; Index ++, TemBuffer --) {
3178 TemString += UnicodeValueToString (TemString, PREFIX_ZERO | RADIX_HEX, *TemBuffer, 2);
3179 }
3180
3181 FreePool (Value);
3182 Value = NULL;
3183
3184 //
3185 // Build a ConfigElement
3186 //
3187 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
3188 ConfigElement = (EFI_STRING) AllocateZeroPool (Length * sizeof (CHAR16));
3189 if (ConfigElement == NULL) {
3190 Status = EFI_OUT_OF_RESOURCES;
3191 goto Exit;
3192 }
3193 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
3194 if (*StringPtr == 0) {
3195 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
3196 }
3197 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
3198 StrCat (ConfigElement, L"VALUE=");
3199 StrCat (ConfigElement, ValueStr);
3200
3201 AppendToMultiString (Config, ConfigElement);
3202
3203 FreePool (ConfigElement);
3204 FreePool (ValueStr);
3205 ConfigElement = NULL;
3206 ValueStr = NULL;
3207
3208 //
3209 // If '\0', parsing is finished. Otherwise skip '&' to continue
3210 //
3211 if (*StringPtr == 0) {
3212 break;
3213 }
3214 AppendToMultiString (Config, L"&");
3215 StringPtr++;
3216
3217 }
3218
3219 if (*StringPtr != 0) {
3220 *Progress = StringPtr - 1;
3221 Status = EFI_INVALID_PARAMETER;
3222 goto Exit;
3223 }
3224
3225 HiiToLower (*Config);
3226 *Progress = StringPtr;
3227 return EFI_SUCCESS;
3228
3229 Exit:
3230 if (*Config != NULL) {
3231 FreePool (*Config);
3232 *Config = NULL;
3233 }
3234 if (ValueStr != NULL) {
3235 FreePool (ValueStr);
3236 }
3237 if (Value != NULL) {
3238 FreePool (Value);
3239 }
3240 if (ConfigElement != NULL) {
3241 FreePool (ConfigElement);
3242 }
3243
3244 return Status;
3245
3246 }
3247
3248
3249 /**
3250 This helper function is to be called by drivers to map configuration strings
3251 to configurations stored in byte array ("block") formats such as UEFI Variables.
3252
3253 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3254 instance.
3255 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
3256 format.
3257 @param Block A possibly null array of bytes representing the
3258 current block. Only bytes referenced in the
3259 ConfigResp string in the block are modified. If
3260 this parameter is null or if the *BlockSize
3261 parameter is (on input) shorter than required by
3262 the Configuration string, only the BlockSize
3263 parameter is updated and an appropriate status
3264 (see below) is returned.
3265 @param BlockSize The length of the Block in units of UINT8. On
3266 input, this is the size of the Block. On output,
3267 if successful, contains the index of the last
3268 modified byte in the Block.
3269 @param Progress On return, points to an element of the ConfigResp
3270 string filled in with the offset of the most
3271 recent '&' before the first failing name / value
3272 pair (or the beginning of the string if the
3273 failure is in the first name / value pair) or the
3274 terminating NULL if all was successful.
3275
3276 @retval EFI_SUCCESS The request succeeded. Progress points to the null
3277 terminator at the end of the ConfigResp string.
3278 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
3279 points to the first character of ConfigResp.
3280 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
3281 Block parameter would result in this type of
3282 error. Progress points to the first character of
3283 ConfigResp.
3284 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
3285 value pair. Block is left updated and
3286 Progress points at the '&' preceding the first
3287 non-<BlockName>.
3288 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
3289 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
3290 Progress points to the "G" in "GUID" of the errant
3291 routing data.
3292
3293 **/
3294 EFI_STATUS
3295 EFIAPI
3296 HiiConfigToBlock (
3297 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3298 IN CONST EFI_STRING ConfigResp,
3299 IN OUT UINT8 *Block,
3300 IN OUT UINTN *BlockSize,
3301 OUT EFI_STRING *Progress
3302 )
3303 {
3304 HII_DATABASE_PRIVATE_DATA *Private;
3305 EFI_STRING StringPtr;
3306 UINTN Length;
3307 EFI_STATUS Status;
3308 UINT8 *TmpBuffer;
3309 UINTN Offset;
3310 UINTN Width;
3311 UINT8 *Value;
3312 UINTN BufferSize;
3313 UINTN MaxBlockSize;
3314
3315 if (This == NULL || BlockSize == NULL || Progress == NULL) {
3316 return EFI_INVALID_PARAMETER;
3317 }
3318
3319 *Progress = ConfigResp;
3320 if (ConfigResp == NULL) {
3321 return EFI_INVALID_PARAMETER;
3322 }
3323
3324 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
3325 ASSERT (Private != NULL);
3326
3327 StringPtr = ConfigResp;
3328 BufferSize = *BlockSize;
3329 Value = NULL;
3330 MaxBlockSize = 0;
3331
3332 //
3333 // Jump <ConfigHdr>
3334 //
3335 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3336 *Progress = StringPtr;
3337 Status = EFI_INVALID_PARAMETER;
3338 goto Exit;
3339 }
3340 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
3341 StringPtr++;
3342 }
3343 if (*StringPtr == 0) {
3344 *Progress = StringPtr;
3345 Status = EFI_INVALID_PARAMETER;
3346 goto Exit;
3347 }
3348
3349 while (*StringPtr != L'&' && *StringPtr != 0) {
3350 StringPtr++;
3351 }
3352 if (*StringPtr == 0) {
3353 *Progress = StringPtr;
3354 Status = EFI_INVALID_PARAMETER;
3355 goto Exit;
3356 }
3357 //
3358 // Skip '&'
3359 //
3360 StringPtr++;
3361
3362 //
3363 // Parse each <ConfigElement> if exists
3364 // Only <BlockConfig> format is supported by this help function.
3365 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
3366 //
3367 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
3368 StringPtr += StrLen (L"OFFSET=");
3369 //
3370 // Get Offset
3371 //
3372 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3373 if (EFI_ERROR (Status)) {
3374 *Progress = ConfigResp;
3375 goto Exit;
3376 }
3377 Offset = 0;
3378 CopyMem (
3379 &Offset,
3380 TmpBuffer,
3381 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3382 );
3383 FreePool (TmpBuffer);
3384
3385 StringPtr += Length;
3386 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3387 *Progress = StringPtr - Length - StrLen (L"OFFSET=") - 1;
3388 Status = EFI_INVALID_PARAMETER;
3389 goto Exit;
3390 }
3391 StringPtr += StrLen (L"&WIDTH=");
3392
3393 //
3394 // Get Width
3395 //
3396 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3397 if (Status == EFI_OUT_OF_RESOURCES) {
3398 *Progress = ConfigResp;
3399 goto Exit;
3400 }
3401 Width = 0;
3402 CopyMem (
3403 &Width,
3404 TmpBuffer,
3405 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
3406 );
3407 FreePool (TmpBuffer);
3408
3409 StringPtr += Length;
3410 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
3411 *Progress = StringPtr - Length - StrLen (L"&WIDTH=");
3412 Status = EFI_INVALID_PARAMETER;
3413 goto Exit;
3414 }
3415 StringPtr += StrLen (L"&VALUE=");
3416
3417 //
3418 // Get Value
3419 //
3420 Status = GetValueOfNumber (StringPtr, &Value, &Length);
3421 if (EFI_ERROR (Status)) {
3422 *Progress = ConfigResp;
3423 goto Exit;
3424 }
3425
3426 StringPtr += Length;
3427 if (*StringPtr != 0 && *StringPtr != L'&') {
3428 *Progress = StringPtr - Length - 7;
3429 Status = EFI_INVALID_PARAMETER;
3430 goto Exit;
3431 }
3432
3433 //
3434 // Update the Block with configuration info
3435 //
3436 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
3437 CopyMem (Block + Offset, Value, Width);
3438 }
3439 if (Offset + Width > MaxBlockSize) {
3440 MaxBlockSize = Offset + Width;
3441 }
3442
3443 FreePool (Value);
3444 Value = NULL;
3445
3446 //
3447 // If '\0', parsing is finished. Otherwise skip '&' to continue
3448 //
3449 if (*StringPtr == 0) {
3450 break;
3451 }
3452
3453 StringPtr++;
3454 }
3455
3456 //
3457 // The input string is ConfigAltResp format.
3458 //
3459 if ((*StringPtr != 0) && (StrnCmp (StringPtr, L"&GUID=", StrLen (L"&GUID=")) != 0)) {
3460 *Progress = StringPtr - 1;
3461 Status = EFI_INVALID_PARAMETER;
3462 goto Exit;
3463 }
3464
3465 *Progress = StringPtr + StrLen (StringPtr);
3466 *BlockSize = MaxBlockSize - 1;
3467
3468 if (MaxBlockSize > BufferSize) {
3469 *BlockSize = MaxBlockSize;
3470 if (Block != NULL) {
3471 return EFI_DEVICE_ERROR;
3472 }
3473 }
3474
3475 if (Block == NULL) {
3476 *Progress = ConfigResp;
3477 return EFI_INVALID_PARAMETER;
3478 }
3479
3480 return EFI_SUCCESS;
3481
3482 Exit:
3483
3484 if (Value != NULL) {
3485 FreePool (Value);
3486 }
3487 return Status;
3488 }
3489
3490
3491 /**
3492 This helper function is to be called by drivers to extract portions of
3493 a larger configuration string.
3494
3495 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
3496 instance.
3497 @param Configuration A null-terminated Unicode string in
3498 <MultiConfigAltResp> format.
3499 @param Guid A pointer to the GUID value to search for in the
3500 routing portion of the ConfigResp string when
3501 retrieving the requested data. If Guid is NULL,
3502 then all GUID values will be searched for.
3503 @param Name A pointer to the NAME value to search for in the
3504 routing portion of the ConfigResp string when
3505 retrieving the requested data. If Name is NULL,
3506 then all Name values will be searched for.
3507 @param DevicePath A pointer to the PATH value to search for in the
3508 routing portion of the ConfigResp string when
3509 retrieving the requested data. If DevicePath is
3510 NULL, then all DevicePath values will be searched
3511 for.
3512 @param AltCfgId A pointer to the ALTCFG value to search for in the
3513 routing portion of the ConfigResp string when
3514 retrieving the requested data. If this parameter
3515 is NULL, then the current setting will be
3516 retrieved.
3517 @param AltCfgResp A pointer to a buffer which will be allocated by
3518 the function which contains the retrieved string
3519 as requested. This buffer is only allocated if
3520 the call was successful. It is <ConfigResp> format.
3521
3522 @retval EFI_SUCCESS The request succeeded. The requested data was
3523 extracted and placed in the newly allocated
3524 AltCfgResp buffer.
3525 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
3526 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
3527 @retval EFI_NOT_FOUND Target for the specified routing data was not
3528 found.
3529
3530 **/
3531 EFI_STATUS
3532 EFIAPI
3533 HiiGetAltCfg (
3534 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
3535 IN CONST EFI_STRING Configuration,
3536 IN CONST EFI_GUID *Guid,
3537 IN CONST EFI_STRING Name,
3538 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3539 IN CONST UINT16 *AltCfgId,
3540 OUT EFI_STRING *AltCfgResp
3541 )
3542 {
3543 EFI_STATUS Status;
3544 EFI_STRING StringPtr;
3545 EFI_STRING HdrStart;
3546 EFI_STRING HdrEnd;
3547 EFI_STRING TmpPtr;
3548 UINTN Length;
3549 EFI_STRING GuidStr;
3550 EFI_STRING NameStr;
3551 EFI_STRING PathStr;
3552 EFI_STRING AltIdStr;
3553 EFI_STRING Result;
3554 BOOLEAN GuidFlag;
3555 BOOLEAN NameFlag;
3556 BOOLEAN PathFlag;
3557
3558 HdrStart = NULL;
3559 HdrEnd = NULL;
3560 GuidStr = NULL;
3561 NameStr = NULL;
3562 PathStr = NULL;
3563 AltIdStr = NULL;
3564 Result = NULL;
3565 GuidFlag = FALSE;
3566 NameFlag = FALSE;
3567 PathFlag = FALSE;
3568
3569 if (This == NULL || Configuration == NULL || AltCfgResp == NULL) {
3570 return EFI_INVALID_PARAMETER;
3571 }
3572
3573 StringPtr = Configuration;
3574 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
3575 return EFI_INVALID_PARAMETER;
3576 }
3577
3578 //
3579 // Generate the sub string for later matching.
3580 //
3581 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *) Guid, 1, &GuidStr);
3582 GenerateSubStr (
3583 L"PATH=",
3584 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *) DevicePath),
3585 (VOID *) DevicePath,
3586 1,
3587 &PathStr
3588 );
3589 if (AltCfgId != NULL) {
3590 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *) AltCfgId, 3, &AltIdStr);
3591 }
3592 if (Name != NULL) {
3593 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *) Name, 2, &NameStr);
3594 } else {
3595 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3596 }
3597
3598 while (*StringPtr != 0) {
3599 //
3600 // Try to match the GUID
3601 //
3602 if (!GuidFlag) {
3603 TmpPtr = StrStr (StringPtr, GuidStr);
3604 if (TmpPtr == NULL) {
3605 Status = EFI_NOT_FOUND;
3606 goto Exit;
3607 }
3608 HdrStart = TmpPtr;
3609
3610 //
3611 // Jump to <NameHdr>
3612 //
3613 if (Guid != NULL) {
3614 StringPtr = TmpPtr + StrLen (GuidStr);
3615 } else {
3616 StringPtr = StrStr (TmpPtr, L"NAME=");
3617 if (StringPtr == NULL) {
3618 Status = EFI_NOT_FOUND;
3619 goto Exit;
3620 }
3621 }
3622 GuidFlag = TRUE;
3623 }
3624
3625 //
3626 // Try to match the NAME
3627 //
3628 if (GuidFlag && !NameFlag) {
3629 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
3630 GuidFlag = FALSE;
3631 } else {
3632 //
3633 // Jump to <PathHdr>
3634 //
3635 if (Name != NULL) {
3636 StringPtr += StrLen (NameStr);
3637 } else {
3638 StringPtr = StrStr (StringPtr, L"PATH=");
3639 if (StringPtr == NULL) {
3640 Status = EFI_NOT_FOUND;
3641 goto Exit;
3642 }
3643 }
3644 NameFlag = TRUE;
3645 }
3646 }
3647
3648 //
3649 // Try to match the DevicePath
3650 //
3651 if (GuidFlag && NameFlag && !PathFlag) {
3652 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
3653 GuidFlag = FALSE;
3654 NameFlag = FALSE;
3655 } else {
3656 //
3657 // Jump to '&' before <DescHdr> or <ConfigBody>
3658 //
3659 if (DevicePath != NULL) {
3660 StringPtr += StrLen (PathStr);
3661 } else {
3662 StringPtr = StrStr (StringPtr, L"&");
3663 if (StringPtr == NULL) {
3664 Status = EFI_NOT_FOUND;
3665 goto Exit;
3666 }
3667 StringPtr ++;
3668 }
3669 PathFlag = TRUE;
3670 HdrEnd = StringPtr;
3671 }
3672 }
3673
3674 //
3675 // Try to match the AltCfgId
3676 //
3677 if (GuidFlag && NameFlag && PathFlag) {
3678 if (AltCfgId == NULL) {
3679 //
3680 // Return Current Setting when AltCfgId is NULL.
3681 //
3682 Status = OutputConfigBody (StringPtr, &Result);
3683 goto Exit;
3684 }
3685 //
3686 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
3687 //
3688 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
3689 GuidFlag = FALSE;
3690 NameFlag = FALSE;
3691 PathFlag = FALSE;
3692 } else {
3693 //
3694 // Skip AltIdStr and &
3695 //
3696 StringPtr = StringPtr + StrLen (AltIdStr);
3697 Status = OutputConfigBody (StringPtr, &Result);
3698 goto Exit;
3699 }
3700 }
3701 }
3702
3703 Status = EFI_NOT_FOUND;
3704
3705 Exit:
3706 *AltCfgResp = NULL;
3707 if (!EFI_ERROR (Status) && (Result != NULL)) {
3708 //
3709 // Copy the <ConfigHdr> and <ConfigBody>
3710 //
3711 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
3712 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
3713 if (*AltCfgResp == NULL) {
3714 Status = EFI_OUT_OF_RESOURCES;
3715 } else {
3716 StrnCpy (*AltCfgResp, HdrStart, HdrEnd - HdrStart);
3717 StrCat (*AltCfgResp, Result);
3718 Status = EFI_SUCCESS;
3719 }
3720 }
3721
3722 if (GuidStr != NULL) {
3723 FreePool (GuidStr);
3724 }
3725 if (NameStr != NULL) {
3726 FreePool (NameStr);
3727 }
3728 if (PathStr != NULL) {
3729 FreePool (PathStr);
3730 }
3731 if (AltIdStr != NULL) {
3732 FreePool (AltIdStr);
3733 }
3734 if (Result != NULL) {
3735 FreePool (Result);
3736 }
3737
3738 return Status;
3739
3740 }
3741
3742