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