]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/HiiDatabaseDxe/ConfigRouting.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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_VARSTORE_EFI *IfrEfiVarStoreTmp;
2175 EFI_IFR_OP_HEADER *IfrOpHdr;
2176 EFI_IFR_ONE_OF *IfrOneOf;
2177 EFI_IFR_REF4 *IfrRef;
2178 EFI_IFR_ONE_OF_OPTION *IfrOneOfOption;
2179 EFI_IFR_DEFAULT *IfrDefault;
2180 EFI_IFR_ORDERED_LIST *IfrOrderedList;
2181 EFI_IFR_CHECKBOX *IfrCheckBox;
2182 EFI_IFR_PASSWORD *IfrPassword;
2183 EFI_IFR_STRING *IfrString;
2184 EFI_IFR_DATE *IfrDate;
2185 EFI_IFR_TIME *IfrTime;
2186 IFR_DEFAULT_DATA DefaultData;
2187 IFR_DEFAULT_DATA *DefaultDataPtr;
2188 IFR_BLOCK_DATA *BlockData;
2189 CHAR16 *VarStoreName;
2190 UINTN NameSize;
2191 UINTN NvDefaultStoreSize;
2192 UINT16 VarWidth;
2193 UINT16 VarDefaultId;
2194 BOOLEAN FirstOneOfOption;
2195 BOOLEAN FirstOrderedList;
2196 LIST_ENTRY *LinkData;
2197 LIST_ENTRY *LinkDefault;
2198 EFI_IFR_VARSTORE_NAME_VALUE *IfrNameValueVarStore;
2199 EFI_HII_PACKAGE_HEADER *PackageHeader;
2200 EFI_VARSTORE_ID VarStoreId;
2201 UINT16 SmallestDefaultId;
2202 BOOLEAN SmallestIdFromFlag;
2203 BOOLEAN FromOtherDefaultOpcode;
2204 BOOLEAN QuestionReferBitField;
2205
2206 Status = EFI_SUCCESS;
2207 BlockData = NULL;
2208 DefaultDataPtr = NULL;
2209 FirstOneOfOption = FALSE;
2210 VarStoreId = 0;
2211 FirstOrderedList = FALSE;
2212 VarStoreName = NULL;
2213 ZeroMem (&DefaultData, sizeof (IFR_DEFAULT_DATA));
2214 SmallestDefaultId = 0xFFFF;
2215 FromOtherDefaultOpcode = FALSE;
2216 QuestionReferBitField = FALSE;
2217 IfrEfiVarStoreTmp = NULL;
2218
2219 //
2220 // Go through the form package to parse OpCode one by one.
2221 //
2222 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
2223 PackageHeader = (EFI_HII_PACKAGE_HEADER *)Package;
2224 IfrOffset = PackageOffset;
2225 while (IfrOffset < PackageLength) {
2226 //
2227 // More than one form package found.
2228 //
2229 if (PackageOffset >= PackageHeader->Length) {
2230 //
2231 // Already found varstore for this request, break;
2232 //
2233 if (VarStoreId != 0) {
2234 VarStoreId = 0;
2235 }
2236
2237 //
2238 // Get next package header info.
2239 //
2240 IfrOffset += sizeof (EFI_HII_PACKAGE_HEADER);
2241 PackageOffset = sizeof (EFI_HII_PACKAGE_HEADER);
2242 PackageHeader = (EFI_HII_PACKAGE_HEADER *)(Package + IfrOffset);
2243 }
2244
2245 IfrOpHdr = (EFI_IFR_OP_HEADER *)(Package + IfrOffset);
2246 switch (IfrOpHdr->OpCode) {
2247 case EFI_IFR_VARSTORE_OP:
2248 //
2249 // VarStore is found. Don't need to search any more.
2250 //
2251 if (VarStoreId != 0) {
2252 break;
2253 }
2254
2255 IfrVarStore = (EFI_IFR_VARSTORE *)IfrOpHdr;
2256
2257 NameSize = AsciiStrSize ((CHAR8 *)IfrVarStore->Name);
2258 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
2259 if (VarStoreName == NULL) {
2260 Status = EFI_OUT_OF_RESOURCES;
2261 goto Done;
2262 }
2263
2264 AsciiStrToUnicodeStrS ((CHAR8 *)IfrVarStore->Name, VarStoreName, NameSize);
2265
2266 if (IsThisVarstore ((VOID *)&IfrVarStore->Guid, VarStoreName, ConfigHdr)) {
2267 //
2268 // Find the matched VarStore
2269 //
2270 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrVarStore->Guid);
2271 VarStorageData->Size = IfrVarStore->Size;
2272 VarStorageData->Name = VarStoreName;
2273 VarStorageData->Type = EFI_HII_VARSTORE_BUFFER;
2274 VarStoreId = IfrVarStore->VarStoreId;
2275 } else {
2276 FreePool (VarStoreName);
2277 VarStoreName = NULL;
2278 }
2279
2280 break;
2281
2282 case EFI_IFR_VARSTORE_EFI_OP:
2283 //
2284 // VarStore is found. Don't need to search any more.
2285 //
2286 if (VarStoreId != 0) {
2287 break;
2288 }
2289
2290 IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *)IfrOpHdr;
2291
2292 //
2293 // If the length is small than the structure, this is from old efi
2294 // varstore definition. Old efi varstore get config directly from
2295 // GetVariable function.
2296 //
2297 if (IfrOpHdr->Length < sizeof (EFI_IFR_VARSTORE_EFI)) {
2298 break;
2299 }
2300
2301 NameSize = AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name);
2302 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
2303 if (VarStoreName == NULL) {
2304 Status = EFI_OUT_OF_RESOURCES;
2305 goto Done;
2306 }
2307
2308 AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, VarStoreName, NameSize);
2309 if (IfrEfiVarStoreTmp != NULL) {
2310 FreePool (IfrEfiVarStoreTmp);
2311 }
2312
2313 IfrEfiVarStoreTmp = AllocatePool (IfrEfiVarStore->Header.Length + AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name));
2314 if (IfrEfiVarStoreTmp == NULL) {
2315 Status = EFI_OUT_OF_RESOURCES;
2316 goto Done;
2317 }
2318
2319 CopyMem (IfrEfiVarStoreTmp, IfrEfiVarStore, IfrEfiVarStore->Header.Length);
2320 AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, (CHAR16 *)&(IfrEfiVarStoreTmp->Name[0]), AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16));
2321
2322 if (IsThisVarstore (&IfrEfiVarStore->Guid, VarStoreName, ConfigHdr)) {
2323 //
2324 // Find the matched VarStore
2325 //
2326 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrEfiVarStore->Guid);
2327 VarStorageData->Size = IfrEfiVarStore->Size;
2328 VarStorageData->Name = VarStoreName;
2329 VarStorageData->Type = EFI_HII_VARSTORE_EFI_VARIABLE_BUFFER;
2330 VarStoreId = IfrEfiVarStore->VarStoreId;
2331 } else {
2332 FreePool (VarStoreName);
2333 VarStoreName = NULL;
2334 }
2335
2336 break;
2337
2338 case EFI_IFR_VARSTORE_NAME_VALUE_OP:
2339 //
2340 // VarStore is found. Don't need to search any more.
2341 //
2342 if (VarStoreId != 0) {
2343 break;
2344 }
2345
2346 IfrNameValueVarStore = (EFI_IFR_VARSTORE_NAME_VALUE *)IfrOpHdr;
2347
2348 if (IsThisVarstore (&IfrNameValueVarStore->Guid, NULL, ConfigHdr)) {
2349 //
2350 // Find the matched VarStore
2351 //
2352 CopyGuid (&VarStorageData->Guid, (EFI_GUID *)(VOID *)&IfrNameValueVarStore->Guid);
2353 VarStorageData->Type = EFI_HII_VARSTORE_NAME_VALUE;
2354 VarStoreId = IfrNameValueVarStore->VarStoreId;
2355 }
2356
2357 break;
2358
2359 case EFI_IFR_DEFAULTSTORE_OP:
2360 //
2361 // Add new the map between default id and default name.
2362 //
2363 DefaultDataPtr = (IFR_DEFAULT_DATA *)AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
2364 if (DefaultDataPtr == NULL) {
2365 Status = EFI_OUT_OF_RESOURCES;
2366 goto Done;
2367 }
2368
2369 DefaultDataPtr->DefaultId = ((EFI_IFR_DEFAULTSTORE *)IfrOpHdr)->DefaultId;
2370 InsertTailList (&DefaultIdArray->Entry, &DefaultDataPtr->Entry);
2371 DefaultDataPtr = NULL;
2372 break;
2373
2374 case EFI_IFR_FORM_OP:
2375 case EFI_IFR_FORM_MAP_OP:
2376 //
2377 // No matched varstore is found and directly return.
2378 //
2379 if ( VarStoreId == 0) {
2380 Status = EFI_SUCCESS;
2381 goto Done;
2382 }
2383
2384 break;
2385
2386 case EFI_IFR_REF_OP:
2387 //
2388 // Ref question is not in IFR Form. This IFR form is not valid.
2389 //
2390 if ( VarStoreId == 0) {
2391 Status = EFI_INVALID_PARAMETER;
2392 goto Done;
2393 }
2394
2395 //
2396 // Check whether this question is for the requested varstore.
2397 //
2398 IfrRef = (EFI_IFR_REF4 *)IfrOpHdr;
2399 if (IfrRef->Question.VarStoreId != VarStoreId) {
2400 break;
2401 }
2402
2403 VarWidth = (UINT16)(sizeof (EFI_HII_REF));
2404
2405 //
2406 // The BlockData may allocate by other opcode,need to clean.
2407 //
2408 if (BlockData != NULL) {
2409 BlockData = NULL;
2410 }
2411
2412 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2413 if (EFI_ERROR (Status)) {
2414 if (Status == EFI_NOT_FOUND) {
2415 //
2416 // The opcode is not required,exit and parse other opcode.
2417 //
2418 break;
2419 }
2420
2421 goto Done;
2422 }
2423
2424 break;
2425
2426 case EFI_IFR_ONE_OF_OP:
2427 case EFI_IFR_NUMERIC_OP:
2428 //
2429 // Numeric and OneOf has the same opcode structure.
2430 //
2431
2432 //
2433 // Numeric and OneOf question is not in IFR Form. This IFR form is not valid.
2434 //
2435 if (VarStoreId == 0) {
2436 Status = EFI_INVALID_PARAMETER;
2437 goto Done;
2438 }
2439
2440 //
2441 // Check whether this question is for the requested varstore.
2442 //
2443 IfrOneOf = (EFI_IFR_ONE_OF *)IfrOpHdr;
2444 if (IfrOneOf->Question.VarStoreId != VarStoreId) {
2445 break;
2446 }
2447
2448 if (QuestionReferBitField) {
2449 VarWidth = IfrOneOf->Flags & EDKII_IFR_NUMERIC_SIZE_BIT;
2450 } else {
2451 VarWidth = (UINT16)(1 << (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE));
2452 }
2453
2454 //
2455 // The BlockData may allocate by other opcode,need to clean.
2456 //
2457 if (BlockData != NULL) {
2458 BlockData = NULL;
2459 }
2460
2461 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
2462 if (EFI_ERROR (Status)) {
2463 if (Status == EFI_NOT_FOUND) {
2464 //
2465 // The opcode is not required,exit and parse other opcode.
2466 //
2467 break;
2468 }
2469
2470 goto Done;
2471 }
2472
2473 //
2474 // when go to there,BlockData can't be NULLL.
2475 //
2476 ASSERT (BlockData != NULL);
2477
2478 if (IfrOpHdr->OpCode == EFI_IFR_ONE_OF_OP) {
2479 //
2480 // Set this flag to TRUE for the first oneof option.
2481 //
2482 FirstOneOfOption = TRUE;
2483 } else if (IfrOpHdr->OpCode == EFI_IFR_NUMERIC_OP) {
2484 //
2485 // Numeric minimum value will be used as default value when no default is specified.
2486 //
2487 DefaultData.Type = DefaultValueFromDefault;
2488 if (QuestionReferBitField) {
2489 //
2490 // Since default value in bit field was stored as UINT32 type.
2491 //
2492 CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
2493 } else {
2494 switch (IfrOneOf->Flags & EFI_IFR_NUMERIC_SIZE) {
2495 case EFI_IFR_NUMERIC_SIZE_1:
2496 DefaultData.Value.u8 = IfrOneOf->data.u8.MinValue;
2497 break;
2498
2499 case EFI_IFR_NUMERIC_SIZE_2:
2500 CopyMem (&DefaultData.Value.u16, &IfrOneOf->data.u16.MinValue, sizeof (UINT16));
2501 break;
2502
2503 case EFI_IFR_NUMERIC_SIZE_4:
2504 CopyMem (&DefaultData.Value.u32, &IfrOneOf->data.u32.MinValue, sizeof (UINT32));
2505 break;
2506
2507 case EFI_IFR_NUMERIC_SIZE_8:
2508 CopyMem (&DefaultData.Value.u64, &IfrOneOf->data.u64.MinValue, sizeof (UINT64));
2509 break;
2510
2511 default:
2512 Status = EFI_INVALID_PARAMETER;
2513 goto Done;
2514 }
2515 }
2516
2517 //
2518 // Set default value base on the DefaultId list get from IFR data.
2519 //
2520 NvDefaultStoreSize = PcdGetSize (PcdNvStoreDefaultValueBuffer);
2521 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2522 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2523 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2524 if (NvDefaultStoreSize > sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) {
2525 FindQuestionDefaultSetting (DefaultData.DefaultId, IfrEfiVarStoreTmp, &(IfrOneOf->Question), &DefaultData.Value, VarWidth, QuestionReferBitField);
2526 }
2527
2528 InsertDefaultValue (BlockData, &DefaultData);
2529 }
2530 }
2531
2532 break;
2533
2534 case EFI_IFR_ORDERED_LIST_OP:
2535 //
2536 // offset by question header
2537 // width by EFI_IFR_ORDERED_LIST MaxContainers * OneofOption Type
2538 //
2539
2540 FirstOrderedList = TRUE;
2541 //
2542 // OrderedList question is not in IFR Form. This IFR form is not valid.
2543 //
2544 if (VarStoreId == 0) {
2545 Status = EFI_INVALID_PARAMETER;
2546 goto Done;
2547 }
2548
2549 //
2550 // Check whether this question is for the requested varstore.
2551 //
2552 IfrOrderedList = (EFI_IFR_ORDERED_LIST *)IfrOpHdr;
2553 if (IfrOrderedList->Question.VarStoreId != VarStoreId) {
2554 BlockData = NULL;
2555 break;
2556 }
2557
2558 VarWidth = IfrOrderedList->MaxContainers;
2559
2560 //
2561 // The BlockData may allocate by other opcode,need to clean.
2562 //
2563 if (BlockData != NULL) {
2564 BlockData = NULL;
2565 }
2566
2567 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2568 if (EFI_ERROR (Status)) {
2569 if (Status == EFI_NOT_FOUND) {
2570 //
2571 // The opcode is not required,exit and parse other opcode.
2572 //
2573 break;
2574 }
2575
2576 goto Done;
2577 }
2578
2579 break;
2580
2581 case EFI_IFR_CHECKBOX_OP:
2582 //
2583 // EFI_IFR_DEFAULT_OP
2584 // offset by question header
2585 // width is 1 sizeof (BOOLEAN)
2586 // default id by CheckBox Flags if CheckBox flags (Default or Mau) is set, the default value is 1 to be set.
2587 // value by DefaultOption
2588 // default id by DeaultOption DefaultId can override CheckBox Flags and Default value.
2589 //
2590
2591 //
2592 // CheckBox question is not in IFR Form. This IFR form is not valid.
2593 //
2594 if (VarStoreId == 0) {
2595 Status = EFI_INVALID_PARAMETER;
2596 goto Done;
2597 }
2598
2599 //
2600 // Check whether this question is for the requested varstore.
2601 //
2602 IfrCheckBox = (EFI_IFR_CHECKBOX *)IfrOpHdr;
2603 if (IfrCheckBox->Question.VarStoreId != VarStoreId) {
2604 break;
2605 }
2606
2607 VarWidth = (UINT16)sizeof (BOOLEAN);
2608
2609 //
2610 // The BlockData may allocate by other opcode,need to clean.
2611 //
2612 if (BlockData != NULL) {
2613 BlockData = NULL;
2614 }
2615
2616 if (QuestionReferBitField) {
2617 VarWidth = 1;
2618 }
2619
2620 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, QuestionReferBitField);
2621 if (EFI_ERROR (Status)) {
2622 if (Status == EFI_NOT_FOUND) {
2623 //
2624 // The opcode is not required,exit and parse other opcode.
2625 //
2626 break;
2627 }
2628
2629 goto Done;
2630 }
2631
2632 //
2633 // when go to there,BlockData can't be NULLL.
2634 //
2635 ASSERT (BlockData != NULL);
2636
2637 SmallestIdFromFlag = FALSE;
2638
2639 //
2640 // Add default value for standard ID by CheckBox Flag
2641 //
2642 VarDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2643 //
2644 // Prepare new DefaultValue
2645 //
2646 DefaultData.DefaultId = VarDefaultId;
2647 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT) == EFI_IFR_CHECKBOX_DEFAULT) {
2648 //
2649 // When flag is set, default value is TRUE.
2650 //
2651 DefaultData.Type = DefaultValueFromFlag;
2652 if (QuestionReferBitField) {
2653 DefaultData.Value.u32 = TRUE;
2654 } else {
2655 DefaultData.Value.b = TRUE;
2656 }
2657
2658 InsertDefaultValue (BlockData, &DefaultData);
2659
2660 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
2661 //
2662 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
2663 //
2664 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
2665 SmallestIdFromFlag = TRUE;
2666 }
2667 }
2668
2669 //
2670 // Add default value for Manufacture ID by CheckBox Flag
2671 //
2672 VarDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2673 //
2674 // Prepare new DefaultValue
2675 //
2676 DefaultData.DefaultId = VarDefaultId;
2677 if ((IfrCheckBox->Flags & EFI_IFR_CHECKBOX_DEFAULT_MFG) == EFI_IFR_CHECKBOX_DEFAULT_MFG) {
2678 //
2679 // When flag is set, default value is TRUE.
2680 //
2681 DefaultData.Type = DefaultValueFromFlag;
2682 if (QuestionReferBitField) {
2683 DefaultData.Value.u32 = TRUE;
2684 } else {
2685 DefaultData.Value.b = TRUE;
2686 }
2687
2688 InsertDefaultValue (BlockData, &DefaultData);
2689
2690 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
2691 //
2692 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
2693 //
2694 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
2695 SmallestIdFromFlag = TRUE;
2696 }
2697 }
2698
2699 if (SmallestIdFromFlag) {
2700 //
2701 // When smallest default Id is given by the flag of CheckBox, set default value with TRUE for other default Id in the DefaultId list.
2702 //
2703 DefaultData.Type = DefaultValueFromOtherDefault;
2704 if (QuestionReferBitField) {
2705 DefaultData.Value.u32 = TRUE;
2706 } else {
2707 DefaultData.Value.b = TRUE;
2708 }
2709
2710 //
2711 // Set default value for all the default id in the DefaultId list.
2712 //
2713 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2714 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2715 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2716 InsertDefaultValue (BlockData, &DefaultData);
2717 }
2718 } else {
2719 //
2720 // When flag is not set, default value is FASLE.
2721 //
2722 DefaultData.Type = DefaultValueFromDefault;
2723 if (QuestionReferBitField) {
2724 DefaultData.Value.u32 = FALSE;
2725 } else {
2726 DefaultData.Value.b = FALSE;
2727 }
2728
2729 //
2730 // Set default value for all the default id in the DefaultId list.
2731 //
2732 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
2733 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
2734 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
2735 InsertDefaultValue (BlockData, &DefaultData);
2736 }
2737 }
2738
2739 break;
2740
2741 case EFI_IFR_DATE_OP:
2742 //
2743 // offset by question header
2744 // width MaxSize * sizeof (CHAR16)
2745 // no default value, only block array
2746 //
2747
2748 //
2749 // Date question is not in IFR Form. This IFR form is not valid.
2750 //
2751 if (VarStoreId == 0) {
2752 Status = EFI_INVALID_PARAMETER;
2753 goto Done;
2754 }
2755
2756 //
2757 // Check whether this question is for the requested varstore.
2758 //
2759 IfrDate = (EFI_IFR_DATE *)IfrOpHdr;
2760 if (IfrDate->Question.VarStoreId != VarStoreId) {
2761 break;
2762 }
2763
2764 //
2765 // The BlockData may allocate by other opcode,need to clean.
2766 //
2767 if (BlockData != NULL) {
2768 BlockData = NULL;
2769 }
2770
2771 VarWidth = (UINT16)sizeof (EFI_HII_DATE);
2772 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2773 if (EFI_ERROR (Status)) {
2774 if (Status == EFI_NOT_FOUND) {
2775 //
2776 // The opcode is not required,exit and parse other opcode.
2777 //
2778 break;
2779 }
2780
2781 goto Done;
2782 }
2783
2784 break;
2785
2786 case EFI_IFR_TIME_OP:
2787 //
2788 // offset by question header
2789 // width MaxSize * sizeof (CHAR16)
2790 // no default value, only block array
2791 //
2792
2793 //
2794 // Time question is not in IFR Form. This IFR form is not valid.
2795 //
2796 if (VarStoreId == 0) {
2797 Status = EFI_INVALID_PARAMETER;
2798 goto Done;
2799 }
2800
2801 //
2802 // Check whether this question is for the requested varstore.
2803 //
2804 IfrTime = (EFI_IFR_TIME *)IfrOpHdr;
2805 if (IfrTime->Question.VarStoreId != VarStoreId) {
2806 break;
2807 }
2808
2809 //
2810 // The BlockData may allocate by other opcode,need to clean.
2811 //
2812 if (BlockData != NULL) {
2813 BlockData = NULL;
2814 }
2815
2816 VarWidth = (UINT16)sizeof (EFI_HII_TIME);
2817 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2818 if (EFI_ERROR (Status)) {
2819 if (Status == EFI_NOT_FOUND) {
2820 //
2821 // The opcode is not required,exit and parse other opcode.
2822 //
2823 break;
2824 }
2825
2826 goto Done;
2827 }
2828
2829 break;
2830
2831 case EFI_IFR_STRING_OP:
2832 //
2833 // offset by question header
2834 // width MaxSize * sizeof (CHAR16)
2835 // no default value, only block array
2836 //
2837
2838 //
2839 // String question is not in IFR Form. This IFR form is not valid.
2840 //
2841 if (VarStoreId == 0) {
2842 Status = EFI_INVALID_PARAMETER;
2843 goto Done;
2844 }
2845
2846 //
2847 // Check whether this question is for the requested varstore.
2848 //
2849 IfrString = (EFI_IFR_STRING *)IfrOpHdr;
2850 if (IfrString->Question.VarStoreId != VarStoreId) {
2851 break;
2852 }
2853
2854 //
2855 // The BlockData may allocate by other opcode,need to clean.
2856 //
2857 if (BlockData != NULL) {
2858 BlockData = NULL;
2859 }
2860
2861 VarWidth = (UINT16)(IfrString->MaxSize * sizeof (UINT16));
2862 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2863 if (EFI_ERROR (Status)) {
2864 if (Status == EFI_NOT_FOUND) {
2865 //
2866 // The opcode is not required,exit and parse other opcode.
2867 //
2868 break;
2869 }
2870
2871 goto Done;
2872 }
2873
2874 break;
2875
2876 case EFI_IFR_PASSWORD_OP:
2877 //
2878 // offset by question header
2879 // width MaxSize * sizeof (CHAR16)
2880 // no default value, only block array
2881 //
2882
2883 //
2884 // Password question is not in IFR Form. This IFR form is not valid.
2885 //
2886 if (VarStoreId == 0) {
2887 Status = EFI_INVALID_PARAMETER;
2888 goto Done;
2889 }
2890
2891 //
2892 // Check whether this question is for the requested varstore.
2893 //
2894 IfrPassword = (EFI_IFR_PASSWORD *)IfrOpHdr;
2895 if (IfrPassword->Question.VarStoreId != VarStoreId) {
2896 break;
2897 }
2898
2899 //
2900 // The BlockData may allocate by other opcode,need to clean.
2901 //
2902 if (BlockData != NULL) {
2903 BlockData = NULL;
2904 }
2905
2906 VarWidth = (UINT16)(IfrPassword->MaxSize * sizeof (UINT16));
2907 Status = IsThisOpcodeRequired (RequestBlockArray, HiiHandle, VarStorageData, IfrOpHdr, VarWidth, &BlockData, FALSE);
2908 if (EFI_ERROR (Status)) {
2909 if (Status == EFI_NOT_FOUND) {
2910 //
2911 // The opcode is not required,exit and parse other opcode.
2912 //
2913 break;
2914 }
2915
2916 goto Done;
2917 }
2918
2919 //
2920 // No default value for string.
2921 //
2922 BlockData = NULL;
2923 break;
2924
2925 case EFI_IFR_ONE_OF_OPTION_OP:
2926 //
2927 // No matched block data is ignored.
2928 //
2929 if ((BlockData == NULL) || (BlockData->Scope == 0)) {
2930 break;
2931 }
2932
2933 IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *)IfrOpHdr;
2934 if (BlockData->OpCode == EFI_IFR_ORDERED_LIST_OP) {
2935 if (!FirstOrderedList) {
2936 break;
2937 }
2938
2939 //
2940 // Get ordered list option data type.
2941 //
2942 if ((IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_8) || (IfrOneOfOption->Type == EFI_IFR_TYPE_BOOLEAN)) {
2943 VarWidth = 1;
2944 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_16) {
2945 VarWidth = 2;
2946 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_32) {
2947 VarWidth = 4;
2948 } else if (IfrOneOfOption->Type == EFI_IFR_TYPE_NUM_SIZE_64) {
2949 VarWidth = 8;
2950 } else {
2951 //
2952 // Invalid ordered list option data type.
2953 //
2954 Status = EFI_INVALID_PARAMETER;
2955 if (BlockData->Name != NULL) {
2956 FreePool (BlockData->Name);
2957 }
2958
2959 FreePool (BlockData);
2960 goto Done;
2961 }
2962
2963 //
2964 // Calculate Ordered list QuestionId width.
2965 //
2966 BlockData->Width = (UINT16)(BlockData->Width * VarWidth);
2967 //
2968 // Check whether this question is in requested block array.
2969 //
2970 if (!BlockArrayCheck (RequestBlockArray, BlockData->Offset, BlockData->Width, (BOOLEAN)(BlockData->Name != NULL), HiiHandle)) {
2971 //
2972 // This question is not in the requested string. Skip it.
2973 //
2974 if (BlockData->Name != NULL) {
2975 FreePool (BlockData->Name);
2976 }
2977
2978 FreePool (BlockData);
2979 BlockData = NULL;
2980 break;
2981 }
2982
2983 //
2984 // Check this var question is in the var storage
2985 //
2986 if ((BlockData->Name == NULL) && ((BlockData->Offset + BlockData->Width) > VarStorageData->Size)) {
2987 Status = EFI_INVALID_PARAMETER;
2988 FreePool (BlockData);
2989 goto Done;
2990 }
2991
2992 //
2993 // Add Block Data into VarStorageData BlockEntry
2994 //
2995 InsertBlockData (&VarStorageData->BlockEntry, &BlockData);
2996
2997 FirstOrderedList = FALSE;
2998
2999 break;
3000 }
3001
3002 //
3003 // 1. Set default value for OneOf option when flag field has default attribute.
3004 // And set the default value with the smallest default id for other default id in the DefaultId list.
3005 //
3006 if (((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) ||
3007 ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG))
3008 {
3009 //
3010 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
3011 // The first oneof option value will be used as default value when no default value is specified.
3012 //
3013 FirstOneOfOption = FALSE;
3014
3015 SmallestIdFromFlag = FALSE;
3016
3017 // Prepare new DefaultValue
3018 //
3019 DefaultData.Type = DefaultValueFromFlag;
3020 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
3021 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT) == EFI_IFR_OPTION_DEFAULT) {
3022 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
3023 InsertDefaultValue (BlockData, &DefaultData);
3024 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_STANDARD) {
3025 //
3026 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
3027 //
3028 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
3029 SmallestIdFromFlag = TRUE;
3030 }
3031 }
3032
3033 if ((IfrOneOfOption->Flags & EFI_IFR_OPTION_DEFAULT_MFG) == EFI_IFR_OPTION_DEFAULT_MFG) {
3034 DefaultData.DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
3035 InsertDefaultValue (BlockData, &DefaultData);
3036 if (SmallestDefaultId > EFI_HII_DEFAULT_CLASS_MANUFACTURING) {
3037 //
3038 // Record the SmallestDefaultId and update the SmallestIdFromFlag.
3039 //
3040 SmallestDefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
3041 SmallestIdFromFlag = TRUE;
3042 }
3043 }
3044
3045 if (SmallestIdFromFlag) {
3046 //
3047 // When smallest default Id is given by the flag of oneofOption, set this option value for other default Id in the DefaultId list.
3048 //
3049 DefaultData.Type = DefaultValueFromOtherDefault;
3050 //
3051 // Set default value for other default id in the DefaultId list.
3052 //
3053 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3054 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3055 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3056 InsertDefaultValue (BlockData, &DefaultData);
3057 }
3058 }
3059 }
3060
3061 //
3062 // 2. Set as the default value when this is the first option.
3063 // The first oneof option value will be used as default value when no default value is specified.
3064 //
3065 if (FirstOneOfOption) {
3066 // This flag is used to specify whether this option is the first. Set it to FALSE for the following options.
3067 FirstOneOfOption = FALSE;
3068
3069 //
3070 // Prepare new DefaultValue
3071 //
3072 DefaultData.Type = DefaultValueFromDefault;
3073 CopyMem (&DefaultData.Value, &IfrOneOfOption->Value, IfrOneOfOption->Header.Length - OFFSET_OF (EFI_IFR_ONE_OF_OPTION, Value));
3074 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3075 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3076 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3077 InsertDefaultValue (BlockData, &DefaultData);
3078 }
3079 }
3080
3081 break;
3082
3083 case EFI_IFR_DEFAULT_OP:
3084 //
3085 // Update Current BlockData to the default value.
3086 //
3087 if ((BlockData == NULL) || (BlockData->Scope == 0)) {
3088 //
3089 // No matched block data is ignored.
3090 //
3091 break;
3092 }
3093
3094 //
3095 // Get the DefaultId
3096 //
3097 IfrDefault = (EFI_IFR_DEFAULT *)IfrOpHdr;
3098 VarDefaultId = IfrDefault->DefaultId;
3099 //
3100 // Prepare new DefaultValue
3101 //
3102 DefaultData.Type = DefaultValueFromOpcode;
3103 DefaultData.DefaultId = VarDefaultId;
3104 if (QuestionReferBitField) {
3105 CopyMem (&DefaultData.Value.u32, &IfrDefault->Value.u32, sizeof (UINT32));
3106 } else {
3107 CopyMem (&DefaultData.Value, &IfrDefault->Value, IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value));
3108 }
3109
3110 // If the value field is expression, set the cleaned flag.
3111 if (IfrDefault->Type == EFI_IFR_TYPE_OTHER) {
3112 DefaultData.Cleaned = TRUE;
3113 }
3114
3115 //
3116 // Add DefaultValue into current BlockData
3117 //
3118 InsertDefaultValue (BlockData, &DefaultData);
3119
3120 //
3121 // Set default value for other default id in the DefaultId list.
3122 // when SmallestDefaultId == VarDefaultId means there are two defaults with same default Id.
3123 // If the two defaults are both from default opcode, use the first default as the default value of other default Id.
3124 // If one from flag and the other form default opcode, use the default opcode value as the default value of other default Id.
3125 //
3126 if ((SmallestDefaultId > VarDefaultId) || ((SmallestDefaultId == VarDefaultId) && !FromOtherDefaultOpcode)) {
3127 FromOtherDefaultOpcode = TRUE;
3128 SmallestDefaultId = VarDefaultId;
3129 for (LinkData = DefaultIdArray->Entry.ForwardLink; LinkData != &DefaultIdArray->Entry; LinkData = LinkData->ForwardLink) {
3130 DefaultDataPtr = BASE_CR (LinkData, IFR_DEFAULT_DATA, Entry);
3131 if (DefaultDataPtr->DefaultId != DefaultData.DefaultId) {
3132 DefaultData.Type = DefaultValueFromOtherDefault;
3133 DefaultData.DefaultId = DefaultDataPtr->DefaultId;
3134 InsertDefaultValue (BlockData, &DefaultData);
3135 }
3136 }
3137 }
3138
3139 //
3140 // After insert the default value, reset the cleaned value for next
3141 // time used. If not set here, need to set the value before every time.
3142 // use it.
3143 //
3144 DefaultData.Cleaned = FALSE;
3145 break;
3146
3147 case EFI_IFR_END_OP:
3148 //
3149 // End Opcode is for Var question.
3150 //
3151 QuestionReferBitField = FALSE;
3152 if (BlockData != NULL) {
3153 if (BlockData->Scope > 0) {
3154 BlockData->Scope--;
3155 }
3156
3157 if (BlockData->Scope == 0) {
3158 BlockData = NULL;
3159 //
3160 // when finishing parsing a question, clean the SmallestDefaultId and GetDefaultFromDefaultOpcode.
3161 //
3162 SmallestDefaultId = 0xFFFF;
3163 FromOtherDefaultOpcode = FALSE;
3164 }
3165 }
3166
3167 break;
3168
3169 case EFI_IFR_GUID_OP:
3170 if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) {
3171 QuestionReferBitField = TRUE;
3172 }
3173
3174 break;
3175
3176 default:
3177 if (BlockData != NULL) {
3178 if (BlockData->Scope > 0) {
3179 BlockData->Scope = (UINT8)(BlockData->Scope + IfrOpHdr->Scope);
3180 }
3181
3182 if (BlockData->Scope == 0) {
3183 BlockData = NULL;
3184 }
3185 }
3186
3187 break;
3188 }
3189
3190 IfrOffset += IfrOpHdr->Length;
3191 PackageOffset += IfrOpHdr->Length;
3192 }
3193
3194 //
3195 // if Status == EFI_NOT_FOUND, just means the opcode is not required,not contain any error,
3196 // so set the Status to EFI_SUCCESS.
3197 //
3198 if (Status == EFI_NOT_FOUND) {
3199 Status = EFI_SUCCESS;
3200 }
3201
3202 Done:
3203 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
3204 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
3205 for (LinkDefault = BlockData->DefaultValueEntry.ForwardLink; LinkDefault != &BlockData->DefaultValueEntry; ) {
3206 DefaultDataPtr = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3207 LinkDefault = LinkDefault->ForwardLink;
3208 if (DefaultDataPtr->Cleaned == TRUE) {
3209 RemoveEntryList (&DefaultDataPtr->Entry);
3210 FreePool (DefaultDataPtr);
3211 }
3212 }
3213 }
3214
3215 if (IfrEfiVarStoreTmp != NULL) {
3216 FreePool (IfrEfiVarStoreTmp);
3217 }
3218
3219 return Status;
3220 }
3221
3222 /**
3223 parse the configrequest string, get the elements.
3224
3225 @param ConfigRequest The input configrequest string.
3226 @param Progress Return the progress data.
3227
3228 @retval Block data pointer.
3229 **/
3230 IFR_BLOCK_DATA *
3231 GetBlockElement (
3232 IN EFI_STRING ConfigRequest,
3233 OUT EFI_STRING *Progress
3234 )
3235 {
3236 EFI_STRING StringPtr;
3237 IFR_BLOCK_DATA *BlockData;
3238 IFR_BLOCK_DATA *RequestBlockArray;
3239 EFI_STATUS Status;
3240 UINT8 *TmpBuffer;
3241 UINT16 Offset;
3242 UINT16 Width;
3243 LIST_ENTRY *Link;
3244 IFR_BLOCK_DATA *NextBlockData;
3245 UINTN Length;
3246
3247 TmpBuffer = NULL;
3248
3249 //
3250 // Init RequestBlockArray
3251 //
3252 RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3253 if (RequestBlockArray == NULL) {
3254 goto Done;
3255 }
3256
3257 InitializeListHead (&RequestBlockArray->Entry);
3258
3259 //
3260 // Get the request Block array from the request string
3261 // Offset and Width
3262 //
3263
3264 //
3265 // Parse each <RequestElement> if exists
3266 // Only <BlockName> format is supported by this help function.
3267 // <BlockName> ::= &'OFFSET='<Number>&'WIDTH='<Number>
3268 //
3269 StringPtr = ConfigRequest;
3270 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
3271 //
3272 // Skip the OFFSET string
3273 //
3274 *Progress = StringPtr;
3275 StringPtr += StrLen (L"&OFFSET=");
3276 //
3277 // Get Offset
3278 //
3279 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3280 if (EFI_ERROR (Status)) {
3281 goto Done;
3282 }
3283
3284 Offset = 0;
3285 CopyMem (
3286 &Offset,
3287 TmpBuffer,
3288 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
3289 );
3290 FreePool (TmpBuffer);
3291
3292 StringPtr += Length;
3293 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
3294 goto Done;
3295 }
3296
3297 StringPtr += StrLen (L"&WIDTH=");
3298
3299 //
3300 // Get Width
3301 //
3302 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3303 if (EFI_ERROR (Status)) {
3304 goto Done;
3305 }
3306
3307 Width = 0;
3308 CopyMem (
3309 &Width,
3310 TmpBuffer,
3311 (((Length + 1) / 2) < sizeof (UINT16)) ? ((Length + 1) / 2) : sizeof (UINT16)
3312 );
3313 FreePool (TmpBuffer);
3314
3315 StringPtr += Length;
3316 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
3317 goto Done;
3318 }
3319
3320 //
3321 // Set Block Data
3322 //
3323 BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3324 if (BlockData == NULL) {
3325 goto Done;
3326 }
3327
3328 BlockData->Offset = Offset;
3329 BlockData->Width = Width;
3330 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
3331
3332 //
3333 // Skip &VALUE string if &VALUE does exists.
3334 //
3335 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) == 0) {
3336 StringPtr += StrLen (L"&VALUE=");
3337
3338 //
3339 // Get Value
3340 //
3341 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
3342 if (EFI_ERROR (Status)) {
3343 goto Done;
3344 }
3345
3346 FreePool (TmpBuffer);
3347 StringPtr += Length;
3348 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
3349 goto Done;
3350 }
3351 }
3352
3353 //
3354 // If '\0', parsing is finished.
3355 //
3356 if (*StringPtr == 0) {
3357 break;
3358 }
3359 }
3360
3361 //
3362 // Merge the requested block data.
3363 //
3364 Link = RequestBlockArray->Entry.ForwardLink;
3365 while ((Link != &RequestBlockArray->Entry) && (Link->ForwardLink != &RequestBlockArray->Entry)) {
3366 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3367 NextBlockData = BASE_CR (Link->ForwardLink, IFR_BLOCK_DATA, Entry);
3368 if ((NextBlockData->Offset >= BlockData->Offset) && (NextBlockData->Offset <= (BlockData->Offset + BlockData->Width))) {
3369 if ((NextBlockData->Offset + NextBlockData->Width) > (BlockData->Offset + BlockData->Width)) {
3370 BlockData->Width = (UINT16)(NextBlockData->Offset + NextBlockData->Width - BlockData->Offset);
3371 }
3372
3373 RemoveEntryList (Link->ForwardLink);
3374 FreePool (NextBlockData);
3375 continue;
3376 }
3377
3378 Link = Link->ForwardLink;
3379 }
3380
3381 return RequestBlockArray;
3382
3383 Done:
3384 if (RequestBlockArray != NULL) {
3385 //
3386 // Free Link Array RequestBlockArray
3387 //
3388 while (!IsListEmpty (&RequestBlockArray->Entry)) {
3389 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3390 RemoveEntryList (&BlockData->Entry);
3391 FreePool (BlockData);
3392 }
3393
3394 FreePool (RequestBlockArray);
3395 }
3396
3397 return NULL;
3398 }
3399
3400 /**
3401 parse the configrequest string, get the elements.
3402
3403 @param ConfigRequest The input config request string.
3404 @param Progress Return the progress data.
3405
3406 @retval return data block array.
3407 **/
3408 IFR_BLOCK_DATA *
3409 GetNameElement (
3410 IN EFI_STRING ConfigRequest,
3411 OUT EFI_STRING *Progress
3412 )
3413 {
3414 EFI_STRING StringPtr;
3415 EFI_STRING NextTag;
3416 IFR_BLOCK_DATA *BlockData;
3417 IFR_BLOCK_DATA *RequestBlockArray;
3418 BOOLEAN HasValue;
3419
3420 StringPtr = ConfigRequest;
3421
3422 //
3423 // Init RequestBlockArray
3424 //
3425 RequestBlockArray = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3426 if (RequestBlockArray == NULL) {
3427 goto Done;
3428 }
3429
3430 InitializeListHead (&RequestBlockArray->Entry);
3431
3432 //
3433 // Get the request Block array from the request string
3434 //
3435
3436 //
3437 // Parse each <RequestElement> if exists
3438 // Only <BlockName> format is supported by this help function.
3439 // <BlockName> ::= &'Name***=***
3440 //
3441 while (StringPtr != NULL && *StringPtr == L'&') {
3442 *Progress = StringPtr;
3443 //
3444 // Skip the L"&" string
3445 //
3446 StringPtr += 1;
3447
3448 HasValue = FALSE;
3449 if ((NextTag = StrStr (StringPtr, L"=")) != NULL) {
3450 *NextTag = L'\0';
3451 HasValue = TRUE;
3452 } else if ((NextTag = StrStr (StringPtr, L"&")) != NULL) {
3453 *NextTag = L'\0';
3454 }
3455
3456 //
3457 // Set Block Data
3458 //
3459 BlockData = (IFR_BLOCK_DATA *)AllocateZeroPool (sizeof (IFR_BLOCK_DATA));
3460 if (BlockData == NULL) {
3461 goto Done;
3462 }
3463
3464 //
3465 // Get Name
3466 //
3467 BlockData->Name = AllocateCopyPool (StrSize (StringPtr), StringPtr);
3468 InsertBlockData (&RequestBlockArray->Entry, &BlockData);
3469
3470 if (HasValue) {
3471 //
3472 // If has value, skip the value.
3473 //
3474 StringPtr = NextTag + 1;
3475 *NextTag = L'=';
3476 StringPtr = StrStr (StringPtr, L"&");
3477 } else if (NextTag != NULL) {
3478 //
3479 // restore the '&' text.
3480 //
3481 StringPtr = NextTag;
3482 *NextTag = L'&';
3483 }
3484 }
3485
3486 return RequestBlockArray;
3487
3488 Done:
3489 if (RequestBlockArray != NULL) {
3490 //
3491 // Free Link Array RequestBlockArray
3492 //
3493 while (!IsListEmpty (&RequestBlockArray->Entry)) {
3494 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
3495 RemoveEntryList (&BlockData->Entry);
3496 if (BlockData->Name != NULL) {
3497 FreePool (BlockData->Name);
3498 }
3499
3500 FreePool (BlockData);
3501 }
3502
3503 FreePool (RequestBlockArray);
3504 }
3505
3506 return NULL;
3507 }
3508
3509 /**
3510 Generate ConfigRequest string base on the varstore info.
3511
3512 @param ConfigHdr The config header for this varstore.
3513 @param VarStorageData The varstore info.
3514 @param Status Return Status.
3515 @param ConfigRequest The ConfigRequest info may be return.
3516
3517 @retval TRUE Need to continue
3518 @retval Others NO need to continue or error occur.
3519 **/
3520 BOOLEAN
3521 GenerateConfigRequest (
3522 IN CHAR16 *ConfigHdr,
3523 IN IFR_VARSTORAGE_DATA *VarStorageData,
3524 OUT EFI_STATUS *Status,
3525 IN OUT EFI_STRING *ConfigRequest
3526 )
3527 {
3528 BOOLEAN DataExist;
3529 UINTN Length;
3530 LIST_ENTRY *Link;
3531 CHAR16 *FullConfigRequest;
3532 CHAR16 *StringPtr;
3533 IFR_BLOCK_DATA *BlockData;
3534
3535 //
3536 // Append VarStorageData BlockEntry into *Request string
3537 // Now support only one varstore in a form package.
3538 //
3539
3540 //
3541 // Go through all VarStorageData Entry and get BlockEntry for each one for the multiple varstore in a single form package
3542 // Then construct them all to return MultiRequest string : ConfigHdr BlockConfig
3543 //
3544
3545 //
3546 // Compute the length of the entire request starting with <ConfigHdr> and a
3547 // Null-terminator
3548 //
3549 DataExist = FALSE;
3550 Length = StrLen (ConfigHdr) + 1;
3551
3552 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
3553 DataExist = TRUE;
3554 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3555 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3556 //
3557 // Add <BlockName> length for each Name
3558 //
3559 // <BlockName> ::= &Name1&Name2&...
3560 // |1| StrLen(Name1)
3561 //
3562 Length = Length + (1 + StrLen (BlockData->Name));
3563 } else {
3564 //
3565 // Add <BlockName> length for each Offset/Width pair
3566 //
3567 // <BlockName> ::= &OFFSET=1234&WIDTH=1234
3568 // | 8 | 4 | 7 | 4 |
3569 //
3570 Length = Length + (8 + 4 + 7 + 4);
3571 }
3572 }
3573
3574 //
3575 // No any request block data is found. The request string can't be constructed.
3576 //
3577 if (!DataExist) {
3578 *Status = EFI_SUCCESS;
3579 return FALSE;
3580 }
3581
3582 //
3583 // Allocate buffer for the entire <ConfigRequest>
3584 //
3585 FullConfigRequest = AllocateZeroPool (Length * sizeof (CHAR16));
3586 if (FullConfigRequest == NULL) {
3587 *Status = EFI_OUT_OF_RESOURCES;
3588 return FALSE;
3589 }
3590
3591 StringPtr = FullConfigRequest;
3592
3593 //
3594 // Start with <ConfigHdr>
3595 //
3596 StrCpyS (StringPtr, Length, ConfigHdr);
3597 StringPtr += StrLen (StringPtr);
3598
3599 //
3600 // Loop through all the Offset/Width pairs and append them to ConfigRequest
3601 //
3602 for (Link = VarStorageData->BlockEntry.ForwardLink; Link != &VarStorageData->BlockEntry; Link = Link->ForwardLink) {
3603 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3604 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
3605 //
3606 // Append &Name1\0
3607 //
3608 UnicodeSPrint (
3609 StringPtr,
3610 (1 + StrLen (BlockData->Name) + 1) * sizeof (CHAR16),
3611 L"&%s",
3612 BlockData->Name
3613 );
3614 } else {
3615 //
3616 // Append &OFFSET=XXXX&WIDTH=YYYY\0
3617 //
3618 UnicodeSPrint (
3619 StringPtr,
3620 (8 + 4 + 7 + 4 + 1) * sizeof (CHAR16),
3621 L"&OFFSET=%04X&WIDTH=%04X",
3622 BlockData->Offset,
3623 BlockData->Width
3624 );
3625 }
3626
3627 StringPtr += StrLen (StringPtr);
3628 }
3629
3630 //
3631 // Set to the got full request string.
3632 //
3633 HiiToLower (FullConfigRequest);
3634
3635 if (*ConfigRequest != NULL) {
3636 FreePool (*ConfigRequest);
3637 }
3638
3639 *ConfigRequest = FullConfigRequest;
3640
3641 return TRUE;
3642 }
3643
3644 /**
3645 Generate ConfigRequest Header base on the varstore info.
3646
3647 @param VarStorageData The varstore info.
3648 @param DevicePath Device path for this varstore.
3649 @param ConfigHdr The config header for this varstore.
3650
3651 @retval EFI_SUCCESS Generate the header success.
3652 @retval EFI_OUT_OF_RESOURCES Allocate buffer fail.
3653 **/
3654 EFI_STATUS
3655 GenerateHdr (
3656 IN IFR_VARSTORAGE_DATA *VarStorageData,
3657 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
3658 OUT EFI_STRING *ConfigHdr
3659 )
3660 {
3661 EFI_STRING GuidStr;
3662 EFI_STRING NameStr;
3663 EFI_STRING PathStr;
3664 UINTN Length;
3665 EFI_STATUS Status;
3666
3667 Status = EFI_SUCCESS;
3668 NameStr = NULL;
3669 GuidStr = NULL;
3670 PathStr = NULL;
3671
3672 //
3673 // Construct <ConfigHdr> : "GUID=...&NAME=...&PATH=..." by VarStorageData Guid, Name and DriverHandle
3674 //
3675 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)&VarStorageData->Guid, 1, &GuidStr);
3676 if (VarStorageData->Name != NULL) {
3677 GenerateSubStr (L"NAME=", StrLen (VarStorageData->Name) * sizeof (CHAR16), (VOID *)VarStorageData->Name, 2, &NameStr);
3678 } else {
3679 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
3680 }
3681
3682 GenerateSubStr (
3683 L"PATH=",
3684 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath),
3685 (VOID *)DevicePath,
3686 1,
3687 &PathStr
3688 );
3689 Length = StrLen (GuidStr) + StrLen (NameStr) + StrLen (PathStr) + 1;
3690 if (VarStorageData->Name == NULL) {
3691 Length += 1;
3692 }
3693
3694 *ConfigHdr = AllocateZeroPool (Length * sizeof (CHAR16));
3695 if (*ConfigHdr == NULL) {
3696 Status = EFI_OUT_OF_RESOURCES;
3697 goto Done;
3698 }
3699
3700 StrCpyS (*ConfigHdr, Length, GuidStr);
3701 StrCatS (*ConfigHdr, Length, NameStr);
3702 if (VarStorageData->Name == NULL) {
3703 StrCatS (*ConfigHdr, Length, L"&");
3704 }
3705
3706 StrCatS (*ConfigHdr, Length, PathStr);
3707
3708 //
3709 // Remove the last character L'&'
3710 //
3711 *(*ConfigHdr + StrLen (*ConfigHdr) - 1) = L'\0';
3712
3713 Done:
3714 if (GuidStr != NULL) {
3715 FreePool (GuidStr);
3716 }
3717
3718 if (NameStr != NULL) {
3719 FreePool (NameStr);
3720 }
3721
3722 if (PathStr != NULL) {
3723 FreePool (PathStr);
3724 }
3725
3726 return Status;
3727 }
3728
3729 /**
3730 Update the default value in the block data which is used as bit var store.
3731
3732 For example:
3733 A question value saved in a bit fied: bitoffset = 1; bitwidth = 2;default value = 1.
3734 And corresponding block data info: offset==0; width==1;currently the default value
3735 is saved as 1.Actually the default value 1 need to be set to bit field 1, so the
3736 default value of this block data shuold be:2.
3737
3738 typedef struct {
3739 UINT8 Bit1 : 1; //
3740 UINT8 Bit2 : 2; // Question saved in Bit2,so originalBlock info: offset = 0; width = 1;(byte level) defaul = 1.
3741 // (default value record for the bit field)
3742 ......
3743 }ExampleData;
3744
3745 After function UpdateDefaultValue,the Block info is: offset = 0; width = 1;(byte level) default = 2.
3746 (default value record for the Block)
3747
3748 UpdateDefaultValue function update default value of bit var block based on the bit field info in the block.
3749
3750 @param BlockLink The Link of the block data.
3751
3752 **/
3753 VOID
3754 UpdateDefaultValue (
3755 IN LIST_ENTRY *BlockLink
3756 )
3757 {
3758 LIST_ENTRY *Link;
3759 LIST_ENTRY *ListEntry;
3760 LIST_ENTRY *LinkDefault;
3761 IFR_BLOCK_DATA *BlockData;
3762 IFR_DEFAULT_DATA *DefaultValueData;
3763 UINTN StartBit;
3764 UINTN EndBit;
3765 UINT32 BitFieldDefaultValue;
3766
3767 for ( Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
3768 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3769 if (!BlockData->IsBitVar) {
3770 continue;
3771 }
3772
3773 ListEntry = &BlockData->DefaultValueEntry;
3774 //
3775 // Update the default value in the block data with all existing default id.
3776 //
3777 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
3778 //
3779 // Get the default data, and the value of the default data is for some field in the block.
3780 // Note: Default value for bit field question is stored as UINT32.
3781 //
3782 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3783 BitFieldDefaultValue = DefaultValueData->Value.u32;
3784
3785 StartBit = BlockData->BitOffset % 8;
3786 EndBit = StartBit + BlockData->BitWidth - 1;
3787
3788 //
3789 // Set the bit field default value to related bit filed, then we will got the new default vaule for the block data.
3790 //
3791 DefaultValueData->Value.u32 = BitFieldWrite32 (0, StartBit, EndBit, BitFieldDefaultValue);
3792 }
3793 }
3794 }
3795
3796 /**
3797 Merge the default value in two block datas which have overlap region.
3798
3799 For bit fields, their related block data may have overlap region, such as:
3800
3801 typedef struct {
3802 UINT16 Bit1 : 6; // Question1 refer Bit1, Block1: offset = 0; width = 1;(byte level) default = 1
3803 UINT16 Bit2 : 5; // Question2 refer Bit2, Block2: offset = 0; width = 2;(byte level) default = 5
3804 // (default value record for the bit field)
3805 ......
3806 }ExampleData;
3807
3808 After function UpdateDefaultValue:
3809 Block1: offset = 0; width = 1;(byte level) default = 1
3810 Block2: offset = 0; width = 2;(byte level) default = 320 (5 * (2 << 6))
3811 (default value record for block)
3812
3813 After function MergeBlockDefaultValue:
3814 Block1: offset = 0; width = 1;(byte level) default = 65
3815 Block2: offset = 0; width = 2;(byte level) default = 321
3816 (Block1 and Block2 has overlap region, merge the overlap value to Block1 and Blcok2)
3817
3818 Block1 and Block2 have overlap byte region, but currntly the default value of Block1 only contains
3819 value of Bit1 (low 6 bits),the default value of Block2 only contains the value of Bit2 (middle 5 bits).
3820
3821 This fuction merge the default value of these two blocks, and make the default value of block1
3822 also contain the value of lower 2 bits of the Bit2. And make the default value of Block2 also
3823 contain the default value of Bit1.
3824
3825 We can get the total value of the whole block that just cover these two blocks(in this case is:
3826 block: offset =0; width =2;) then the value of block2 is same as block, the value of block1 is
3827 the first byte value of block.
3828
3829 @param FirstBlock Point to the block date whose default value need to be merged.
3830 @param SecondBlock Point to the block date whose default value need to be merged.
3831
3832 **/
3833 VOID
3834 MergeBlockDefaultValue (
3835 IN OUT IFR_BLOCK_DATA *FirstBlock,
3836 IN OUT IFR_BLOCK_DATA *SecondBlock
3837 )
3838 {
3839 LIST_ENTRY *FirstListEntry;
3840 LIST_ENTRY *SecondListEntry;
3841 LIST_ENTRY *FirstDefaultLink;
3842 LIST_ENTRY *SecondDefaultLink;
3843 IFR_DEFAULT_DATA *FirstDefaultValueData;
3844 IFR_DEFAULT_DATA *SecondDefaultValueData;
3845 UINT32 *FirstDefaultValue;
3846 UINT32 *SecondDefaultValue;
3847 UINT64 TotalValue;
3848 UINT64 ShiftedValue;
3849 UINT16 OffsetShift;
3850
3851 FirstListEntry = &FirstBlock->DefaultValueEntry;
3852 for (FirstDefaultLink = FirstListEntry->ForwardLink; FirstDefaultLink != FirstListEntry; FirstDefaultLink = FirstDefaultLink->ForwardLink) {
3853 FirstDefaultValueData = BASE_CR (FirstDefaultLink, IFR_DEFAULT_DATA, Entry);
3854 SecondListEntry = &SecondBlock->DefaultValueEntry;
3855 for (SecondDefaultLink = SecondListEntry->ForwardLink; SecondDefaultLink != SecondListEntry; SecondDefaultLink = SecondDefaultLink->ForwardLink) {
3856 SecondDefaultValueData = BASE_CR (SecondDefaultLink, IFR_DEFAULT_DATA, Entry);
3857 if (FirstDefaultValueData->DefaultId != SecondDefaultValueData->DefaultId) {
3858 continue;
3859 }
3860
3861 //
3862 // Find default value with same default id in the two blocks.
3863 // Note: Default value for bit field question is stored as UINT32 type.
3864 //
3865 FirstDefaultValue = &FirstDefaultValueData->Value.u32;
3866 SecondDefaultValue = &SecondDefaultValueData->Value.u32;
3867 //
3868 // 1. Get the default value of the whole blcok that can just cover FirstBlock and SecondBlock.
3869 // 2. Get the default value of FirstBlock and SecondBlock form the value of whole block based
3870 // on the offset and width of FirstBlock and SecondBlock.
3871 //
3872 if (FirstBlock->Offset > SecondBlock->Offset) {
3873 OffsetShift = FirstBlock->Offset - SecondBlock->Offset;
3874 ShiftedValue = LShiftU64 ((UINT64)(*FirstDefaultValue), OffsetShift * 8);
3875 TotalValue = ShiftedValue | (UINT64)(*SecondDefaultValue);
3876 *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, SecondBlock->Width * 8 -1);
3877 *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + FirstBlock->Width *8 -1);
3878 } else {
3879 OffsetShift = SecondBlock->Offset -FirstBlock->Offset;
3880 ShiftedValue = LShiftU64 ((UINT64)(*SecondDefaultValue), OffsetShift * 8);
3881 TotalValue = ShiftedValue | (UINT64)(*FirstDefaultValue);
3882 *FirstDefaultValue = (UINT32)BitFieldRead64 (TotalValue, 0, FirstBlock->Width * 8 -1);
3883 *SecondDefaultValue = (UINT32)BitFieldRead64 (TotalValue, OffsetShift * 8, OffsetShift * 8 + SecondBlock->Width *8 -1);
3884 }
3885 }
3886 }
3887 }
3888
3889 /**
3890
3891 Update the default value in the block data which used as Bit VarStore
3892
3893 @param BlockLink The Link of the block data.
3894
3895 **/
3896 VOID
3897 UpdateBlockDataArray (
3898 IN LIST_ENTRY *BlockLink
3899 )
3900 {
3901 LIST_ENTRY *Link;
3902 LIST_ENTRY *TempLink;
3903 IFR_BLOCK_DATA *BlockData;
3904 IFR_BLOCK_DATA *NextBlockData;
3905
3906 //
3907 // 1. Update default value in BitVar block data.
3908 // Sine some block datas are used as BitVarStore, then the default value recored in the block
3909 // is for related bit field in the block. so we need to set the default value to the related bit
3910 // fields in the block data if the block data is used as bit varstore, then the default value of
3911 // the block will be updated.
3912 //
3913 UpdateDefaultValue (BlockLink);
3914
3915 //
3916 // 2.Update default value for overlap BitVar blcok datas.
3917 // For block datas have overlap region, we need to merge the default value in different blocks.
3918 //
3919 for (Link = BlockLink->ForwardLink; Link != BlockLink; Link = Link->ForwardLink) {
3920 BlockData = BASE_CR (Link, IFR_BLOCK_DATA, Entry);
3921 if (!BlockData->IsBitVar) {
3922 continue;
3923 }
3924
3925 for (TempLink = Link->ForwardLink; TempLink != BlockLink; TempLink = TempLink->ForwardLink) {
3926 NextBlockData = BASE_CR (TempLink, IFR_BLOCK_DATA, Entry);
3927 if (!NextBlockData->IsBitVar || (NextBlockData->Offset >= BlockData->Offset + BlockData->Width) || (BlockData->Offset >= NextBlockData->Offset + NextBlockData->Width)) {
3928 continue;
3929 }
3930
3931 //
3932 // Find two blocks are used as bit VarStore and have overlap region, so need to merge default value of these two blocks.
3933 //
3934 MergeBlockDefaultValue (BlockData, NextBlockData);
3935 }
3936 }
3937 }
3938
3939 /**
3940 Generate ConfigAltResp string base on the varstore info.
3941
3942 @param HiiHandle Hii Handle for this hii package.
3943 @param ConfigHdr The config header for this varstore.
3944 @param VarStorageData The varstore info.
3945 @param DefaultIdArray The Default id array.
3946 @param DefaultAltCfgResp The DefaultAltCfgResp info may be return.
3947
3948 @retval TRUE Need to continue
3949 @retval Others NO need to continue or error occur.
3950 **/
3951 EFI_STATUS
3952 GenerateAltConfigResp (
3953 IN EFI_HII_HANDLE HiiHandle,
3954 IN CHAR16 *ConfigHdr,
3955 IN IFR_VARSTORAGE_DATA *VarStorageData,
3956 IN IFR_DEFAULT_DATA *DefaultIdArray,
3957 IN OUT EFI_STRING *DefaultAltCfgResp
3958 )
3959 {
3960 BOOLEAN DataExist;
3961 UINTN Length;
3962 LIST_ENTRY *Link;
3963 LIST_ENTRY *LinkData;
3964 LIST_ENTRY *LinkDefault;
3965 LIST_ENTRY *ListEntry;
3966 CHAR16 *StringPtr;
3967 IFR_BLOCK_DATA *BlockData;
3968 IFR_DEFAULT_DATA *DefaultId;
3969 IFR_DEFAULT_DATA *DefaultValueData;
3970 UINTN Width;
3971 UINT8 *TmpBuffer;
3972 CHAR16 *DefaultString;
3973 UINTN StrSize;
3974
3975 BlockData = NULL;
3976 DataExist = FALSE;
3977 DefaultString = NULL;
3978 //
3979 // Add length for <ConfigHdr> + '\0'
3980 //
3981 Length = StrLen (ConfigHdr) + 1;
3982
3983 UpdateBlockDataArray (&VarStorageData->BlockEntry);
3984
3985 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
3986 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
3987 //
3988 // Add length for "&<ConfigHdr>&ALTCFG=XXXX"
3989 // |1| StrLen (ConfigHdr) | 8 | 4 |
3990 //
3991 Length += (1 + StrLen (ConfigHdr) + 8 + 4);
3992
3993 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
3994 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
3995 ListEntry = &BlockData->DefaultValueEntry;
3996 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
3997 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
3998 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
3999 continue;
4000 }
4001
4002 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4003 //
4004 // Add length for "&Name1=zzzzzzzzzzzz"
4005 // |1|Name|1|Value|
4006 //
4007 Length += (1 + StrLen (BlockData->Name) + 1 + BlockData->Width * 2);
4008 } else {
4009 //
4010 // Add length for "&OFFSET=XXXX&WIDTH=YYYY&VALUE=zzzzzzzzzzzz"
4011 // | 8 | 4 | 7 | 4 | 7 | Width * 2 |
4012 //
4013 Length += (8 + 4 + 7 + 4 + 7 + BlockData->Width * 2);
4014 }
4015
4016 DataExist = TRUE;
4017 }
4018 }
4019 }
4020
4021 //
4022 // No default value is found. The default string doesn't exist.
4023 //
4024 if (!DataExist) {
4025 return EFI_SUCCESS;
4026 }
4027
4028 //
4029 // Allocate buffer for the entire <DefaultAltCfgResp>
4030 //
4031 *DefaultAltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
4032 if (*DefaultAltCfgResp == NULL) {
4033 return EFI_OUT_OF_RESOURCES;
4034 }
4035
4036 StringPtr = *DefaultAltCfgResp;
4037
4038 //
4039 // Start with <ConfigHdr>
4040 //
4041 StrCpyS (StringPtr, Length, ConfigHdr);
4042 StringPtr += StrLen (StringPtr);
4043
4044 for (Link = DefaultIdArray->Entry.ForwardLink; Link != &DefaultIdArray->Entry; Link = Link->ForwardLink) {
4045 DefaultId = BASE_CR (Link, IFR_DEFAULT_DATA, Entry);
4046 //
4047 // Add <AltConfigHdr> of the form "&<ConfigHdr>&ALTCFG=XXXX\0"
4048 // |1| StrLen (ConfigHdr) | 8 | 4 |
4049 //
4050 UnicodeSPrint (
4051 StringPtr,
4052 (1 + StrLen (ConfigHdr) + 8 + 4 + 1) * sizeof (CHAR16),
4053 L"&%s&ALTCFG=%04X",
4054 ConfigHdr,
4055 DefaultId->DefaultId
4056 );
4057 StringPtr += StrLen (StringPtr);
4058
4059 for (LinkData = VarStorageData->BlockEntry.ForwardLink; LinkData != &VarStorageData->BlockEntry; LinkData = LinkData->ForwardLink) {
4060 BlockData = BASE_CR (LinkData, IFR_BLOCK_DATA, Entry);
4061 ListEntry = &BlockData->DefaultValueEntry;
4062 for (LinkDefault = ListEntry->ForwardLink; LinkDefault != ListEntry; LinkDefault = LinkDefault->ForwardLink) {
4063 DefaultValueData = BASE_CR (LinkDefault, IFR_DEFAULT_DATA, Entry);
4064 if (DefaultValueData->DefaultId != DefaultId->DefaultId) {
4065 continue;
4066 }
4067
4068 if (VarStorageData->Type == EFI_HII_VARSTORE_NAME_VALUE) {
4069 UnicodeSPrint (
4070 StringPtr,
4071 (1 + StrLen (ConfigHdr) + 1) * sizeof (CHAR16),
4072 L"&%s=",
4073 BlockData->Name
4074 );
4075 StringPtr += StrLen (StringPtr);
4076 } else {
4077 //
4078 // Add <BlockConfig>
4079 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE'=<Number>
4080 //
4081 UnicodeSPrint (
4082 StringPtr,
4083 (8 + 4 + 7 + 4 + 7 + 1) * sizeof (CHAR16),
4084 L"&OFFSET=%04X&WIDTH=%04X&VALUE=",
4085 BlockData->Offset,
4086 BlockData->Width
4087 );
4088 StringPtr += StrLen (StringPtr);
4089 }
4090
4091 Width = BlockData->Width;
4092 //
4093 // Convert Value to a hex string in "%x" format
4094 // NOTE: This is in the opposite byte that GUID and PATH use
4095 //
4096 if (BlockData->OpCode == EFI_IFR_STRING_OP) {
4097 DefaultString = InternalGetString (HiiHandle, DefaultValueData->Value.string);
4098 TmpBuffer = AllocateZeroPool (Width);
4099 ASSERT (TmpBuffer != NULL);
4100 if (DefaultString != NULL) {
4101 StrSize = StrLen (DefaultString)* sizeof (CHAR16);
4102 if (StrSize > Width) {
4103 StrSize = Width;
4104 }
4105
4106 CopyMem (TmpBuffer, (UINT8 *)DefaultString, StrSize);
4107 }
4108 } else {
4109 TmpBuffer = (UINT8 *)&(DefaultValueData->Value);
4110 }
4111
4112 for ( ; Width > 0 && (TmpBuffer != NULL); Width--) {
4113 UnicodeValueToStringS (
4114 StringPtr,
4115 Length * sizeof (CHAR16) - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp),
4116 PREFIX_ZERO | RADIX_HEX,
4117 TmpBuffer[Width - 1],
4118 2
4119 );
4120 StringPtr += StrnLenS (StringPtr, Length - ((UINTN)StringPtr - (UINTN)*DefaultAltCfgResp) / sizeof (CHAR16));
4121 }
4122
4123 if (DefaultString != NULL) {
4124 FreePool (DefaultString);
4125 DefaultString = NULL;
4126 }
4127
4128 if ((BlockData->OpCode == EFI_IFR_STRING_OP) && (TmpBuffer != NULL)) {
4129 FreePool (TmpBuffer);
4130 TmpBuffer = NULL;
4131 }
4132 }
4133 }
4134 }
4135
4136 HiiToLower (*DefaultAltCfgResp);
4137
4138 return EFI_SUCCESS;
4139 }
4140
4141 /**
4142 This function gets the full request string and full default value string by
4143 parsing IFR data in HII form packages.
4144
4145 When Request points to NULL string, the request string and default value string
4146 for each varstore in form package will return.
4147
4148 @param DataBaseRecord The DataBaseRecord instance contains the found Hii handle and package.
4149 @param DevicePath Device Path which Hii Config Access Protocol is registered.
4150 @param Request Pointer to a null-terminated Unicode string in
4151 <ConfigRequest> format. When it doesn't contain
4152 any RequestElement, it will be updated to return
4153 the full RequestElement retrieved from IFR data.
4154 If it points to NULL, the request string for the first
4155 varstore in form package will be merged into a
4156 <MultiConfigRequest> format string and return.
4157 @param AltCfgResp Pointer to a null-terminated Unicode string in
4158 <ConfigAltResp> format. When the pointer is to NULL,
4159 the full default value string retrieved from IFR data
4160 will return. When the pinter is to a string, the
4161 full default value string retrieved from IFR data
4162 will be merged into the input string and return.
4163 When Request points to NULL, the default value string
4164 for each varstore in form package will be merged into
4165 a <MultiConfigAltResp> format string and return.
4166 @param PointerProgress Optional parameter, it can be NULL.
4167 When it is not NULL, if Request is NULL, it returns NULL.
4168 On return, points to a character in the Request
4169 string. Points to the string's null terminator if
4170 request was successful. Points to the most recent
4171 & before the first failing name / value pair (or
4172 the beginning of the string if the failure is in
4173 the first name / value pair) if the request was
4174 not successful.
4175 @retval EFI_SUCCESS The Results string is set to the full request string.
4176 And AltCfgResp contains all default value string.
4177 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4178 @retval EFI_NOT_FOUND The varstore (Guid and Name) in Request string
4179 can't be found in Form package.
4180 @retval EFI_NOT_FOUND HiiPackage can't be got on the input HiiHandle.
4181 @retval EFI_INVALID_PARAMETER Request points to NULL.
4182
4183 **/
4184 EFI_STATUS
4185 EFIAPI
4186 GetFullStringFromHiiFormPackages (
4187 IN HII_DATABASE_RECORD *DataBaseRecord,
4188 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
4189 IN OUT EFI_STRING *Request,
4190 IN OUT EFI_STRING *AltCfgResp,
4191 OUT EFI_STRING *PointerProgress OPTIONAL
4192 )
4193 {
4194 EFI_STATUS Status;
4195 UINT8 *HiiFormPackage;
4196 UINTN PackageSize;
4197 IFR_BLOCK_DATA *RequestBlockArray;
4198 IFR_BLOCK_DATA *BlockData;
4199 IFR_DEFAULT_DATA *DefaultValueData;
4200 IFR_DEFAULT_DATA *DefaultId;
4201 IFR_DEFAULT_DATA *DefaultIdArray;
4202 IFR_VARSTORAGE_DATA *VarStorageData;
4203 EFI_STRING DefaultAltCfgResp;
4204 EFI_STRING ConfigHdr;
4205 EFI_STRING StringPtr;
4206 EFI_STRING Progress;
4207
4208 if ((DataBaseRecord == NULL) || (DevicePath == NULL) || (Request == NULL) || (AltCfgResp == NULL)) {
4209 return EFI_INVALID_PARAMETER;
4210 }
4211
4212 //
4213 // Initialize the local variables.
4214 //
4215 RequestBlockArray = NULL;
4216 DefaultIdArray = NULL;
4217 VarStorageData = NULL;
4218 DefaultAltCfgResp = NULL;
4219 ConfigHdr = NULL;
4220 HiiFormPackage = NULL;
4221 PackageSize = 0;
4222 Progress = *Request;
4223
4224 Status = GetFormPackageData (DataBaseRecord, &HiiFormPackage, &PackageSize);
4225 if (EFI_ERROR (Status)) {
4226 goto Done;
4227 }
4228
4229 //
4230 // 1. Get the request block array by Request String when Request string contains the block array.
4231 //
4232 StringPtr = NULL;
4233 if (*Request != NULL) {
4234 StringPtr = *Request;
4235 //
4236 // Jump <ConfigHdr>
4237 //
4238 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4239 Status = EFI_INVALID_PARAMETER;
4240 goto Done;
4241 }
4242
4243 StringPtr += StrLen (L"GUID=");
4244 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
4245 StringPtr++;
4246 }
4247
4248 if (*StringPtr == L'\0') {
4249 Status = EFI_INVALID_PARAMETER;
4250 goto Done;
4251 }
4252
4253 StringPtr += StrLen (L"&NAME=");
4254 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
4255 StringPtr++;
4256 }
4257
4258 if (*StringPtr == L'\0') {
4259 Status = EFI_INVALID_PARAMETER;
4260 goto Done;
4261 }
4262
4263 StringPtr += StrLen (L"&PATH=");
4264 while (*StringPtr != L'\0' && *StringPtr != L'&') {
4265 StringPtr++;
4266 }
4267
4268 if (*StringPtr == L'\0') {
4269 //
4270 // No request block is found.
4271 //
4272 StringPtr = NULL;
4273 }
4274 }
4275
4276 //
4277 // If StringPtr != NULL, get the request elements.
4278 //
4279 if (StringPtr != NULL) {
4280 if (StrStr (StringPtr, L"&OFFSET=") != NULL) {
4281 RequestBlockArray = GetBlockElement (StringPtr, &Progress);
4282 } else {
4283 RequestBlockArray = GetNameElement (StringPtr, &Progress);
4284 }
4285
4286 if (RequestBlockArray == NULL) {
4287 Status = EFI_INVALID_PARAMETER;
4288 goto Done;
4289 }
4290 }
4291
4292 //
4293 // Initialize DefaultIdArray to store the map between DeaultId and DefaultName
4294 //
4295 DefaultIdArray = (IFR_DEFAULT_DATA *)AllocateZeroPool (sizeof (IFR_DEFAULT_DATA));
4296 if (DefaultIdArray == NULL) {
4297 Status = EFI_OUT_OF_RESOURCES;
4298 goto Done;
4299 }
4300
4301 InitializeListHead (&DefaultIdArray->Entry);
4302
4303 //
4304 // Initialize VarStorageData to store the var store Block and Default value information.
4305 //
4306 VarStorageData = (IFR_VARSTORAGE_DATA *)AllocateZeroPool (sizeof (IFR_VARSTORAGE_DATA));
4307 if (VarStorageData == NULL) {
4308 Status = EFI_OUT_OF_RESOURCES;
4309 goto Done;
4310 }
4311
4312 InitializeListHead (&VarStorageData->Entry);
4313 InitializeListHead (&VarStorageData->BlockEntry);
4314
4315 //
4316 // 2. Parse FormPackage to get BlockArray and DefaultId Array for the request BlockArray.
4317 //
4318
4319 //
4320 // Parse the opcode in form package to get the default setting.
4321 //
4322 Status = ParseIfrData (
4323 DataBaseRecord->Handle,
4324 HiiFormPackage,
4325 (UINT32)PackageSize,
4326 *Request,
4327 RequestBlockArray,
4328 VarStorageData,
4329 DefaultIdArray
4330 );
4331 if (EFI_ERROR (Status)) {
4332 goto Done;
4333 }
4334
4335 //
4336 // No requested varstore in IFR data and directly return
4337 //
4338 if ((VarStorageData->Type == 0) && (VarStorageData->Name == NULL)) {
4339 Status = EFI_SUCCESS;
4340 goto Done;
4341 }
4342
4343 //
4344 // 3. Construct Request Element (Block Name) for 2.1 and 2.2 case.
4345 //
4346 Status = GenerateHdr (VarStorageData, DevicePath, &ConfigHdr);
4347 if (EFI_ERROR (Status)) {
4348 goto Done;
4349 }
4350
4351 if (RequestBlockArray == NULL) {
4352 if (!GenerateConfigRequest (ConfigHdr, VarStorageData, &Status, Request)) {
4353 goto Done;
4354 }
4355 }
4356
4357 //
4358 // 4. Construct Default Value string in AltResp according to request element.
4359 // Go through all VarStorageData Entry and get the DefaultId array for each one
4360 // Then construct them all to : ConfigHdr AltConfigHdr ConfigBody AltConfigHdr ConfigBody
4361 //
4362 Status = GenerateAltConfigResp (DataBaseRecord->Handle, ConfigHdr, VarStorageData, DefaultIdArray, &DefaultAltCfgResp);
4363 if (EFI_ERROR (Status)) {
4364 goto Done;
4365 }
4366
4367 //
4368 // 5. Merge string into the input AltCfgResp if the input *AltCfgResp is not NULL.
4369 //
4370 if ((*AltCfgResp != NULL) && (DefaultAltCfgResp != NULL)) {
4371 Status = MergeDefaultString (AltCfgResp, DefaultAltCfgResp);
4372 FreePool (DefaultAltCfgResp);
4373 } else if (*AltCfgResp == NULL) {
4374 *AltCfgResp = DefaultAltCfgResp;
4375 }
4376
4377 Done:
4378 if (RequestBlockArray != NULL) {
4379 //
4380 // Free Link Array RequestBlockArray
4381 //
4382 while (!IsListEmpty (&RequestBlockArray->Entry)) {
4383 BlockData = BASE_CR (RequestBlockArray->Entry.ForwardLink, IFR_BLOCK_DATA, Entry);
4384 RemoveEntryList (&BlockData->Entry);
4385 if (BlockData->Name != NULL) {
4386 FreePool (BlockData->Name);
4387 }
4388
4389 FreePool (BlockData);
4390 }
4391
4392 FreePool (RequestBlockArray);
4393 }
4394
4395 if (VarStorageData != NULL) {
4396 //
4397 // Free link array VarStorageData
4398 //
4399 while (!IsListEmpty (&VarStorageData->BlockEntry)) {
4400 BlockData = BASE_CR (VarStorageData->BlockEntry.ForwardLink, IFR_BLOCK_DATA, Entry);
4401 RemoveEntryList (&BlockData->Entry);
4402 if (BlockData->Name != NULL) {
4403 FreePool (BlockData->Name);
4404 }
4405
4406 //
4407 // Free default value link array
4408 //
4409 while (!IsListEmpty (&BlockData->DefaultValueEntry)) {
4410 DefaultValueData = BASE_CR (BlockData->DefaultValueEntry.ForwardLink, IFR_DEFAULT_DATA, Entry);
4411 RemoveEntryList (&DefaultValueData->Entry);
4412 FreePool (DefaultValueData);
4413 }
4414
4415 FreePool (BlockData);
4416 }
4417
4418 if (VarStorageData->Name != NULL) {
4419 FreePool (VarStorageData->Name);
4420 VarStorageData->Name = NULL;
4421 }
4422
4423 FreePool (VarStorageData);
4424 }
4425
4426 if (DefaultIdArray != NULL) {
4427 //
4428 // Free DefaultId Array
4429 //
4430 while (!IsListEmpty (&DefaultIdArray->Entry)) {
4431 DefaultId = BASE_CR (DefaultIdArray->Entry.ForwardLink, IFR_DEFAULT_DATA, Entry);
4432 RemoveEntryList (&DefaultId->Entry);
4433 FreePool (DefaultId);
4434 }
4435
4436 FreePool (DefaultIdArray);
4437 }
4438
4439 //
4440 // Free the allocated string
4441 //
4442 if (ConfigHdr != NULL) {
4443 FreePool (ConfigHdr);
4444 }
4445
4446 //
4447 // Free Package data
4448 //
4449 if (HiiFormPackage != NULL) {
4450 FreePool (HiiFormPackage);
4451 }
4452
4453 if (PointerProgress != NULL) {
4454 if (*Request == NULL) {
4455 *PointerProgress = NULL;
4456 } else if (EFI_ERROR (Status)) {
4457 *PointerProgress = *Request;
4458 } else {
4459 *PointerProgress = *Request + StrLen (*Request);
4460 }
4461 }
4462
4463 return Status;
4464 }
4465
4466 /**
4467 This function gets the full request resp string by
4468 parsing IFR data in HII form packages.
4469
4470 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4471 instance.
4472 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
4473 varstore data structure.
4474 @param Request Pointer to a null-terminated Unicode string in
4475 <ConfigRequest> format.
4476 @param RequestResp Pointer to a null-terminated Unicode string in
4477 <ConfigResp> format.
4478 @param AccessProgress On return, points to a character in the Request
4479 string. Points to the string's null terminator if
4480 request was successful. Points to the most recent
4481 & before the first failing name / value pair (or
4482 the beginning of the string if the failure is in
4483 the first name / value pair) if the request was
4484 not successful.
4485
4486 @retval EFI_SUCCESS The Results string is set to the full request string.
4487 And AltCfgResp contains all default value string.
4488 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4489 @retval EFI_INVALID_PARAMETER Request points to NULL.
4490
4491 **/
4492 EFI_STATUS
4493 GetConfigRespFromEfiVarStore (
4494 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4495 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
4496 IN EFI_STRING Request,
4497 OUT EFI_STRING *RequestResp,
4498 OUT EFI_STRING *AccessProgress
4499 )
4500 {
4501 EFI_STATUS Status;
4502 EFI_STRING VarStoreName;
4503 UINTN NameSize;
4504 UINT8 *VarStore;
4505 UINTN BufferSize;
4506
4507 Status = EFI_SUCCESS;
4508 BufferSize = 0;
4509 VarStore = NULL;
4510 VarStoreName = NULL;
4511 *AccessProgress = Request;
4512
4513 NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
4514 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
4515 if (VarStoreName == NULL) {
4516 Status = EFI_OUT_OF_RESOURCES;
4517 goto Done;
4518 }
4519
4520 AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize);
4521
4522 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
4523 if (Status != EFI_BUFFER_TOO_SMALL) {
4524 goto Done;
4525 }
4526
4527 VarStore = AllocateZeroPool (BufferSize);
4528 ASSERT (VarStore != NULL);
4529 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
4530 if (EFI_ERROR (Status)) {
4531 goto Done;
4532 }
4533
4534 Status = HiiBlockToConfig (This, Request, VarStore, BufferSize, RequestResp, AccessProgress);
4535 if (EFI_ERROR (Status)) {
4536 goto Done;
4537 }
4538
4539 Done:
4540 if (VarStoreName != NULL) {
4541 FreePool (VarStoreName);
4542 }
4543
4544 if (VarStore != NULL) {
4545 FreePool (VarStore);
4546 }
4547
4548 return Status;
4549 }
4550
4551 /**
4552 This function route the full request resp string for efi varstore.
4553
4554 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4555 instance.
4556 @param EfiVarStoreInfo The efi varstore info which is save in the EFI
4557 varstore data structure.
4558 @param RequestResp Pointer to a null-terminated Unicode string in
4559 <ConfigResp> format.
4560 @param Result Pointer to a null-terminated Unicode string in
4561 <ConfigResp> format.
4562
4563 @retval EFI_SUCCESS The Results string is set to the full request string.
4564 And AltCfgResp contains all default value string.
4565 @retval EFI_OUT_OF_RESOURCES Not enough memory for the return string.
4566 @retval EFI_INVALID_PARAMETER Request points to NULL.
4567
4568 **/
4569 EFI_STATUS
4570 RouteConfigRespForEfiVarStore (
4571 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4572 IN EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo,
4573 IN EFI_STRING RequestResp,
4574 OUT EFI_STRING *Result
4575 )
4576 {
4577 EFI_STATUS Status;
4578 EFI_STRING VarStoreName;
4579 UINTN NameSize;
4580 UINT8 *VarStore;
4581 UINTN BufferSize;
4582 UINTN BlockSize;
4583
4584 Status = EFI_SUCCESS;
4585 BufferSize = 0;
4586 VarStore = NULL;
4587 VarStoreName = NULL;
4588 *Result = RequestResp;
4589
4590 NameSize = AsciiStrSize ((CHAR8 *)EfiVarStoreInfo->Name);
4591 VarStoreName = AllocateZeroPool (NameSize * sizeof (CHAR16));
4592 if (VarStoreName == NULL) {
4593 Status = EFI_OUT_OF_RESOURCES;
4594 goto Done;
4595 }
4596
4597 AsciiStrToUnicodeStrS ((CHAR8 *)EfiVarStoreInfo->Name, VarStoreName, NameSize);
4598
4599 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, NULL);
4600 if (Status != EFI_BUFFER_TOO_SMALL) {
4601 DEBUG ((DEBUG_ERROR, "The variable does not exist!"));
4602 goto Done;
4603 }
4604
4605 BlockSize = BufferSize;
4606 VarStore = AllocateZeroPool (BufferSize);
4607 ASSERT (VarStore != NULL);
4608 Status = gRT->GetVariable (VarStoreName, &EfiVarStoreInfo->Guid, NULL, &BufferSize, VarStore);
4609 if (EFI_ERROR (Status)) {
4610 goto Done;
4611 }
4612
4613 Status = HiiConfigToBlock (This, RequestResp, VarStore, &BlockSize, Result);
4614 if (EFI_ERROR (Status)) {
4615 goto Done;
4616 }
4617
4618 Status = gRT->SetVariable (VarStoreName, &EfiVarStoreInfo->Guid, EfiVarStoreInfo->Attributes, BufferSize, VarStore);
4619 if (EFI_ERROR (Status)) {
4620 *Result = RequestResp;
4621 goto Done;
4622 }
4623
4624 Done:
4625 if (VarStoreName != NULL) {
4626 FreePool (VarStoreName);
4627 }
4628
4629 if (VarStore != NULL) {
4630 FreePool (VarStore);
4631 }
4632
4633 return Status;
4634 }
4635
4636 /**
4637 Validate the config request elements.
4638
4639 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
4640 without configHdr field.
4641
4642 @retval CHAR16 * THE first Name/value pair not correct.
4643 @retval NULL Success parse the name/value pair
4644 **/
4645 CHAR16 *
4646 OffsetWidthValidate (
4647 CHAR16 *ConfigElements
4648 )
4649 {
4650 CHAR16 *StringPtr;
4651 CHAR16 *RetVal;
4652
4653 StringPtr = ConfigElements;
4654
4655 while (1) {
4656 RetVal = StringPtr;
4657 if (StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
4658 return RetVal;
4659 }
4660
4661 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
4662 StringPtr++;
4663 }
4664
4665 if (*StringPtr == L'\0') {
4666 return RetVal;
4667 }
4668
4669 StringPtr += StrLen (L"&WIDTH=");
4670 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) != 0) {
4671 StringPtr++;
4672 }
4673
4674 if (*StringPtr == L'\0') {
4675 return NULL;
4676 }
4677 }
4678 }
4679
4680 /**
4681 Validate the config request elements.
4682
4683 @param ConfigElements A null-terminated Unicode string in <ConfigRequest> format,
4684 without configHdr field.
4685
4686 @retval CHAR16 * THE first Name/value pair not correct.
4687 @retval NULL Success parse the name/value pair
4688
4689 **/
4690 CHAR16 *
4691 NameValueValidate (
4692 CHAR16 *ConfigElements
4693 )
4694 {
4695 CHAR16 *StringPtr;
4696 CHAR16 *RetVal;
4697
4698 StringPtr = ConfigElements;
4699
4700 while (1) {
4701 RetVal = StringPtr;
4702 if (*StringPtr != L'&') {
4703 return RetVal;
4704 }
4705
4706 StringPtr += 1;
4707
4708 StringPtr = StrStr (StringPtr, L"&");
4709
4710 if (StringPtr == NULL) {
4711 return NULL;
4712 }
4713 }
4714 }
4715
4716 /**
4717 Validate the config request string.
4718
4719 @param ConfigRequest A null-terminated Unicode string in <ConfigRequest> format.
4720
4721 @retval CHAR16 * THE first element not correct.
4722 @retval NULL Success parse the name/value pair
4723
4724 **/
4725 CHAR16 *
4726 ConfigRequestValidate (
4727 CHAR16 *ConfigRequest
4728 )
4729 {
4730 BOOLEAN HasNameField;
4731 CHAR16 *StringPtr;
4732
4733 HasNameField = TRUE;
4734 StringPtr = ConfigRequest;
4735
4736 //
4737 // Check <ConfigHdr>
4738 //
4739 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4740 return ConfigRequest;
4741 }
4742
4743 StringPtr += StrLen (L"GUID=");
4744 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&NAME=", StrLen (L"&NAME=")) != 0) {
4745 StringPtr++;
4746 }
4747
4748 if (*StringPtr == L'\0') {
4749 return ConfigRequest;
4750 }
4751
4752 StringPtr += StrLen (L"&NAME=");
4753 if (*StringPtr == L'&') {
4754 HasNameField = FALSE;
4755 }
4756
4757 while (*StringPtr != L'\0' && StrnCmp (StringPtr, L"&PATH=", StrLen (L"&PATH=")) != 0) {
4758 StringPtr++;
4759 }
4760
4761 if (*StringPtr == L'\0') {
4762 return ConfigRequest;
4763 }
4764
4765 StringPtr += StrLen (L"&PATH=");
4766 while (*StringPtr != L'\0' && *StringPtr != L'&') {
4767 StringPtr++;
4768 }
4769
4770 if (*StringPtr == L'\0') {
4771 return NULL;
4772 }
4773
4774 if (HasNameField) {
4775 //
4776 // Should be Buffer varstore, config request should be "OFFSET/Width" pairs.
4777 //
4778 return OffsetWidthValidate (StringPtr);
4779 } else {
4780 //
4781 // Should be Name/Value varstore, config request should be "&name1&name2..." pairs.
4782 //
4783 return NameValueValidate (StringPtr);
4784 }
4785 }
4786
4787 /**
4788 This function allows a caller to extract the current configuration
4789 for one or more named elements from one or more drivers.
4790
4791 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
4792 instance.
4793 @param Request A null-terminated Unicode string in
4794 <MultiConfigRequest> format.
4795 @param Progress On return, points to a character in the Request
4796 string. Points to the string's null terminator if
4797 request was successful. Points to the most recent
4798 & before the first failing name / value pair (or
4799 the beginning of the string if the failure is in
4800 the first name / value pair) if the request was
4801 not successful.
4802 @param Results Null-terminated Unicode string in
4803 <MultiConfigAltResp> format which has all values
4804 filled in for the names in the Request string.
4805 String to be allocated by the called function.
4806
4807 @retval EFI_SUCCESS The Results string is filled with the values
4808 corresponding to all requested names.
4809 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
4810 results that must be stored awaiting possible
4811 future protocols.
4812 @retval EFI_NOT_FOUND Routing data doesn't match any known driver.
4813 Progress set to the "G" in "GUID" of the routing
4814 header that doesn't match. Note: There is no
4815 requirement that all routing data be validated
4816 before any configuration extraction.
4817 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Request
4818 parameter would result in this type of error. The
4819 Progress parameter is set to NULL.
4820 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent &
4821 before the error or the beginning of the string.
4822 @retval EFI_INVALID_PARAMETER The ExtractConfig function of the underlying HII
4823 Configuration Access Protocol returned
4824 EFI_INVALID_PARAMETER. Progress set to most recent
4825 & before the error or the beginning of the string.
4826
4827 **/
4828 EFI_STATUS
4829 EFIAPI
4830 HiiConfigRoutingExtractConfig (
4831 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
4832 IN CONST EFI_STRING Request,
4833 OUT EFI_STRING *Progress,
4834 OUT EFI_STRING *Results
4835 )
4836 {
4837 HII_DATABASE_PRIVATE_DATA *Private;
4838 EFI_STRING StringPtr;
4839 EFI_STRING ConfigRequest;
4840 UINTN Length;
4841 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
4842 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
4843 EFI_STATUS Status;
4844 LIST_ENTRY *Link;
4845 HII_DATABASE_RECORD *Database;
4846 UINT8 *DevicePathPkg;
4847 UINT8 *CurrentDevicePath;
4848 EFI_HANDLE DriverHandle;
4849 EFI_HII_HANDLE HiiHandle;
4850 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
4851 EFI_STRING AccessProgress;
4852 EFI_STRING AccessResults;
4853 EFI_STRING AccessProgressBackup;
4854 EFI_STRING AccessResultsBackup;
4855 EFI_STRING DefaultResults;
4856 BOOLEAN FirstElement;
4857 BOOLEAN IfrDataParsedFlag;
4858 BOOLEAN IsEfiVarStore;
4859 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
4860 EFI_STRING ErrorPtr;
4861 UINTN DevicePathSize;
4862 UINTN ConigStringSize;
4863 UINTN ConigStringSizeNewsize;
4864 EFI_STRING ConfigStringPtr;
4865
4866 if ((This == NULL) || (Progress == NULL) || (Results == NULL)) {
4867 return EFI_INVALID_PARAMETER;
4868 }
4869
4870 if (Request == NULL) {
4871 *Progress = NULL;
4872 return EFI_INVALID_PARAMETER;
4873 }
4874
4875 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
4876 StringPtr = Request;
4877 *Progress = StringPtr;
4878 DefaultResults = NULL;
4879 ConfigRequest = NULL;
4880 Status = EFI_SUCCESS;
4881 AccessResults = NULL;
4882 AccessProgress = NULL;
4883 AccessResultsBackup = NULL;
4884 AccessProgressBackup = NULL;
4885 DevicePath = NULL;
4886 IfrDataParsedFlag = FALSE;
4887 IsEfiVarStore = FALSE;
4888 EfiVarStoreInfo = NULL;
4889
4890 //
4891 // The first element of <MultiConfigRequest> should be
4892 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
4893 //
4894 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
4895 return EFI_INVALID_PARAMETER;
4896 }
4897
4898 FirstElement = TRUE;
4899
4900 //
4901 // Allocate a fix length of memory to store Results. Reallocate memory for
4902 // Results if this fix length is insufficient.
4903 //
4904 *Results = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
4905 if (*Results == NULL) {
4906 return EFI_OUT_OF_RESOURCES;
4907 }
4908
4909 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
4910 //
4911 // If parsing error, set Progress to the beginning of the <MultiConfigRequest>
4912 // or most recent & before the error.
4913 //
4914 if (StringPtr == Request) {
4915 *Progress = StringPtr;
4916 } else {
4917 *Progress = StringPtr - 1;
4918 }
4919
4920 //
4921 // Process each <ConfigRequest> of <MultiConfigRequest>
4922 //
4923 Length = CalculateConfigStringLen (StringPtr);
4924 ConfigRequest = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
4925 if (ConfigRequest == NULL) {
4926 Status = EFI_OUT_OF_RESOURCES;
4927 goto Done;
4928 }
4929
4930 *(ConfigRequest + Length) = 0;
4931
4932 //
4933 // Get the UEFI device path
4934 //
4935 Status = GetDevicePath (ConfigRequest, (UINT8 **)&DevicePath);
4936 if (EFI_ERROR (Status)) {
4937 goto Done;
4938 }
4939
4940 //
4941 // Find driver which matches the routing data.
4942 //
4943 DriverHandle = NULL;
4944 HiiHandle = NULL;
4945 Database = NULL;
4946 for (Link = Private->DatabaseList.ForwardLink;
4947 Link != &Private->DatabaseList;
4948 Link = Link->ForwardLink
4949 )
4950 {
4951 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
4952 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
4953 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
4954 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath);
4955 if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigRequest)) {
4956 DriverHandle = Database->DriverHandle;
4957 HiiHandle = Database->Handle;
4958 break;
4959 }
4960 }
4961 }
4962
4963 //
4964 // Try to find driver handle by device path.
4965 //
4966 if (DriverHandle == NULL) {
4967 TempDevicePath = DevicePath;
4968 Status = gBS->LocateDevicePath (
4969 &gEfiDevicePathProtocolGuid,
4970 &TempDevicePath,
4971 &DriverHandle
4972 );
4973 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
4974 //
4975 // Routing data does not match any known driver.
4976 // Set Progress to the 'G' in "GUID" of the routing header.
4977 //
4978 *Progress = StringPtr;
4979 Status = EFI_NOT_FOUND;
4980 goto Done;
4981 }
4982 }
4983
4984 //
4985 // Validate ConfigRequest String.
4986 //
4987 ErrorPtr = ConfigRequestValidate (ConfigRequest);
4988 if (ErrorPtr != NULL) {
4989 *Progress = StrStr (StringPtr, ErrorPtr);
4990 Status = EFI_INVALID_PARAMETER;
4991 goto Done;
4992 }
4993
4994 //
4995 // Check whether ConfigRequest contains request string.
4996 //
4997 IfrDataParsedFlag = FALSE;
4998 if ((HiiHandle != NULL) && !GetElementsFromRequest (ConfigRequest)) {
4999 //
5000 // Get the full request string from IFR when HiiPackage is registered to HiiHandle
5001 //
5002 IfrDataParsedFlag = TRUE;
5003 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, &AccessProgress);
5004 if (EFI_ERROR (Status)) {
5005 //
5006 // AccessProgress indicates the parsing progress on <ConfigRequest>.
5007 // Map it to the progress on <MultiConfigRequest> then return it.
5008 //
5009 ASSERT (AccessProgress != NULL);
5010 *Progress = StrStr (StringPtr, AccessProgress);
5011 goto Done;
5012 }
5013
5014 //
5015 // Not any request block is found.
5016 //
5017 if (!GetElementsFromRequest (ConfigRequest)) {
5018 AccessResults = AllocateCopyPool (StrSize (ConfigRequest), ConfigRequest);
5019 goto NextConfigString;
5020 }
5021 }
5022
5023 //
5024 // Check whether this ConfigRequest is search from Efi varstore type storage.
5025 //
5026 Status = GetVarStoreType (Database, ConfigRequest, &IsEfiVarStore, &EfiVarStoreInfo);
5027 if (EFI_ERROR (Status)) {
5028 goto Done;
5029 }
5030
5031 if (IsEfiVarStore) {
5032 //
5033 // Call the GetVariable function to extract settings.
5034 //
5035 Status = GetConfigRespFromEfiVarStore (This, EfiVarStoreInfo, ConfigRequest, &AccessResults, &AccessProgress);
5036 FreePool (EfiVarStoreInfo);
5037 if (EFI_ERROR (Status)) {
5038 //
5039 // AccessProgress indicates the parsing progress on <ConfigRequest>.
5040 // Map it to the progress on <MultiConfigRequest> then return it.
5041 //
5042 *Progress = StrStr (StringPtr, AccessProgress);
5043 goto Done;
5044 }
5045
5046 //
5047 // For EfiVarstore, call corresponding ConfigAccess protocol to get the AltCfgResp from driver.
5048 //
5049 Status = gBS->HandleProtocol (
5050 DriverHandle,
5051 &gEfiHiiConfigAccessProtocolGuid,
5052 (VOID **)&ConfigAccess
5053 );
5054 if (EFI_ERROR (Status)) {
5055 //
5056 // The driver has EfiVarStore, may not install ConfigAccess protocol.
5057 // So ignore the error status in this case.
5058 //
5059 Status = EFI_SUCCESS;
5060 } else {
5061 Status = ConfigAccess->ExtractConfig (
5062 ConfigAccess,
5063 ConfigRequest,
5064 &AccessProgressBackup,
5065 &AccessResultsBackup
5066 );
5067 if (!EFI_ERROR (Status)) {
5068 //
5069 // Merge the AltCfgResp in AccessResultsBackup to AccessResults
5070 //
5071 if ((AccessResultsBackup != NULL) && (StrStr (AccessResultsBackup, L"&ALTCFG=") != NULL)) {
5072 ConigStringSize = StrSize (AccessResults);
5073 ConfigStringPtr = StrStr (AccessResultsBackup, L"&GUID=");
5074 ConigStringSizeNewsize = StrSize (ConfigStringPtr) + ConigStringSize + sizeof (CHAR16);
5075 AccessResults = (EFI_STRING)ReallocatePool (
5076 ConigStringSize,
5077 ConigStringSizeNewsize,
5078 AccessResults
5079 );
5080 StrCatS (AccessResults, ConigStringSizeNewsize / sizeof (CHAR16), ConfigStringPtr);
5081 }
5082 } else {
5083 //
5084 // In the ExtractConfig function of some driver may not support EfiVarStore,
5085 // may return error status, just ignore the error status in this case.
5086 //
5087 Status = EFI_SUCCESS;
5088 }
5089
5090 if (AccessResultsBackup != NULL) {
5091 FreePool (AccessResultsBackup);
5092 AccessResultsBackup = NULL;
5093 }
5094 }
5095 } else {
5096 //
5097 // Call corresponding ConfigAccess protocol to extract settings
5098 //
5099 Status = gBS->HandleProtocol (
5100 DriverHandle,
5101 &gEfiHiiConfigAccessProtocolGuid,
5102 (VOID **)&ConfigAccess
5103 );
5104 if (EFI_ERROR (Status)) {
5105 goto Done;
5106 }
5107
5108 Status = ConfigAccess->ExtractConfig (
5109 ConfigAccess,
5110 ConfigRequest,
5111 &AccessProgress,
5112 &AccessResults
5113 );
5114 }
5115
5116 if (EFI_ERROR (Status)) {
5117 //
5118 // AccessProgress indicates the parsing progress on <ConfigRequest>.
5119 // Map it to the progress on <MultiConfigRequest> then return it.
5120 //
5121 *Progress = StrStr (StringPtr, AccessProgress);
5122 goto Done;
5123 }
5124
5125 //
5126 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
5127 // which separates the first <ConfigAltResp> and the following ones.
5128 //
5129 ASSERT (*AccessProgress == 0);
5130
5131 //
5132 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
5133 //
5134 if (!IfrDataParsedFlag && (HiiHandle != NULL)) {
5135 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
5136 ASSERT_EFI_ERROR (Status);
5137 }
5138
5139 FreePool (DevicePath);
5140 DevicePath = NULL;
5141
5142 if (DefaultResults != NULL) {
5143 Status = MergeDefaultString (&AccessResults, DefaultResults);
5144 ASSERT_EFI_ERROR (Status);
5145 FreePool (DefaultResults);
5146 DefaultResults = NULL;
5147 }
5148
5149 NextConfigString:
5150 if (!FirstElement) {
5151 Status = AppendToMultiString (Results, L"&");
5152 ASSERT_EFI_ERROR (Status);
5153 }
5154
5155 Status = AppendToMultiString (Results, AccessResults);
5156 ASSERT_EFI_ERROR (Status);
5157
5158 FirstElement = FALSE;
5159
5160 FreePool (AccessResults);
5161 AccessResults = NULL;
5162 FreePool (ConfigRequest);
5163 ConfigRequest = NULL;
5164
5165 //
5166 // Go to next <ConfigRequest> (skip '&').
5167 //
5168 StringPtr += Length;
5169 if (*StringPtr == 0) {
5170 *Progress = StringPtr;
5171 break;
5172 }
5173
5174 StringPtr++;
5175 }
5176
5177 Done:
5178 if (EFI_ERROR (Status)) {
5179 FreePool (*Results);
5180 *Results = NULL;
5181 }
5182
5183 if (ConfigRequest != NULL) {
5184 FreePool (ConfigRequest);
5185 }
5186
5187 if (AccessResults != NULL) {
5188 FreePool (AccessResults);
5189 }
5190
5191 if (DefaultResults != NULL) {
5192 FreePool (DefaultResults);
5193 }
5194
5195 if (DevicePath != NULL) {
5196 FreePool (DevicePath);
5197 }
5198
5199 return Status;
5200 }
5201
5202 /**
5203 This function allows the caller to request the current configuration for the
5204 entirety of the current HII database and returns the data in a
5205 null-terminated Unicode string.
5206
5207 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5208 instance.
5209 @param Results Null-terminated Unicode string in
5210 <MultiConfigAltResp> format which has all values
5211 filled in for the entirety of the current HII
5212 database. String to be allocated by the called
5213 function. De-allocation is up to the caller.
5214
5215 @retval EFI_SUCCESS The Results string is filled with the values
5216 corresponding to all requested names.
5217 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
5218 results that must be stored awaiting possible
5219 future protocols.
5220 @retval EFI_INVALID_PARAMETER For example, passing in a NULL for the Results
5221 parameter would result in this type of error.
5222
5223 **/
5224 EFI_STATUS
5225 EFIAPI
5226 HiiConfigRoutingExportConfig (
5227 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5228 OUT EFI_STRING *Results
5229 )
5230 {
5231 EFI_STATUS Status;
5232 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5233 EFI_STRING AccessResults;
5234 EFI_STRING Progress;
5235 EFI_STRING StringPtr;
5236 EFI_STRING ConfigRequest;
5237 UINTN Index;
5238 EFI_HANDLE *ConfigAccessHandles;
5239 UINTN NumberConfigAccessHandles;
5240 BOOLEAN FirstElement;
5241 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
5242 EFI_HII_HANDLE HiiHandle;
5243 EFI_STRING DefaultResults;
5244 HII_DATABASE_PRIVATE_DATA *Private;
5245 LIST_ENTRY *Link;
5246 HII_DATABASE_RECORD *Database;
5247 UINT8 *DevicePathPkg;
5248 UINT8 *CurrentDevicePath;
5249 BOOLEAN IfrDataParsedFlag;
5250
5251 if ((This == NULL) || (Results == NULL)) {
5252 return EFI_INVALID_PARAMETER;
5253 }
5254
5255 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5256
5257 //
5258 // Allocate a fix length of memory to store Results. Reallocate memory for
5259 // Results if this fix length is insufficient.
5260 //
5261 *Results = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
5262 if (*Results == NULL) {
5263 return EFI_OUT_OF_RESOURCES;
5264 }
5265
5266 NumberConfigAccessHandles = 0;
5267 Status = gBS->LocateHandleBuffer (
5268 ByProtocol,
5269 &gEfiHiiConfigAccessProtocolGuid,
5270 NULL,
5271 &NumberConfigAccessHandles,
5272 &ConfigAccessHandles
5273 );
5274 if (EFI_ERROR (Status)) {
5275 return Status;
5276 }
5277
5278 FirstElement = TRUE;
5279
5280 for (Index = 0; Index < NumberConfigAccessHandles; Index++) {
5281 Status = gBS->HandleProtocol (
5282 ConfigAccessHandles[Index],
5283 &gEfiHiiConfigAccessProtocolGuid,
5284 (VOID **)&ConfigAccess
5285 );
5286 if (EFI_ERROR (Status)) {
5287 continue;
5288 }
5289
5290 //
5291 // Get DevicePath and HiiHandle for this ConfigAccess driver handle
5292 //
5293 IfrDataParsedFlag = FALSE;
5294 Progress = NULL;
5295 HiiHandle = NULL;
5296 DefaultResults = NULL;
5297 Database = NULL;
5298 ConfigRequest = NULL;
5299 DevicePath = DevicePathFromHandle (ConfigAccessHandles[Index]);
5300 if (DevicePath != NULL) {
5301 for (Link = Private->DatabaseList.ForwardLink;
5302 Link != &Private->DatabaseList;
5303 Link = Link->ForwardLink
5304 )
5305 {
5306 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
5307 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
5308 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
5309 if (CompareMem (
5310 DevicePath,
5311 CurrentDevicePath,
5312 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath)
5313 ) == 0)
5314 {
5315 HiiHandle = Database->Handle;
5316 break;
5317 }
5318 }
5319 }
5320 }
5321
5322 Status = ConfigAccess->ExtractConfig (
5323 ConfigAccess,
5324 NULL,
5325 &Progress,
5326 &AccessResults
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 ((HiiHandle != NULL) && (DevicePath != NULL)) {
5333 IfrDataParsedFlag = TRUE;
5334 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &ConfigRequest, &DefaultResults, NULL);
5335 //
5336 // Get the full request string to get the Current setting again.
5337 //
5338 if (!EFI_ERROR (Status) && (ConfigRequest != NULL)) {
5339 Status = ConfigAccess->ExtractConfig (
5340 ConfigAccess,
5341 ConfigRequest,
5342 &Progress,
5343 &AccessResults
5344 );
5345 FreePool (ConfigRequest);
5346 } else {
5347 Status = EFI_NOT_FOUND;
5348 }
5349 }
5350 }
5351
5352 if (!EFI_ERROR (Status)) {
5353 //
5354 // Update AccessResults by getting default setting from IFR when HiiPackage is registered to HiiHandle
5355 //
5356 if (!IfrDataParsedFlag && (HiiHandle != NULL) && (DevicePath != NULL)) {
5357 StringPtr = StrStr (AccessResults, L"&GUID=");
5358 if (StringPtr != NULL) {
5359 *StringPtr = 0;
5360 }
5361
5362 if (GetElementsFromRequest (AccessResults)) {
5363 Status = GetFullStringFromHiiFormPackages (Database, DevicePath, &AccessResults, &DefaultResults, NULL);
5364 ASSERT_EFI_ERROR (Status);
5365 }
5366
5367 if (StringPtr != NULL) {
5368 *StringPtr = L'&';
5369 }
5370 }
5371
5372 //
5373 // Merge the default sting from IFR code into the got setting from driver.
5374 //
5375 if (DefaultResults != NULL) {
5376 Status = MergeDefaultString (&AccessResults, DefaultResults);
5377 ASSERT_EFI_ERROR (Status);
5378 FreePool (DefaultResults);
5379 DefaultResults = NULL;
5380 }
5381
5382 //
5383 // Attach this <ConfigAltResp> to a <MultiConfigAltResp>. There is a '&'
5384 // which separates the first <ConfigAltResp> and the following ones.
5385 //
5386 if (!FirstElement) {
5387 Status = AppendToMultiString (Results, L"&");
5388 ASSERT_EFI_ERROR (Status);
5389 }
5390
5391 Status = AppendToMultiString (Results, AccessResults);
5392 ASSERT_EFI_ERROR (Status);
5393
5394 FirstElement = FALSE;
5395
5396 FreePool (AccessResults);
5397 AccessResults = NULL;
5398 }
5399 }
5400
5401 FreePool (ConfigAccessHandles);
5402
5403 return EFI_SUCCESS;
5404 }
5405
5406 /**
5407 This function processes the results of processing forms and routes it to the
5408 appropriate handlers or storage.
5409
5410 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5411 instance.
5412 @param Configuration A null-terminated Unicode string in
5413 <MulltiConfigResp> format.
5414 @param Progress A pointer to a string filled in with the offset of
5415 the most recent & before the first failing name /
5416 value pair (or the beginning of the string if the
5417 failure is in the first name / value pair) or the
5418 terminating NULL if all was successful.
5419
5420 @retval EFI_SUCCESS The results have been distributed or are awaiting
5421 distribution.
5422 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the
5423 results that must be stored awaiting possible
5424 future protocols.
5425 @retval EFI_INVALID_PARAMETER Passing in a NULL for the Configuration parameter
5426 would result in this type of error.
5427 @retval EFI_NOT_FOUND Target for the specified routing data was not
5428 found.
5429
5430 **/
5431 EFI_STATUS
5432 EFIAPI
5433 HiiConfigRoutingRouteConfig (
5434 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5435 IN CONST EFI_STRING Configuration,
5436 OUT EFI_STRING *Progress
5437 )
5438 {
5439 HII_DATABASE_PRIVATE_DATA *Private;
5440 EFI_STRING StringPtr;
5441 EFI_STRING ConfigResp;
5442 UINTN Length;
5443 EFI_STATUS Status;
5444 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
5445 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
5446 LIST_ENTRY *Link;
5447 HII_DATABASE_RECORD *Database;
5448 UINT8 *DevicePathPkg;
5449 UINT8 *CurrentDevicePath;
5450 EFI_HANDLE DriverHandle;
5451 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5452 EFI_STRING AccessProgress;
5453 EFI_IFR_VARSTORE_EFI *EfiVarStoreInfo;
5454 BOOLEAN IsEfiVarstore;
5455 UINTN DevicePathSize;
5456
5457 if ((This == NULL) || (Progress == NULL)) {
5458 return EFI_INVALID_PARAMETER;
5459 }
5460
5461 if (Configuration == NULL) {
5462 *Progress = NULL;
5463 return EFI_INVALID_PARAMETER;
5464 }
5465
5466 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5467 StringPtr = Configuration;
5468 *Progress = StringPtr;
5469 Database = NULL;
5470 AccessProgress = NULL;
5471 EfiVarStoreInfo = NULL;
5472 IsEfiVarstore = FALSE;
5473
5474 //
5475 // The first element of <MultiConfigResp> should be
5476 // <GuidHdr>, which is in 'GUID='<Guid> syntax.
5477 //
5478 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
5479 return EFI_INVALID_PARAMETER;
5480 }
5481
5482 while (*StringPtr != 0 && StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) == 0) {
5483 //
5484 // If parsing error, set Progress to the beginning of the <MultiConfigResp>
5485 // or most recent & before the error.
5486 //
5487 if (StringPtr == Configuration) {
5488 *Progress = StringPtr;
5489 } else {
5490 *Progress = StringPtr - 1;
5491 }
5492
5493 //
5494 // Process each <ConfigResp> of <MultiConfigResp>
5495 //
5496 Length = CalculateConfigStringLen (StringPtr);
5497 ConfigResp = AllocateCopyPool ((Length + 1) * sizeof (CHAR16), StringPtr);
5498 if (ConfigResp == NULL) {
5499 return EFI_OUT_OF_RESOURCES;
5500 }
5501
5502 //
5503 // Append '\0' to the end of ConfigRequest
5504 //
5505 *(ConfigResp + Length) = 0;
5506
5507 //
5508 // Get the UEFI device path
5509 //
5510 Status = GetDevicePath (ConfigResp, (UINT8 **)&DevicePath);
5511 if (EFI_ERROR (Status)) {
5512 FreePool (ConfigResp);
5513 return Status;
5514 }
5515
5516 //
5517 // Find driver which matches the routing data.
5518 //
5519 DriverHandle = NULL;
5520 for (Link = Private->DatabaseList.ForwardLink;
5521 Link != &Private->DatabaseList;
5522 Link = Link->ForwardLink
5523 )
5524 {
5525 Database = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE);
5526
5527 if ((DevicePathPkg = Database->PackageList->DevicePathPkg) != NULL) {
5528 CurrentDevicePath = DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER);
5529 DevicePathSize = GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)CurrentDevicePath);
5530 if ((CompareMem (DevicePath, CurrentDevicePath, DevicePathSize) == 0) && IsThisPackageList (Database, ConfigResp)) {
5531 DriverHandle = Database->DriverHandle;
5532 break;
5533 }
5534 }
5535 }
5536
5537 //
5538 // Try to find driver handle by device path.
5539 //
5540 if (DriverHandle == NULL) {
5541 TempDevicePath = DevicePath;
5542 Status = gBS->LocateDevicePath (
5543 &gEfiDevicePathProtocolGuid,
5544 &TempDevicePath,
5545 &DriverHandle
5546 );
5547 if (EFI_ERROR (Status) || (DriverHandle == NULL)) {
5548 //
5549 // Routing data does not match any known driver.
5550 // Set Progress to the 'G' in "GUID" of the routing header.
5551 //
5552 FreePool (DevicePath);
5553 *Progress = StringPtr;
5554 FreePool (ConfigResp);
5555 return EFI_NOT_FOUND;
5556 }
5557 }
5558
5559 FreePool (DevicePath);
5560
5561 //
5562 // Check whether this ConfigRequest is search from Efi varstore type storage.
5563 //
5564 Status = GetVarStoreType (Database, ConfigResp, &IsEfiVarstore, &EfiVarStoreInfo);
5565 if (EFI_ERROR (Status)) {
5566 return Status;
5567 }
5568
5569 if (IsEfiVarstore) {
5570 //
5571 // Call the SetVariable function to route settings.
5572 //
5573 Status = RouteConfigRespForEfiVarStore (This, EfiVarStoreInfo, ConfigResp, &AccessProgress);
5574 FreePool (EfiVarStoreInfo);
5575 } else {
5576 //
5577 // Call corresponding ConfigAccess protocol to route settings
5578 //
5579 Status = gBS->HandleProtocol (
5580 DriverHandle,
5581 &gEfiHiiConfigAccessProtocolGuid,
5582 (VOID **)&ConfigAccess
5583 );
5584 if (EFI_ERROR (Status)) {
5585 *Progress = StringPtr;
5586 FreePool (ConfigResp);
5587 return EFI_NOT_FOUND;
5588 }
5589
5590 Status = ConfigAccess->RouteConfig (
5591 ConfigAccess,
5592 ConfigResp,
5593 &AccessProgress
5594 );
5595 }
5596
5597 if (EFI_ERROR (Status)) {
5598 ASSERT (AccessProgress != NULL);
5599 //
5600 // AccessProgress indicates the parsing progress on <ConfigResp>.
5601 // Map it to the progress on <MultiConfigResp> then return it.
5602 //
5603 *Progress = StrStr (StringPtr, AccessProgress);
5604
5605 FreePool (ConfigResp);
5606 return Status;
5607 }
5608
5609 FreePool (ConfigResp);
5610 ConfigResp = NULL;
5611
5612 //
5613 // Go to next <ConfigResp> (skip '&').
5614 //
5615 StringPtr += Length;
5616 if (*StringPtr == 0) {
5617 *Progress = StringPtr;
5618 break;
5619 }
5620
5621 StringPtr++;
5622 }
5623
5624 return EFI_SUCCESS;
5625 }
5626
5627 /**
5628 This helper function is to be called by drivers to map configuration data
5629 stored in byte array ("block") formats such as UEFI Variables into current
5630 configuration strings.
5631
5632 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5633 instance.
5634 @param ConfigRequest A null-terminated Unicode string in
5635 <ConfigRequest> format.
5636 @param Block Array of bytes defining the block's configuration.
5637 @param BlockSize Length in bytes of Block.
5638 @param Config Filled-in configuration string. String allocated
5639 by the function. Returned only if call is
5640 successful. It is <ConfigResp> string format.
5641 @param Progress A pointer to a string filled in with the offset of
5642 the most recent & before the first failing
5643 name/value pair (or the beginning of the string if
5644 the failure is in the first name / value pair) or
5645 the terminating NULL if all was successful.
5646
5647 @retval EFI_SUCCESS The request succeeded. Progress points to the null
5648 terminator at the end of the ConfigRequest
5649 string.
5650 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
5651 points to the first character of ConfigRequest.
5652 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigRequest or
5653 Block parameter would result in this type of
5654 error. Progress points to the first character of
5655 ConfigRequest.
5656 @retval EFI_DEVICE_ERROR Block not large enough. Progress undefined.
5657 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted string.
5658 Block is left updated and Progress points at
5659 the "&" preceding the first non-<BlockName>.
5660
5661 **/
5662 EFI_STATUS
5663 EFIAPI
5664 HiiBlockToConfig (
5665 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5666 IN CONST EFI_STRING ConfigRequest,
5667 IN CONST UINT8 *Block,
5668 IN CONST UINTN BlockSize,
5669 OUT EFI_STRING *Config,
5670 OUT EFI_STRING *Progress
5671 )
5672 {
5673 HII_DATABASE_PRIVATE_DATA *Private;
5674 EFI_STRING StringPtr;
5675 UINTN Length;
5676 EFI_STATUS Status;
5677 EFI_STRING TmpPtr;
5678 UINT8 *TmpBuffer;
5679 UINTN Offset;
5680 UINTN Width;
5681 UINT8 *Value;
5682 EFI_STRING ValueStr;
5683 EFI_STRING ConfigElement;
5684 UINTN Index;
5685 UINT8 *TemBuffer;
5686 CHAR16 *TemString;
5687
5688 TmpBuffer = NULL;
5689
5690 if ((This == NULL) || (Progress == NULL) || (Config == NULL)) {
5691 return EFI_INVALID_PARAMETER;
5692 }
5693
5694 if ((Block == NULL) || (ConfigRequest == NULL)) {
5695 *Progress = ConfigRequest;
5696 return EFI_INVALID_PARAMETER;
5697 }
5698
5699 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
5700 ASSERT (Private != NULL);
5701
5702 StringPtr = ConfigRequest;
5703 ValueStr = NULL;
5704 Value = NULL;
5705 ConfigElement = NULL;
5706
5707 //
5708 // Allocate a fix length of memory to store Results. Reallocate memory for
5709 // Results if this fix length is insufficient.
5710 //
5711 *Config = (EFI_STRING)AllocateZeroPool (MAX_STRING_LENGTH);
5712 if (*Config == NULL) {
5713 return EFI_OUT_OF_RESOURCES;
5714 }
5715
5716 //
5717 // Jump <ConfigHdr>
5718 //
5719 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
5720 *Progress = StringPtr;
5721 Status = EFI_INVALID_PARAMETER;
5722 goto Exit;
5723 }
5724
5725 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
5726 StringPtr++;
5727 }
5728
5729 if (*StringPtr == 0) {
5730 *Progress = StringPtr - 1;
5731 Status = EFI_INVALID_PARAMETER;
5732 goto Exit;
5733 }
5734
5735 while (*StringPtr != L'&' && *StringPtr != 0) {
5736 StringPtr++;
5737 }
5738
5739 if (*StringPtr == 0) {
5740 *Progress = StringPtr;
5741
5742 AppendToMultiString (Config, ConfigRequest);
5743 HiiToLower (*Config);
5744
5745 return EFI_SUCCESS;
5746 }
5747
5748 //
5749 // Skip '&'
5750 //
5751 StringPtr++;
5752
5753 //
5754 // Copy <ConfigHdr> and an additional '&' to <ConfigResp>
5755 //
5756 TemString = AllocateCopyPool (sizeof (CHAR16) * (StringPtr - ConfigRequest + 1), ConfigRequest);
5757 if (TemString == NULL) {
5758 return EFI_OUT_OF_RESOURCES;
5759 }
5760
5761 TemString[StringPtr - ConfigRequest] = '\0';
5762 AppendToMultiString (Config, TemString);
5763 FreePool (TemString);
5764
5765 //
5766 // Parse each <RequestElement> if exists
5767 // Only <BlockName> format is supported by this help function.
5768 // <BlockName> ::= 'OFFSET='<Number>&'WIDTH='<Number>
5769 //
5770 while (*StringPtr != 0 && StrnCmp (StringPtr, L"OFFSET=", StrLen (L"OFFSET=")) == 0) {
5771 //
5772 // Back up the header of one <BlockName>
5773 //
5774 TmpPtr = StringPtr;
5775
5776 StringPtr += StrLen (L"OFFSET=");
5777 //
5778 // Get Offset
5779 //
5780 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
5781 if (EFI_ERROR (Status)) {
5782 *Progress = TmpPtr - 1;
5783 goto Exit;
5784 }
5785
5786 Offset = 0;
5787 CopyMem (
5788 &Offset,
5789 TmpBuffer,
5790 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
5791 );
5792 FreePool (TmpBuffer);
5793
5794 StringPtr += Length;
5795 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
5796 *Progress = TmpPtr - 1;
5797 Status = EFI_INVALID_PARAMETER;
5798 goto Exit;
5799 }
5800
5801 StringPtr += StrLen (L"&WIDTH=");
5802
5803 //
5804 // Get Width
5805 //
5806 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
5807 if (EFI_ERROR (Status)) {
5808 *Progress = TmpPtr - 1;
5809 goto Exit;
5810 }
5811
5812 Width = 0;
5813 CopyMem (
5814 &Width,
5815 TmpBuffer,
5816 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
5817 );
5818 FreePool (TmpBuffer);
5819
5820 StringPtr += Length;
5821 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
5822 *Progress = TmpPtr - 1;
5823 Status = EFI_INVALID_PARAMETER;
5824 goto Exit;
5825 }
5826
5827 //
5828 // Calculate Value and convert it to hex string.
5829 //
5830 if (Offset + Width > BlockSize) {
5831 *Progress = StringPtr;
5832 Status = EFI_DEVICE_ERROR;
5833 goto Exit;
5834 }
5835
5836 Value = (UINT8 *)AllocateZeroPool (Width);
5837 if (Value == NULL) {
5838 *Progress = ConfigRequest;
5839 Status = EFI_OUT_OF_RESOURCES;
5840 goto Exit;
5841 }
5842
5843 CopyMem (Value, (UINT8 *)Block + Offset, Width);
5844
5845 Length = Width * 2 + 1;
5846 ValueStr = (EFI_STRING)AllocateZeroPool (Length * sizeof (CHAR16));
5847 if (ValueStr == NULL) {
5848 *Progress = ConfigRequest;
5849 Status = EFI_OUT_OF_RESOURCES;
5850 goto Exit;
5851 }
5852
5853 TemString = ValueStr;
5854 TemBuffer = Value + Width - 1;
5855 for (Index = 0; Index < Width; Index++, TemBuffer--) {
5856 UnicodeValueToStringS (
5857 TemString,
5858 Length * sizeof (CHAR16) - ((UINTN)TemString - (UINTN)ValueStr),
5859 PREFIX_ZERO | RADIX_HEX,
5860 *TemBuffer,
5861 2
5862 );
5863 TemString += StrnLenS (TemString, Length - ((UINTN)TemString - (UINTN)ValueStr) / sizeof (CHAR16));
5864 }
5865
5866 FreePool (Value);
5867 Value = NULL;
5868
5869 //
5870 // Build a ConfigElement
5871 //
5872 Length += StringPtr - TmpPtr + 1 + StrLen (L"VALUE=");
5873 ConfigElement = (EFI_STRING)AllocateZeroPool (Length * sizeof (CHAR16));
5874 if (ConfigElement == NULL) {
5875 Status = EFI_OUT_OF_RESOURCES;
5876 goto Exit;
5877 }
5878
5879 CopyMem (ConfigElement, TmpPtr, (StringPtr - TmpPtr + 1) * sizeof (CHAR16));
5880 if (*StringPtr == 0) {
5881 *(ConfigElement + (StringPtr - TmpPtr)) = L'&';
5882 }
5883
5884 *(ConfigElement + (StringPtr - TmpPtr) + 1) = 0;
5885 StrCatS (ConfigElement, Length, L"VALUE=");
5886 StrCatS (ConfigElement, Length, ValueStr);
5887
5888 AppendToMultiString (Config, ConfigElement);
5889
5890 FreePool (ConfigElement);
5891 FreePool (ValueStr);
5892 ConfigElement = NULL;
5893 ValueStr = NULL;
5894
5895 //
5896 // If '\0', parsing is finished. Otherwise skip '&' to continue
5897 //
5898 if (*StringPtr == 0) {
5899 break;
5900 }
5901
5902 AppendToMultiString (Config, L"&");
5903 StringPtr++;
5904 }
5905
5906 if (*StringPtr != 0) {
5907 *Progress = StringPtr - 1;
5908 Status = EFI_INVALID_PARAMETER;
5909 goto Exit;
5910 }
5911
5912 HiiToLower (*Config);
5913 *Progress = StringPtr;
5914 return EFI_SUCCESS;
5915
5916 Exit:
5917 if (*Config != NULL) {
5918 FreePool (*Config);
5919 *Config = NULL;
5920 }
5921
5922 if (ValueStr != NULL) {
5923 FreePool (ValueStr);
5924 }
5925
5926 if (Value != NULL) {
5927 FreePool (Value);
5928 }
5929
5930 if (ConfigElement != NULL) {
5931 FreePool (ConfigElement);
5932 }
5933
5934 return Status;
5935 }
5936
5937 /**
5938 This helper function is to be called by drivers to map configuration strings
5939 to configurations stored in byte array ("block") formats such as UEFI Variables.
5940
5941 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
5942 instance.
5943 @param ConfigResp A null-terminated Unicode string in <ConfigResp>
5944 format.
5945 @param Block A possibly null array of bytes representing the
5946 current block. Only bytes referenced in the
5947 ConfigResp string in the block are modified. If
5948 this parameter is null or if the *BlockSize
5949 parameter is (on input) shorter than required by
5950 the Configuration string, only the BlockSize
5951 parameter is updated and an appropriate status
5952 (see below) is returned.
5953 @param BlockSize The length of the Block in units of UINT8. On
5954 input, this is the size of the Block. On output,
5955 if successful, contains the largest index of the
5956 modified byte in the Block, or the required buffer
5957 size if the Block is not large enough.
5958 @param Progress On return, points to an element of the ConfigResp
5959 string filled in with the offset of the most
5960 recent '&' before the first failing name / value
5961 pair (or the beginning of the string if the
5962 failure is in the first name / value pair) or the
5963 terminating NULL if all was successful.
5964
5965 @retval EFI_SUCCESS The request succeeded. Progress points to the null
5966 terminator at the end of the ConfigResp string.
5967 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate Config. Progress
5968 points to the first character of ConfigResp.
5969 @retval EFI_INVALID_PARAMETER Passing in a NULL for the ConfigResp or
5970 Block parameter would result in this type of
5971 error. Progress points to the first character of
5972 ConfigResp.
5973 @retval EFI_INVALID_PARAMETER Encountered non <BlockName> formatted name /
5974 value pair. Block is left updated and
5975 Progress points at the '&' preceding the first
5976 non-<BlockName>.
5977 @retval EFI_BUFFER_TOO_SMALL Block not large enough. Progress undefined.
5978 BlockSize is updated with the required buffer size.
5979 @retval EFI_NOT_FOUND Target for the specified routing data was not found.
5980 Progress points to the "G" in "GUID" of the errant
5981 routing data.
5982
5983 **/
5984 EFI_STATUS
5985 EFIAPI
5986 HiiConfigToBlock (
5987 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
5988 IN CONST EFI_STRING ConfigResp,
5989 IN OUT UINT8 *Block,
5990 IN OUT UINTN *BlockSize,
5991 OUT EFI_STRING *Progress
5992 )
5993 {
5994 HII_DATABASE_PRIVATE_DATA *Private;
5995 EFI_STRING StringPtr;
5996 EFI_STRING TmpPtr;
5997 UINTN Length;
5998 EFI_STATUS Status;
5999 UINT8 *TmpBuffer;
6000 UINTN Offset;
6001 UINTN Width;
6002 UINT8 *Value;
6003 UINTN BufferSize;
6004 UINTN MaxBlockSize;
6005
6006 TmpBuffer = NULL;
6007
6008 if ((This == NULL) || (BlockSize == NULL) || (Progress == NULL)) {
6009 return EFI_INVALID_PARAMETER;
6010 }
6011
6012 *Progress = ConfigResp;
6013 if (ConfigResp == NULL) {
6014 return EFI_INVALID_PARAMETER;
6015 }
6016
6017 Private = CONFIG_ROUTING_DATABASE_PRIVATE_DATA_FROM_THIS (This);
6018 ASSERT (Private != NULL);
6019
6020 StringPtr = ConfigResp;
6021 BufferSize = *BlockSize;
6022 Value = NULL;
6023 MaxBlockSize = 0;
6024
6025 //
6026 // Jump <ConfigHdr>
6027 //
6028 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
6029 *Progress = StringPtr;
6030 Status = EFI_INVALID_PARAMETER;
6031 goto Exit;
6032 }
6033
6034 while (*StringPtr != 0 && StrnCmp (StringPtr, L"PATH=", StrLen (L"PATH=")) != 0) {
6035 StringPtr++;
6036 }
6037
6038 if (*StringPtr == 0) {
6039 *Progress = StringPtr;
6040 Status = EFI_INVALID_PARAMETER;
6041 goto Exit;
6042 }
6043
6044 while (*StringPtr != L'&' && *StringPtr != 0) {
6045 StringPtr++;
6046 }
6047
6048 if (*StringPtr == 0) {
6049 *Progress = StringPtr;
6050 Status = EFI_INVALID_PARAMETER;
6051 goto Exit;
6052 }
6053
6054 //
6055 // Parse each <ConfigElement> if exists
6056 // Only '&'<BlockConfig> format is supported by this help function.
6057 // <BlockConfig> ::= 'OFFSET='<Number>&'WIDTH='<Number>&'VALUE='<Number>
6058 //
6059 while (*StringPtr != 0 && StrnCmp (StringPtr, L"&OFFSET=", StrLen (L"&OFFSET=")) == 0) {
6060 TmpPtr = StringPtr;
6061 StringPtr += StrLen (L"&OFFSET=");
6062 //
6063 // Get Offset
6064 //
6065 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
6066 if (EFI_ERROR (Status)) {
6067 *Progress = TmpPtr;
6068 goto Exit;
6069 }
6070
6071 Offset = 0;
6072 CopyMem (
6073 &Offset,
6074 TmpBuffer,
6075 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
6076 );
6077 FreePool (TmpBuffer);
6078
6079 StringPtr += Length;
6080 if (StrnCmp (StringPtr, L"&WIDTH=", StrLen (L"&WIDTH=")) != 0) {
6081 *Progress = TmpPtr;
6082 Status = EFI_INVALID_PARAMETER;
6083 goto Exit;
6084 }
6085
6086 StringPtr += StrLen (L"&WIDTH=");
6087
6088 //
6089 // Get Width
6090 //
6091 Status = GetValueOfNumber (StringPtr, &TmpBuffer, &Length);
6092 if (EFI_ERROR (Status)) {
6093 *Progress = TmpPtr;
6094 goto Exit;
6095 }
6096
6097 Width = 0;
6098 CopyMem (
6099 &Width,
6100 TmpBuffer,
6101 (((Length + 1) / 2) < sizeof (UINTN)) ? ((Length + 1) / 2) : sizeof (UINTN)
6102 );
6103 FreePool (TmpBuffer);
6104
6105 StringPtr += Length;
6106 if (StrnCmp (StringPtr, L"&VALUE=", StrLen (L"&VALUE=")) != 0) {
6107 *Progress = TmpPtr;
6108 Status = EFI_INVALID_PARAMETER;
6109 goto Exit;
6110 }
6111
6112 StringPtr += StrLen (L"&VALUE=");
6113
6114 //
6115 // Get Value
6116 //
6117 Status = GetValueOfNumber (StringPtr, &Value, &Length);
6118 if (EFI_ERROR (Status)) {
6119 *Progress = TmpPtr;
6120 goto Exit;
6121 }
6122
6123 StringPtr += Length;
6124 if ((*StringPtr != 0) && (*StringPtr != L'&')) {
6125 *Progress = TmpPtr;
6126 Status = EFI_INVALID_PARAMETER;
6127 goto Exit;
6128 }
6129
6130 //
6131 // Update the Block with configuration info
6132 //
6133 if ((Block != NULL) && (Offset + Width <= BufferSize)) {
6134 CopyMem (Block + Offset, Value, Width);
6135 }
6136
6137 if (Offset + Width > MaxBlockSize) {
6138 MaxBlockSize = Offset + Width;
6139 }
6140
6141 FreePool (Value);
6142 Value = NULL;
6143
6144 //
6145 // If '\0', parsing is finished.
6146 //
6147 if (*StringPtr == 0) {
6148 break;
6149 }
6150 }
6151
6152 //
6153 // The input string is not ConfigResp format, return error.
6154 //
6155 if (*StringPtr != 0) {
6156 *Progress = StringPtr;
6157 Status = EFI_INVALID_PARAMETER;
6158 goto Exit;
6159 }
6160
6161 *Progress = StringPtr + StrLen (StringPtr);
6162 *BlockSize = MaxBlockSize - 1;
6163
6164 if (MaxBlockSize > BufferSize) {
6165 *BlockSize = MaxBlockSize;
6166 if (Block != NULL) {
6167 return EFI_BUFFER_TOO_SMALL;
6168 }
6169 }
6170
6171 if (Block == NULL) {
6172 *Progress = ConfigResp;
6173 return EFI_INVALID_PARAMETER;
6174 }
6175
6176 return EFI_SUCCESS;
6177
6178 Exit:
6179
6180 if (Value != NULL) {
6181 FreePool (Value);
6182 }
6183
6184 return Status;
6185 }
6186
6187 /**
6188 This helper function is to be called by drivers to extract portions of
6189 a larger configuration string.
6190
6191 @param This A pointer to the EFI_HII_CONFIG_ROUTING_PROTOCOL
6192 instance.
6193 @param Configuration A null-terminated Unicode string in
6194 <MultiConfigAltResp> format.
6195 @param Guid A pointer to the GUID value to search for in the
6196 routing portion of the ConfigResp string when
6197 retrieving the requested data. If Guid is NULL,
6198 then all GUID values will be searched for.
6199 @param Name A pointer to the NAME value to search for in the
6200 routing portion of the ConfigResp string when
6201 retrieving the requested data. If Name is NULL,
6202 then all Name values will be searched for.
6203 @param DevicePath A pointer to the PATH value to search for in the
6204 routing portion of the ConfigResp string when
6205 retrieving the requested data. If DevicePath is
6206 NULL, then all DevicePath values will be searched
6207 for.
6208 @param AltCfgId A pointer to the ALTCFG value to search for in the
6209 routing portion of the ConfigResp string when
6210 retrieving the requested data. If this parameter
6211 is NULL, then the current setting will be
6212 retrieved.
6213 @param AltCfgResp A pointer to a buffer which will be allocated by
6214 the function which contains the retrieved string
6215 as requested. This buffer is only allocated if
6216 the call was successful. It is <ConfigResp> format.
6217
6218 @retval EFI_SUCCESS The request succeeded. The requested data was
6219 extracted and placed in the newly allocated
6220 AltCfgResp buffer.
6221 @retval EFI_OUT_OF_RESOURCES Not enough memory to allocate AltCfgResp.
6222 @retval EFI_INVALID_PARAMETER Any parameter is invalid.
6223 @retval EFI_NOT_FOUND Target for the specified routing data was not
6224 found.
6225
6226 **/
6227 EFI_STATUS
6228 EFIAPI
6229 HiiGetAltCfg (
6230 IN CONST EFI_HII_CONFIG_ROUTING_PROTOCOL *This,
6231 IN CONST EFI_STRING Configuration,
6232 IN CONST EFI_GUID *Guid,
6233 IN CONST EFI_STRING Name,
6234 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
6235 IN CONST UINT16 *AltCfgId,
6236 OUT EFI_STRING *AltCfgResp
6237 )
6238 {
6239 EFI_STATUS Status;
6240 EFI_STRING StringPtr;
6241 EFI_STRING HdrStart;
6242 EFI_STRING HdrEnd;
6243 EFI_STRING TmpPtr;
6244 UINTN Length;
6245 EFI_STRING GuidStr;
6246 EFI_STRING NameStr;
6247 EFI_STRING PathStr;
6248 EFI_STRING AltIdStr;
6249 EFI_STRING Result;
6250 BOOLEAN GuidFlag;
6251 BOOLEAN NameFlag;
6252 BOOLEAN PathFlag;
6253
6254 HdrStart = NULL;
6255 HdrEnd = NULL;
6256 GuidStr = NULL;
6257 NameStr = NULL;
6258 PathStr = NULL;
6259 AltIdStr = NULL;
6260 Result = NULL;
6261 GuidFlag = FALSE;
6262 NameFlag = FALSE;
6263 PathFlag = FALSE;
6264
6265 if ((This == NULL) || (Configuration == NULL) || (AltCfgResp == NULL)) {
6266 return EFI_INVALID_PARAMETER;
6267 }
6268
6269 StringPtr = Configuration;
6270 if (StrnCmp (StringPtr, L"GUID=", StrLen (L"GUID=")) != 0) {
6271 return EFI_INVALID_PARAMETER;
6272 }
6273
6274 //
6275 // Generate the sub string for later matching.
6276 //
6277 GenerateSubStr (L"GUID=", sizeof (EFI_GUID), (VOID *)Guid, 1, &GuidStr);
6278 GenerateSubStr (
6279 L"PATH=",
6280 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DevicePath),
6281 (VOID *)DevicePath,
6282 1,
6283 &PathStr
6284 );
6285 if (AltCfgId != NULL) {
6286 GenerateSubStr (L"ALTCFG=", sizeof (UINT16), (VOID *)AltCfgId, 3, &AltIdStr);
6287 }
6288
6289 if (Name != NULL) {
6290 GenerateSubStr (L"NAME=", StrLen (Name) * sizeof (CHAR16), (VOID *)Name, 2, &NameStr);
6291 } else {
6292 GenerateSubStr (L"NAME=", 0, NULL, 2, &NameStr);
6293 }
6294
6295 while (*StringPtr != 0) {
6296 //
6297 // Try to match the GUID
6298 //
6299 if (!GuidFlag) {
6300 TmpPtr = StrStr (StringPtr, GuidStr);
6301 if (TmpPtr == NULL) {
6302 Status = EFI_NOT_FOUND;
6303 goto Exit;
6304 }
6305
6306 HdrStart = TmpPtr;
6307
6308 //
6309 // Jump to <NameHdr>
6310 //
6311 if (Guid != NULL) {
6312 StringPtr = TmpPtr + StrLen (GuidStr);
6313 } else {
6314 StringPtr = StrStr (TmpPtr, L"NAME=");
6315 if (StringPtr == NULL) {
6316 Status = EFI_NOT_FOUND;
6317 goto Exit;
6318 }
6319 }
6320
6321 GuidFlag = TRUE;
6322 }
6323
6324 //
6325 // Try to match the NAME
6326 //
6327 if (GuidFlag && !NameFlag) {
6328 if (StrnCmp (StringPtr, NameStr, StrLen (NameStr)) != 0) {
6329 GuidFlag = FALSE;
6330 } else {
6331 //
6332 // Jump to <PathHdr>
6333 //
6334 if (Name != NULL) {
6335 StringPtr += StrLen (NameStr);
6336 } else {
6337 StringPtr = StrStr (StringPtr, L"PATH=");
6338 if (StringPtr == NULL) {
6339 Status = EFI_NOT_FOUND;
6340 goto Exit;
6341 }
6342 }
6343
6344 NameFlag = TRUE;
6345 }
6346 }
6347
6348 //
6349 // Try to match the DevicePath
6350 //
6351 if (GuidFlag && NameFlag && !PathFlag) {
6352 if (StrnCmp (StringPtr, PathStr, StrLen (PathStr)) != 0) {
6353 GuidFlag = FALSE;
6354 NameFlag = FALSE;
6355 } else {
6356 //
6357 // Jump to '&' before <DescHdr> or <ConfigBody>
6358 //
6359 if (DevicePath != NULL) {
6360 StringPtr += StrLen (PathStr);
6361 } else {
6362 StringPtr = StrStr (StringPtr, L"&");
6363 if (StringPtr == NULL) {
6364 Status = EFI_NOT_FOUND;
6365 goto Exit;
6366 }
6367
6368 StringPtr++;
6369 }
6370
6371 PathFlag = TRUE;
6372 HdrEnd = StringPtr;
6373 }
6374 }
6375
6376 //
6377 // Try to match the AltCfgId
6378 //
6379 if (GuidFlag && NameFlag && PathFlag) {
6380 if (AltCfgId == NULL) {
6381 //
6382 // Return Current Setting when AltCfgId is NULL.
6383 //
6384 Status = OutputConfigBody (StringPtr, &Result);
6385 goto Exit;
6386 }
6387
6388 //
6389 // Search the <ConfigAltResp> to get the <AltResp> with AltCfgId.
6390 //
6391 if (StrnCmp (StringPtr, AltIdStr, StrLen (AltIdStr)) != 0) {
6392 GuidFlag = FALSE;
6393 NameFlag = FALSE;
6394 PathFlag = FALSE;
6395 } else {
6396 //
6397 // Skip AltIdStr and &
6398 //
6399 StringPtr = StringPtr + StrLen (AltIdStr);
6400 Status = OutputConfigBody (StringPtr, &Result);
6401 goto Exit;
6402 }
6403 }
6404 }
6405
6406 Status = EFI_NOT_FOUND;
6407
6408 Exit:
6409 *AltCfgResp = NULL;
6410 if (!EFI_ERROR (Status) && (Result != NULL)) {
6411 //
6412 // Copy the <ConfigHdr> and <ConfigBody>
6413 //
6414 Length = HdrEnd - HdrStart + StrLen (Result) + 1;
6415 *AltCfgResp = AllocateZeroPool (Length * sizeof (CHAR16));
6416 if (*AltCfgResp == NULL) {
6417 Status = EFI_OUT_OF_RESOURCES;
6418 } else {
6419 StrnCpyS (*AltCfgResp, Length, HdrStart, HdrEnd - HdrStart);
6420 StrCatS (*AltCfgResp, Length, Result);
6421 Status = EFI_SUCCESS;
6422 }
6423 }
6424
6425 if (GuidStr != NULL) {
6426 FreePool (GuidStr);
6427 }
6428
6429 if (NameStr != NULL) {
6430 FreePool (NameStr);
6431 }
6432
6433 if (PathStr != NULL) {
6434 FreePool (PathStr);
6435 }
6436
6437 if (AltIdStr != NULL) {
6438 FreePool (AltIdStr);
6439 }
6440
6441 if (Result != NULL) {
6442 FreePool (Result);
6443 }
6444
6445 return Status;
6446 }