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