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