]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
2f792d296530a2a3b4f5739dd60c8c51329bc6d0
[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 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "HiiDatabase.h"
10 extern HII_DATABASE_PRIVATE_DATA mPrivate;
11
12 /**
13 Calculate the number of Unicode characters of the incoming Configuration string,
14 not including NULL terminator.
15
16 This is a internal function.
17
18 @param String String in <MultiConfigRequest> or
19 <MultiConfigResp> format.
20
21 @return The number of Unicode characters.
22
23 **/
24 UINTN
25 CalculateConfigStringLen (
26 IN EFI_STRING String
27 )
28 {
29 EFI_STRING TmpPtr;
30
31 //
32 // "GUID=" should be the first element of incoming string.
33 //
34 ASSERT (String != NULL);
35 ASSERT (StrnCmp (String, L"GUID=", StrLen (L"GUID=")) == 0);
36
37 //
38 // The beginning of next <ConfigRequest>/<ConfigResp> should be "&GUID=".
39 // Will meet '\0' if there is only one <ConfigRequest>/<ConfigResp>.
40 //
41 TmpPtr = StrStr (String, L"&GUID=");
42 if (TmpPtr == NULL) {
43 return StrLen (String);
44 }
45
46 return (TmpPtr - String);
47 }
48
49 /**
50 Convert the hex UNICODE %02x encoding of a UEFI device path to binary
51 from <PathHdr> of <ConfigHdr>.
52
53 This is a internal function.
54
55 @param String UEFI configuration string
56 @param DevicePathData Binary of a UEFI device path.
57
58 @retval EFI_NOT_FOUND The device path is not invalid.
59 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
60 @retval EFI_OUT_OF_RESOURCES Lake of resources to store necessary structures.
61 @retval EFI_SUCCESS The device path is retrieved and translated to
62 binary format.
63
64 **/
65 EFI_STATUS
66 GetDevicePath (
67 IN EFI_STRING String,
68 OUT UINT8 **DevicePathData
69 )
70 {
71 UINTN Length;
72 EFI_STRING PathHdr;
73 UINT8 *DevicePathBuffer;
74 CHAR16 TemStr[2];
75 UINTN Index;
76 UINT8 DigitUint8;
77 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
78
79 if ((String == NULL) || (DevicePathData == NULL)) {
80 return EFI_INVALID_PARAMETER;
81 }
82
83 //
84 // Find the 'PATH=' of <PathHdr> and skip it.
85 //
86 for ( ; (*String != 0 && StrnCmp (String, L"PATH=", StrLen (L"PATH=")) != 0); String++) {
87 }
88
89 if (*String == 0) {
90 return EFI_INVALID_PARAMETER;
91 }
92
93 //
94 // Check whether path data does exist.
95 //
96 String += StrLen (L"PATH=");
97 if (*String == 0) {
98 return EFI_INVALID_PARAMETER;
99 }
100
101 PathHdr = String;
102
103 //
104 // The content between 'PATH=' of <ConfigHdr> and '&' of next element
105 // or '\0' (end of configuration string) is the UNICODE %02x bytes encoding
106 // of UEFI device path.
107 //
108 for (Length = 0; *String != 0 && *String != L'&'; String++, Length++) {
109 }
110
111 //
112 // Check DevicePath Length
113 //
114 if (((Length + 1) / 2) < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
115 return EFI_NOT_FOUND;
116 }
117
118 //
119 // The data in <PathHdr> is encoded as hex UNICODE %02x bytes in the same order
120 // as the device path resides in RAM memory.
121 // Translate the data into binary.
122 //
123 DevicePathBuffer = (UINT8 *)AllocateZeroPool ((Length + 1) / 2);
124 if (DevicePathBuffer == NULL) {
125 return EFI_OUT_OF_RESOURCES;
126 }
127
128 //
129 // Convert DevicePath
130 //
131 ZeroMem (TemStr, sizeof (TemStr));
132 for (Index = 0; Index < Length; Index++) {
133 TemStr[0] = PathHdr[Index];
134 DigitUint8 = (UINT8)StrHexToUint64 (TemStr);
135 if ((Index & 1) == 0) {
136 DevicePathBuffer[Index/2] = DigitUint8;
137 } else {
138 DevicePathBuffer[Index/2] = (UINT8)((DevicePathBuffer[Index/2] << 4) + DigitUint8);
139 }
140 }
141
142 //
143 // Validate DevicePath
144 //
145 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePathBuffer;
146 while (!IsDevicePathEnd (DevicePath)) {
147 if ((DevicePath->Type == 0) || (DevicePath->SubType == 0) || (DevicePathNodeLength (DevicePath) < sizeof (EFI_DEVICE_PATH_PROTOCOL))) {
148 //
149 // Invalid device path
150 //
151 FreePool (DevicePathBuffer);
152 return EFI_NOT_FOUND;
153 }
154
155 DevicePath = NextDevicePathNode (DevicePath);
156 }
157
158 //
159 // return the device path
160 //
161 *DevicePathData = DevicePathBuffer;
162 return EFI_SUCCESS;
163 }
164
165 /**
166 Converts the unicode character of the string from uppercase to lowercase.
167 This is a internal function.
168
169 @param ConfigString String to be converted
170
171 **/
172 VOID
173 EFIAPI
174 HiiToLower (
175 IN EFI_STRING ConfigString
176 )
177 {
178 EFI_STRING String;
179 BOOLEAN Lower;
180
181 ASSERT (ConfigString != NULL);
182
183 //
184 // Convert all hex digits in range [A-F] in the configuration header to [a-f]
185 //
186 for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
187 if (*String == L'=') {
188 Lower = TRUE;
189 } else if (*String == L'&') {
190 Lower = FALSE;
191 } else if (Lower && (*String >= L'A') && (*String <= L'F')) {
192 *String = (CHAR16)(*String - L'A' + L'a');
193 }
194 }
195
196 return;
197 }
198
199 /**
200 Generate a sub string then output it.
201
202 This is a internal function.
203
204 @param String A constant string which is the prefix of the to be
205 generated string, e.g. GUID=
206
207 @param BufferLen The length of the Buffer in bytes.
208
209 @param Buffer Points to a buffer which will be converted to be the
210 content of the generated string.
211
212 @param Flag If 1, the buffer contains data for the value of GUID or PATH stored in
213 UINT8 *; if 2, the buffer contains unicode string for the value of NAME;
214 if 3, the buffer contains other data.
215
216 @param SubStr Points to the output string. It's caller's
217 responsibility to free this buffer.
218
219
220 **/
221 VOID
222 GenerateSubStr (
223 IN CONST EFI_STRING String,
224 IN UINTN BufferLen,
225 IN VOID *Buffer,
226 IN UINT8 Flag,
227 OUT EFI_STRING *SubStr
228 )
229 {
230 UINTN Length;
231 EFI_STRING Str;
232 EFI_STRING StringHeader;
233 CHAR16 *TemString;
234 CHAR16 *TemName;
235 UINT8 *TemBuffer;
236 UINTN Index;
237
238 ASSERT (String != NULL && SubStr != NULL);
239
240 if (Buffer == NULL) {
241 *SubStr = AllocateCopyPool (StrSize (String), String);
242 ASSERT (*SubStr != NULL);
243 return;
244 }
245
246 //
247 // Header + Data + '&' + '\0'
248 //
249 Length = StrLen (String) + BufferLen * 2 + 1 + 1;
250 Str = AllocateZeroPool (Length * sizeof (CHAR16));
251 ASSERT (Str != NULL);
252
253 StrCpyS (Str, Length, String);
254
255 StringHeader = Str + StrLen (String);
256 TemString = (CHAR16 *)StringHeader;
257
258 switch (Flag) {
259 case 1:
260 //
261 // Convert Buffer to Hex String in reverse order
262 //
263 TemBuffer = ((UINT8 *)Buffer);
264 for (Index = 0; Index < BufferLen; Index++, TemBuffer++) {
265 UnicodeValueToStringS (
266 TemString,
267 sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
268 PREFIX_ZERO | RADIX_HEX,
269 *TemBuffer,
270 2
271 );
272 TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
273 }
274
275 break;
276 case 2:
277 //
278 // Check buffer is enough
279 //
280 TemName = (CHAR16 *)Buffer;
281 ASSERT ((BufferLen * 2 + 1) >= (StrLen (TemName) * 4 + 1));
282 //
283 // Convert Unicode String to Config String, e.g. "ABCD" => "0041004200430044"
284 //
285 for ( ; *TemName != L'\0'; TemName++) {
286 UnicodeValueToStringS (
287 TemString,
288 sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
289 PREFIX_ZERO | RADIX_HEX,
290 *TemName,
291 4
292 );
293 TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
294 }
295
296 break;
297 case 3:
298 //
299 // Convert Buffer to Hex String
300 //
301 TemBuffer = ((UINT8 *)Buffer) + BufferLen - 1;
302 for (Index = 0; Index < BufferLen; Index++, TemBuffer--) {
303 UnicodeValueToStringS (
304 TemString,
305 sizeof (CHAR16) * (Length - StrnLenS (Str, Length)),
306 PREFIX_ZERO | RADIX_HEX,
307 *TemBuffer,
308 2
309 );
310 TemString += StrnLenS (TemString, Length - StrnLenS (Str, Length));
311 }
312
313 break;
314 default:
315 break;
316 }
317
318 //
319 // Convert the uppercase to lowercase since <HexAf> is defined in lowercase format.
320 //
321 StrCatS (Str, Length, L"&");
322 HiiToLower (Str);
323
324 *SubStr = Str;
325 }
326
327 /**
328 Retrieve the <ConfigBody> from String then output it.
329
330 This is a internal function.
331
332 @param String A sub string of a configuration string in
333 <MultiConfigAltResp> format.
334 @param ConfigBody Points to the output string. It's caller's
335 responsibility to free this buffer.
336
337 @retval EFI_INVALID_PARAMETER There is no form package in current hii database.
338 @retval EFI_OUT_OF_RESOURCES Not enough memory to finish this operation.
339 @retval EFI_SUCCESS All existing storage is exported.
340
341 **/
342 EFI_STATUS
343 OutputConfigBody (
344 IN EFI_STRING String,
345 OUT EFI_STRING *ConfigBody
346 )
347 {
348 EFI_STRING TmpPtr;
349 EFI_STRING Result;
350 UINTN Length;
351
352 if ((String == NULL) || (ConfigBody == NULL)) {
353 return EFI_INVALID_PARAMETER;
354 }
355
356 //
357 // The setting information should start OFFSET, not ALTCFG.
358 //
359 if (StrnCmp (String, L"&ALTCFG=", StrLen (L"&ALTCFG=")) == 0) {
360 return EFI_INVALID_PARAMETER;
361 }
362
363 TmpPtr = StrStr (String, L"GUID=");
364 if (TmpPtr == NULL) {
365 //
366 // It is the last <ConfigResp> of the incoming configuration string.
367 //
368 Result = AllocateCopyPool (StrSize (String), String);
369 if (Result == NULL) {
370 return EFI_OUT_OF_RESOURCES;
371 } else {
372 *ConfigBody = Result;
373 return EFI_SUCCESS;
374 }
375 }
376
377 Length = TmpPtr - String;
378 if (Length == 0) {
379 return EFI_NOT_FOUND;
380 }
381
382 Result = AllocateCopyPool (Length * sizeof (CHAR16), String);
383 if (Result == NULL) {
384 return EFI_OUT_OF_RESOURCES;
385 }
386
387 *(Result + Length - 1) = 0;
388 *ConfigBody = Result;
389 return EFI_SUCCESS;
390 }
391
392 /**
393 Append a string to a multi-string format.
394
395 This is a internal function.
396
397 @param MultiString String in <MultiConfigRequest>,
398 <MultiConfigAltResp>, or <MultiConfigResp>. On
399 input, the buffer length of this string is
400 MAX_STRING_LENGTH. On output, the buffer length
401 might be updated.
402 @param AppendString NULL-terminated Unicode string.
403
404 @retval EFI_INVALID_PARAMETER Any incoming parameter is invalid.
405 @retval EFI_SUCCESS AppendString is append to the end of MultiString
406
407 **/
408 EFI_STATUS
409 AppendToMultiString (
410 IN OUT EFI_STRING *MultiString,
411 IN EFI_STRING AppendString
412 )
413 {
414 UINTN AppendStringSize;
415 UINTN MultiStringSize;
416 UINTN MaxLen;
417
418 if ((MultiString == NULL) || (*MultiString == NULL) || (AppendString == NULL)) {
419 return EFI_INVALID_PARAMETER;
420 }
421
422 AppendStringSize = StrSize (AppendString);
423 MultiStringSize = StrSize (*MultiString);
424 MaxLen = MAX_STRING_LENGTH / sizeof (CHAR16);
425
426 //
427 // Enlarge the buffer each time when length exceeds MAX_STRING_LENGTH.
428 //
429 if ((MultiStringSize + AppendStringSize > MAX_STRING_LENGTH) ||
430 (MultiStringSize > MAX_STRING_LENGTH))
431 {
432 *MultiString = (EFI_STRING)ReallocatePool (
433 MultiStringSize,
434 MultiStringSize + AppendStringSize,
435 (VOID *)(*MultiString)
436 );
437 MaxLen = (MultiStringSize + AppendStringSize) / sizeof (CHAR16);
438 ASSERT (*MultiString != NULL);
439 }
440
441 //
442 // Append the incoming string
443 //
444 StrCatS (*MultiString, MaxLen, AppendString);
445
446 return EFI_SUCCESS;
447 }
448
449 /**
450 Get the value of <Number> in <BlockConfig> format, i.e. the value of OFFSET
451 or WIDTH or VALUE.
452 <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
453
454 This is a internal function.
455
456 @param StringPtr String in <BlockConfig> format and points to the
457 first character of <Number>.
458 @param Number The output value. Caller takes the responsibility
459 to free memory.
460 @param Len Length of the <Number>, in characters.
461
462 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary
463 structures.
464 @retval EFI_SUCCESS Value of <Number> is outputted in Number
465 successfully.
466
467 **/
468 EFI_STATUS
469 GetValueOfNumber (
470 IN EFI_STRING StringPtr,
471 OUT UINT8 **Number,
472 OUT UINTN *Len
473 )
474 {
475 EFI_STRING TmpPtr;
476 UINTN Length;
477 EFI_STRING Str;
478 UINT8 *Buf;
479 EFI_STATUS Status;
480 UINT8 DigitUint8;
481 UINTN Index;
482 CHAR16 TemStr[2];
483
484 if ((StringPtr == NULL) || (*StringPtr == L'\0') || (Number == NULL) || (Len == NULL)) {
485 return EFI_INVALID_PARAMETER;
486 }
487
488 Buf = NULL;
489
490 TmpPtr = StringPtr;
491 while (*StringPtr != L'\0' && *StringPtr != L'&') {
492 StringPtr++;
493 }
494
495 *Len = StringPtr - TmpPtr;
496 Length = *Len + 1;
497
498 Str = (EFI_STRING)AllocateZeroPool (Length * sizeof (CHAR16));
499 if (Str == NULL) {
500 Status = EFI_OUT_OF_RESOURCES;
501 goto Exit;
502 }
503
504 CopyMem (Str, TmpPtr, *Len * sizeof (CHAR16));
505 *(Str + *Len) = L'\0';
506
507 Length = (Length + 1) / 2;
508 Buf = (UINT8 *)AllocateZeroPool (Length);
509 if (Buf == NULL) {
510 Status = EFI_OUT_OF_RESOURCES;
511 goto Exit;
512 }
513
514 Length = *Len;
515 ZeroMem (TemStr, sizeof (TemStr));
516 for (Index = 0; Index < Length; Index++) {
517 TemStr[0] = Str[Length - Index - 1];
518 DigitUint8 = (UINT8)StrHexToUint64 (TemStr);
519 if ((Index & 1) == 0) {
520 Buf[Index/2] = DigitUint8;
521 } else {
522 Buf[Index/2] = (UINT8)((DigitUint8 << 4) + Buf[Index/2]);
523 }
524 }
525
526 *Number = Buf;
527 Status = EFI_SUCCESS;
528
529 Exit:
530 if (Str != NULL) {
531 FreePool (Str);
532 }
533
534 return Status;
535 }
536
537 /**
538 To find the BlockName in the string with same value.
539
540 @param String Pointer to a Null-terminated Unicode string.
541 @param BlockName Pointer to a Null-terminated Unicode string to search for.
542 @param Buffer Pointer to the value correspond to the BlockName.
543 @param Found The Block whether has been found.
544 @param BufferLen The length of the buffer.
545
546 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
547 @retval EFI_SUCCESS The function finishes successfully.
548
549 **/
550 EFI_STATUS
551 FindSameBlockElement (
552 IN EFI_STRING String,
553 IN EFI_STRING BlockName,
554 IN UINT8 *Buffer,
555 OUT BOOLEAN *Found,
556 IN UINTN BufferLen
557 )
558 {
559 EFI_STRING BlockPtr;
560 UINTN Length;
561 UINT8 *TempBuffer;
562 EFI_STATUS Status;
563
564 TempBuffer = NULL;
565 *Found = FALSE;
566 BlockPtr = StrStr (String, BlockName);
567
568 while (BlockPtr != NULL) {
569 BlockPtr += StrLen (BlockName);
570 Status = GetValueOfNumber (BlockPtr, &TempBuffer, &Length);
571 if (EFI_ERROR (Status)) {
572 return Status;
573 }
574
575 ASSERT (TempBuffer != NULL);
576 if ((BufferLen == Length) && (0 == CompareMem (Buffer, TempBuffer, Length))) {
577 *Found = TRUE;
578 FreePool (TempBuffer);
579 TempBuffer = NULL;
580 return EFI_SUCCESS;
581 } else {
582 FreePool (TempBuffer);
583 TempBuffer = NULL;
584 BlockPtr = StrStr (BlockPtr + 1, BlockName);
585 }
586 }
587
588 return EFI_SUCCESS;
589 }
590
591 /**
592 Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp>
593 in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp.
594
595 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
596 <MultiConfigAltResp> format. The default value
597 string may contain more than one ConfigAltResp
598 string for the different varstore buffer.
599 @param ConfigAltResp Pointer to a null-terminated Unicode string in
600 <ConfigAltResp> format.
601 @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
602 @param ConfigAltRespChanged Whether the ConfigAltResp has been changed.
603
604 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
605 @retval EFI_SUCCESS The function finishes successfully.
606
607 **/
608 EFI_STATUS
609 CompareBlockElementDefault (
610 IN EFI_STRING DefaultAltCfgResp,
611 IN OUT EFI_STRING *ConfigAltResp,
612 IN EFI_STRING AltConfigHdr,
613 IN OUT BOOLEAN *ConfigAltRespChanged
614 )
615 {
616 EFI_STATUS Status;
617 EFI_STRING BlockPtr;
618 EFI_STRING BlockPtrStart;
619 EFI_STRING StringPtr;
620 EFI_STRING AppendString;
621 EFI_STRING AltConfigHdrPtr;
622 UINT8 *TempBuffer;
623 UINTN OffsetLength;
624 UINTN AppendSize;
625 UINTN TotalSize;
626 BOOLEAN FoundOffset;
627
628 AppendString = NULL;
629 TempBuffer = NULL;
630 //
631 // Make BlockPtr point to the first <BlockConfig> with AltConfigHdr in DefaultAltCfgResp.
632 //
633 AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
634 ASSERT (AltConfigHdrPtr != NULL);
635 BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET=");
636 //
637 // Make StringPtr point to the AltConfigHdr in ConfigAltResp.
638 //
639 StringPtr = StrStr (*ConfigAltResp, AltConfigHdr);
640 ASSERT (StringPtr != NULL);
641
642 while (BlockPtr != NULL) {
643 //
644 // Find the "&OFFSET=<Number>" block and get the value of the Number with AltConfigHdr in DefaultAltCfgResp.
645 //
646 BlockPtrStart = BlockPtr;
647 BlockPtr += StrLen (L"&OFFSET=");
648 Status = GetValueOfNumber (BlockPtr, &TempBuffer, &OffsetLength);
649 if (EFI_ERROR (Status)) {
650 Status = EFI_OUT_OF_RESOURCES;
651 goto Exit;
652 }
653
654 //
655 // To find the same "&OFFSET=<Number>" block in ConfigAltResp.
656 //
657 Status = FindSameBlockElement (StringPtr, L"&OFFSET=", TempBuffer, &FoundOffset, OffsetLength);
658 if (TempBuffer != NULL) {
659 FreePool (TempBuffer);
660 TempBuffer = NULL;
661 }
662
663 if (EFI_ERROR (Status)) {
664 Status = EFI_OUT_OF_RESOURCES;
665 goto Exit;
666 }
667
668 if (!FoundOffset) {
669 //
670 // Don't find the same "&OFFSET=<Number>" block in ConfigAltResp.
671 // Calculate the size of <BlockConfig>.
672 // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number>.
673 //
674 BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET=");
675 if (BlockPtr != NULL) {
676 AppendSize = (BlockPtr - BlockPtrStart) * sizeof (CHAR16);
677 } else {
678 AppendSize = StrSize (BlockPtrStart);
679 }
680
681 //
682 // Copy the <BlockConfig> to AppendString.
683 //
684 if (AppendString == NULL) {
685 AppendString = (EFI_STRING)AllocateZeroPool (AppendSize + sizeof (CHAR16));
686 StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, BlockPtrStart, AppendSize / sizeof (CHAR16));
687 } else {
688 TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16);
689 AppendString = (EFI_STRING)ReallocatePool (
690 StrSize (AppendString),
691 TotalSize,
692 AppendString
693 );
694 if (AppendString == NULL) {
695 Status = EFI_OUT_OF_RESOURCES;
696 goto Exit;
697 }
698
699 StrnCatS (AppendString, TotalSize / sizeof (CHAR16), BlockPtrStart, AppendSize / sizeof (CHAR16));
700 }
701 } else {
702 //
703 // To find next "&OFFSET=<Number>" block with AltConfigHdr in DefaultAltCfgResp.
704 //
705 BlockPtr = StrStr (BlockPtr + 1, L"&OFFSET=");
706 }
707 }
708
709 if (AppendString != NULL) {
710 //
711 // Reallocate ConfigAltResp to copy the AppendString.
712 //
713 TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16);
714 *ConfigAltResp = (EFI_STRING)ReallocatePool (
715 StrSize (*ConfigAltResp),
716 TotalSize,
717 *ConfigAltResp
718 );
719 if (*ConfigAltResp == NULL) {
720 Status = EFI_OUT_OF_RESOURCES;
721 goto Exit;
722 }
723
724 StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString);
725 *ConfigAltRespChanged = TRUE;
726 }
727
728 Status = EFI_SUCCESS;
729
730 Exit:
731 if (AppendString != NULL) {
732 FreePool (AppendString);
733 }
734
735 return Status;
736 }
737
738 /**
739 Compare the <AltResp> in ConfigAltResp and DefaultAltCfgResp, if the <AltResp>
740 in DefaultAltCfgResp but not in ConfigAltResp,add it to the ConfigAltResp.
741
742 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
743 <MultiConfigAltResp> format. The default value
744 string may contain more than one ConfigAltResp
745 string for the different varstore buffer.
746 @param ConfigAltResp Pointer to a null-terminated Unicode string in
747 <ConfigAltResp> format.
748 @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
749 @param ConfigAltRespChanged Whether the ConfigAltResp has been changed.
750
751 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary structures.
752 @retval EFI_SUCCESS The function finishes successfully.
753
754 **/
755 EFI_STATUS
756 CompareNameElementDefault (
757 IN EFI_STRING DefaultAltCfgResp,
758 IN OUT EFI_STRING *ConfigAltResp,
759 IN EFI_STRING AltConfigHdr,
760 IN OUT BOOLEAN *ConfigAltRespChanged
761 )
762 {
763 EFI_STATUS Status;
764 EFI_STRING NvConfigPtr;
765 EFI_STRING NvConfigStart;
766 EFI_STRING NvConfigValuePtr;
767 EFI_STRING StringPtr;
768 EFI_STRING NvConfigExist;
769 EFI_STRING AppendString;
770 CHAR16 TempChar;
771 UINTN AppendSize;
772 UINTN TotalSize;
773
774 AppendString = NULL;
775 NvConfigExist = NULL;
776 //
777 // Make NvConfigPtr point to the first <NvConfig> with AltConfigHdr in DefaultAltCfgResp.
778 //
779 NvConfigPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
780 ASSERT (NvConfigPtr != NULL);
781 NvConfigPtr = StrStr (NvConfigPtr + StrLen (AltConfigHdr), L"&");
782 //
783 // Make StringPtr point to the first <NvConfig> with AltConfigHdr in ConfigAltResp.
784 //
785 StringPtr = StrStr (*ConfigAltResp, AltConfigHdr);
786 ASSERT (StringPtr != NULL);
787 StringPtr = StrStr (StringPtr + StrLen (AltConfigHdr), L"&");
788 ASSERT (StringPtr != NULL);
789
790 while (NvConfigPtr != NULL) {
791 //
792 // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number>.
793 // Get the <Label> with AltConfigHdr in DefaultAltCfgResp.
794 //
795 NvConfigStart = NvConfigPtr;
796 NvConfigValuePtr = StrStr (NvConfigPtr + 1, L"=");
797 ASSERT (NvConfigValuePtr != NULL);
798 TempChar = *NvConfigValuePtr;
799 *NvConfigValuePtr = L'\0';
800 //
801 // Get the <Label> with AltConfigHdr in ConfigAltResp.
802 //
803 NvConfigExist = StrStr (StringPtr, NvConfigPtr);
804 if (NvConfigExist == NULL) {
805 //
806 // Don't find same <Label> in ConfigAltResp.
807 // Calculate the size of <NvConfig>.
808 //
809 *NvConfigValuePtr = TempChar;
810 NvConfigPtr = StrStr (NvConfigPtr + 1, L"&");
811 if (NvConfigPtr != NULL) {
812 AppendSize = (NvConfigPtr - NvConfigStart) * sizeof (CHAR16);
813 } else {
814 AppendSize = StrSize (NvConfigStart);
815 }
816
817 //
818 // Copy the <NvConfig> to AppendString.
819 //
820 if (AppendString == NULL) {
821 AppendString = (EFI_STRING)AllocateZeroPool (AppendSize + sizeof (CHAR16));
822 StrnCatS (AppendString, AppendSize / sizeof (CHAR16) + 1, NvConfigStart, AppendSize / sizeof (CHAR16));
823 } else {
824 TotalSize = StrSize (AppendString) + AppendSize + sizeof (CHAR16);
825 AppendString = (EFI_STRING)ReallocatePool (
826 StrSize (AppendString),
827 TotalSize,
828 AppendString
829 );
830 if (AppendString == NULL) {
831 Status = EFI_OUT_OF_RESOURCES;
832 goto Exit;
833 }
834
835 StrnCatS (AppendString, TotalSize / sizeof (CHAR16), NvConfigStart, AppendSize / sizeof (CHAR16));
836 }
837 } else {
838 //
839 // To find next <Label> in DefaultAltCfgResp.
840 //
841 *NvConfigValuePtr = TempChar;
842 NvConfigPtr = StrStr (NvConfigPtr + 1, L"&");
843 }
844 }
845
846 if (AppendString != NULL) {
847 //
848 // Reallocate ConfigAltResp to copy the AppendString.
849 //
850 TotalSize = StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16);
851 *ConfigAltResp = (EFI_STRING)ReallocatePool (
852 StrSize (*ConfigAltResp),
853 StrSize (*ConfigAltResp) + StrSize (AppendString) + sizeof (CHAR16),
854 *ConfigAltResp
855 );
856 if (*ConfigAltResp == NULL) {
857 Status = EFI_OUT_OF_RESOURCES;
858 goto Exit;
859 }
860
861 StrCatS (*ConfigAltResp, TotalSize / sizeof (CHAR16), AppendString);
862 *ConfigAltRespChanged = TRUE;
863 }
864
865 Status = EFI_SUCCESS;
866
867 Exit:
868 if (AppendString != NULL) {
869 FreePool (AppendString);
870 }
871
872 return Status;
873 }
874
875 /**
876 Compare the <AltResp> in AltCfgResp and DefaultAltCfgResp, if the <AltResp>
877 in DefaultAltCfgResp but not in AltCfgResp,add it to the AltCfgResp.
878
879 @param AltCfgResp Pointer to a null-terminated Unicode string in
880 <ConfigAltResp> format.
881 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
882 <MultiConfigAltResp> format. The default value
883 string may contain more than one ConfigAltResp
884 string for the different varstore buffer.
885 @param AltConfigHdr Pointer to a Unicode string in <AltConfigHdr> format.
886
887 @retval EFI_OUT_OF_RESOURCES Insufficient resources to store necessary
888 structures.
889 @retval EFI_SUCCESS The function finishes successfully.
890
891 **/
892 EFI_STATUS
893 CompareAndMergeDefaultString (
894 IN OUT EFI_STRING *AltCfgResp,
895 IN EFI_STRING DefaultAltCfgResp,
896 IN EFI_STRING AltConfigHdr
897 )
898 {
899 EFI_STATUS Status;
900 EFI_STRING AltCfgRespBackup;
901 EFI_STRING AltConfigHdrPtr;
902 EFI_STRING AltConfigHdrPtrNext;
903 EFI_STRING ConfigAltResp;
904 EFI_STRING StringPtr;
905 EFI_STRING StringPtrNext;
906 EFI_STRING BlockPtr;
907 UINTN ReallocateSize;
908 CHAR16 TempChar;
909 CHAR16 TempCharA;
910 BOOLEAN ConfigAltRespChanged;
911
912 Status = EFI_OUT_OF_RESOURCES;
913 BlockPtr = NULL;
914 AltConfigHdrPtrNext = NULL;
915 StringPtrNext = NULL;
916 ConfigAltResp = NULL;
917 AltCfgRespBackup = NULL;
918 TempChar = L'\0';
919 TempCharA = L'\0';
920 ConfigAltRespChanged = FALSE;
921
922 //
923 // To find the <AltResp> with AltConfigHdr in DefaultAltCfgResp, ignore other <AltResp> which follow it.
924 //
925 AltConfigHdrPtr = StrStr (DefaultAltCfgResp, AltConfigHdr);
926 ASSERT (AltConfigHdrPtr != NULL);
927 AltConfigHdrPtrNext = StrStr (AltConfigHdrPtr + 1, L"&GUID");
928 if (AltConfigHdrPtrNext != NULL) {
929 TempChar = *AltConfigHdrPtrNext;
930 *AltConfigHdrPtrNext = L'\0';
931 }
932
933 //
934 // To find the <AltResp> with AltConfigHdr in AltCfgResp, ignore other <AltResp> which follow it.
935 //
936 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
937 ASSERT (StringPtr != NULL);
938 StringPtrNext = StrStr (StringPtr + 1, L"&GUID");
939 if (StringPtrNext != NULL) {
940 TempCharA = *StringPtrNext;
941 *StringPtrNext = L'\0';
942 }
943
944 //
945 // Copy the content of <ConfigAltResp> which contain current AltConfigHdr in AltCfgResp.
946 //
947 ConfigAltResp = AllocateCopyPool (StrSize (*AltCfgResp), *AltCfgResp);
948 if (ConfigAltResp == NULL) {
949 goto Exit;
950 }
951
952 //
953 // To find the <ConfigBody> with AltConfigHdr in DefaultAltCfgResp.
954 //
955 BlockPtr = StrStr (AltConfigHdrPtr, L"&OFFSET=");
956 if (BlockPtr != NULL) {
957 //
958 // <BlockConfig>::='OFFSET='<Number>'&WIDTH='<Number>'&VALUE='<Number> style.
959 // Call function CompareBlockElementDefault to compare the <BlockConfig> in DefaultAltCfgResp and ConfigAltResp.
960 // The ConfigAltResp which may contain the new <BlockConfig> get from DefaultAltCfgResp.
961 //
962 Status = CompareBlockElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);
963 if (EFI_ERROR (Status)) {
964 goto Exit;
965 }
966 } else {
967 //
968 // <NvConfig> ::= <Label>'='<String> | <Label>'='<Number> style.
969 // Call function CompareNameElementDefault to compare the <NvConfig> in DefaultAltCfgResp and ConfigAltResp.
970 // The ConfigAltResp which may contain the new <NvConfig> get from DefaultAltCfgResp.
971 //
972 Status = CompareNameElementDefault (DefaultAltCfgResp, &ConfigAltResp, AltConfigHdr, &ConfigAltRespChanged);
973 if (EFI_ERROR (Status)) {
974 goto Exit;
975 }
976 }
977
978 //
979 // Restore the AltCfgResp.
980 //
981 if (StringPtrNext != NULL) {
982 *StringPtrNext = TempCharA;
983 }
984
985 //
986 // If the ConfigAltResp has no change,no need to update the content in AltCfgResp.
987 //
988 if (!ConfigAltRespChanged) {
989 Status = EFI_SUCCESS;
990 goto Exit;
991 }
992
993 //
994 // ConfigAltResp has been changed, need to update the content in AltCfgResp.
995 //
996 if (StringPtrNext != NULL) {
997 ReallocateSize = StrSize (ConfigAltResp) + StrSize (StringPtrNext) + sizeof (CHAR16);
998 } else {
999 ReallocateSize = StrSize (ConfigAltResp) + sizeof (CHAR16);
1000 }
1001
1002 AltCfgRespBackup = (EFI_STRING)AllocateZeroPool (ReallocateSize);
1003 if (AltCfgRespBackup == NULL) {
1004 goto Exit;
1005 }
1006
1007 StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), ConfigAltResp);
1008 if (StringPtrNext != NULL) {
1009 StrCatS (AltCfgRespBackup, ReallocateSize / sizeof (CHAR16), StringPtrNext);
1010 }
1011
1012 FreePool (*AltCfgResp);
1013 *AltCfgResp = AltCfgRespBackup;
1014
1015 Status = EFI_SUCCESS;
1016
1017 Exit:
1018 if (ConfigAltResp != NULL) {
1019 FreePool (ConfigAltResp);
1020 }
1021
1022 //
1023 // Restore the DefaultAltCfgResp.
1024 //
1025 if ( AltConfigHdrPtrNext != NULL) {
1026 *AltConfigHdrPtrNext = TempChar;
1027 AltConfigHdrPtrNext = NULL;
1028 }
1029
1030 return Status;
1031 }
1032
1033 /**
1034 This function merges DefaultAltCfgResp string into AltCfgResp string for
1035 the missing AltCfgId in AltCfgResq.
1036
1037 @param AltCfgResp Pointer to a null-terminated Unicode string in
1038 <ConfigAltResp> format. The default value string
1039 will be merged into it.
1040 @param DefaultAltCfgResp Pointer to a null-terminated Unicode string in
1041 <MultiConfigAltResp> format. The default value
1042 string may contain more than one ConfigAltResp
1043 string for the different varstore buffer.
1044
1045 @retval EFI_SUCCESS The merged string returns.
1046 @retval EFI_INVALID_PARAMETER *AltCfgResp is to NULL.
1047 **/
1048 EFI_STATUS
1049 EFIAPI
1050 MergeDefaultString (
1051 IN OUT EFI_STRING *AltCfgResp,
1052 IN EFI_STRING DefaultAltCfgResp
1053 )
1054 {
1055 EFI_STRING StringPtrDefault;
1056 EFI_STRING StringPtrEnd;
1057 CHAR16 TempChar;
1058 EFI_STRING StringPtr;
1059 EFI_STRING AltConfigHdr;
1060 UINTN HeaderLength;
1061 UINTN SizeAltCfgResp;
1062 UINTN MaxLen;
1063 UINTN TotalSize;
1064
1065 if (*AltCfgResp == NULL) {
1066 return EFI_INVALID_PARAMETER;
1067 }
1068
1069 //
1070 // Get the request ConfigHdr
1071 //
1072 SizeAltCfgResp = 0;
1073 StringPtr = *AltCfgResp;
1074
1075 //
1076 // Find <ConfigHdr> GUID=...&NAME=...&PATH=...
1077 //
1078 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
1079 return EFI_INVALID_PARAMETER;
1080 }
1081
1082 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
1083 StringPtr++;
1084 }
1085
1086 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
1087 StringPtr++;
1088 }
1089
1090 if (*StringPtr == L'\0') {
1091 return EFI_INVALID_PARAMETER;
1092 }
1093
1094 StringPtr += StrLen (L"&PATH=");
1095 while (*StringPtr != L'\0' && *StringPtr != L'&') {
1096 StringPtr++;
1097 }
1098
1099 HeaderLength = StringPtr - *AltCfgResp;
1100
1101 //
1102 // Construct AltConfigHdr string "&<ConfigHdr>&ALTCFG=XXXX\0"
1103 // |1| StrLen (ConfigHdr) | 8 | 4 | 1 |
1104 //
1105 MaxLen = 1 + HeaderLength + 8 + 4 + 1;
1106 AltConfigHdr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
1107 if (AltConfigHdr == NULL) {
1108 return EFI_OUT_OF_RESOURCES;
1109 }
1110
1111 StrCpyS (AltConfigHdr, MaxLen, L"&");
1112 StrnCatS (AltConfigHdr, MaxLen, *AltCfgResp, HeaderLength);
1113 StrCatS (AltConfigHdr, MaxLen, L"&ALTCFG=");
1114 HeaderLength = StrLen (AltConfigHdr);
1115
1116 StringPtrDefault = StrStr (DefaultAltCfgResp, AltConfigHdr);
1117 while (StringPtrDefault != NULL) {
1118 //
1119 // Get AltCfg Name
1120 //
1121 StrnCatS (AltConfigHdr, MaxLen, StringPtrDefault + HeaderLength, 4);
1122 StringPtr = StrStr (*AltCfgResp, AltConfigHdr);
1123
1124 //
1125 // Append the found default value string to the input AltCfgResp
1126 //
1127 if (StringPtr == NULL) {
1128 StringPtrEnd = StrStr (StringPtrDefault + 1, L"&GUID");
1129 SizeAltCfgResp = StrSize (*AltCfgResp);
1130 if (StringPtrEnd == NULL) {
1131 //
1132 // No more default string is found.
1133 //
1134 TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);
1135 *AltCfgResp = (EFI_STRING)ReallocatePool (
1136 SizeAltCfgResp,
1137 TotalSize,
1138 (VOID *)(*AltCfgResp)
1139 );
1140 if (*AltCfgResp == NULL) {
1141 FreePool (AltConfigHdr);
1142 return EFI_OUT_OF_RESOURCES;
1143 }
1144
1145 StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
1146 break;
1147 } else {
1148 TempChar = *StringPtrEnd;
1149 *StringPtrEnd = L'\0';
1150 TotalSize = SizeAltCfgResp + StrSize (StringPtrDefault);
1151 *AltCfgResp = (EFI_STRING)ReallocatePool (
1152 SizeAltCfgResp,
1153 TotalSize,
1154 (VOID *)(*AltCfgResp)
1155 );
1156 if (*AltCfgResp == NULL) {
1157 FreePool (AltConfigHdr);
1158 return EFI_OUT_OF_RESOURCES;
1159 }
1160
1161 StrCatS (*AltCfgResp, TotalSize / sizeof (CHAR16), StringPtrDefault);
1162 *StringPtrEnd = TempChar;
1163 }
1164 } else {
1165 //
1166 // The AltCfgResp contains <AltCfgResp>.
1167 // If the <ConfigElement> in <AltCfgResp> in the DefaultAltCfgResp but not in the
1168 // related <AltCfgResp> in AltCfgResp, merge it to AltCfgResp. else no need to merge.
1169 //
1170 CompareAndMergeDefaultString (AltCfgResp, DefaultAltCfgResp, AltConfigHdr);
1171 }
1172
1173 //
1174 // Find next AltCfg String
1175 //
1176 *(AltConfigHdr + HeaderLength) = L'\0';
1177 StringPtrDefault = StrStr (StringPtrDefault + 1, AltConfigHdr);
1178 }
1179
1180 FreePool (AltConfigHdr);
1181 return EFI_SUCCESS;
1182 }
1183
1184 /**
1185 This function inserts new DefaultValueData into the BlockData DefaultValue array.
1186
1187 @param BlockData The BlockData is updated to add new default value.
1188 @param DefaultValueData The DefaultValue is added.
1189
1190 **/
1191 VOID
1192 InsertDefaultValue (
1193 IN IFR_BLOCK_DATA *BlockData,
1194 IN IFR_DEFAULT_DATA *DefaultValueData
1195 )
1196 {
1197 LIST_ENTRY *Link;
1198 IFR_DEFAULT_DATA *DefaultValueArray;
1199 LIST_ENTRY *DefaultLink;
1200
1201 DefaultLink = &BlockData->DefaultValueEntry;
1202
1203 for (Link = DefaultLink->ForwardLink; Link != DefaultLink; Link = Link->ForwardLink) {
1204 DefaultValueArray = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
1205 if (DefaultValueArray->DefaultId == DefaultValueData->DefaultId) {
1206 //
1207 // DEFAULT_VALUE_FROM_OPCODE has high priority, DEFAULT_VALUE_FROM_DEFAULT has low priority.
1208 // When default types are DEFAULT_VALUE_FROM_OTHER_DEFAULT, the default value can be overrode.
1209 //
1210 if ((DefaultValueData->Type > DefaultValueArray->Type) || ((DefaultValueData->Type == DefaultValueArray->Type) && (DefaultValueData->Type == DefaultValueFromOtherDefault))) {
1211 //
1212 // Update the default value array in BlockData.
1213 //
1214 CopyMem (&DefaultValueArray->Value, &DefaultValueData->Value, sizeof (EFI_IFR_TYPE_VALUE));
1215 DefaultValueArray->Type = DefaultValueData->Type;
1216 DefaultValueArray->Cleaned = DefaultValueData->Cleaned;
1217 }
1218
1219 return;
1220 }
1221 }
1222
1223 //
1224 // Insert new default value data in tail.
1225 //
1226 DefaultValueArray = AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
1227 ASSERT (DefaultValueArray != NULL);
1228 CopyMem (DefaultValueArray, DefaultValueData, sizeof (IFR_DEFAULT_DATA));
1229 InsertTailList (Link, &DefaultValueArray->Entry);
1230 }
1231
1232 /**
1233 This function inserts new BlockData into the block link
1234
1235 @param BlockLink The list entry points to block array.
1236 @param BlockData The point to BlockData is added.
1237
1238 **/
1239 VOID
1240 InsertBlockData (
1241 IN LIST_ENTRY *BlockLink,
1242 IN IFR_BLOCK_DATA **BlockData
1243 )
1244 {
1245 LIST_ENTRY *Link;
1246 IFR_BLOCK_DATA *BlockArray;
1247 IFR_BLOCK_DATA *BlockSingleData;
1248
1249 BlockSingleData = *BlockData;
1250
1251 if (BlockSingleData->Name != NULL) {
1252 InsertTailList (BlockLink, &BlockSingleData->Entry);
1253 return;
1254 }
1255
1256 //
1257 // Insert block data in its Offset and Width order.
1258 //
1259 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
1260 BlockArray = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1261 if (BlockArray->Offset == BlockSingleData->Offset) {
1262 if ((BlockArray->Width > BlockSingleData->Width) || (BlockSingleData->IsBitVar && (BlockArray->Width == BlockSingleData->Width))) {
1263 //
1264 // Insert this block data in the front of block array
1265 //
1266 InsertTailList (Link, &BlockSingleData->Entry);
1267 return;
1268 }
1269
1270 if ((!BlockSingleData->IsBitVar) && (BlockArray->Width == BlockSingleData->Width)) {
1271 //
1272 // The same block array has been added.
1273 //
1274 if (BlockSingleData != BlockArray) {
1275 FreePool (BlockSingleData);
1276 *BlockData = BlockArray;
1277 }
1278
1279 return;
1280 }
1281 } else if (BlockArray->Offset > BlockSingleData->Offset) {
1282 //
1283 // Insert new block data in the front of block array
1284 //
1285 InsertTailList (Link, &BlockSingleData->Entry);
1286 return;
1287 }
1288 }
1289
1290 //
1291 // Add new block data into the tail.
1292 //
1293 InsertTailList (Link, &BlockSingleData->Entry);
1294 }
1295
1296 /**
1297 Retrieves a pointer to the a Null-terminated ASCII string containing the list
1298 of languages that an HII handle in the HII Database supports. The returned
1299 string is allocated using AllocatePool(). The caller is responsible for freeing
1300 the returned string using FreePool(). The format of the returned string follows
1301 the language format assumed the HII Database.
1302
1303 If HiiHandle is NULL, then ASSERT().
1304
1305 @param[in] HiiHandle A handle that was previously registered in the HII Database.
1306
1307 @retval NULL HiiHandle is not registered in the HII database
1308 @retval NULL There are not enough resources available to retrieve the supported
1309 languages.
1310 @retval NULL The list of supported languages could not be retrieved.
1311 @retval Other A pointer to the Null-terminated ASCII string of supported languages.
1312
1313 **/
1314 CHAR8 *
1315 GetSupportedLanguages (
1316 IN EFI_HII_HANDLE HiiHandle
1317 )
1318 {
1319 EFI_STATUS Status;
1320 UINTN LanguageSize;
1321 CHAR8 TempSupportedLanguages;
1322 CHAR8 *SupportedLanguages;
1323
1324 ASSERT (HiiHandle != NULL);
1325
1326 //
1327 // Retrieve the size required for the supported languages buffer.
1328 //
1329 LanguageSize = 0;
1330 Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, &TempSupportedLanguages, &LanguageSize);
1331
1332 //
1333 // If GetLanguages() returns EFI_SUCCESS for a zero size,
1334 // then there are no supported languages registered for HiiHandle. If GetLanguages()
1335 // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
1336 // in the HII Database
1337 //
1338 if (Status != EFI_BUFFER_TOO_SMALL) {
1339 //
1340 // Return NULL if the size can not be retrieved, or if HiiHandle is not in the HII Database
1341 //
1342 return NULL;
1343 }
1344
1345 //
1346 // Allocate the supported languages buffer.
1347 //
1348 SupportedLanguages = AllocateZeroPool (LanguageSize);
1349 if (SupportedLanguages == NULL) {
1350 //
1351 // Return NULL if allocation fails.
1352 //
1353 return NULL;
1354 }
1355
1356 //
1357 // Retrieve the supported languages string
1358 //
1359 Status = mPrivate.HiiString.GetLanguages (&mPrivate.HiiString, HiiHandle, SupportedLanguages, &LanguageSize);
1360 if (EFI_ERROR (Status)) {
1361 //
1362 // Free the buffer and return NULL if the supported languages can not be retrieved.
1363 //
1364 FreePool (SupportedLanguages);
1365 return NULL;
1366 }
1367
1368 //
1369 // Return the Null-terminated ASCII string of supported languages
1370 //
1371 return SupportedLanguages;
1372 }
1373
1374 /**
1375 Retrieves a string from a string package.
1376
1377 If HiiHandle is NULL, then ASSERT().
1378 If StringId is 0, then ASSET.
1379
1380 @param[in] HiiHandle A handle that was previously registered in the HII Database.
1381 @param[in] StringId The identifier of the string to retrieved from the string
1382 package associated with HiiHandle.
1383
1384 @retval NULL The string specified by StringId is not present in the string package.
1385 @retval Other The string was returned.
1386
1387 **/
1388 EFI_STRING
1389 InternalGetString (
1390 IN EFI_HII_HANDLE HiiHandle,
1391 IN EFI_STRING_ID StringId
1392 )
1393 {
1394 EFI_STATUS Status;
1395 UINTN StringSize;
1396 CHAR16 TempString;
1397 EFI_STRING String;
1398 CHAR8 *SupportedLanguages;
1399 CHAR8 *PlatformLanguage;
1400 CHAR8 *BestLanguage;
1401 CHAR8 *Language;
1402
1403 ASSERT (HiiHandle != NULL);
1404 ASSERT (StringId != 0);
1405
1406 //
1407 // Initialize all allocated buffers to NULL
1408 //
1409 SupportedLanguages = NULL;
1410 PlatformLanguage = NULL;
1411 BestLanguage = NULL;
1412 String = NULL;
1413 Language = "";
1414
1415 //
1416 // Get the languages that the package specified by HiiHandle supports
1417 //
1418 SupportedLanguages = GetSupportedLanguages (HiiHandle);
1419 if (SupportedLanguages == NULL) {
1420 goto Error;
1421 }
1422
1423 //
1424 // Get the current platform language setting
1425 //
1426 GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&PlatformLanguage, NULL);
1427
1428 //
1429 // Get the best matching language from SupportedLanguages
1430 //
1431 BestLanguage = GetBestLanguage (
1432 SupportedLanguages,
1433 FALSE, // RFC 4646 mode
1434 Language, // Highest priority
1435 PlatformLanguage != NULL ? PlatformLanguage : "", // Next highest priority
1436 SupportedLanguages, // Lowest priority
1437 NULL
1438 );
1439 if (BestLanguage == NULL) {
1440 goto Error;
1441 }
1442
1443 //
1444 // Retrieve the size of the string in the string package for the BestLanguage
1445 //
1446 StringSize = 0;
1447 Status = mPrivate.HiiString.GetString (
1448 &mPrivate.HiiString,
1449 BestLanguage,
1450 HiiHandle,
1451 StringId,
1452 &TempString,
1453 &StringSize,
1454 NULL
1455 );
1456 //
1457 // If GetString() returns EFI_SUCCESS for a zero size,
1458 // then there are no supported languages registered for HiiHandle. If GetString()
1459 // returns an error other than EFI_BUFFER_TOO_SMALL, then HiiHandle is not present
1460 // in the HII Database
1461 //
1462 if (Status != EFI_BUFFER_TOO_SMALL) {
1463 goto Error;
1464 }
1465
1466 //
1467 // Allocate a buffer for the return string
1468 //
1469 String = AllocateZeroPool (StringSize);
1470 if (String == NULL) {
1471 goto Error;
1472 }
1473
1474 //
1475 // Retrieve the string from the string package
1476 //
1477 Status = mPrivate.HiiString.GetString (
1478 &mPrivate.HiiString,
1479 BestLanguage,
1480 HiiHandle,
1481 StringId,
1482 String,
1483 &StringSize,
1484 NULL
1485 );
1486 if (EFI_ERROR (Status)) {
1487 //
1488 // Free the buffer and return NULL if the supported languages can not be retrieved.
1489 //
1490 FreePool (String);
1491 String = NULL;
1492 }
1493
1494 Error:
1495 //
1496 // Free allocated buffers
1497 //
1498 if (SupportedLanguages != NULL) {
1499 FreePool (SupportedLanguages);
1500 }
1501
1502 if (PlatformLanguage != NULL) {
1503 FreePool (PlatformLanguage);
1504 }
1505
1506 if (BestLanguage != NULL) {
1507 FreePool (BestLanguage);
1508 }
1509
1510 //
1511 // Return the Null-terminated Unicode string
1512 //
1513 return String;
1514 }
1515
1516 /**
1517 This function checks VarOffset and VarWidth is in the block range.
1518
1519 @param RequestBlockArray The block array is to be checked.
1520 @param VarOffset Offset of var to the structure
1521 @param VarWidth Width of var.
1522 @param IsNameValueType Whether this varstore is name/value varstore or not.
1523 @param HiiHandle Hii handle for this hii package.
1524
1525 @retval TRUE This Var is in the block range.
1526 @retval FALSE This Var is not in the block range.
1527 **/
1528 BOOLEAN
1529 BlockArrayCheck (
1530 IN IFR_BLOCK_DATA *RequestBlockArray,
1531 IN UINT16 VarOffset,
1532 IN UINT16 VarWidth,
1533 IN BOOLEAN IsNameValueType,
1534 IN EFI_HII_HANDLE HiiHandle
1535 )
1536 {
1537 LIST_ENTRY *Link;
1538 IFR_BLOCK_DATA *BlockData;
1539 EFI_STRING Name;
1540
1541 //
1542 // No Request Block array, all vars are got.
1543 //
1544 if (RequestBlockArray == NULL) {
1545 return TRUE;
1546 }
1547
1548 //
1549 // Check the input var is in the request block range.
1550 //
1551 for (Link = RequestBlockArray->Entry.ForwardLink; Link != &RequestBlockArray->Entry; Link = Link->ForwardLink) {
1552 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
1553
1554 if (IsNameValueType) {
1555 Name = InternalGetString (HiiHandle, VarOffset);
1556 ASSERT (Name != NULL);
1557
1558 if (StrnCmp (BlockData->Name, Name, StrLen (Name)) == 0) {
1559 FreePool (Name);
1560 return TRUE;
1561 }
1562
1563 FreePool (Name);
1564 } else {
1565 if ((VarOffset >= BlockData->Offset) && ((VarOffset + VarWidth) <= (BlockData->Offset + BlockData->Width))) {
1566 return TRUE;
1567 }
1568 }
1569 }
1570
1571 return FALSE;
1572 }
1573
1574 /**
1575 Get form package data from data base.
1576
1577 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1578 @param HiiFormPackage The buffer saves the package data.
1579 @param PackageSize The buffer size of the package data.
1580
1581 **/
1582 EFI_STATUS
1583 GetFormPackageData (
1584 IN HII_DATABASE_RECORD *DataBaseRecord,
1585 IN OUT UINT8 **HiiFormPackage,
1586 OUT UINTN *PackageSize
1587 )
1588 {
1589 EFI_STATUS Status;
1590 UINTN Size;
1591 UINTN ResultSize;
1592
1593 if ((DataBaseRecord == NULL) || (HiiFormPackage == NULL) || (PackageSize == NULL)) {
1594 return EFI_INVALID_PARAMETER;
1595 }
1596
1597 Size = 0;
1598 ResultSize = 0;
1599 //
1600 // 0. Get Hii Form Package by HiiHandle
1601 //
1602 Status = ExportFormPackages (
1603 &mPrivate,
1604 DataBaseRecord->Handle,
1605 DataBaseRecord->PackageList,
1606 0,
1607 Size,
1608 HiiFormPackage,
1609 &ResultSize
1610 );
1611 if (EFI_ERROR (Status)) {
1612 return Status;
1613 }
1614
1615 (*HiiFormPackage) = AllocatePool (ResultSize);
1616 if (*HiiFormPackage == NULL) {
1617 Status = EFI_OUT_OF_RESOURCES;
1618 return Status;
1619 }
1620
1621 //
1622 // Get HiiFormPackage by HiiHandle
1623 //
1624 Size = ResultSize;
1625 ResultSize = 0;
1626 Status = ExportFormPackages (
1627 &mPrivate,
1628 DataBaseRecord->Handle,
1629 DataBaseRecord->PackageList,
1630 0,
1631 Size,
1632 *HiiFormPackage,
1633 &ResultSize
1634 );
1635 if (EFI_ERROR (Status)) {
1636 FreePool (*HiiFormPackage);
1637 }
1638
1639 *PackageSize = Size;
1640
1641 return Status;
1642 }
1643
1644 /**
1645 This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1646
1647 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1648 @param ConfigHdr Request string ConfigHdr. If it is NULL,
1649 the first found varstore will be as ConfigHdr.
1650 @param IsEfiVarstore Whether the request storage type is efi varstore type.
1651 @param EfiVarStore The efi varstore info which will return.
1652 **/
1653 EFI_STATUS
1654 GetVarStoreType (
1655 IN HII_DATABASE_RECORD *DataBaseRecord,
1656 IN EFI_STRING ConfigHdr,
1657 OUT BOOLEAN *IsEfiVarstore,
1658 OUT EFI_IFR_VARSTORE_EFI **EfiVarStore
1659 )
1660 {
1661 EFI_STATUS Status;
1662 UINTN IfrOffset;
1663 UINTN PackageOffset;
1664 EFI_IFR_OP_HEADER *IfrOpHdr;
1665 CHAR16 *VarStoreName;
1666 UINTN NameSize;
1667 EFI_STRING GuidStr;
1668 EFI_STRING NameStr;
1669 EFI_STRING TempStr;
1670 UINTN LengthString;
1671 UINT8 *HiiFormPackage;
1672 UINTN PackageSize;
1673 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
1674 EFI_HII_PACKAGE_HEADER *PackageHeader;
1675
1676 HiiFormPackage = NULL;
1677 LengthString = 0;
1678 Status = EFI_SUCCESS;
1679 GuidStr = NULL;
1680 NameStr = NULL;
1681 TempStr = NULL;
1682 *IsEfiVarstore = FALSE;
1683
1684 Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
1685 if (EFI_ERROR (Status)) {
1686 return Status;
1687 }
1688
1689 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1690 PackageOffset = IfrOffset;
1691 PackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiFormPackage;
1692
1693 while (IfrOffset < PackageSize) {
1694 //
1695 // More than one form packages exist.
1696 //
1697 if (PackageOffset >= PackageHeader->Length) {
1698 //
1699 // Process the new form package.
1700 //
1701 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1702 IfrOffset += PackageOffset;
1703 PackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiFormPackage + IfrOffset);
1704 }
1705
1706 IfrOpHdr = (EFI_IFR_OP_HEADER *)(HiiFormPackage + IfrOffset);
1707 IfrOffset += IfrOpHdr->Length;
1708 PackageOffset += IfrOpHdr->Length;
1709
1710 if (IfrOpHdr->OpCode == EFI_IFR_VARSTORE_EFI_OP ) {
1711 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr;
1712 //
1713 // If the length is small than the structure, this is from old efi
1714 // varstore definition. Old efi varstore get config directly from
1715 // GetVariable function.
1716 //
1717 if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
1718 continue;
1719 }
1720
1721 NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
1722 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
1723 if (VarStoreName == NULL) {
1724 Status = EFI_OUT_OF_RESOURCES;
1725 goto Done;
1726 }
1727
1728 AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
1729
1730 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)&IfrEfiVarStore->Guid, 1, &GuidStr);
1731 GenerateSubStr (L"NAME=", StrLen (VarStoreName) * sizeof (CHAR16), (VOID *)VarStoreName, 2, &NameStr);
1732 LengthString = StrLen (GuidStr);
1733 LengthString = LengthString + StrLen (NameStr) + 1;
1734 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1735 if (TempStr == NULL) {
1736 FreePool (GuidStr);
1737 FreePool (NameStr);
1738 FreePool (VarStoreName);
1739 Status = EFI_OUT_OF_RESOURCES;
1740 goto Done;
1741 }
1742
1743 StrCpyS (TempStr, LengthString, GuidStr);
1744 StrCatS (TempStr, LengthString, NameStr);
1745 if ((ConfigHdr == NULL) || (StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0)) {
1746 *EfiVarStore = (EFI_IFR_VARSTORE_EFI *)AllocateZeroPool (IfrOpHdr->Length);
1747 if (*EfiVarStore == NULL) {
1748 FreePool (VarStoreName);
1749 FreePool (GuidStr);
1750 FreePool (NameStr);
1751 FreePool (TempStr);
1752 Status = EFI_OUT_OF_RESOURCES;
1753 goto Done;
1754 }
1755
1756 *IsEfiVarstore = TRUE;
1757 CopyMem (*EfiVarStore, IfrEfiVarStore, IfrOpHdr->Length);
1758 }
1759
1760 //
1761 // Free allocated temp string.
1762 //
1763 FreePool (VarStoreName);
1764 FreePool (GuidStr);
1765 FreePool (NameStr);
1766 FreePool (TempStr);
1767
1768 //
1769 // Already found the varstore, break;
1770 //
1771 if (*IsEfiVarstore) {
1772 break;
1773 }
1774 }
1775 }
1776
1777 Done:
1778 if (HiiFormPackage != NULL) {
1779 FreePool (HiiFormPackage);
1780 }
1781
1782 return Status;
1783 }
1784
1785 /**
1786 Check whether the ConfigRequest string has the request elements.
1787 For EFI_HII_VARSTORE_BUFFER type, the request has "&OFFSET=****&WIDTH=****..." format.
1788 For EFI_HII_VARSTORE_NAME_VALUE type, the request has "&NAME1**&NAME2..." format.
1789
1790 @param ConfigRequest The input config request string.
1791
1792 @retval TRUE The input include config request elements.
1793 @retval FALSE The input string not includes.
1794
1795 **/
1796 BOOLEAN
1797 GetElementsFromRequest (
1798 IN EFI_STRING ConfigRequest
1799 )
1800 {
1801 EFI_STRING TmpRequest;
1802
1803 TmpRequest = StrStr (ConfigRequest, L"PATH=");
1804 ASSERT (TmpRequest != NULL);
1805
1806 if ((StrStr (TmpRequest, L"&OFFSET=") != NULL) || (StrStr (TmpRequest, L"&") != NULL)) {
1807 return TRUE;
1808 }
1809
1810 return FALSE;
1811 }
1812
1813 /**
1814 Check whether the this varstore is the request varstore.
1815
1816 @param VarstoreGuid Varstore guid.
1817 @param Name Varstore name.
1818 @param ConfigHdr Current configRequest info.
1819
1820 @retval TRUE This varstore is the request one.
1821 @retval FALSE This varstore is not the request one.
1822
1823 **/
1824 BOOLEAN
1825 IsThisVarstore (
1826 IN EFI_GUID *VarstoreGuid,
1827 IN CHAR16 *Name,
1828 IN CHAR16 *ConfigHdr
1829 )
1830 {
1831 EFI_STRING GuidStr;
1832 EFI_STRING NameStr;
1833 EFI_STRING TempStr;
1834 UINTN LengthString;
1835 BOOLEAN RetVal;
1836
1837 RetVal = FALSE;
1838 GuidStr = NULL;
1839 TempStr = NULL;
1840
1841 //
1842 // If ConfigHdr has name field and varstore not has name, return FALSE.
1843 //
1844 if ((Name == NULL) && (ConfigHdr != NULL) && (StrStr (ConfigHdr, L"NAME=&") == NULL)) {
1845 return FALSE;
1846 }
1847
1848 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)VarstoreGuid, 1, &GuidStr);
1849 if (Name != NULL) {
1850 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *)Name, 2, &NameStr);
1851 } else {
1852 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
1853 }
1854
1855 LengthString = StrLen (GuidStr);
1856 LengthString = LengthString + StrLen (NameStr) + 1;
1857 TempStr = AllocateZeroPool (LengthString * sizeof (CHAR16));
1858 if (TempStr == NULL) {
1859 goto Done;
1860 }
1861
1862 StrCpyS (TempStr, LengthString, GuidStr);
1863 StrCatS (TempStr, LengthString, NameStr);
1864
1865 if ((ConfigHdr == NULL) || (StrnCmp (ConfigHdr, TempStr, StrLen (TempStr)) == 0)) {
1866 RetVal = TRUE;
1867 }
1868
1869 Done:
1870 if (GuidStr != NULL) {
1871 FreePool (GuidStr);
1872 }
1873
1874 if (NameStr != NULL) {
1875 FreePool (NameStr);
1876 }
1877
1878 if (TempStr != NULL) {
1879 FreePool (TempStr);
1880 }
1881
1882 return RetVal;
1883 }
1884
1885 /**
1886 This function parses Form Package to get the efi varstore info according to the request ConfigHdr.
1887
1888 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
1889 @param ConfigHdr Request string ConfigHdr. If it is NULL,
1890 the first found varstore will be as ConfigHdr.
1891 @retval TRUE This hii package is the request one.
1892 @retval FALSE This hii package is not the request one.
1893 **/
1894 BOOLEAN
1895 IsThisPackageList (
1896 IN HII_DATABASE_RECORD *DataBaseRecord,
1897 IN EFI_STRING ConfigHdr
1898 )
1899 {
1900 EFI_STATUS Status;
1901 UINTN IfrOffset;
1902 UINTN PackageOffset;
1903 EFI_IFR_OP_HEADER *IfrOpHdr;
1904 CHAR16 *VarStoreName;
1905 UINTN NameSize;
1906 UINT8 *HiiFormPackage;
1907 UINTN PackageSize;
1908 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
1909 EFI_HII_PACKAGE_HEADER *PackageHeader;
1910 EFI_IFR_VARSTORE *IfrVarStore;
1911 EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
1912 BOOLEAN FindVarstore;
1913
1914 HiiFormPackage = NULL;
1915 VarStoreName = NULL;
1916 Status = EFI_SUCCESS;
1917 FindVarstore = FALSE;
1918
1919 Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
1920 if (EFI_ERROR (Status)) {
1921 return FALSE;
1922 }
1923
1924 IfrOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1925 PackageOffset = IfrOffset;
1926 PackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiFormPackage;
1927
1928 while (IfrOffset < PackageSize) {
1929 //
1930 // More than one form packages exist.
1931 //
1932 if (PackageOffset >= PackageHeader->Length) {
1933 //
1934 // Process the new form package.
1935 //
1936 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
1937 IfrOffset += PackageOffset;
1938 PackageHeader = (EFI_HII_PACKAGE_HEADER *)(HiiFormPackage + IfrOffset);
1939 }
1940
1941 IfrOpHdr = (EFI_IFR_OP_HEADER *)(HiiFormPackage + IfrOffset);
1942 IfrOffset += IfrOpHdr->Length;
1943 PackageOffset += IfrOpHdr->Length;
1944
1945 switch (IfrOpHdr->OpCode) {
1946 case EFI_IFR_VARSTORE_OP:
1947 IfrVarStore = (EFI_IFR_VARSTORE *)IfrOpHdr;
1948
1949 NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name);
1950 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
1951 if (VarStoreName == NULL) {
1952 goto Done;
1953 }
1954
1955 AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize);
1956
1957 if (IsThisVarstore ((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
1958 FindVarstore = TRUE;
1959 goto Done;
1960 } else {
1961 FreePool (VarStoreName);
1962 VarStoreName = NULL;
1963 }
1964
1965 break;
1966
1967 case EFI_IFR_VARSTORE_EFI_OP:
1968 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr;
1969 NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
1970 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
1971 if (VarStoreName == NULL) {
1972 goto Done;
1973 }
1974
1975 AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
1976
1977 if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
1978 FindVarstore = TRUE;
1979 goto Done;
1980 } else {
1981 FreePool (VarStoreName);
1982 VarStoreName = NULL;
1983 }
1984
1985 break;
1986
1987 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
1988 IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *)IfrOpHdr;
1989
1990 if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
1991 FindVarstore = TRUE;
1992 goto Done;
1993 }
1994
1995 break;
1996
1997 case EFI_IFR_FORM_OP:
1998 case EFI_IFR_FORM_MAP_OP:
1999 //
2000 // No matched varstore is found and directly return.
2001 //
2002 goto Done;
2003
2004 default:
2005 break;
2006 }
2007 }
2008
2009 Done:
2010 if (HiiFormPackage != NULL) {
2011 FreePool (HiiFormPackage);
2012 }
2013
2014 if (VarStoreName != NULL) {
2015 FreePool (VarStoreName);
2016 }
2017
2018 return FindVarstore;
2019 }
2020
2021 /**
2022 Check whether the this op code is required.
2023
2024 @param RequestBlockArray The array includes all the request info or NULL.
2025 @param HiiHandle The hii handle for this form package.
2026 @param VarStorageData The varstore data structure.
2027 @param IfrOpHdr Ifr opcode header for this opcode.
2028 @param VarWidth The buffer width for this opcode.
2029 @param ReturnData The data block added for this opcode.
2030 @param IsBitVar Whether the the opcode refers to bit storage.
2031
2032 @retval EFI_SUCCESS This opcode is required.
2033 @retval EFI_NOT_FOUND This opcode is not required.
2034 @retval Others Contain some error.
2035
2036 **/
2037 EFI_STATUS
2038 IsThisOpcodeRequired (
2039 IN IFR_BLOCK_DATA *RequestBlockArray,
2040 IN EFI_HII_HANDLE HiiHandle,
2041 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
2042 IN EFI_IFR_OP_HEADER *IfrOpHdr,
2043 IN UINT16 VarWidth,
2044 OUT IFR_BLOCK_DATA **ReturnData,
2045 IN BOOLEAN IsBitVar
2046 )
2047 {
2048 IFR_BLOCK_DATA *BlockData;
2049 UINT16 VarOffset;
2050 EFI_STRING_ID NameId;
2051 EFI_IFR_QUESTION_HEADER *IfrQuestionHdr;
2052 UINT16 BitOffset;
2053 UINT16 BitWidth;
2054 UINT16 TotalBits;
2055
2056 NameId = 0;
2057 VarOffset = 0;
2058 BitOffset = 0;
2059 BitWidth = 0;
2060 IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *)((CHAR8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER));
2061
2062 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2063 NameId = IfrQuestionHdr->VarStoreInfo.VarName;
2064
2065 //
2066 // Check whether this question is in requested block array.
2067 //
2068 if (!BlockArrayCheck (RequestBlockArray, NameId, 0, TRUE, HiiHandle)) {
2069 //
2070 // This question is not in the requested string. Skip it.
2071 //
2072 return EFI_NOT_FOUND;
2073 }
2074 } else {
2075 //
2076 // Get the byte offset/with and bit offset/width
2077 //
2078 if (IsBitVar) {
2079 BitOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
2080 BitWidth = VarWidth;
2081 VarOffset = BitOffset / 8;
2082 //
2083 // Use current bit width and the bit width before current bit (with same byte offset) to calculate the byte width.
2084 //
2085 TotalBits = BitOffset % 8 + BitWidth;
2086 VarWidth = (TotalBits % 8 == 0 ? TotalBits / 8 : TotalBits / 8 + 1);
2087 } else {
2088 VarOffset = IfrQuestionHdr->VarStoreInfo.VarOffset;
2089 BitWidth = VarWidth;
2090 BitOffset = VarOffset * 8;
2091 }
2092
2093 //
2094 // Check whether this question is in requested block array.
2095 //
2096 if (!BlockArrayCheck (RequestBlockArray, VarOffset, VarWidth, FALSE, HiiHandle)) {
2097 //
2098 // This question is not in the requested string. Skip it.
2099 //
2100 return EFI_NOT_FOUND;
2101 }
2102
2103 //
2104 // Check this var question is in the var storage
2105 //
2106 if (((VarOffset + VarWidth) > VarStorageData->Size)) {
2107 return EFI_INVALID_PARAMETER;
2108 }
2109 }
2110
2111 BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
2112 if (BlockData == NULL) {
2113 return EFI_OUT_OF_RESOURCES;
2114 }
2115
2116 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
2117 BlockData->Name = InternalGetString (HiiHandle, NameId);
2118 } else {
2119 BlockData->Offset = VarOffset;
2120 }
2121
2122 BlockData->Width = VarWidth;
2123 BlockData->QuestionId = IfrQuestionHdr->QuestionId;
2124 BlockData->OpCode = IfrOpHdr->OpCode;
2125 BlockData->Scope = IfrOpHdr->Scope;
2126 BlockData->IsBitVar = IsBitVar;
2127 BlockData->BitOffset = BitOffset;
2128 BlockData->BitWidth = BitWidth;
2129 InitializeListHead (&BlockData->DefaultValueEntry);
2130 //
2131 // Add Block Data into VarStorageData BlockEntry
2132 //
2133 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
2134 *ReturnData = BlockData;
2135
2136 return EFI_SUCCESS;
2137 }
2138
2139 /**
2140 This function parses Form Package to get the block array and the default
2141 value array according to the request ConfigHdr.
2142
2143 @param HiiHandle Hii Handle for this hii package.
2144 @param Package Pointer to the form package data.
2145 @param PackageLength Length of the package.
2146 @param ConfigHdr Request string ConfigHdr. If it is NULL,
2147 the first found varstore will be as ConfigHdr.
2148 @param RequestBlockArray The block array is retrieved from the request string.
2149 @param VarStorageData VarStorage structure contains the got block and default value.
2150 @param DefaultIdArray Point to the got default id and default name array.
2151
2152 @retval EFI_SUCCESS The block array and the default value array are got.
2153 @retval EFI_INVALID_PARAMETER The varstore definition in the different form packages
2154 are conflicted.
2155 @retval EFI_OUT_OF_RESOURCES No enough memory.
2156 **/
2157 EFI_STATUS
2158 EFIAPI
2159 ParseIfrData (
2160 IN EFI_HII_HANDLE HiiHandle,
2161 IN UINT8 *Package,
2162 IN UINT32 PackageLength,
2163 IN EFI_STRING ConfigHdr,
2164 IN IFR_BLOCK_DATA *RequestBlockArray,
2165 IN OUT IFR_VARSTORAGE_DATA *VarStorageData,
2166 OUT IFR_DEFAULT_DATA *DefaultIdArray
2167 )
2168 {
2169 EFI_STATUS Status;
2170 UINTN IfrOffset;
2171 UINTN PackageOffset;
2172 EFI_IFR_VARSTORE *IfrVarStore;
2173 EFI_IFR_VARSTORE_EFI *IfrEfiVarStore;
2174 EFI_IFR_OP_HEADER *IfrOpHdr;
2175 EFI_IFR_ONE_OF *IfrOneOf;
2176 EFI_IFR_REF4 *IfrRef;
2177 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
2178 EFI_IFR_DEFAULT *IfrDefault;
2179 EFI_IFR_ORDERED_LIST *IfrOrderedList;
2180 EFI_IFR_CHECKBOX *IfrCheckBox;
2181 EFI_IFR_PASSWORD *IfrPassword;
2182 EFI_IFR_STRING *IfrString;
2183 EFI_IFR_DATE *IfrDate;
2184 EFI_IFR_TIME *IfrTime;
2185 IFR_DEFAULT_DATA DefaultData;
2186 IFR_DEFAULT_DATA *DefaultDataPtr;
2187 IFR_BLOCK_DATA *BlockData;
2188 CHAR16 *VarStoreName;
2189 UINTN NameSize;
2190 UINT16 VarWidth;
2191 UINT16 VarDefaultId;
2192 BOOLEAN FirstOneOfOption;
2193 BOOLEAN FirstOrderedList;
2194 LIST_ENTRY *LinkData;
2195 LIST_ENTRY *LinkDefault;
2196 EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
2197 EFI_HII_PACKAGE_HEADER *PackageHeader;
2198 EFI_VARSTORE_ID VarStoreId;
2199 UINT16 SmallestDefaultId;
2200 BOOLEAN SmallestIdFromFlag;
2201 BOOLEAN FromOtherDefaultOpcode;
2202 BOOLEAN QuestionReferBitField;
2203
2204 Status = EFI_SUCCESS;
2205 BlockData = NULL;
2206 DefaultDataPtr = NULL;
2207 FirstOneOfOption = FALSE;
2208 VarStoreId = 0;
2209 FirstOrderedList = FALSE;
2210 VarStoreName = NULL;
2211 ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA));
2212 SmallestDefaultId = 0xFFFF;
2213 FromOtherDefaultOpcode = FALSE;
2214 QuestionReferBitField = FALSE;
2215
2216 //
2217 // Go through the form package to parse OpCode one by one.
2218 //
2219 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
2220 PackageHeader = (EFI_HII_PACKAGE_HEADER *)Package;
2221 IfrOffset = PackageOffset;
2222 while (IfrOffset < PackageLength) {
2223 //
2224 // More than one form package found.
2225 //
2226 if (PackageOffset >= PackageHeader->Length) {
2227 //
2228 // Already found varstore for this request, break;
2229 //
2230 if (VarStoreId != 0) {
2231 VarStoreId = 0;
2232 }
2233
2234 //
2235 // Get next package header info.
2236 //
2237 IfrOffset += sizeof (EFI_HII_PACKAGE_HEADER);
2238 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
2239 PackageHeader = (EFI_HII_PACKAGE_HEADER *)(Package + IfrOffset);
2240 }
2241
2242 IfrOpHdr = (EFI_IFR_OP_HEADER *)(Package + IfrOffset);
2243 switch (IfrOpHdr->OpCode) {
2244 case EFI_IFR_VARSTORE_OP:
2245 //
2246 // VarStore is found. Don't need to search any more.
2247 //
2248 if (VarStoreId != 0) {
2249 break;
2250 }
2251
2252 IfrVarStore = (EFI_IFR_VARSTORE *)IfrOpHdr;
2253
2254 NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name);
2255 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
2256 if (VarStoreName == NULL) {
2257 Status = EFI_OUT_OF_RESOURCES;
2258 goto Done;
2259 }
2260
2261 AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize);
2262
2263 if (IsThisVarstore ((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
2264 //
2265 // Find the matched VarStore
2266 //
2267 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrVarStore->Guid);
2268 VarStorageData->Size = IfrVarStore->Size;
2269 VarStorageData->Name = VarStoreName;
2270 VarStorageData->Type = EFI_HII_VARSTORE_BUFFER;
2271 VarStoreId = IfrVarStore->VarStoreId;
2272 } else {
2273 FreePool (VarStoreName);
2274 VarStoreName = NULL;
2275 }
2276
2277 break;
2278
2279 case EFI_IFR_VARSTORE_EFI_OP:
2280 //
2281 // VarStore is found. Don't need to search any more.
2282 //
2283 if (VarStoreId != 0) {
2284 break;
2285 }
2286
2287 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr;
2288
2289 //
2290 // If the length is small than the structure, this is from old efi
2291 // varstore definition. Old efi varstore get config directly from
2292 // GetVariable function.
2293 //
2294 if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
2295 break;
2296 }
2297
2298 NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
2299 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
2300 if (VarStoreName == NULL) {
2301 Status = EFI_OUT_OF_RESOURCES;
2302 goto Done;
2303 }
2304
2305 AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
2306
2307 if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
2308 //
2309 // Find the matched VarStore
2310 //
2311 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrEfiVarStore->Guid);
2312 VarStorageData->Size = IfrEfiVarStore->Size;
2313 VarStorageData->Name = VarStoreName;
2314 VarStorageData->Type = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER;
2315 VarStoreId = IfrEfiVarStore->VarStoreId;
2316 } else {
2317 FreePool (VarStoreName);
2318 VarStoreName = NULL;
2319 }
2320
2321 break;
2322
2323 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
2324 //
2325 // VarStore is found. Don't need to search any more.
2326 //
2327 if (VarStoreId != 0) {
2328 break;
2329 }
2330
2331 IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *)IfrOpHdr;
2332
2333 if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
2334 //
2335 // Find the matched VarStore
2336 //
2337 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrNameValueVarStore->Guid);
2338 VarStorageData->Type = EFI_HII_VARSTORE_NAME_VALUE;
2339 VarStoreId = IfrNameValueVarStore->VarStoreId;
2340 }
2341
2342 break;
2343
2344 case EFI_IFR_DEFAULTSTORE_OP:
2345 //
2346 // Add new the map between default id and default name.
2347 //
2348 DefaultDataPtr = (IFR_DEFAULT_DATA *)AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
2349 if (DefaultDataPtr == NULL) {
2350 Status = EFI_OUT_OF_RESOURCES;
2351 goto Done;
2352 }
2353
2354 DefaultDataPtr->DefaultId = ((EFI_IFR_DEFAULTSTORE *)IfrOpHdr)->DefaultId;
2355 InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry);
2356 DefaultDataPtr = NULL;
2357 break;
2358
2359 case EFI_IFR_FORM_OP:
2360 case EFI_IFR_FORM_MAP_OP:
2361 //
2362 // No matched varstore is found and directly return.
2363 //
2364 if ( VarStoreId == 0) {
2365 Status = EFI_SUCCESS;
2366 goto Done;
2367 }
2368
2369 break;
2370
2371 case EFI_IFR_REF_OP:
2372 //
2373 // Ref question is not in IFR Form. This IFR form is not valid.
2374 //
2375 if ( VarStoreId == 0) {
2376 Status = EFI_INVALID_PARAMETER;
2377 goto Done;
2378 }
2379
2380 //
2381 // Check whether this question is for the requested varstore.
2382 //
2383 IfrRef = (EFI_IFR_REF4 *)IfrOpHdr;
2384 if (IfrRef->Question.VarStoreId != VarStoreId) {
2385 break;
2386 }
2387
2388 VarWidth = (UINT16)(sizeof (EFI_HII_REF));
2389
2390 //
2391 // The BlockData may allocate by other opcode,need to clean.
2392 //
2393 if (BlockData != NULL) {
2394 BlockData = NULL;
2395 }
2396
2397 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2398 if (EFI_ERROR (Status)) {
2399 if (Status == EFI_NOT_FOUND) {
2400 //
2401 // The opcode is not required,exit and parse other opcode.
2402 //
2403 break;
2404 }
2405
2406 goto Done;
2407 }
2408
2409 break;
2410
2411 case EFI_IFR_ONE_OF_OP:
2412 case EFI_IFR_NUMERIC_OP:
2413 //
2414 // Numeric and OneOf has the same opcode structure.
2415 //
2416
2417 //
2418 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
2419 //
2420 if (VarStoreId == 0) {
2421 Status = EFI_INVALID_PARAMETER;
2422 goto Done;
2423 }
2424
2425 //
2426 // Check whether this question is for the requested varstore.
2427 //
2428 IfrOneOf = (EFI_IFR_ONE_OF *)IfrOpHdr;
2429 if (IfrOneOf->Question.VarStoreId != VarStoreId) {
2430 break;
2431 }
2432
2433 if (QuestionReferBitField) {
2434 VarWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
2435 } else {
2436 VarWidth = (UINT16)(1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
2437 }
2438
2439 //
2440 // The BlockData may allocate by other opcode,need to clean.
2441 //
2442 if (BlockData != NULL) {
2443 BlockData = NULL;
2444 }
2445
2446 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
2447 if (EFI_ERROR (Status)) {
2448 if (Status == EFI_NOT_FOUND) {
2449 //
2450 // The opcode is not required,exit and parse other opcode.
2451 //
2452 break;
2453 }
2454
2455 goto Done;
2456 }
2457
2458 //
2459 // when go to there,BlockData can't be NULLL.
2460 //
2461 ASSERT (BlockData != NULL);
2462
2463 if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
2464 //
2465 // Set this flag to TRUE for the first oneof option.
2466 //
2467 FirstOneOfOption = TRUE;
2468 } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
2469 //
2470 // Numeric minimum value will be used as default value when no default is specified.
2471 //
2472 DefaultData.Type = DefaultValueFromDefault;
2473 if (QuestionReferBitField) {
2474 //
2475 // Since default value in bit field was stored as UINT32 type.
2476 //
2477 CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
2478 } else {
2479 switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
2480 case EFI_IFR_NUMERIC_SIZE_1:
2481 DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue;
2482 break;
2483
2484 case EFI_IFR_NUMERIC_SIZE_2:
2485 CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
2486 break;
2487
2488 case EFI_IFR_NUMERIC_SIZE_4:
2489 CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
2490 break;
2491
2492 case EFI_IFR_NUMERIC_SIZE_8:
2493 CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
2494 break;
2495
2496 default:
2497 Status = EFI_INVALID_PARAMETER;
2498 goto Done;
2499 }
2500 }
2501
2502 //
2503 // Set default value base on the DefaultId list get from IFR data.
2504 //
2505 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2506 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2507 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2508 InsertDefaultValue (BlockData, &DefaultData);
2509 }
2510 }
2511
2512 break;
2513
2514 case EFI_IFR_ORDERED_LIST_OP:
2515 //
2516 // offset by question header
2517 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
2518 //
2519
2520 FirstOrderedList = TRUE;
2521 //
2522 // OrderedList question is not in IFR Form. This IFR form is not valid.
2523 //
2524 if (VarStoreId == 0) {
2525 Status = EFI_INVALID_PARAMETER;
2526 goto Done;
2527 }
2528
2529 //
2530 // Check whether this question is for the requested varstore.
2531 //
2532 IfrOrderedList = (EFI_IFR_ORDERED_LIST *)IfrOpHdr;
2533 if (IfrOrderedList->Question.VarStoreId != VarStoreId) {
2534 BlockData = NULL;
2535 break;
2536 }
2537
2538 VarWidth = IfrOrderedList->MaxContainers;
2539
2540 //
2541 // The BlockData may allocate by other opcode,need to clean.
2542 //
2543 if (BlockData != NULL) {
2544 BlockData = NULL;
2545 }
2546
2547 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2548 if (EFI_ERROR (Status)) {
2549 if (Status == EFI_NOT_FOUND) {
2550 //
2551 // The opcode is not required,exit and parse other opcode.
2552 //
2553 break;
2554 }
2555
2556 goto Done;
2557 }
2558
2559 break;
2560
2561 case EFI_IFR_CHECKBOX_OP:
2562 //
2563 // EFI_IFR_DEFAULT_OP
2564 // offset by question header
2565 // width is 1 sizeof (BOOLEAN)
2566 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
2567 // value by DefaultOption
2568 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
2569 //
2570
2571 //
2572 // CheckBox question is not in IFR Form. This IFR form is not valid.
2573 //
2574 if (VarStoreId == 0) {
2575 Status = EFI_INVALID_PARAMETER;
2576 goto Done;
2577 }
2578
2579 //
2580 // Check whether this question is for the requested varstore.
2581 //
2582 IfrCheckBox = (EFI_IFR_CHECKBOX *)IfrOpHdr;
2583 if (IfrCheckBox->Question.VarStoreId != VarStoreId) {
2584 break;
2585 }
2586
2587 VarWidth = (UINT16)sizeof (BOOLEAN);
2588
2589 //
2590 // The BlockData may allocate by other opcode,need to clean.
2591 //
2592 if (BlockData != NULL) {
2593 BlockData = NULL;
2594 }
2595
2596 if (QuestionReferBitField) {
2597 VarWidth = 1;
2598 }
2599
2600 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
2601 if (EFI_ERROR (Status)) {
2602 if (Status == EFI_NOT_FOUND) {
2603 //
2604 // The opcode is not required,exit and parse other opcode.
2605 //
2606 break;
2607 }
2608
2609 goto Done;
2610 }
2611
2612 //
2613 // when go to there,BlockData can't be NULLL.
2614 //
2615 ASSERT (BlockData != NULL);
2616
2617 SmallestIdFromFlag = FALSE;
2618
2619 //
2620 // Add default value for standard ID by CheckBox Flag
2621 //
2622 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2623 //
2624 // Prepare new DefaultValue
2625 //
2626 DefaultData.DefaultId = VarDefaultId;
2627 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
2628 //
2629 // When flag is set, default value is TRUE.
2630 //
2631 DefaultData.Type = DefaultValueFromFlag;
2632 if (QuestionReferBitField) {
2633 DefaultData.Value.u32 = TRUE;
2634 } else {
2635 DefaultData.Value.b = TRUE;
2636 }
2637
2638 InsertDefaultValue (BlockData, &DefaultData);
2639
2640 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
2641 //
2642 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
2643 //
2644 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2645 SmallestIdFromFlag = TRUE;
2646 }
2647 }
2648
2649 //
2650 // Add default value for Manufacture ID by CheckBox Flag
2651 //
2652 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2653 //
2654 // Prepare new DefaultValue
2655 //
2656 DefaultData.DefaultId = VarDefaultId;
2657 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
2658 //
2659 // When flag is set, default value is TRUE.
2660 //
2661 DefaultData.Type = DefaultValueFromFlag;
2662 if (QuestionReferBitField) {
2663 DefaultData.Value.u32 = TRUE;
2664 } else {
2665 DefaultData.Value.b = TRUE;
2666 }
2667
2668 InsertDefaultValue (BlockData, &DefaultData);
2669
2670 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2671 //
2672 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
2673 //
2674 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2675 SmallestIdFromFlag = TRUE;
2676 }
2677 }
2678
2679 if (SmallestIdFromFlag) {
2680 //
2681 // When smallest default Id is given by the flag of CheckBox, set default value with TRUE for other default Id in the DefaultId list.
2682 //
2683 DefaultData.Type = DefaultValueFromOtherDefault;
2684 if (QuestionReferBitField) {
2685 DefaultData.Value.u32 = TRUE;
2686 } else {
2687 DefaultData.Value.b = TRUE;
2688 }
2689
2690 //
2691 // Set default value for all the default id in the DefaultId list.
2692 //
2693 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2694 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2695 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2696 InsertDefaultValue (BlockData, &DefaultData);
2697 }
2698 } else {
2699 //
2700 // When flag is not set, default value is FASLE.
2701 //
2702 DefaultData.Type = DefaultValueFromDefault;
2703 if (QuestionReferBitField) {
2704 DefaultData.Value.u32 = FALSE;
2705 } else {
2706 DefaultData.Value.b = FALSE;
2707 }
2708
2709 //
2710 // Set default value for all the default id in the DefaultId list.
2711 //
2712 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2713 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2714 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2715 InsertDefaultValue (BlockData, &DefaultData);
2716 }
2717 }
2718
2719 break;
2720
2721 case EFI_IFR_DATE_OP:
2722 //
2723 // offset by question header
2724 // width MaxSize * sizeof (CHAR16)
2725 // no default value, only block array
2726 //
2727
2728 //
2729 // Date question is not in IFR Form. This IFR form is not valid.
2730 //
2731 if (VarStoreId == 0) {
2732 Status = EFI_INVALID_PARAMETER;
2733 goto Done;
2734 }
2735
2736 //
2737 // Check whether this question is for the requested varstore.
2738 //
2739 IfrDate = (EFI_IFR_DATE *)IfrOpHdr;
2740 if (IfrDate->Question.VarStoreId != VarStoreId) {
2741 break;
2742 }
2743
2744 //
2745 // The BlockData may allocate by other opcode,need to clean.
2746 //
2747 if (BlockData != NULL) {
2748 BlockData = NULL;
2749 }
2750
2751 VarWidth = (UINT16)sizeof (EFI_HII_DATE);
2752 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2753 if (EFI_ERROR (Status)) {
2754 if (Status == EFI_NOT_FOUND) {
2755 //
2756 // The opcode is not required,exit and parse other opcode.
2757 //
2758 break;
2759 }
2760
2761 goto Done;
2762 }
2763
2764 break;
2765
2766 case EFI_IFR_TIME_OP:
2767 //
2768 // offset by question header
2769 // width MaxSize * sizeof (CHAR16)
2770 // no default value, only block array
2771 //
2772
2773 //
2774 // Time question is not in IFR Form. This IFR form is not valid.
2775 //
2776 if (VarStoreId == 0) {
2777 Status = EFI_INVALID_PARAMETER;
2778 goto Done;
2779 }
2780
2781 //
2782 // Check whether this question is for the requested varstore.
2783 //
2784 IfrTime = (EFI_IFR_TIME *)IfrOpHdr;
2785 if (IfrTime->Question.VarStoreId != VarStoreId) {
2786 break;
2787 }
2788
2789 //
2790 // The BlockData may allocate by other opcode,need to clean.
2791 //
2792 if (BlockData != NULL) {
2793 BlockData = NULL;
2794 }
2795
2796 VarWidth = (UINT16)sizeof (EFI_HII_TIME);
2797 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2798 if (EFI_ERROR (Status)) {
2799 if (Status == EFI_NOT_FOUND) {
2800 //
2801 // The opcode is not required,exit and parse other opcode.
2802 //
2803 break;
2804 }
2805
2806 goto Done;
2807 }
2808
2809 break;
2810
2811 case EFI_IFR_STRING_OP:
2812 //
2813 // offset by question header
2814 // width MaxSize * sizeof (CHAR16)
2815 // no default value, only block array
2816 //
2817
2818 //
2819 // String question is not in IFR Form. This IFR form is not valid.
2820 //
2821 if (VarStoreId == 0) {
2822 Status = EFI_INVALID_PARAMETER;
2823 goto Done;
2824 }
2825
2826 //
2827 // Check whether this question is for the requested varstore.
2828 //
2829 IfrString = (EFI_IFR_STRING *)IfrOpHdr;
2830 if (IfrString->Question.VarStoreId != VarStoreId) {
2831 break;
2832 }
2833
2834 //
2835 // The BlockData may allocate by other opcode,need to clean.
2836 //
2837 if (BlockData != NULL) {
2838 BlockData = NULL;
2839 }
2840
2841 VarWidth = (UINT16)(IfrString->MaxSize * sizeof (UINT16));
2842 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2843 if (EFI_ERROR (Status)) {
2844 if (Status == EFI_NOT_FOUND) {
2845 //
2846 // The opcode is not required,exit and parse other opcode.
2847 //
2848 break;
2849 }
2850
2851 goto Done;
2852 }
2853
2854 break;
2855
2856 case EFI_IFR_PASSWORD_OP:
2857 //
2858 // offset by question header
2859 // width MaxSize * sizeof (CHAR16)
2860 // no default value, only block array
2861 //
2862
2863 //
2864 // Password question is not in IFR Form. This IFR form is not valid.
2865 //
2866 if (VarStoreId == 0) {
2867 Status = EFI_INVALID_PARAMETER;
2868 goto Done;
2869 }
2870
2871 //
2872 // Check whether this question is for the requested varstore.
2873 //
2874 IfrPassword = (EFI_IFR_PASSWORD *)IfrOpHdr;
2875 if (IfrPassword->Question.VarStoreId != VarStoreId) {
2876 break;
2877 }
2878
2879 //
2880 // The BlockData may allocate by other opcode,need to clean.
2881 //
2882 if (BlockData != NULL) {
2883 BlockData = NULL;
2884 }
2885
2886 VarWidth = (UINT16)(IfrPassword->MaxSize * sizeof (UINT16));
2887 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2888 if (EFI_ERROR (Status)) {
2889 if (Status == EFI_NOT_FOUND) {
2890 //
2891 // The opcode is not required,exit and parse other opcode.
2892 //
2893 break;
2894 }
2895
2896 goto Done;
2897 }
2898
2899 //
2900 // No default value for string.
2901 //
2902 BlockData = NULL;
2903 break;
2904
2905 case EFI_IFR_ONE_OF_OPTION_OP:
2906 //
2907 // No matched block data is ignored.
2908 //
2909 if ((BlockData == NULL) || (BlockData->Scope == 0)) {
2910 break;
2911 }
2912
2913 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *)IfrOpHdr;
2914 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
2915 if (!FirstOrderedList) {
2916 break;
2917 }
2918
2919 //
2920 // Get ordered list option data type.
2921 //
2922 if ((IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8) || (IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN)) {
2923 VarWidth = 1;
2924 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
2925 VarWidth = 2;
2926 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
2927 VarWidth = 4;
2928 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
2929 VarWidth = 8;
2930 } else {
2931 //
2932 // Invalid ordered list option data type.
2933 //
2934 Status = EFI_INVALID_PARAMETER;
2935 if (BlockData->Name != NULL) {
2936 FreePool (BlockData->Name);
2937 }
2938
2939 FreePool (BlockData);
2940 goto Done;
2941 }
2942
2943 //
2944 // Calculate Ordered list QuestionId width.
2945 //
2946 BlockData->Width = (UINT16)(BlockData->Width * VarWidth);
2947 //
2948 // Check whether this question is in requested block array.
2949 //
2950 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) {
2951 //
2952 // This question is not in the requested string. Skip it.
2953 //
2954 if (BlockData->Name != NULL) {
2955 FreePool (BlockData->Name);
2956 }
2957
2958 FreePool (BlockData);
2959 BlockData = NULL;
2960 break;
2961 }
2962
2963 //
2964 // Check this var question is in the var storage
2965 //
2966 if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) {
2967 Status = EFI_INVALID_PARAMETER;
2968 FreePool (BlockData);
2969 goto Done;
2970 }
2971
2972 //
2973 // Add Block Data into VarStorageData BlockEntry
2974 //
2975 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
2976
2977 FirstOrderedList = FALSE;
2978
2979 break;
2980 }
2981
2982 //
2983 // 1. Set default value for OneOf option when flag field has default attribute.
2984 // And set the default value with the smallest default id for other default id in the DefaultId list.
2985 //
2986 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
2987 ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG))
2988 {
2989 //
2990 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
2991 // The first oneof option value will be used as default value when no default value is specified.
2992 //
2993 FirstOneOfOption = FALSE;
2994
2995 SmallestIdFromFlag = FALSE;
2996
2997 // Prepare new DefaultValue
2998 //
2999 DefaultData.Type = DefaultValueFromFlag;
3000 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
3001 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
3002 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
3003 InsertDefaultValue (BlockData, &DefaultData);
3004 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
3005 //
3006 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
3007 //
3008 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
3009 SmallestIdFromFlag = TRUE;
3010 }
3011 }
3012
3013 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
3014 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
3015 InsertDefaultValue (BlockData, &DefaultData);
3016 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3017 //
3018 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
3019 //
3020 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
3021 SmallestIdFromFlag = TRUE;
3022 }
3023 }
3024
3025 if (SmallestIdFromFlag) {
3026 //
3027 // When smallest default Id is given by the flag of oneofOption, set this option value for other default Id in the DefaultId list.
3028 //
3029 DefaultData.Type = DefaultValueFromOtherDefault;
3030 //
3031 // Set default value for other default id in the DefaultId list.
3032 //
3033 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3034 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3035 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3036 InsertDefaultValue (BlockData, &DefaultData);
3037 }
3038 }
3039 }
3040
3041 //
3042 // 2. Set as the default value when this is the first option.
3043 // The first oneof option value will be used as default value when no default value is specified.
3044 //
3045 if (FirstOneOfOption) {
3046 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
3047 FirstOneOfOption = FALSE;
3048
3049 //
3050 // Prepare new DefaultValue
3051 //
3052 DefaultData.Type = DefaultValueFromDefault;
3053 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
3054 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3055 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3056 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3057 InsertDefaultValue (BlockData, &DefaultData);
3058 }
3059 }
3060
3061 break;
3062
3063 case EFI_IFR_DEFAULT_OP:
3064 //
3065 // Update Current BlockData to the default value.
3066 //
3067 if ((BlockData == NULL) || (BlockData->Scope == 0)) {
3068 //
3069 // No matched block data is ignored.
3070 //
3071 break;
3072 }
3073
3074 //
3075 // Get the DefaultId
3076 //
3077 IfrDefault = (EFI_IFR_DEFAULT *)IfrOpHdr;
3078 VarDefaultId = IfrDefault->DefaultId;
3079 //
3080 // Prepare new DefaultValue
3081 //
3082 DefaultData.Type = DefaultValueFromOpcode;
3083 DefaultData.DefaultId = VarDefaultId;
3084 if (QuestionReferBitField) {
3085 CopyMem (&DefaultData.Value.u32, &IfrDefault->Value.u32, sizeof (UINT32));
3086 } else {
3087 CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value));
3088 }
3089
3090 // If the value field is expression, set the cleaned flag.
3091 if (IfrDefault->Type == EFI_IFR_TYPE_OTHER) {
3092 DefaultData.Cleaned = TRUE;
3093 }
3094
3095 //
3096 // Add DefaultValue into current BlockData
3097 //
3098 InsertDefaultValue (BlockData, &DefaultData);
3099
3100 //
3101 // Set default value for other default id in the DefaultId list.
3102 // when SmallestDefaultId == VarDefaultId means there are two defaults with same default Id.
3103 // If the two defaults are both from default opcode, use the first default as the default value of other default Id.
3104 // If one from flag and the other form default opcode, use the default opcode value as the default value of other default Id.
3105 //
3106 if ((SmallestDefaultId > VarDefaultId) || ((SmallestDefaultId == VarDefaultId) && !FromOtherDefaultOpcode)) {
3107 FromOtherDefaultOpcode = TRUE;
3108 SmallestDefaultId = VarDefaultId;
3109 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3110 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3111 if (DefaultDataPtr->DefaultId != DefaultData.DefaultId) {
3112 DefaultData.Type = DefaultValueFromOtherDefault;
3113 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3114 InsertDefaultValue (BlockData, &DefaultData);
3115 }
3116 }
3117 }
3118
3119 //
3120 // After insert the default value, reset the cleaned value for next
3121 // time used. If not set here, need to set the value before every time.
3122 // use it.
3123 //
3124 DefaultData.Cleaned = FALSE;
3125 break;
3126
3127 case EFI_IFR_END_OP:
3128 //
3129 // End Opcode is for Var question.
3130 //
3131 QuestionReferBitField = FALSE;
3132 if (BlockData != NULL) {
3133 if (BlockData->Scope > 0) {
3134 BlockData->Scope--;
3135 }
3136
3137 if (BlockData->Scope == 0) {
3138 BlockData = NULL;
3139 //
3140 // when finishing parsing a question, clean the SmallestDefaultId and GetDefaultFromDefaultOpcode.
3141 //
3142 SmallestDefaultId = 0xFFFF;
3143 FromOtherDefaultOpcode = FALSE;
3144 }
3145 }
3146
3147 break;
3148
3149 case EFI_IFR_GUID_OP:
3150 if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
3151 QuestionReferBitField = TRUE;
3152 }
3153
3154 break;
3155
3156 default:
3157 if (BlockData != NULL) {
3158 if (BlockData->Scope > 0) {
3159 BlockData->Scope = (UINT8)(BlockData->Scope + IfrOpHdr->Scope);
3160 }
3161
3162 if (BlockData->Scope == 0) {
3163 BlockData = NULL;
3164 }
3165 }
3166
3167 break;
3168 }
3169
3170 IfrOffset += IfrOpHdr->Length;
3171 PackageOffset += IfrOpHdr->Length;
3172 }
3173
3174 //
3175 // if Status == EFI_NOT_FOUND, just means the opcode is not required,not contain any error,
3176 // so set the Status to EFI_SUCCESS.
3177 //
3178 if (Status == EFI_NOT_FOUND) {
3179 Status = EFI_SUCCESS;
3180 }
3181
3182 Done:
3183 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
3184 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
3185 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; ) {
3186 DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3187 LinkDefault = LinkDefault->ForwardLink;
3188 if (DefaultDataPtr->Cleaned == TRUE) {
3189 RemoveEntryList (&DefaultDataPtr->Entry);
3190 FreePool (DefaultDataPtr);
3191 }
3192 }
3193 }
3194
3195 return Status;
3196 }
3197
3198 /**
3199 parse the configrequest string, get the elements.
3200
3201 @param ConfigRequest The input configrequest string.
3202 @param Progress Return the progress data.
3203
3204 @retval Block data pointer.
3205 **/
3206 IFR_BLOCK_DATA *
3207 GetBlockElement (
3208 IN EFI_STRING ConfigRequest,
3209 OUT EFI_STRING *Progress
3210 )
3211 {
3212 EFI_STRING StringPtr;
3213 IFR_BLOCK_DATA *BlockData;
3214 IFR_BLOCK_DATA *RequestBlockArray;
3215 EFI_STATUS Status;
3216 UINT8 *TmpBuffer;
3217 UINT16 Offset;
3218 UINT16 Width;
3219 LIST_ENTRY *Link;
3220 IFR_BLOCK_DATA *NextBlockData;
3221 UINTN Length;
3222
3223 TmpBuffer = NULL;
3224
3225 //
3226 // Init RequestBlockArray
3227 //
3228 RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3229 if (RequestBlockArray == NULL) {
3230 goto Done;
3231 }
3232
3233 InitializeListHead (&RequestBlockArray->Entry);
3234
3235 //
3236 // Get the request Block array from the request string
3237 // Offset and Width
3238 //
3239
3240 //
3241 // Parse each <RequestElement> if exists
3242 // Only <BlockName> format is supported by this help function.
3243 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
3244 //
3245 StringPtr = ConfigRequest;
3246 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
3247 //
3248 // Skip the OFFSET string
3249 //
3250 *Progress = StringPtr;
3251 StringPtr += StrLen (L"&OFFSET=");
3252 //
3253 // Get Offset
3254 //
3255 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3256 if (EFI_ERROR (Status)) {
3257 goto Done;
3258 }
3259
3260 Offset = 0;
3261 CopyMem (
3262 &Offset,
3263 TmpBuffer,
3264 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
3265 );
3266 FreePool (TmpBuffer);
3267
3268 StringPtr += Length;
3269 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3270 goto Done;
3271 }
3272
3273 StringPtr += StrLen (L"&WIDTH=");
3274
3275 //
3276 // Get Width
3277 //
3278 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3279 if (EFI_ERROR (Status)) {
3280 goto Done;
3281 }
3282
3283 Width = 0;
3284 CopyMem (
3285 &Width,
3286 TmpBuffer,
3287 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
3288 );
3289 FreePool (TmpBuffer);
3290
3291 StringPtr += Length;
3292 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
3293 goto Done;
3294 }
3295
3296 //
3297 // Set Block Data
3298 //
3299 BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3300 if (BlockData == NULL) {
3301 goto Done;
3302 }
3303
3304 BlockData->Offset = Offset;
3305 BlockData->Width = Width;
3306 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
3307
3308 //
3309 // Skip &VALUE string if &VALUE does exists.
3310 //
3311 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
3312 StringPtr += StrLen (L"&VALUE=");
3313
3314 //
3315 // Get Value
3316 //
3317 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3318 if (EFI_ERROR (Status)) {
3319 goto Done;
3320 }
3321
3322 FreePool (TmpBuffer);
3323 StringPtr += Length;
3324 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
3325 goto Done;
3326 }
3327 }
3328
3329 //
3330 // If '\0', parsing is finished.
3331 //
3332 if (*StringPtr == 0) {
3333 break;
3334 }
3335 }
3336
3337 //
3338 // Merge the requested block data.
3339 //
3340 Link = RequestBlockArray->Entry.ForwardLink;
3341 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
3342 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3343 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
3344 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
3345 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
3346 BlockData->Width = (UINT16)(NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
3347 }
3348
3349 RemoveEntryList (Link->ForwardLink);
3350 FreePool (NextBlockData);
3351 continue;
3352 }
3353
3354 Link = Link->ForwardLink;
3355 }
3356
3357 return RequestBlockArray;
3358
3359 Done:
3360 if (RequestBlockArray != NULL) {
3361 //
3362 // Free Link Array RequestBlockArray
3363 //
3364 while (!IsListEmpty (&RequestBlockArray->Entry)) {
3365 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3366 RemoveEntryList (&BlockData->Entry);
3367 FreePool (BlockData);
3368 }
3369
3370 FreePool (RequestBlockArray);
3371 }
3372
3373 return NULL;
3374 }
3375
3376 /**
3377 parse the configrequest string, get the elements.
3378
3379 @param ConfigRequest The input config request string.
3380 @param Progress Return the progress data.
3381
3382 @retval return data block array.
3383 **/
3384 IFR_BLOCK_DATA *
3385 GetNameElement (
3386 IN EFI_STRING ConfigRequest,
3387 OUT EFI_STRING *Progress
3388 )
3389 {
3390 EFI_STRING StringPtr;
3391 EFI_STRING NextTag;
3392 IFR_BLOCK_DATA *BlockData;
3393 IFR_BLOCK_DATA *RequestBlockArray;
3394 BOOLEAN HasValue;
3395
3396 StringPtr = ConfigRequest;
3397
3398 //
3399 // Init RequestBlockArray
3400 //
3401 RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3402 if (RequestBlockArray == NULL) {
3403 goto Done;
3404 }
3405
3406 InitializeListHead (&RequestBlockArray->Entry);
3407
3408 //
3409 // Get the request Block array from the request string
3410 //
3411
3412 //
3413 // Parse each <RequestElement> if exists
3414 // Only <BlockName> format is supported by this help function.
3415 // <BlockName> ::= &'Name***=***
3416 //
3417 while (StringPtr != NULL && *StringPtr == L'&') {
3418 *Progress = StringPtr;
3419 //
3420 // Skip the L"&" string
3421 //
3422 StringPtr += 1;
3423
3424 HasValue = FALSE;
3425 if ((NextTag = StrStr (StringPtr, L"=")) != NULL) {
3426 *NextTag = L'\0';
3427 HasValue = TRUE;
3428 } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) {
3429 *NextTag = L'\0';
3430 }
3431
3432 //
3433 // Set Block Data
3434 //
3435 BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3436 if (BlockData == NULL) {
3437 goto Done;
3438 }
3439
3440 //
3441 // Get Name
3442 //
3443 BlockData->Name = AllocateCopyPool (StrSize (StringPtr), StringPtr);
3444 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
3445
3446 if (HasValue) {
3447 //
3448 // If has value, skip the value.
3449 //
3450 StringPtr = NextTag + 1;
3451 *NextTag = L'=';
3452 StringPtr = StrStr (StringPtr, L"&");
3453 } else if (NextTag != NULL) {
3454 //
3455 // restore the '&' text.
3456 //
3457 StringPtr = NextTag;
3458 *NextTag = L'&';
3459 }
3460 }
3461
3462 return RequestBlockArray;
3463
3464 Done:
3465 if (RequestBlockArray != NULL) {
3466 //
3467 // Free Link Array RequestBlockArray
3468 //
3469 while (!IsListEmpty (&RequestBlockArray->Entry)) {
3470 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3471 RemoveEntryList (&BlockData->Entry);
3472 if (BlockData->Name != NULL) {
3473 FreePool (BlockData->Name);
3474 }
3475
3476 FreePool (BlockData);
3477 }
3478
3479 FreePool (RequestBlockArray);
3480 }
3481
3482 return NULL;
3483 }
3484
3485 /**
3486 Generate ConfigRequest string base on the varstore info.
3487
3488 @param ConfigHdr The config header for this varstore.
3489 @param VarStorageData The varstore info.
3490 @param Status Return Status.
3491 @param ConfigRequest The ConfigRequest info may be return.
3492
3493 @retval TRUE Need to continue
3494 @retval Others NO need to continue or error occur.
3495 **/
3496 BOOLEAN
3497 GenerateConfigRequest (
3498 IN CHAR16 *ConfigHdr,
3499 IN IFR_VARSTORAGE_DATA *VarStorageData,
3500 OUT EFI_STATUS *Status,
3501 IN OUT EFI_STRING *ConfigRequest
3502 )
3503 {
3504 BOOLEAN DataExist;
3505 UINTN Length;
3506 LIST_ENTRY *Link;
3507 CHAR16 *FullConfigRequest;
3508 CHAR16 *StringPtr;
3509 IFR_BLOCK_DATA *BlockData;
3510
3511 //
3512 // Append VarStorageData BlockEntry into *Request string
3513 // Now support only one varstore in a form package.
3514 //
3515
3516 //
3517 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
3518 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
3519 //
3520
3521 //
3522 // Compute the length of the entire request starting with <ConfigHdr> and a
3523 // Null-terminator
3524 //
3525 DataExist = FALSE;
3526 Length = StrLen (ConfigHdr) + 1;
3527
3528 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
3529 DataExist = TRUE;
3530 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3531 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3532 //
3533 // Add <BlockName> length for each Name
3534 //
3535 // <BlockName> ::= &Name1&Name2&...
3536 // |1| StrLen(Name1)
3537 //
3538 Length = Length + (1 + StrLen (BlockData->Name));
3539 } else {
3540 //
3541 // Add <BlockName> length for each Offset/Width pair
3542 //
3543 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
3544 // | 8 | 4 | 7 | 4 |
3545 //
3546 Length = Length + (8 + 4 + 7 + 4);
3547 }
3548 }
3549
3550 //
3551 // No any request block data is found. The request string can't be constructed.
3552 //
3553 if (!DataExist) {
3554 *Status = EFI_SUCCESS;
3555 return FALSE;
3556 }
3557
3558 //
3559 // Allocate buffer for the entire <ConfigRequest>
3560 //
3561 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
3562 if (FullConfigRequest == NULL) {
3563 *Status = EFI_OUT_OF_RESOURCES;
3564 return FALSE;
3565 }
3566
3567 StringPtr = FullConfigRequest;
3568
3569 //
3570 // Start with <ConfigHdr>
3571 //
3572 StrCpyS (StringPtr, Length, ConfigHdr);
3573 StringPtr += StrLen (StringPtr);
3574
3575 //
3576 // Loop through all the Offset/Width pairs and append them to ConfigRequest
3577 //
3578 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
3579 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3580 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3581 //
3582 // Append &Name1\0
3583 //
3584 UnicodeSPrint (
3585 StringPtr,
3586 (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16),
3587 L"&%s",
3588 BlockData->Name
3589 );
3590 } else {
3591 //
3592 // Append &OFFSET=XXXX&WIDTH=YYYY\0
3593 //
3594 UnicodeSPrint (
3595 StringPtr,
3596 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
3597 L"&OFFSET=%04X&WIDTH=%04X",
3598 BlockData->Offset,
3599 BlockData->Width
3600 );
3601 }
3602
3603 StringPtr += StrLen (StringPtr);
3604 }
3605
3606 //
3607 // Set to the got full request string.
3608 //
3609 HiiToLower (FullConfigRequest);
3610
3611 if (*ConfigRequest != NULL) {
3612 FreePool (*ConfigRequest);
3613 }
3614
3615 *ConfigRequest = FullConfigRequest;
3616
3617 return TRUE;
3618 }
3619
3620 /**
3621 Generate ConfigRequest Header base on the varstore info.
3622
3623 @param VarStorageData The varstore info.
3624 @param DevicePath Device path for this varstore.
3625 @param ConfigHdr The config header for this varstore.
3626
3627 @retval EFI_SUCCESS Generate the header success.
3628 @retval EFI_OUT_OF_RESOURCES Allocate buffer fail.
3629 **/
3630 EFI_STATUS
3631 GenerateHdr (
3632 IN IFR_VARSTORAGE_DATA *VarStorageData,
3633 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3634 OUT EFI_STRING *ConfigHdr
3635 )
3636 {
3637 EFI_STRING GuidStr;
3638 EFI_STRING NameStr;
3639 EFI_STRING PathStr;
3640 UINTN Length;
3641 EFI_STATUS Status;
3642
3643 Status = EFI_SUCCESS;
3644 NameStr = NULL;
3645 GuidStr = NULL;
3646 PathStr = NULL;
3647
3648 //
3649 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
3650 //
3651 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)&VarStorageData->Guid, 1, &GuidStr);
3652 if (VarStorageData->Name != NULL) {
3653 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *)VarStorageData->Name, 2, &NameStr);
3654 } else {
3655 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3656 }
3657
3658 GenerateSubStr (
3659 L"PATH=",
3660 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath),
3661 (VOID *)DevicePath,
3662 1,
3663 &PathStr
3664 );
3665 Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1;
3666 if (VarStorageData->Name == NULL) {
3667 Length += 1;
3668 }
3669
3670 *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
3671 if (*ConfigHdr == NULL) {
3672 Status = EFI_OUT_OF_RESOURCES;
3673 goto Done;
3674 }
3675
3676 StrCpyS (*ConfigHdr, Length, GuidStr);
3677 StrCatS (*ConfigHdr, Length, NameStr);
3678 if (VarStorageData->Name == NULL) {
3679 StrCatS (*ConfigHdr, Length, L"&");
3680 }
3681
3682 StrCatS (*ConfigHdr, Length, PathStr);
3683
3684 //
3685 // Remove the last character L'&'
3686 //
3687 *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0';
3688
3689 Done:
3690 if (GuidStr != NULL) {
3691 FreePool (GuidStr);
3692 }
3693
3694 if (NameStr != NULL) {
3695 FreePool (NameStr);
3696 }
3697
3698 if (PathStr != NULL) {
3699 FreePool (PathStr);
3700 }
3701
3702 return Status;
3703 }
3704
3705 /**
3706 Update the default value in the block data which is used as bit var store.
3707
3708 For example:
3709 A question value saved in a bit fied: bitoffset = 1; bitwidth = 2;default value = 1.
3710 And corresponding block data info: offset==0; width==1;currently the default value
3711 is saved as 1.Actually the default value 1 need to be set to bit field 1, so the
3712 default value of this block data shuold be:2.
3713
3714 typedef struct {
3715 UINT8 Bit1 : 1; //
3716 UINT8 Bit2 : 2; // Question saved in Bit2,so originalBlock info: offset = 0; width = 1;(byte level) defaul = 1.
3717 // (default value record for the bit field)
3718 ......
3719 }ExampleData;
3720
3721 After function UpdateDefaultValue,the Block info is: offset = 0; width = 1;(byte level) default = 2.
3722 (default value record for the Block)
3723
3724 UpdateDefaultValue function update default value of bit var block based on the bit field info in the block.
3725
3726 @param BlockLink The Link of the block data.
3727
3728 **/
3729 VOID
3730 UpdateDefaultValue (
3731 IN LIST_ENTRY *BlockLink
3732 )
3733 {
3734 LIST_ENTRY *Link;
3735 LIST_ENTRY *ListEntry;
3736 LIST_ENTRY *LinkDefault;
3737 IFR_BLOCK_DATA *BlockData;
3738 IFR_DEFAULT_DATA *DefaultValueData;
3739 UINTN StartBit;
3740 UINTN EndBit;
3741 UINT32 BitFieldDefaultValue;
3742
3743 for ( Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
3744 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3745 if (!BlockData->IsBitVar) {
3746 continue;
3747 }
3748
3749 ListEntry = &BlockData->DefaultValueEntry;
3750 //
3751 // Update the default value in the block data with all existing default id.
3752 //
3753 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
3754 //
3755 // Get the default data, and the value of the default data is for some field in the block.
3756 // Note: Default value for bit field question is stored as UINT32.
3757 //
3758 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3759 BitFieldDefaultValue = DefaultValueData->Value.u32;
3760
3761 StartBit = BlockData->BitOffset % 8;
3762 EndBit = StartBit + BlockData->BitWidth - 1;
3763
3764 //
3765 // Set the bit field default value to related bit filed, then we will got the new default vaule for the block data.
3766 //
3767 DefaultValueData->Value.u32 = BitFieldWrite32 (0, StartBit, EndBit, BitFieldDefaultValue);
3768 }
3769 }
3770 }
3771
3772 /**
3773 Merge the default value in two block datas which have overlap region.
3774
3775 For bit fields, their related block data may have overlap region, such as:
3776
3777 typedef struct {
3778 UINT16 Bit1 : 6; // Question1 refer Bit1, Block1: offset = 0; width = 1;(byte level) default = 1
3779 UINT16 Bit2 : 5; // Question2 refer Bit2, Block2: offset = 0; width = 2;(byte level) default = 5
3780 // (default value record for the bit field)
3781 ......
3782 }ExampleData;
3783
3784 After function UpdateDefaultValue:
3785 Block1: offset = 0; width = 1;(byte level) default = 1
3786 Block2: offset = 0; width = 2;(byte level) default = 320 (5 * (2 << 6))
3787 (default value record for block)
3788
3789 After function MergeBlockDefaultValue:
3790 Block1: offset = 0; width = 1;(byte level) default = 65
3791 Block2: offset = 0; width = 2;(byte level) default = 321
3792 (Block1 and Block2 has overlap region, merge the overlap value to Block1 and Blcok2)
3793
3794 Block1 and Block2 have overlap byte region, but currntly the default value of Block1 only contains
3795 value of Bit1 (low 6 bits),the default value of Block2 only contains the value of Bit2 (middle 5 bits).
3796
3797 This fuction merge the default value of these two blocks, and make the default value of block1
3798 also contain the value of lower 2 bits of the Bit2. And make the default value of Block2 also
3799 contain the default value of Bit1.
3800
3801 We can get the total value of the whole block that just cover these two blocks(in this case is:
3802 block: offset =0; width =2;) then the value of block2 is same as block, the value of block1 is
3803 the first byte value of block.
3804
3805 @param FirstBlock Point to the block date whose default value need to be merged.
3806 @param SecondBlock Point to the block date whose default value need to be merged.
3807
3808 **/
3809 VOID
3810 MergeBlockDefaultValue (
3811 IN OUT IFR_BLOCK_DATA *FirstBlock,
3812 IN OUT IFR_BLOCK_DATA *SecondBlock
3813 )
3814 {
3815 LIST_ENTRY *FirstListEntry;
3816 LIST_ENTRY *SecondListEntry;
3817 LIST_ENTRY *FirstDefaultLink;
3818 LIST_ENTRY *SecondDefaultLink;
3819 IFR_DEFAULT_DATA *FirstDefaultValueData;
3820 IFR_DEFAULT_DATA *SecondDefaultValueData;
3821 UINT32 *FirstDefaultValue;
3822 UINT32 *SecondDefaultValue;
3823 UINT64 TotalValue;
3824 UINT64 ShiftedValue;
3825 UINT16 OffsetShift;
3826
3827 FirstListEntry = &FirstBlock->DefaultValueEntry;
3828 for (FirstDefaultLink = FirstListEntry->ForwardLink; FirstDefaultLink != FirstListEntry; FirstDefaultLink = FirstDefaultLink->ForwardLink) {
3829 FirstDefaultValueData = BASE_CR (FirstDefaultLink, IFR_DEFAULT_DATA, Entry);
3830 SecondListEntry = &SecondBlock->DefaultValueEntry;
3831 for (SecondDefaultLink = SecondListEntry->ForwardLink; SecondDefaultLink != SecondListEntry; SecondDefaultLink = SecondDefaultLink->ForwardLink) {
3832 SecondDefaultValueData = BASE_CR (SecondDefaultLink, IFR_DEFAULT_DATA, Entry);
3833 if (FirstDefaultValueData->DefaultId != SecondDefaultValueData->DefaultId) {
3834 continue;
3835 }
3836
3837 //
3838 // Find default value with same default id in the two blocks.
3839 // Note: Default value for bit field question is stored as UINT32 type.
3840 //
3841 FirstDefaultValue = &FirstDefaultValueData->Value.u32;
3842 SecondDefaultValue = &SecondDefaultValueData->Value.u32;
3843 //
3844 // 1. Get the default value of the whole blcok that can just cover FirstBlock and SecondBlock.
3845 // 2. Get the default value of FirstBlock and SecondBlock form the value of whole block based
3846 // on the offset and width of FirstBlock and SecondBlock.
3847 //
3848 if (FirstBlock->Offset > SecondBlock->Offset) {
3849 OffsetShift = FirstBlock->Offset - SecondBlock->Offset;
3850 ShiftedValue = LShiftU64 ((UINT64)(*FirstDefaultValue), OffsetShift * 8);
3851 TotalValue = ShiftedValue | (UINT64)(*SecondDefaultValue);
3852 *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, SecondBlock->Width * 8 -1);
3853 *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + FirstBlock->Width *8 -1);
3854 } else {
3855 OffsetShift = SecondBlock->Offset -FirstBlock->Offset;
3856 ShiftedValue = LShiftU64 ((UINT64)(*SecondDefaultValue), OffsetShift * 8);
3857 TotalValue = ShiftedValue | (UINT64)(*FirstDefaultValue);
3858 *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, FirstBlock->Width * 8 -1);
3859 *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + SecondBlock->Width *8 -1);
3860 }
3861 }
3862 }
3863 }
3864
3865 /**
3866
3867 Update the default value in the block data which used as Bit VarStore
3868
3869 @param BlockLink The Link of the block data.
3870
3871 **/
3872 VOID
3873 UpdateBlockDataArray (
3874 IN LIST_ENTRY *BlockLink
3875 )
3876 {
3877 LIST_ENTRY *Link;
3878 LIST_ENTRY *TempLink;
3879 IFR_BLOCK_DATA *BlockData;
3880 IFR_BLOCK_DATA *NextBlockData;
3881
3882 //
3883 // 1. Update default value in BitVar block data.
3884 // Sine some block datas are used as BitVarStore, then the default value recored in the block
3885 // is for related bit field in the block. so we need to set the default value to the related bit
3886 // fields in the block data if the block data is used as bit varstore, then the default value of
3887 // the block will be updated.
3888 //
3889 UpdateDefaultValue (BlockLink);
3890
3891 //
3892 // 2.Update default value for overlap BitVar blcok datas.
3893 // For block datas have overlap region, we need to merge the default value in different blocks.
3894 //
3895 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
3896 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3897 if (!BlockData->IsBitVar) {
3898 continue;
3899 }
3900
3901 for (TempLink = Link->ForwardLink; TempLink != BlockLink; TempLink = TempLink->ForwardLink) {
3902 NextBlockData = BASE_CR (TempLink, IFR_BLOCK_DATA, Entry);
3903 if (!NextBlockData->IsBitVar || (NextBlockData->Offset >= BlockData->Offset + BlockData->Width) || (BlockData->Offset >= NextBlockData->Offset + NextBlockData->Width)) {
3904 continue;
3905 }
3906
3907 //
3908 // Find two blocks are used as bit VarStore and have overlap region, so need to merge default value of these two blocks.
3909 //
3910 MergeBlockDefaultValue (BlockData, NextBlockData);
3911 }
3912 }
3913 }
3914
3915 /**
3916 Generate ConfigAltResp string base on the varstore info.
3917
3918 @param HiiHandle Hii Handle for this hii package.
3919 @param ConfigHdr The config header for this varstore.
3920 @param VarStorageData The varstore info.
3921 @param DefaultIdArray The Default id array.
3922 @param DefaultAltCfgResp The DefaultAltCfgResp info may be return.
3923
3924 @retval TRUE Need to continue
3925 @retval Others NO need to continue or error occur.
3926 **/
3927 EFI_STATUS
3928 GenerateAltConfigResp (
3929 IN EFI_HII_HANDLE HiiHandle,
3930 IN CHAR16 *ConfigHdr,
3931 IN IFR_VARSTORAGE_DATA *VarStorageData,
3932 IN IFR_DEFAULT_DATA *DefaultIdArray,
3933 IN OUT EFI_STRING *DefaultAltCfgResp
3934 )
3935 {
3936 BOOLEAN DataExist;
3937 UINTN Length;
3938 LIST_ENTRY *Link;
3939 LIST_ENTRY *LinkData;
3940 LIST_ENTRY *LinkDefault;
3941 LIST_ENTRY *ListEntry;
3942 CHAR16 *StringPtr;
3943 IFR_BLOCK_DATA *BlockData;
3944 IFR_DEFAULT_DATA *DefaultId;
3945 IFR_DEFAULT_DATA *DefaultValueData;
3946 UINTN Width;
3947 UINT8 *TmpBuffer;
3948 CHAR16 *DefaultString;
3949 UINTN StrSize;
3950
3951 BlockData = NULL;
3952 DataExist = FALSE;
3953 DefaultString = NULL;
3954 //
3955 // Add length for <ConfigHdr> + '\0'
3956 //
3957 Length = StrLen (ConfigHdr) + 1;
3958
3959 UpdateBlockDataArray (&VarStorageData->BlockEntry);
3960
3961 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
3962 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
3963 //
3964 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
3965 // |1| StrLen (ConfigHdr) | 8 | 4 |
3966 //
3967 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
3968
3969 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
3970 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
3971 ListEntry = &BlockData->DefaultValueEntry;
3972 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
3973 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3974 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
3975 continue;
3976 }
3977
3978 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3979 //
3980 // Add length for "&Name1=zzzzzzzzzzzz"
3981 // |1|Name|1|Value|
3982 //
3983 Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2);
3984 } else {
3985 //
3986 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
3987 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
3988 //
3989 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
3990 }
3991
3992 DataExist = TRUE;
3993 }
3994 }
3995 }
3996
3997 //
3998 // No default value is found. The default string doesn't exist.
3999 //
4000 if (!DataExist) {
4001 return EFI_SUCCESS;
4002 }
4003
4004 //
4005 // Allocate buffer for the entire <DefaultAltCfgResp>
4006 //
4007 *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
4008 if (*DefaultAltCfgResp == NULL) {
4009 return EFI_OUT_OF_RESOURCES;
4010 }
4011
4012 StringPtr = *DefaultAltCfgResp;
4013
4014 //
4015 // Start with <ConfigHdr>
4016 //
4017 StrCpyS (StringPtr, Length, ConfigHdr);
4018 StringPtr += StrLen (StringPtr);
4019
4020 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
4021 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
4022 //
4023 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
4024 // |1| StrLen (ConfigHdr) | 8 | 4 |
4025 //
4026 UnicodeSPrint (
4027 StringPtr,
4028 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
4029 L"&%s&ALTCFG=%04X",
4030 ConfigHdr,
4031 DefaultId->DefaultId
4032 );
4033 StringPtr += StrLen (StringPtr);
4034
4035 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
4036 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
4037 ListEntry = &BlockData->DefaultValueEntry;
4038 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
4039 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
4040 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
4041 continue;
4042 }
4043
4044 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4045 UnicodeSPrint (
4046 StringPtr,
4047 (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16),
4048 L"&%s=",
4049 BlockData->Name
4050 );
4051 StringPtr += StrLen (StringPtr);
4052 } else {
4053 //
4054 // Add <BlockConfig>
4055 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
4056 //
4057 UnicodeSPrint (
4058 StringPtr,
4059 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
4060 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
4061 BlockData->Offset,
4062 BlockData->Width
4063 );
4064 StringPtr += StrLen (StringPtr);
4065 }
4066
4067 Width = BlockData->Width;
4068 //
4069 // Convert Value to a hex string in "%x" format
4070 // NOTE: This is in the opposite byte that GUID and PATH use
4071 //
4072 if (BlockData->OpCode == EFI_IFR_STRING_OP) {
4073 DefaultString = InternalGetString (HiiHandle, DefaultValueData->Value.string);
4074 TmpBuffer = AllocateZeroPool (Width);
4075 ASSERT (TmpBuffer != NULL);
4076 if (DefaultString != NULL) {
4077 StrSize = StrLen (DefaultString)* sizeof (CHAR16);
4078 if (StrSize > Width) {
4079 StrSize = Width;
4080 }
4081
4082 CopyMem (TmpBuffer, (UINT8 *)DefaultString, StrSize);
4083 }
4084 } else {
4085 TmpBuffer = (UINT8 *)&(DefaultValueData->Value);
4086 }
4087
4088 for ( ; Width > 0 && (TmpBuffer != NULL); Width--) {
4089 UnicodeValueToStringS (
4090 StringPtr,
4091 Length * sizeof (CHAR16) - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp),
4092 PREFIX_ZERO | RADIX_HEX,
4093 TmpBuffer[Width - 1],
4094 2
4095 );
4096 StringPtr += StrnLenS (StringPtr, Length - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp) / sizeof (CHAR16));
4097 }
4098
4099 if (DefaultString != NULL) {
4100 FreePool (DefaultString);
4101 DefaultString = NULL;
4102 }
4103
4104 if ((BlockData->OpCode == EFI_IFR_STRING_OP) && (TmpBuffer != NULL)) {
4105 FreePool (TmpBuffer);
4106 TmpBuffer = NULL;
4107 }
4108 }
4109 }
4110 }
4111
4112 HiiToLower (*DefaultAltCfgResp);
4113
4114 return EFI_SUCCESS;
4115 }
4116
4117 /**
4118 This function gets the full request string and full default value string by
4119 parsing IFR data in HII form packages.
4120
4121 When Request points to NULL string, the request string and default value string
4122 for each varstore in form package will return.
4123
4124 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
4125 @param DevicePath Device Path which Hii Config Access Protocol is registered.
4126 @param Request Pointer to a null-terminated Unicode string in
4127 <ConfigRequest> format. When it doesn't contain
4128 any RequestElement, it will be updated to return
4129 the full RequestElement retrieved from IFR data.
4130 If it points to NULL, the request string for the first
4131 varstore in form package will be merged into a
4132 <MultiConfigRequest> format string and return.
4133 @param AltCfgResp Pointer to a null-terminated Unicode string in
4134 <ConfigAltResp> format. When the pointer is to NULL,
4135 the full default value string retrieved from IFR data
4136 will return. When the pinter is to a string, the
4137 full default value string retrieved from IFR data
4138 will be merged into the input string and return.
4139 When Request points to NULL, the default value string
4140 for each varstore in form package will be merged into
4141 a <MultiConfigAltResp> format string and return.
4142 @param PointerProgress Optional parameter, it can be NULL.
4143 When it is not NULL, if Request is NULL, it returns NULL.
4144 On return, points to a character in the Request
4145 string. Points to the string's null terminator if
4146 request was successful. Points to the most recent
4147 & before the first failing name / value pair (or
4148 the beginning of the string if the failure is in
4149 the first name / value pair) if the request was
4150 not successful.
4151 @retval EFI_SUCCESS The Results string is set to the full request string.
4152 And AltCfgResp contains all default value string.
4153 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4154 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
4155 can't be found in Form package.
4156 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
4157 @retval EFI_INVALID_PARAMETER Request points to NULL.
4158
4159 **/
4160 EFI_STATUS
4161 EFIAPI
4162 GetFullStringFromHiiFormPackages (
4163 IN HII_DATABASE_RECORD *DataBaseRecord,
4164 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
4165 IN OUT EFI_STRING *Request,
4166 IN OUT EFI_STRING *AltCfgResp,
4167 OUT EFI_STRING *PointerProgress OPTIONAL
4168 )
4169 {
4170 EFI_STATUS Status;
4171 UINT8 *HiiFormPackage;
4172 UINTN PackageSize;
4173 IFR_BLOCK_DATA *RequestBlockArray;
4174 IFR_BLOCK_DATA *BlockData;
4175 IFR_DEFAULT_DATA *DefaultValueData;
4176 IFR_DEFAULT_DATA *DefaultId;
4177 IFR_DEFAULT_DATA *DefaultIdArray;
4178 IFR_VARSTORAGE_DATA *VarStorageData;
4179 EFI_STRING DefaultAltCfgResp;
4180 EFI_STRING ConfigHdr;
4181 EFI_STRING StringPtr;
4182 EFI_STRING Progress;
4183
4184 if ((DataBaseRecord == NULL) || (DevicePath == NULL) || (Request == NULL) || (AltCfgResp == NULL)) {
4185 return EFI_INVALID_PARAMETER;
4186 }
4187
4188 //
4189 // Initialize the local variables.
4190 //
4191 RequestBlockArray = NULL;
4192 DefaultIdArray = NULL;
4193 VarStorageData = NULL;
4194 DefaultAltCfgResp = NULL;
4195 ConfigHdr = NULL;
4196 HiiFormPackage = NULL;
4197 PackageSize = 0;
4198 Progress = *Request;
4199
4200 Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
4201 if (EFI_ERROR (Status)) {
4202 goto Done;
4203 }
4204
4205 //
4206 // 1. Get the request block array by Request String when Request string contains the block array.
4207 //
4208 StringPtr = NULL;
4209 if (*Request != NULL) {
4210 StringPtr = *Request;
4211 //
4212 // Jump <ConfigHdr>
4213 //
4214 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4215 Status = EFI_INVALID_PARAMETER;
4216 goto Done;
4217 }
4218
4219 StringPtr += StrLen (L"GUID=");
4220 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
4221 StringPtr++;
4222 }
4223
4224 if (*StringPtr == L'\0') {
4225 Status = EFI_INVALID_PARAMETER;
4226 goto Done;
4227 }
4228
4229 StringPtr += StrLen (L"&NAME=");
4230 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
4231 StringPtr++;
4232 }
4233
4234 if (*StringPtr == L'\0') {
4235 Status = EFI_INVALID_PARAMETER;
4236 goto Done;
4237 }
4238
4239 StringPtr += StrLen (L"&PATH=");
4240 while (*StringPtr != L'\0' && *StringPtr != L'&') {
4241 StringPtr++;
4242 }
4243
4244 if (*StringPtr == L'\0') {
4245 //
4246 // No request block is found.
4247 //
4248 StringPtr = NULL;
4249 }
4250 }
4251
4252 //
4253 // If StringPtr != NULL, get the request elements.
4254 //
4255 if (StringPtr != NULL) {
4256 if (StrStr (StringPtr, L"&OFFSET=") != NULL) {
4257 RequestBlockArray = GetBlockElement (StringPtr, &Progress);
4258 } else {
4259 RequestBlockArray = GetNameElement (StringPtr, &Progress);
4260 }
4261
4262 if (RequestBlockArray == NULL) {
4263 Status = EFI_INVALID_PARAMETER;
4264 goto Done;
4265 }
4266 }
4267
4268 //
4269 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
4270 //
4271 DefaultIdArray = (IFR_DEFAULT_DATA *)AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
4272 if (DefaultIdArray == NULL) {
4273 Status = EFI_OUT_OF_RESOURCES;
4274 goto Done;
4275 }
4276
4277 InitializeListHead (&DefaultIdArray->Entry);
4278
4279 //
4280 // Initialize VarStorageData to store the var store Block and Default value information.
4281 //
4282 VarStorageData = (IFR_VARSTORAGE_DATA *)AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
4283 if (VarStorageData == NULL) {
4284 Status = EFI_OUT_OF_RESOURCES;
4285 goto Done;
4286 }
4287
4288 InitializeListHead (&VarStorageData->Entry);
4289 InitializeListHead (&VarStorageData->BlockEntry);
4290
4291 //
4292 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
4293 //
4294
4295 //
4296 // Parse the opcode in form package to get the default setting.
4297 //
4298 Status = ParseIfrData (
4299 DataBaseRecord->Handle,
4300 HiiFormPackage,
4301 (UINT32)PackageSize,
4302 *Request,
4303 RequestBlockArray,
4304 VarStorageData,
4305 DefaultIdArray
4306 );
4307 if (EFI_ERROR (Status)) {
4308 goto Done;
4309 }
4310
4311 //
4312 // No requested varstore in IFR data and directly return
4313 //
4314 if ((VarStorageData->Type == 0) && (VarStorageData->Name == NULL)) {
4315 Status = EFI_SUCCESS;
4316 goto Done;
4317 }
4318
4319 //
4320 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
4321 //
4322 Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr);
4323 if (EFI_ERROR (Status)) {
4324 goto Done;
4325 }
4326
4327 if (RequestBlockArray == NULL) {
4328 if (!GenerateConfigRequest (ConfigHdr, VarStorageData, &Status, Request)) {
4329 goto Done;
4330 }
4331 }
4332
4333 //
4334 // 4. Construct Default Value string in AltResp according to request element.
4335 // Go through all VarStorageData Entry and get the DefaultId array for each one
4336 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
4337 //
4338 Status = GenerateAltConfigResp (DataBaseRecord->Handle, ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp);
4339 if (EFI_ERROR (Status)) {
4340 goto Done;
4341 }
4342
4343 //
4344 // 5. Merge string into the input AltCfgResp if the input *AltCfgResp is not NULL.
4345 //
4346 if ((*AltCfgResp != NULL) && (DefaultAltCfgResp != NULL)) {
4347 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
4348 FreePool (DefaultAltCfgResp);
4349 } else if (*AltCfgResp == NULL) {
4350 *AltCfgResp = DefaultAltCfgResp;
4351 }
4352
4353 Done:
4354 if (RequestBlockArray != NULL) {
4355 //
4356 // Free Link Array RequestBlockArray
4357 //
4358 while (!IsListEmpty (&RequestBlockArray->Entry)) {
4359 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
4360 RemoveEntryList (&BlockData->Entry);
4361 if (BlockData->Name != NULL) {
4362 FreePool (BlockData->Name);
4363 }
4364
4365 FreePool (BlockData);
4366 }
4367
4368 FreePool (RequestBlockArray);
4369 }
4370
4371 if (VarStorageData != NULL) {
4372 //
4373 // Free link array VarStorageData
4374 //
4375 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
4376 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
4377 RemoveEntryList (&BlockData->Entry);
4378 if (BlockData->Name != NULL) {
4379 FreePool (BlockData->Name);
4380 }
4381
4382 //
4383 // Free default value link array
4384 //
4385 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
4386 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
4387 RemoveEntryList (&DefaultValueData->Entry);
4388 FreePool (DefaultValueData);
4389 }
4390
4391 FreePool (BlockData);
4392 }
4393
4394 if (VarStorageData->Name != NULL) {
4395 FreePool (VarStorageData->Name);
4396 VarStorageData->Name = NULL;
4397 }
4398
4399 FreePool (VarStorageData);
4400 }
4401
4402 if (DefaultIdArray != NULL) {
4403 //
4404 // Free DefaultId Array
4405 //
4406 while (!IsListEmpty (&DefaultIdArray->Entry)) {
4407 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
4408 RemoveEntryList (&DefaultId->Entry);
4409 FreePool (DefaultId);
4410 }
4411
4412 FreePool (DefaultIdArray);
4413 }
4414
4415 //
4416 // Free the allocated string
4417 //
4418 if (ConfigHdr != NULL) {
4419 FreePool (ConfigHdr);
4420 }
4421
4422 //
4423 // Free Package data
4424 //
4425 if (HiiFormPackage != NULL) {
4426 FreePool (HiiFormPackage);
4427 }
4428
4429 if (PointerProgress != NULL) {
4430 if (*Request == NULL) {
4431 *PointerProgress = NULL;
4432 } else if (EFI_ERROR (Status)) {
4433 *PointerProgress = *Request;
4434 } else {
4435 *PointerProgress = *Request + StrLen (*Request);
4436 }
4437 }
4438
4439 return Status;
4440 }
4441
4442 /**
4443 This function gets the full request resp string by
4444 parsing IFR data in HII form packages.
4445
4446 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4447 instance.
4448 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
4449 varstore data structure.
4450 @param Request Pointer to a null-terminated Unicode string in
4451 <ConfigRequest> format.
4452 @param RequestResp Pointer to a null-terminated Unicode string in
4453 <ConfigResp> format.
4454 @param AccessProgress On return, points to a character in the Request
4455 string. Points to the string's null terminator if
4456 request was successful. Points to the most recent
4457 & before the first failing name / value pair (or
4458 the beginning of the string if the failure is in
4459 the first name / value pair) if the request was
4460 not successful.
4461
4462 @retval EFI_SUCCESS The Results string is set to the full request string.
4463 And AltCfgResp contains all default value string.
4464 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4465 @retval EFI_INVALID_PARAMETER Request points to NULL.
4466
4467 **/
4468 EFI_STATUS
4469 GetConfigRespFromEfiVarStore (
4470 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4471 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
4472 IN EFI_STRING Request,
4473 OUT EFI_STRING *RequestResp,
4474 OUT EFI_STRING *AccessProgress
4475 )
4476 {
4477 EFI_STATUS Status;
4478 EFI_STRING VarStoreName;
4479 UINTN NameSize;
4480 UINT8 *VarStore;
4481 UINTN BufferSize;
4482
4483 Status = EFI_SUCCESS;
4484 BufferSize = 0;
4485 VarStore = NULL;
4486 VarStoreName = NULL;
4487 *AccessProgress = Request;
4488
4489 NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
4490 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
4491 if (VarStoreName == NULL) {
4492 Status = EFI_OUT_OF_RESOURCES;
4493 goto Done;
4494 }
4495
4496 AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize);
4497
4498 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
4499 if (Status != EFI_BUFFER_TOO_SMALL) {
4500 goto Done;
4501 }
4502
4503 VarStore = AllocateZeroPool (BufferSize);
4504 ASSERT (VarStore != NULL);
4505 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
4506 if (EFI_ERROR (Status)) {
4507 goto Done;
4508 }
4509
4510 Status = HiiBlockToConfig (This, Request, VarStore, BufferSize, RequestResp, AccessProgress);
4511 if (EFI_ERROR (Status)) {
4512 goto Done;
4513 }
4514
4515 Done:
4516 if (VarStoreName != NULL) {
4517 FreePool (VarStoreName);
4518 }
4519
4520 if (VarStore != NULL) {
4521 FreePool (VarStore);
4522 }
4523
4524 return Status;
4525 }
4526
4527 /**
4528 This function route the full request resp string for efi varstore.
4529
4530 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4531 instance.
4532 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
4533 varstore data structure.
4534 @param RequestResp Pointer to a null-terminated Unicode string in
4535 <ConfigResp> format.
4536 @param Result Pointer to a null-terminated Unicode string in
4537 <ConfigResp> format.
4538
4539 @retval EFI_SUCCESS The Results string is set to the full request string.
4540 And AltCfgResp contains all default value string.
4541 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4542 @retval EFI_INVALID_PARAMETER Request points to NULL.
4543
4544 **/
4545 EFI_STATUS
4546 RouteConfigRespForEfiVarStore (
4547 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4548 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
4549 IN EFI_STRING RequestResp,
4550 OUT EFI_STRING *Result
4551 )
4552 {
4553 EFI_STATUS Status;
4554 EFI_STRING VarStoreName;
4555 UINTN NameSize;
4556 UINT8 *VarStore;
4557 UINTN BufferSize;
4558 UINTN BlockSize;
4559
4560 Status = EFI_SUCCESS;
4561 BufferSize = 0;
4562 VarStore = NULL;
4563 VarStoreName = NULL;
4564 *Result = RequestResp;
4565
4566 NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
4567 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
4568 if (VarStoreName == NULL) {
4569 Status = EFI_OUT_OF_RESOURCES;
4570 goto Done;
4571 }
4572
4573 AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize);
4574
4575 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
4576 if (Status != EFI_BUFFER_TOO_SMALL) {
4577 DEBUG ((DEBUG_ERROR, "The variable does not exist!"));
4578 goto Done;
4579 }
4580
4581 BlockSize = BufferSize;
4582 VarStore = AllocateZeroPool (BufferSize);
4583 ASSERT (VarStore != NULL);
4584 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
4585 if (EFI_ERROR (Status)) {
4586 goto Done;
4587 }
4588
4589 Status = HiiConfigToBlock (This, RequestResp, VarStore, &BlockSize, Result);
4590 if (EFI_ERROR (Status)) {
4591 goto Done;
4592 }
4593
4594 Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore);
4595 if (EFI_ERROR (Status)) {
4596 *Result = RequestResp;
4597 goto Done;
4598 }
4599
4600 Done:
4601 if (VarStoreName != NULL) {
4602 FreePool (VarStoreName);
4603 }
4604
4605 if (VarStore != NULL) {
4606 FreePool (VarStore);
4607 }
4608
4609 return Status;
4610 }
4611
4612 /**
4613 Validate the config request elements.
4614
4615 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
4616 without configHdr field.
4617
4618 @retval CHAR16 * THE first Name/value pair not correct.
4619 @retval NULL Success parse the name/value pair
4620 **/
4621 CHAR16 *
4622 OffsetWidthValidate (
4623 CHAR16 *ConfigElements
4624 )
4625 {
4626 CHAR16 *StringPtr;
4627 CHAR16 *RetVal;
4628
4629 StringPtr = ConfigElements;
4630
4631 while (1) {
4632 RetVal = StringPtr;
4633 if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
4634 return RetVal;
4635 }
4636
4637 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4638 StringPtr++;
4639 }
4640
4641 if (*StringPtr == L'\0') {
4642 return RetVal;
4643 }
4644
4645 StringPtr += StrLen (L"&WIDTH=");
4646 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
4647 StringPtr++;
4648 }
4649
4650 if (*StringPtr == L'\0') {
4651 return NULL;
4652 }
4653 }
4654 }
4655
4656 /**
4657 Validate the config request elements.
4658
4659 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
4660 without configHdr field.
4661
4662 @retval CHAR16 * THE first Name/value pair not correct.
4663 @retval NULL Success parse the name/value pair
4664
4665 **/
4666 CHAR16 *
4667 NameValueValidate (
4668 CHAR16 *ConfigElements
4669 )
4670 {
4671 CHAR16 *StringPtr;
4672 CHAR16 *RetVal;
4673
4674 StringPtr = ConfigElements;
4675
4676 while (1) {
4677 RetVal = StringPtr;
4678 if (*StringPtr != L'&') {
4679 return RetVal;
4680 }
4681
4682 StringPtr += 1;
4683
4684 StringPtr = StrStr (StringPtr, L"&");
4685
4686 if (StringPtr == NULL) {
4687 return NULL;
4688 }
4689 }
4690 }
4691
4692 /**
4693 Validate the config request string.
4694
4695 @param ConfigRequest A null-terminated Unicode string in <ConfigRequest> format.
4696
4697 @retval CHAR16 * THE first element not correct.
4698 @retval NULL Success parse the name/value pair
4699
4700 **/
4701 CHAR16 *
4702 ConfigRequestValidate (
4703 CHAR16 *ConfigRequest
4704 )
4705 {
4706 BOOLEAN HasNameField;
4707 CHAR16 *StringPtr;
4708
4709 HasNameField = TRUE;
4710 StringPtr = ConfigRequest;
4711
4712 //
4713 // Check <ConfigHdr>
4714 //
4715 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4716 return ConfigRequest;
4717 }
4718
4719 StringPtr += StrLen (L"GUID=");
4720 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
4721 StringPtr++;
4722 }
4723
4724 if (*StringPtr == L'\0') {
4725 return ConfigRequest;
4726 }
4727
4728 StringPtr += StrLen (L"&NAME=");
4729 if (*StringPtr == L'&') {
4730 HasNameField = FALSE;
4731 }
4732
4733 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
4734 StringPtr++;
4735 }
4736
4737 if (*StringPtr == L'\0') {
4738 return ConfigRequest;
4739 }
4740
4741 StringPtr += StrLen (L"&PATH=");
4742 while (*StringPtr != L'\0' && *StringPtr != L'&') {
4743 StringPtr++;
4744 }
4745
4746 if (*StringPtr == L'\0') {
4747 return NULL;
4748 }
4749
4750 if (HasNameField) {
4751 //
4752 // Should be Buffer varstore, config request should be "OFFSET/Width" pairs.
4753 //
4754 return OffsetWidthValidate (StringPtr);
4755 } else {
4756 //
4757 // Should be Name/Value varstore, config request should be "&name1&name2..." pairs.
4758 //
4759 return NameValueValidate (StringPtr);
4760 }
4761 }
4762
4763 /**
4764 This function allows a caller to extract the current configuration
4765 for one or more named elements from one or more drivers.
4766
4767 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4768 instance.
4769 @param Request A null-terminated Unicode string in
4770 <MultiConfigRequest> format.
4771 @param Progress On return, points to a character in the Request
4772 string. Points to the string's null terminator if
4773 request was successful. Points to the most recent
4774 & before the first failing name / value pair (or
4775 the beginning of the string if the failure is in
4776 the first name / value pair) if the request was
4777 not successful.
4778 @param Results Null-terminated Unicode string in
4779 <MultiConfigAltResp> format which has all values
4780 filled in for the names in the Request string.
4781 String to be allocated by the called function.
4782
4783 @retval EFI_SUCCESS The Results string is filled with the values
4784 corresponding to all requested names.
4785 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
4786 results that must be stored awaiting possible
4787 future protocols.
4788 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
4789 Progress set to the "G" in "GUID" of the routing
4790 header that doesn't match. Note: There is no
4791 requirement that all routing data be validated
4792 before any configuration extraction.
4793 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
4794 parameter would result in this type of error. The
4795 Progress parameter is set to NULL.
4796 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
4797 before the error or the beginning of the string.
4798 @retval EFI_INVALID_PARAMETER The ExtractConfig function of the underlying HII
4799 Configuration Access Protocol returned
4800 EFI_INVALID_PARAMETER. Progress set to most recent
4801 & before the error or the beginning of the string.
4802
4803 **/
4804 EFI_STATUS
4805 EFIAPI
4806 HiiConfigRoutingExtractConfig (
4807 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4808 IN CONST EFI_STRING Request,
4809 OUT EFI_STRING *Progress,
4810 OUT EFI_STRING *Results
4811 )
4812 {
4813 HII_DATABASE_PRIVATE_DATA *Private;
4814 EFI_STRING StringPtr;
4815 EFI_STRING ConfigRequest;
4816 UINTN Length;
4817 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
4818 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4819 EFI_STATUS Status;
4820 LIST_ENTRY *Link;
4821 HII_DATABASE_RECORD *Database;
4822 UINT8 *DevicePathPkg;
4823 UINT8 *CurrentDevicePath;
4824 EFI_HANDLE DriverHandle;
4825 EFI_HII_HANDLE HiiHandle;
4826 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4827 EFI_STRING AccessProgress;
4828 EFI_STRING AccessResults;
4829 EFI_STRING AccessProgressBackup;
4830 EFI_STRING AccessResultsBackup;
4831 EFI_STRING DefaultResults;
4832 BOOLEAN FirstElement;
4833 BOOLEAN IfrDataParsedFlag;
4834 BOOLEAN IsEfiVarStore;
4835 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
4836 EFI_STRING ErrorPtr;
4837 UINTN DevicePathSize;
4838 UINTN ConigStringSize;
4839 UINTN ConigStringSizeNewsize;
4840 EFI_STRING ConfigStringPtr;
4841
4842 if ((This == NULL) || (Progress == NULL) || (Results == NULL)) {
4843 return EFI_INVALID_PARAMETER;
4844 }
4845
4846 if (Request == NULL) {
4847 *Progress = NULL;
4848 return EFI_INVALID_PARAMETER;
4849 }
4850
4851 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4852 StringPtr = Request;
4853 *Progress = StringPtr;
4854 DefaultResults = NULL;
4855 ConfigRequest = NULL;
4856 Status = EFI_SUCCESS;
4857 AccessResults = NULL;
4858 AccessProgress = NULL;
4859 AccessResultsBackup = NULL;
4860 AccessProgressBackup = NULL;
4861 DevicePath = NULL;
4862 IfrDataParsedFlag = FALSE;
4863 IsEfiVarStore = FALSE;
4864 EfiVarStoreInfo = NULL;
4865
4866 //
4867 // The first element of <MultiConfigRequest> should be
4868 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
4869 //
4870 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4871 return EFI_INVALID_PARAMETER;
4872 }
4873
4874 FirstElement = TRUE;
4875
4876 //
4877 // Allocate a fix length of memory to store Results. Reallocate memory for
4878 // Results if this fix length is insufficient.
4879 //
4880 *Results = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
4881 if (*Results == NULL) {
4882 return EFI_OUT_OF_RESOURCES;
4883 }
4884
4885 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
4886 //
4887 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
4888 // or most recent & before the error.
4889 //
4890 if (StringPtr == Request) {
4891 *Progress = StringPtr;
4892 } else {
4893 *Progress = StringPtr - 1;
4894 }
4895
4896 //
4897 // Process each <ConfigRequest> of <MultiConfigRequest>
4898 //
4899 Length = CalculateConfigStringLen (StringPtr);
4900 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
4901 if (ConfigRequest == NULL) {
4902 Status = EFI_OUT_OF_RESOURCES;
4903 goto Done;
4904 }
4905
4906 *(ConfigRequest + Length) = 0;
4907
4908 //
4909 // Get the UEFI device path
4910 //
4911 Status = GetDevicePath (ConfigRequest, (UINT8 **)&DevicePath);
4912 if (EFI_ERROR (Status)) {
4913 goto Done;
4914 }
4915
4916 //
4917 // Find driver which matches the routing data.
4918 //
4919 DriverHandle = NULL;
4920 HiiHandle = NULL;
4921 Database = NULL;
4922 for (Link = Private->DatabaseList.ForwardLink;
4923 Link != &Private->DatabaseList;
4924 Link = Link->ForwardLink
4925 )
4926 {
4927 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4928 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4929 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4930 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath);
4931 if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigRequest)) {
4932 DriverHandle = Database->DriverHandle;
4933 HiiHandle = Database->Handle;
4934 break;
4935 }
4936 }
4937 }
4938
4939 //
4940 // Try to find driver handle by device path.
4941 //
4942 if (DriverHandle == NULL) {
4943 TempDevicePath = DevicePath;
4944 Status = gBS->LocateDevicePath (
4945 &gEfiDevicePathProtocolGuid,
4946 &TempDevicePath,
4947 &DriverHandle
4948 );
4949 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
4950 //
4951 // Routing data does not match any known driver.
4952 // Set Progress to the 'G' in "GUID" of the routing header.
4953 //
4954 *Progress = StringPtr;
4955 Status = EFI_NOT_FOUND;
4956 goto Done;
4957 }
4958 }
4959
4960 //
4961 // Validate ConfigRequest String.
4962 //
4963 ErrorPtr = ConfigRequestValidate (ConfigRequest);
4964 if (ErrorPtr != NULL) {
4965 *Progress = StrStr (StringPtr, ErrorPtr);
4966 Status = EFI_INVALID_PARAMETER;
4967 goto Done;
4968 }
4969
4970 //
4971 // Check whether ConfigRequest contains request string.
4972 //
4973 IfrDataParsedFlag = FALSE;
4974 if ((HiiHandle != NULL) && !GetElementsFromRequest (ConfigRequest)) {
4975 //
4976 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
4977 //
4978 IfrDataParsedFlag = TRUE;
4979 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
4980 if (EFI_ERROR (Status)) {
4981 //
4982 // AccessProgress indicates the parsing progress on <ConfigRequest>.
4983 // Map it to the progress on <MultiConfigRequest> then return it.
4984 //
4985 ASSERT (AccessProgress != NULL);
4986 *Progress = StrStr (StringPtr, AccessProgress);
4987 goto Done;
4988 }
4989
4990 //
4991 // Not any request block is found.
4992 //
4993 if (!GetElementsFromRequest (ConfigRequest)) {
4994 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
4995 goto NextConfigString;
4996 }
4997 }
4998
4999 //
5000 // Check whether this ConfigRequest is search from Efi varstore type storage.
5001 //
5002 Status = GetVarStoreType (Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo);
5003 if (EFI_ERROR (Status)) {
5004 goto Done;
5005 }
5006
5007 if (IsEfiVarStore) {
5008 //
5009 // Call the GetVariable function to extract settings.
5010 //
5011 Status = GetConfigRespFromEfiVarStore (This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress);
5012 FreePool (EfiVarStoreInfo);
5013 if (EFI_ERROR (Status)) {
5014 //
5015 // AccessProgress indicates the parsing progress on <ConfigRequest>.
5016 // Map it to the progress on <MultiConfigRequest> then return it.
5017 //
5018 *Progress = StrStr (StringPtr, AccessProgress);
5019 goto Done;
5020 }
5021
5022 //
5023 // For EfiVarstore, call corresponding ConfigAccess protocol to get the AltCfgResp from driver.
5024 //
5025 Status = gBS->HandleProtocol (
5026 DriverHandle,
5027 &gEfiHiiConfigAccessProtocolGuid,
5028 (VOID **)&ConfigAccess
5029 );
5030 if (EFI_ERROR (Status)) {
5031 //
5032 // The driver has EfiVarStore, may not install ConfigAccess protocol.
5033 // So ignore the error status in this case.
5034 //
5035 Status = EFI_SUCCESS;
5036 } else {
5037 Status = ConfigAccess->ExtractConfig (
5038 ConfigAccess,
5039 ConfigRequest,
5040 &AccessProgressBackup,
5041 &AccessResultsBackup
5042 );
5043 if (!EFI_ERROR (Status)) {
5044 //
5045 // Merge the AltCfgResp in AccessResultsBackup to AccessResults
5046 //
5047 if ((AccessResultsBackup != NULL) && (StrStr (AccessResultsBackup, L"&ALTCFG=") != NULL)) {
5048 ConigStringSize = StrSize (AccessResults);
5049 ConfigStringPtr = StrStr (AccessResultsBackup, L"&GUID=");
5050 ConigStringSizeNewsize = StrSize (ConfigStringPtr) + ConigStringSize + sizeof (CHAR16);
5051 AccessResults = (EFI_STRING)ReallocatePool (
5052 ConigStringSize,
5053 ConigStringSizeNewsize,
5054 AccessResults
5055 );
5056 StrCatS (AccessResults, ConigStringSizeNewsize / sizeof (CHAR16), ConfigStringPtr);
5057 }
5058 } else {
5059 //
5060 // In the ExtractConfig function of some driver may not support EfiVarStore,
5061 // may return error status, just ignore the error status in this case.
5062 //
5063 Status = EFI_SUCCESS;
5064 }
5065
5066 if (AccessResultsBackup != NULL) {
5067 FreePool (AccessResultsBackup);
5068 AccessResultsBackup = NULL;
5069 }
5070 }
5071 } else {
5072 //
5073 // Call corresponding ConfigAccess protocol to extract settings
5074 //
5075 Status = gBS->HandleProtocol (
5076 DriverHandle,
5077 &gEfiHiiConfigAccessProtocolGuid,
5078 (VOID **)&ConfigAccess
5079 );
5080 if (EFI_ERROR (Status)) {
5081 goto Done;
5082 }
5083
5084 Status = ConfigAccess->ExtractConfig (
5085 ConfigAccess,
5086 ConfigRequest,
5087 &AccessProgress,
5088 &AccessResults
5089 );
5090 }
5091
5092 if (EFI_ERROR (Status)) {
5093 //
5094 // AccessProgress indicates the parsing progress on <ConfigRequest>.
5095 // Map it to the progress on <MultiConfigRequest> then return it.
5096 //
5097 *Progress = StrStr (StringPtr, AccessProgress);
5098 goto Done;
5099 }
5100
5101 //
5102 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
5103 // which separates the first <ConfigAltResp> and the following ones.
5104 //
5105 ASSERT (*AccessProgress == 0);
5106
5107 //
5108 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
5109 //
5110 if (!IfrDataParsedFlag && (HiiHandle != NULL)) {
5111 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
5112 ASSERT_EFI_ERROR (Status);
5113 }
5114
5115 FreePool (DevicePath);
5116 DevicePath = NULL;
5117
5118 if (DefaultResults != NULL) {
5119 Status = MergeDefaultString (&AccessResults, DefaultResults);
5120 ASSERT_EFI_ERROR (Status);
5121 FreePool (DefaultResults);
5122 DefaultResults = NULL;
5123 }
5124
5125 NextConfigString:
5126 if (!FirstElement) {
5127 Status = AppendToMultiString (Results, L"&");
5128 ASSERT_EFI_ERROR (Status);
5129 }
5130
5131 Status = AppendToMultiString (Results, AccessResults);
5132 ASSERT_EFI_ERROR (Status);
5133
5134 FirstElement = FALSE;
5135
5136 FreePool (AccessResults);
5137 AccessResults = NULL;
5138 FreePool (ConfigRequest);
5139 ConfigRequest = NULL;
5140
5141 //
5142 // Go to next <ConfigRequest> (skip '&').
5143 //
5144 StringPtr += Length;
5145 if (*StringPtr == 0) {
5146 *Progress = StringPtr;
5147 break;
5148 }
5149
5150 StringPtr++;
5151 }
5152
5153 Done:
5154 if (EFI_ERROR (Status)) {
5155 FreePool (*Results);
5156 *Results = NULL;
5157 }
5158
5159 if (ConfigRequest != NULL) {
5160 FreePool (ConfigRequest);
5161 }
5162
5163 if (AccessResults != NULL) {
5164 FreePool (AccessResults);
5165 }
5166
5167 if (DefaultResults != NULL) {
5168 FreePool (DefaultResults);
5169 }
5170
5171 if (DevicePath != NULL) {
5172 FreePool (DevicePath);
5173 }
5174
5175 return Status;
5176 }
5177
5178 /**
5179 This function allows the caller to request the current configuration for the
5180 entirety of the current HII database and returns the data in a
5181 null-terminated Unicode string.
5182
5183 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5184 instance.
5185 @param Results Null-terminated Unicode string in
5186 <MultiConfigAltResp> format which has all values
5187 filled in for the entirety of the current HII
5188 database. String to be allocated by the called
5189 function. De-allocation is up to the caller.
5190
5191 @retval EFI_SUCCESS The Results string is filled with the values
5192 corresponding to all requested names.
5193 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
5194 results that must be stored awaiting possible
5195 future protocols.
5196 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
5197 parameter would result in this type of error.
5198
5199 **/
5200 EFI_STATUS
5201 EFIAPI
5202 HiiConfigRoutingExportConfig (
5203 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5204 OUT EFI_STRING *Results
5205 )
5206 {
5207 EFI_STATUS Status;
5208 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5209 EFI_STRING AccessResults;
5210 EFI_STRING Progress;
5211 EFI_STRING StringPtr;
5212 EFI_STRING ConfigRequest;
5213 UINTN Index;
5214 EFI_HANDLE *ConfigAccessHandles;
5215 UINTN NumberConfigAccessHandles;
5216 BOOLEAN FirstElement;
5217 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
5218 EFI_HII_HANDLE HiiHandle;
5219 EFI_STRING DefaultResults;
5220 HII_DATABASE_PRIVATE_DATA *Private;
5221 LIST_ENTRY *Link;
5222 HII_DATABASE_RECORD *Database;
5223 UINT8 *DevicePathPkg;
5224 UINT8 *CurrentDevicePath;
5225 BOOLEAN IfrDataParsedFlag;
5226
5227 if ((This == NULL) || (Results == NULL)) {
5228 return EFI_INVALID_PARAMETER;
5229 }
5230
5231 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5232
5233 //
5234 // Allocate a fix length of memory to store Results. Reallocate memory for
5235 // Results if this fix length is insufficient.
5236 //
5237 *Results = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
5238 if (*Results == NULL) {
5239 return EFI_OUT_OF_RESOURCES;
5240 }
5241
5242 NumberConfigAccessHandles = 0;
5243 Status = gBS->LocateHandleBuffer (
5244 ByProtocol,
5245 &gEfiHiiConfigAccessProtocolGuid,
5246 NULL,
5247 &NumberConfigAccessHandles,
5248 &ConfigAccessHandles
5249 );
5250 if (EFI_ERROR (Status)) {
5251 return Status;
5252 }
5253
5254 FirstElement = TRUE;
5255
5256 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
5257 Status = gBS->HandleProtocol (
5258 ConfigAccessHandles[Index],
5259 &gEfiHiiConfigAccessProtocolGuid,
5260 (VOID **)&ConfigAccess
5261 );
5262 if (EFI_ERROR (Status)) {
5263 continue;
5264 }
5265
5266 //
5267 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
5268 //
5269 IfrDataParsedFlag = FALSE;
5270 Progress = NULL;
5271 HiiHandle = NULL;
5272 DefaultResults = NULL;
5273 Database = NULL;
5274 ConfigRequest = NULL;
5275 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
5276 if (DevicePath != NULL) {
5277 for (Link = Private->DatabaseList.ForwardLink;
5278 Link != &Private->DatabaseList;
5279 Link = Link->ForwardLink
5280 )
5281 {
5282 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
5283 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
5284 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
5285 if (CompareMem (
5286 DevicePath,
5287 CurrentDevicePath,
5288 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath)
5289 ) == 0)
5290 {
5291 HiiHandle = Database->Handle;
5292 break;
5293 }
5294 }
5295 }
5296 }
5297
5298 Status = ConfigAccess->ExtractConfig (
5299 ConfigAccess,
5300 NULL,
5301 &Progress,
5302 &AccessResults
5303 );
5304 if (EFI_ERROR (Status)) {
5305 //
5306 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
5307 //
5308 if ((HiiHandle != NULL) && (DevicePath != NULL)) {
5309 IfrDataParsedFlag = TRUE;
5310 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
5311 //
5312 // Get the full request string to get the Current setting again.
5313 //
5314 if (!EFI_ERROR (Status) && (ConfigRequest != NULL)) {
5315 Status = ConfigAccess->ExtractConfig (
5316 ConfigAccess,
5317 ConfigRequest,
5318 &Progress,
5319 &AccessResults
5320 );
5321 FreePool (ConfigRequest);
5322 } else {
5323 Status = EFI_NOT_FOUND;
5324 }
5325 }
5326 }
5327
5328 if (!EFI_ERROR (Status)) {
5329 //
5330 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
5331 //
5332 if (!IfrDataParsedFlag && (HiiHandle != NULL) && (DevicePath != NULL)) {
5333 StringPtr = StrStr (AccessResults, L"&GUID=");
5334 if (StringPtr != NULL) {
5335 *StringPtr = 0;
5336 }
5337
5338 if (GetElementsFromRequest (AccessResults)) {
5339 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
5340 ASSERT_EFI_ERROR (Status);
5341 }
5342
5343 if (StringPtr != NULL) {
5344 *StringPtr = L'&';
5345 }
5346 }
5347
5348 //
5349 // Merge the default sting from IFR code into the got setting from driver.
5350 //
5351 if (DefaultResults != NULL) {
5352 Status = MergeDefaultString (&AccessResults, DefaultResults);
5353 ASSERT_EFI_ERROR (Status);
5354 FreePool (DefaultResults);
5355 DefaultResults = NULL;
5356 }
5357
5358 //
5359 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
5360 // which separates the first <ConfigAltResp> and the following ones.
5361 //
5362 if (!FirstElement) {
5363 Status = AppendToMultiString (Results, L"&");
5364 ASSERT_EFI_ERROR (Status);
5365 }
5366
5367 Status = AppendToMultiString (Results, AccessResults);
5368 ASSERT_EFI_ERROR (Status);
5369
5370 FirstElement = FALSE;
5371
5372 FreePool (AccessResults);
5373 AccessResults = NULL;
5374 }
5375 }
5376
5377 FreePool (ConfigAccessHandles);
5378
5379 return EFI_SUCCESS;
5380 }
5381
5382 /**
5383 This function processes the results of processing forms and routes it to the
5384 appropriate handlers or storage.
5385
5386 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5387 instance.
5388 @param Configuration A null-terminated Unicode string in
5389 <MulltiConfigResp> format.
5390 @param Progress A pointer to a string filled in with the offset of
5391 the most recent & before the first failing name /
5392 value pair (or the beginning of the string if the
5393 failure is in the first name / value pair) or the
5394 terminating NULL if all was successful.
5395
5396 @retval EFI_SUCCESS The results have been distributed or are awaiting
5397 distribution.
5398 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
5399 results that must be stored awaiting possible
5400 future protocols.
5401 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
5402 would result in this type of error.
5403 @retval EFI_NOT_FOUND Target for the specified routing data was not
5404 found.
5405
5406 **/
5407 EFI_STATUS
5408 EFIAPI
5409 HiiConfigRoutingRouteConfig (
5410 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5411 IN CONST EFI_STRING Configuration,
5412 OUT EFI_STRING *Progress
5413 )
5414 {
5415 HII_DATABASE_PRIVATE_DATA *Private;
5416 EFI_STRING StringPtr;
5417 EFI_STRING ConfigResp;
5418 UINTN Length;
5419 EFI_STATUS Status;
5420 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
5421 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
5422 LIST_ENTRY *Link;
5423 HII_DATABASE_RECORD *Database;
5424 UINT8 *DevicePathPkg;
5425 UINT8 *CurrentDevicePath;
5426 EFI_HANDLE DriverHandle;
5427 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5428 EFI_STRING AccessProgress;
5429 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
5430 BOOLEAN IsEfiVarstore;
5431 UINTN DevicePathSize;
5432
5433 if ((This == NULL) || (Progress == NULL)) {
5434 return EFI_INVALID_PARAMETER;
5435 }
5436
5437 if (Configuration == NULL) {
5438 *Progress = NULL;
5439 return EFI_INVALID_PARAMETER;
5440 }
5441
5442 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5443 StringPtr = Configuration;
5444 *Progress = StringPtr;
5445 Database = NULL;
5446 AccessProgress = NULL;
5447 EfiVarStoreInfo = NULL;
5448 IsEfiVarstore = FALSE;
5449
5450 //
5451 // The first element of <MultiConfigResp> should be
5452 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
5453 //
5454 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
5455 return EFI_INVALID_PARAMETER;
5456 }
5457
5458 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
5459 //
5460 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
5461 // or most recent & before the error.
5462 //
5463 if (StringPtr == Configuration) {
5464 *Progress = StringPtr;
5465 } else {
5466 *Progress = StringPtr - 1;
5467 }
5468
5469 //
5470 // Process each <ConfigResp> of <MultiConfigResp>
5471 //
5472 Length = CalculateConfigStringLen (StringPtr);
5473 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
5474 if (ConfigResp == NULL) {
5475 return EFI_OUT_OF_RESOURCES;
5476 }
5477
5478 //
5479 // Append '\0' to the end of ConfigRequest
5480 //
5481 *(ConfigResp + Length) = 0;
5482
5483 //
5484 // Get the UEFI device path
5485 //
5486 Status = GetDevicePath (ConfigResp, (UINT8 **)&DevicePath);
5487 if (EFI_ERROR (Status)) {
5488 FreePool (ConfigResp);
5489 return Status;
5490 }
5491
5492 //
5493 // Find driver which matches the routing data.
5494 //
5495 DriverHandle = NULL;
5496 for (Link = Private->DatabaseList.ForwardLink;
5497 Link != &Private->DatabaseList;
5498 Link = Link->ForwardLink
5499 )
5500 {
5501 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
5502
5503 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
5504 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
5505 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath);
5506 if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigResp)) {
5507 DriverHandle = Database->DriverHandle;
5508 break;
5509 }
5510 }
5511 }
5512
5513 //
5514 // Try to find driver handle by device path.
5515 //
5516 if (DriverHandle == NULL) {
5517 TempDevicePath = DevicePath;
5518 Status = gBS->LocateDevicePath (
5519 &gEfiDevicePathProtocolGuid,
5520 &TempDevicePath,
5521 &DriverHandle
5522 );
5523 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
5524 //
5525 // Routing data does not match any known driver.
5526 // Set Progress to the 'G' in "GUID" of the routing header.
5527 //
5528 FreePool (DevicePath);
5529 *Progress = StringPtr;
5530 FreePool (ConfigResp);
5531 return EFI_NOT_FOUND;
5532 }
5533 }
5534
5535 FreePool (DevicePath);
5536
5537 //
5538 // Check whether this ConfigRequest is search from Efi varstore type storage.
5539 //
5540 Status = GetVarStoreType (Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo);
5541 if (EFI_ERROR (Status)) {
5542 return Status;
5543 }
5544
5545 if (IsEfiVarstore) {
5546 //
5547 // Call the SetVariable function to route settings.
5548 //
5549 Status = RouteConfigRespForEfiVarStore (This, EfiVarStoreInfo, ConfigResp, &AccessProgress);
5550 FreePool (EfiVarStoreInfo);
5551 } else {
5552 //
5553 // Call corresponding ConfigAccess protocol to route settings
5554 //
5555 Status = gBS->HandleProtocol (
5556 DriverHandle,
5557 &gEfiHiiConfigAccessProtocolGuid,
5558 (VOID **)&ConfigAccess
5559 );
5560 if (EFI_ERROR (Status)) {
5561 *Progress = StringPtr;
5562 FreePool (ConfigResp);
5563 return EFI_NOT_FOUND;
5564 }
5565
5566 Status = ConfigAccess->RouteConfig (
5567 ConfigAccess,
5568 ConfigResp,
5569 &AccessProgress
5570 );
5571 }
5572
5573 if (EFI_ERROR (Status)) {
5574 ASSERT (AccessProgress != NULL);
5575 //
5576 // AccessProgress indicates the parsing progress on <ConfigResp>.
5577 // Map it to the progress on <MultiConfigResp> then return it.
5578 //
5579 *Progress = StrStr (StringPtr, AccessProgress);
5580
5581 FreePool (ConfigResp);
5582 return Status;
5583 }
5584
5585 FreePool (ConfigResp);
5586 ConfigResp = NULL;
5587
5588 //
5589 // Go to next <ConfigResp> (skip '&').
5590 //
5591 StringPtr += Length;
5592 if (*StringPtr == 0) {
5593 *Progress = StringPtr;
5594 break;
5595 }
5596
5597 StringPtr++;
5598 }
5599
5600 return EFI_SUCCESS;
5601 }
5602
5603 /**
5604 This helper function is to be called by drivers to map configuration data
5605 stored in byte array ("block") formats such as UEFI Variables into current
5606 configuration strings.
5607
5608 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5609 instance.
5610 @param ConfigRequest A null-terminated Unicode string in
5611 <ConfigRequest> format.
5612 @param Block Array of bytes defining the block's configuration.
5613 @param BlockSize Length in bytes of Block.
5614 @param Config Filled-in configuration string. String allocated
5615 by the function. Returned only if call is
5616 successful. It is <ConfigResp> string format.
5617 @param Progress A pointer to a string filled in with the offset of
5618 the most recent & before the first failing
5619 name/value pair (or the beginning of the string if
5620 the failure is in the first name / value pair) or
5621 the terminating NULL if all was successful.
5622
5623 @retval EFI_SUCCESS The request succeeded. Progress points to the null
5624 terminator at the end of the ConfigRequest
5625 string.
5626 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
5627 points to the first character of ConfigRequest.
5628 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
5629 Block parameter would result in this type of
5630 error. Progress points to the first character of
5631 ConfigRequest.
5632 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
5633 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
5634 Block is left updated and Progress points at
5635 the "&" preceding the first non-<BlockName>.
5636
5637 **/
5638 EFI_STATUS
5639 EFIAPI
5640 HiiBlockToConfig (
5641 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5642 IN CONST EFI_STRING ConfigRequest,
5643 IN CONST UINT8 *Block,
5644 IN CONST UINTN BlockSize,
5645 OUT EFI_STRING *Config,
5646 OUT EFI_STRING *Progress
5647 )
5648 {
5649 HII_DATABASE_PRIVATE_DATA *Private;
5650 EFI_STRING StringPtr;
5651 UINTN Length;
5652 EFI_STATUS Status;
5653 EFI_STRING TmpPtr;
5654 UINT8 *TmpBuffer;
5655 UINTN Offset;
5656 UINTN Width;
5657 UINT8 *Value;
5658 EFI_STRING ValueStr;
5659 EFI_STRING ConfigElement;
5660 UINTN Index;
5661 UINT8 *TemBuffer;
5662 CHAR16 *TemString;
5663
5664 TmpBuffer = NULL;
5665
5666 if ((This == NULL) || (Progress == NULL) || (Config == NULL)) {
5667 return EFI_INVALID_PARAMETER;
5668 }
5669
5670 if ((Block == NULL) || (ConfigRequest == NULL)) {
5671 *Progress = ConfigRequest;
5672 return EFI_INVALID_PARAMETER;
5673 }
5674
5675 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5676 ASSERT (Private != NULL);
5677
5678 StringPtr = ConfigRequest;
5679 ValueStr = NULL;
5680 Value = NULL;
5681 ConfigElement = NULL;
5682
5683 //
5684 // Allocate a fix length of memory to store Results. Reallocate memory for
5685 // Results if this fix length is insufficient.
5686 //
5687 *Config = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
5688 if (*Config == NULL) {
5689 return EFI_OUT_OF_RESOURCES;
5690 }
5691
5692 //
5693 // Jump <ConfigHdr>
5694 //
5695 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
5696 *Progress = StringPtr;
5697 Status = EFI_INVALID_PARAMETER;
5698 goto Exit;
5699 }
5700
5701 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
5702 StringPtr++;
5703 }
5704
5705 if (*StringPtr == 0) {
5706 *Progress = StringPtr - 1;
5707 Status = EFI_INVALID_PARAMETER;
5708 goto Exit;
5709 }
5710
5711 while (*StringPtr != L'&' && *StringPtr != 0) {
5712 StringPtr++;
5713 }
5714
5715 if (*StringPtr == 0) {
5716 *Progress = StringPtr;
5717
5718 AppendToMultiString (Config, ConfigRequest);
5719 HiiToLower (*Config);
5720
5721 return EFI_SUCCESS;
5722 }
5723
5724 //
5725 // Skip '&'
5726 //
5727 StringPtr++;
5728
5729 //
5730 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
5731 //
5732 TemString = AllocateCopyPool (sizeof (CHAR16) * (StringPtr - ConfigRequest + 1), ConfigRequest);
5733 if (TemString == NULL) {
5734 return EFI_OUT_OF_RESOURCES;
5735 }
5736
5737 TemString[StringPtr - ConfigRequest] = '\0';
5738 AppendToMultiString (Config, TemString);
5739 FreePool (TemString);
5740
5741 //
5742 // Parse each <RequestElement> if exists
5743 // Only <BlockName> format is supported by this help function.
5744 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
5745 //
5746 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
5747 //
5748 // Back up the header of one <BlockName>
5749 //
5750 TmpPtr = StringPtr;
5751
5752 StringPtr += StrLen (L"OFFSET=");
5753 //
5754 // Get Offset
5755 //
5756 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
5757 if (EFI_ERROR (Status)) {
5758 *Progress = TmpPtr - 1;
5759 goto Exit;
5760 }
5761
5762 Offset = 0;
5763 CopyMem (
5764 &Offset,
5765 TmpBuffer,
5766 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
5767 );
5768 FreePool (TmpBuffer);
5769
5770 StringPtr += Length;
5771 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
5772 *Progress = TmpPtr - 1;
5773 Status = EFI_INVALID_PARAMETER;
5774 goto Exit;
5775 }
5776
5777 StringPtr += StrLen (L"&WIDTH=");
5778
5779 //
5780 // Get Width
5781 //
5782 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
5783 if (EFI_ERROR (Status)) {
5784 *Progress = TmpPtr - 1;
5785 goto Exit;
5786 }
5787
5788 Width = 0;
5789 CopyMem (
5790 &Width,
5791 TmpBuffer,
5792 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
5793 );
5794 FreePool (TmpBuffer);
5795
5796 StringPtr += Length;
5797 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
5798 *Progress = TmpPtr - 1;
5799 Status = EFI_INVALID_PARAMETER;
5800 goto Exit;
5801 }
5802
5803 //
5804 // Calculate Value and convert it to hex string.
5805 //
5806 if (Offset + Width > BlockSize) {
5807 *Progress = StringPtr;
5808 Status = EFI_DEVICE_ERROR;
5809 goto Exit;
5810 }
5811
5812 Value = (UINT8 *)AllocateZeroPool (Width);
5813 if (Value == NULL) {
5814 *Progress = ConfigRequest;
5815 Status = EFI_OUT_OF_RESOURCES;
5816 goto Exit;
5817 }
5818
5819 CopyMem (Value, (UINT8 *)Block + Offset, Width);
5820
5821 Length = Width * 2 + 1;
5822 ValueStr = (EFI_STRING)AllocateZeroPool (Length * sizeof (CHAR16));
5823 if (ValueStr == NULL) {
5824 *Progress = ConfigRequest;
5825 Status = EFI_OUT_OF_RESOURCES;
5826 goto Exit;
5827 }
5828
5829 TemString = ValueStr;
5830 TemBuffer = Value + Width - 1;
5831 for (Index = 0; Index < Width; Index++, TemBuffer--) {
5832 UnicodeValueToStringS (
5833 TemString,
5834 Length * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ValueStr),
5835 PREFIX_ZERO | RADIX_HEX,
5836 *TemBuffer,
5837 2
5838 );
5839 TemString += StrnLenS (TemString, Length - ((UINTN)TemString - (UINTN)ValueStr) / sizeof (CHAR16));
5840 }
5841
5842 FreePool (Value);
5843 Value = NULL;
5844
5845 //
5846 // Build a ConfigElement
5847 //
5848 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
5849 ConfigElement = (EFI_STRING)AllocateZeroPool (Length * sizeof (CHAR16));
5850 if (ConfigElement == NULL) {
5851 Status = EFI_OUT_OF_RESOURCES;
5852 goto Exit;
5853 }
5854
5855 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
5856 if (*StringPtr == 0) {
5857 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
5858 }
5859
5860 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
5861 StrCatS (ConfigElement, Length, L"VALUE=");
5862 StrCatS (ConfigElement, Length, ValueStr);
5863
5864 AppendToMultiString (Config, ConfigElement);
5865
5866 FreePool (ConfigElement);
5867 FreePool (ValueStr);
5868 ConfigElement = NULL;
5869 ValueStr = NULL;
5870
5871 //
5872 // If '\0', parsing is finished. Otherwise skip '&' to continue
5873 //
5874 if (*StringPtr == 0) {
5875 break;
5876 }
5877
5878 AppendToMultiString (Config, L"&");
5879 StringPtr++;
5880 }
5881
5882 if (*StringPtr != 0) {
5883 *Progress = StringPtr - 1;
5884 Status = EFI_INVALID_PARAMETER;
5885 goto Exit;
5886 }
5887
5888 HiiToLower (*Config);
5889 *Progress = StringPtr;
5890 return EFI_SUCCESS;
5891
5892 Exit:
5893 if (*Config != NULL) {
5894 FreePool (*Config);
5895 *Config = NULL;
5896 }
5897
5898 if (ValueStr != NULL) {
5899 FreePool (ValueStr);
5900 }
5901
5902 if (Value != NULL) {
5903 FreePool (Value);
5904 }
5905
5906 if (ConfigElement != NULL) {
5907 FreePool (ConfigElement);
5908 }
5909
5910 return Status;
5911 }
5912
5913 /**
5914 This helper function is to be called by drivers to map configuration strings
5915 to configurations stored in byte array ("block") formats such as UEFI Variables.
5916
5917 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5918 instance.
5919 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
5920 format.
5921 @param Block A possibly null array of bytes representing the
5922 current block. Only bytes referenced in the
5923 ConfigResp string in the block are modified. If
5924 this parameter is null or if the *BlockSize
5925 parameter is (on input) shorter than required by
5926 the Configuration string, only the BlockSize
5927 parameter is updated and an appropriate status
5928 (see below) is returned.
5929 @param BlockSize The length of the Block in units of UINT8. On
5930 input, this is the size of the Block. On output,
5931 if successful, contains the largest index of the
5932 modified byte in the Block, or the required buffer
5933 size if the Block is not large enough.
5934 @param Progress On return, points to an element of the ConfigResp
5935 string filled in with the offset of the most
5936 recent '&' before the first failing name / value
5937 pair (or the beginning of the string if the
5938 failure is in the first name / value pair) or the
5939 terminating NULL if all was successful.
5940
5941 @retval EFI_SUCCESS The request succeeded. Progress points to the null
5942 terminator at the end of the ConfigResp string.
5943 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
5944 points to the first character of ConfigResp.
5945 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
5946 Block parameter would result in this type of
5947 error. Progress points to the first character of
5948 ConfigResp.
5949 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
5950 value pair. Block is left updated and
5951 Progress points at the '&' preceding the first
5952 non-<BlockName>.
5953 @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined.
5954 BlockSize is updated with the required buffer size.
5955 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
5956 Progress points to the "G" in "GUID" of the errant
5957 routing data.
5958
5959 **/
5960 EFI_STATUS
5961 EFIAPI
5962 HiiConfigToBlock (
5963 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5964 IN CONST EFI_STRING ConfigResp,
5965 IN OUT UINT8 *Block,
5966 IN OUT UINTN *BlockSize,
5967 OUT EFI_STRING *Progress
5968 )
5969 {
5970 HII_DATABASE_PRIVATE_DATA *Private;
5971 EFI_STRING StringPtr;
5972 EFI_STRING TmpPtr;
5973 UINTN Length;
5974 EFI_STATUS Status;
5975 UINT8 *TmpBuffer;
5976 UINTN Offset;
5977 UINTN Width;
5978 UINT8 *Value;
5979 UINTN BufferSize;
5980 UINTN MaxBlockSize;
5981
5982 TmpBuffer = NULL;
5983
5984 if ((This == NULL) || (BlockSize == NULL) || (Progress == NULL)) {
5985 return EFI_INVALID_PARAMETER;
5986 }
5987
5988 *Progress = ConfigResp;
5989 if (ConfigResp == NULL) {
5990 return EFI_INVALID_PARAMETER;
5991 }
5992
5993 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5994 ASSERT (Private != NULL);
5995
5996 StringPtr = ConfigResp;
5997 BufferSize = *BlockSize;
5998 Value = NULL;
5999 MaxBlockSize = 0;
6000
6001 //
6002 // Jump <ConfigHdr>
6003 //
6004 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
6005 *Progress = StringPtr;
6006 Status = EFI_INVALID_PARAMETER;
6007 goto Exit;
6008 }
6009
6010 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
6011 StringPtr++;
6012 }
6013
6014 if (*StringPtr == 0) {
6015 *Progress = StringPtr;
6016 Status = EFI_INVALID_PARAMETER;
6017 goto Exit;
6018 }
6019
6020 while (*StringPtr != L'&' && *StringPtr != 0) {
6021 StringPtr++;
6022 }
6023
6024 if (*StringPtr == 0) {
6025 *Progress = StringPtr;
6026 Status = EFI_INVALID_PARAMETER;
6027 goto Exit;
6028 }
6029
6030 //
6031 // Parse each <ConfigElement> if exists
6032 // Only '&'<BlockConfig> format is supported by this help function.
6033 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
6034 //
6035 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
6036 TmpPtr = StringPtr;
6037 StringPtr += StrLen (L"&OFFSET=");
6038 //
6039 // Get Offset
6040 //
6041 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
6042 if (EFI_ERROR (Status)) {
6043 *Progress = TmpPtr;
6044 goto Exit;
6045 }
6046
6047 Offset = 0;
6048 CopyMem (
6049 &Offset,
6050 TmpBuffer,
6051 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
6052 );
6053 FreePool (TmpBuffer);
6054
6055 StringPtr += Length;
6056 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
6057 *Progress = TmpPtr;
6058 Status = EFI_INVALID_PARAMETER;
6059 goto Exit;
6060 }
6061
6062 StringPtr += StrLen (L"&WIDTH=");
6063
6064 //
6065 // Get Width
6066 //
6067 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
6068 if (EFI_ERROR (Status)) {
6069 *Progress = TmpPtr;
6070 goto Exit;
6071 }
6072
6073 Width = 0;
6074 CopyMem (
6075 &Width,
6076 TmpBuffer,
6077 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
6078 );
6079 FreePool (TmpBuffer);
6080
6081 StringPtr += Length;
6082 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
6083 *Progress = TmpPtr;
6084 Status = EFI_INVALID_PARAMETER;
6085 goto Exit;
6086 }
6087
6088 StringPtr += StrLen (L"&VALUE=");
6089
6090 //
6091 // Get Value
6092 //
6093 Status = GetValueOfNumber (StringPtr, &Value, &Length);
6094 if (EFI_ERROR (Status)) {
6095 *Progress = TmpPtr;
6096 goto Exit;
6097 }
6098
6099 StringPtr += Length;
6100 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
6101 *Progress = TmpPtr;
6102 Status = EFI_INVALID_PARAMETER;
6103 goto Exit;
6104 }
6105
6106 //
6107 // Update the Block with configuration info
6108 //
6109 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
6110 CopyMem (Block + Offset, Value, Width);
6111 }
6112
6113 if (Offset + Width > MaxBlockSize) {
6114 MaxBlockSize = Offset + Width;
6115 }
6116
6117 FreePool (Value);
6118 Value = NULL;
6119
6120 //
6121 // If '\0', parsing is finished.
6122 //
6123 if (*StringPtr == 0) {
6124 break;
6125 }
6126 }
6127
6128 //
6129 // The input string is not ConfigResp format, return error.
6130 //
6131 if (*StringPtr != 0) {
6132 *Progress = StringPtr;
6133 Status = EFI_INVALID_PARAMETER;
6134 goto Exit;
6135 }
6136
6137 *Progress = StringPtr + StrLen (StringPtr);
6138 *BlockSize = MaxBlockSize - 1;
6139
6140 if (MaxBlockSize > BufferSize) {
6141 *BlockSize = MaxBlockSize;
6142 if (Block != NULL) {
6143 return EFI_BUFFER_TOO_SMALL;
6144 }
6145 }
6146
6147 if (Block == NULL) {
6148 *Progress = ConfigResp;
6149 return EFI_INVALID_PARAMETER;
6150 }
6151
6152 return EFI_SUCCESS;
6153
6154 Exit:
6155
6156 if (Value != NULL) {
6157 FreePool (Value);
6158 }
6159
6160 return Status;
6161 }
6162
6163 /**
6164 This helper function is to be called by drivers to extract portions of
6165 a larger configuration string.
6166
6167 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
6168 instance.
6169 @param Configuration A null-terminated Unicode string in
6170 <MultiConfigAltResp> format.
6171 @param Guid A pointer to the GUID value to search for in the
6172 routing portion of the ConfigResp string when
6173 retrieving the requested data. If Guid is NULL,
6174 then all GUID values will be searched for.
6175 @param Name A pointer to the NAME value to search for in the
6176 routing portion of the ConfigResp string when
6177 retrieving the requested data. If Name is NULL,
6178 then all Name values will be searched for.
6179 @param DevicePath A pointer to the PATH value to search for in the
6180 routing portion of the ConfigResp string when
6181 retrieving the requested data. If DevicePath is
6182 NULL, then all DevicePath values will be searched
6183 for.
6184 @param AltCfgId A pointer to the ALTCFG value to search for in the
6185 routing portion of the ConfigResp string when
6186 retrieving the requested data. If this parameter
6187 is NULL, then the current setting will be
6188 retrieved.
6189 @param AltCfgResp A pointer to a buffer which will be allocated by
6190 the function which contains the retrieved string
6191 as requested. This buffer is only allocated if
6192 the call was successful. It is <ConfigResp> format.
6193
6194 @retval EFI_SUCCESS The request succeeded. The requested data was
6195 extracted and placed in the newly allocated
6196 AltCfgResp buffer.
6197 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
6198 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
6199 @retval EFI_NOT_FOUND Target for the specified routing data was not
6200 found.
6201
6202 **/
6203 EFI_STATUS
6204 EFIAPI
6205 HiiGetAltCfg (
6206 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
6207 IN CONST EFI_STRING Configuration,
6208 IN CONST EFI_GUID *Guid,
6209 IN CONST EFI_STRING Name,
6210 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
6211 IN CONST UINT16 *AltCfgId,
6212 OUT EFI_STRING *AltCfgResp
6213 )
6214 {
6215 EFI_STATUS Status;
6216 EFI_STRING StringPtr;
6217 EFI_STRING HdrStart;
6218 EFI_STRING HdrEnd;
6219 EFI_STRING TmpPtr;
6220 UINTN Length;
6221 EFI_STRING GuidStr;
6222 EFI_STRING NameStr;
6223 EFI_STRING PathStr;
6224 EFI_STRING AltIdStr;
6225 EFI_STRING Result;
6226 BOOLEAN GuidFlag;
6227 BOOLEAN NameFlag;
6228 BOOLEAN PathFlag;
6229
6230 HdrStart = NULL;
6231 HdrEnd = NULL;
6232 GuidStr = NULL;
6233 NameStr = NULL;
6234 PathStr = NULL;
6235 AltIdStr = NULL;
6236 Result = NULL;
6237 GuidFlag = FALSE;
6238 NameFlag = FALSE;
6239 PathFlag = FALSE;
6240
6241 if ((This == NULL) || (Configuration == NULL) || (AltCfgResp == NULL)) {
6242 return EFI_INVALID_PARAMETER;
6243 }
6244
6245 StringPtr = Configuration;
6246 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
6247 return EFI_INVALID_PARAMETER;
6248 }
6249
6250 //
6251 // Generate the sub string for later matching.
6252 //
6253 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)Guid, 1, &GuidStr);
6254 GenerateSubStr (
6255 L"PATH=",
6256 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath),
6257 (VOID *)DevicePath,
6258 1,
6259 &PathStr
6260 );
6261 if (AltCfgId != NULL) {
6262 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *)AltCfgId, 3, &AltIdStr);
6263 }
6264
6265 if (Name != NULL) {
6266 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *)Name, 2, &NameStr);
6267 } else {
6268 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
6269 }
6270
6271 while (*StringPtr != 0) {
6272 //
6273 // Try to match the GUID
6274 //
6275 if (!GuidFlag) {
6276 TmpPtr = StrStr (StringPtr, GuidStr);
6277 if (TmpPtr == NULL) {
6278 Status = EFI_NOT_FOUND;
6279 goto Exit;
6280 }
6281
6282 HdrStart = TmpPtr;
6283
6284 //
6285 // Jump to <NameHdr>
6286 //
6287 if (Guid != NULL) {
6288 StringPtr = TmpPtr + StrLen (GuidStr);
6289 } else {
6290 StringPtr = StrStr (TmpPtr, L"NAME=");
6291 if (StringPtr == NULL) {
6292 Status = EFI_NOT_FOUND;
6293 goto Exit;
6294 }
6295 }
6296
6297 GuidFlag = TRUE;
6298 }
6299
6300 //
6301 // Try to match the NAME
6302 //
6303 if (GuidFlag && !NameFlag) {
6304 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
6305 GuidFlag = FALSE;
6306 } else {
6307 //
6308 // Jump to <PathHdr>
6309 //
6310 if (Name != NULL) {
6311 StringPtr += StrLen (NameStr);
6312 } else {
6313 StringPtr = StrStr (StringPtr, L"PATH=");
6314 if (StringPtr == NULL) {
6315 Status = EFI_NOT_FOUND;
6316 goto Exit;
6317 }
6318 }
6319
6320 NameFlag = TRUE;
6321 }
6322 }
6323
6324 //
6325 // Try to match the DevicePath
6326 //
6327 if (GuidFlag && NameFlag && !PathFlag) {
6328 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
6329 GuidFlag = FALSE;
6330 NameFlag = FALSE;
6331 } else {
6332 //
6333 // Jump to '&' before <DescHdr> or <ConfigBody>
6334 //
6335 if (DevicePath != NULL) {
6336 StringPtr += StrLen (PathStr);
6337 } else {
6338 StringPtr = StrStr (StringPtr, L"&");
6339 if (StringPtr == NULL) {
6340 Status = EFI_NOT_FOUND;
6341 goto Exit;
6342 }
6343
6344 StringPtr++;
6345 }
6346
6347 PathFlag = TRUE;
6348 HdrEnd = StringPtr;
6349 }
6350 }
6351
6352 //
6353 // Try to match the AltCfgId
6354 //
6355 if (GuidFlag && NameFlag && PathFlag) {
6356 if (AltCfgId == NULL) {
6357 //
6358 // Return Current Setting when AltCfgId is NULL.
6359 //
6360 Status = OutputConfigBody (StringPtr, &Result);
6361 goto Exit;
6362 }
6363
6364 //
6365 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
6366 //
6367 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
6368 GuidFlag = FALSE;
6369 NameFlag = FALSE;
6370 PathFlag = FALSE;
6371 } else {
6372 //
6373 // Skip AltIdStr and &
6374 //
6375 StringPtr = StringPtr + StrLen (AltIdStr);
6376 Status = OutputConfigBody (StringPtr, &Result);
6377 goto Exit;
6378 }
6379 }
6380 }
6381
6382 Status = EFI_NOT_FOUND;
6383
6384 Exit:
6385 *AltCfgResp = NULL;
6386 if (!EFI_ERROR (Status) && (Result != NULL)) {
6387 //
6388 // Copy the <ConfigHdr> and <ConfigBody>
6389 //
6390 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
6391 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
6392 if (*AltCfgResp == NULL) {
6393 Status = EFI_OUT_OF_RESOURCES;
6394 } else {
6395 StrnCpyS (*AltCfgResp, Length, HdrStart, HdrEnd - HdrStart);
6396 StrCatS (*AltCfgResp, Length, Result);
6397 Status = EFI_SUCCESS;
6398 }
6399 }
6400
6401 if (GuidStr != NULL) {
6402 FreePool (GuidStr);
6403 }
6404
6405 if (NameStr != NULL) {
6406 FreePool (NameStr);
6407 }
6408
6409 if (PathStr != NULL) {
6410 FreePool (PathStr);
6411 }
6412
6413 if (AltIdStr != NULL) {
6414 FreePool (AltIdStr);
6415 }
6416
6417 if (Result != NULL) {
6418 FreePool (Result);
6419 }
6420
6421 return Status;
6422 }