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