]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Library/EdkIfrSupportLib/IfrCommon.c
cff559cf4d41a0df25315cde7ced199be287ad70
[mirror_edk2.git] / EdkModulePkg / Library / EdkIfrSupportLib / IfrCommon.c
1 /*++
2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 Module Name:
12 IfrCommon.c
13
14 Abstract:
15
16 Common Library Routines to assist in IFR creation on-the-fly
17
18 Revision History:
19
20 --*/
21
22 EFI_STATUS
23 EFIAPI
24 IfrLibConstruct (
25 IN EFI_HANDLE ImageHandle,
26 IN EFI_SYSTEM_TABLE *SystemTable
27 )
28 {
29 return EFI_SUCCESS;
30 }
31
32 EFI_STATUS
33 GetCurrentLanguage (
34 OUT CHAR16 *Lang
35 )
36 /*++
37
38 Routine Description:
39
40 Determine what is the current language setting
41
42 Arguments:
43
44 Lang - Pointer of system language
45
46 Returns:
47
48 Status code
49
50 --*/
51 {
52 EFI_STATUS Status;
53 UINTN Size;
54 UINTN Index;
55 CHAR8 Language[4];
56
57 //
58 // Getting the system language and placing it into our Global Data
59 //
60 Size = sizeof (Language);
61
62 Status = gRT->GetVariable (
63 (CHAR16 *) L"Lang",
64 &gEfiGlobalVariableGuid,
65 NULL,
66 &Size,
67 Language
68 );
69
70 if (EFI_ERROR (Status)) {
71 AsciiStrCpy (Language, "eng");
72 }
73
74 for (Index = 0; Index < 3; Index++) {
75 //
76 // Bitwise AND ascii value with 0xDF yields an uppercase value.
77 // Sign extend into a unicode value
78 //
79 Lang[Index] = (CHAR16) (Language[Index] & 0xDF);
80 }
81
82 //
83 // Null-terminate the value
84 //
85 Lang[3] = (CHAR16) 0;
86
87 return Status;
88 }
89
90
91 EFI_STATUS
92 AddString (
93 IN VOID *StringBuffer,
94 IN CHAR16 *Language,
95 IN CHAR16 *String,
96 IN OUT STRING_REF *StringToken
97 )
98 /*++
99
100 Routine Description:
101
102 Add a string to the incoming buffer and return the token and offset data
103
104 Arguments:
105
106 StringBuffer - The incoming buffer
107
108 Language - Currrent language
109
110 String - The string to be added
111
112 StringToken - The index where the string placed
113
114 Returns:
115
116 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
117
118 EFI_SUCCESS - String successfully added to the incoming buffer
119
120 --*/
121 {
122 EFI_HII_STRING_PACK *StringPack;
123 EFI_HII_STRING_PACK *StringPackBuffer;
124 VOID *NewBuffer;
125 RELOFST *PackSource;
126 RELOFST *PackDestination;
127 UINT8 *Source;
128 UINT8 *Destination;
129 UINTN Index;
130 BOOLEAN Finished;
131
132 StringPack = (EFI_HII_STRING_PACK *) StringBuffer;
133 Finished = FALSE;
134
135 //
136 // Pre-allocate a buffer sufficient for us to work on.
137 // We will use it as a destination scratch pad to build data on
138 // and when complete shift the data back to the original buffer
139 //
140 NewBuffer = AllocateZeroPool (DEFAULT_STRING_BUFFER_SIZE);
141 if (NewBuffer == NULL) {
142 return EFI_OUT_OF_RESOURCES;
143 }
144
145 StringPackBuffer = (EFI_HII_STRING_PACK *) NewBuffer;
146
147 //
148 // StringPack is terminated with a length 0 entry
149 //
150 for (; StringPack->Header.Length != 0;) {
151 //
152 // If this stringpack's language is same as CurrentLanguage, use it
153 //
154 if (CompareMem ((VOID *) ((CHAR8 *) (StringPack) + StringPack->LanguageNameString), Language, 3) == 0) {
155 //
156 // We have some data in this string pack, copy the string package up to the string data
157 //
158 CopyMem (&StringPackBuffer->Header, &StringPack->Header, sizeof (StringPack));
159
160 //
161 // These are references in the structure to tokens, need to increase them by the space occupied by an additional StringPointer
162 //
163 StringPackBuffer->LanguageNameString = (UINT16) (StringPackBuffer->LanguageNameString + (UINT16) sizeof (RELOFST));
164 StringPackBuffer->PrintableLanguageName = (UINT16) (StringPackBuffer->PrintableLanguageName + (UINT16) sizeof (RELOFST));
165
166 PackSource = (RELOFST *) (StringPack + 1);
167 PackDestination = (RELOFST *) (StringPackBuffer + 1);
168 for (Index = 0; PackSource[Index] != 0x0000; Index++) {
169 //
170 // Copy the stringpointers from old to new buffer
171 // remember that we are adding a string, so the string offsets will all go up by sizeof (RELOFST)
172 //
173 PackDestination[Index] = (UINT16) (PackDestination[Index] + sizeof (RELOFST));
174 }
175
176 //
177 // Add a new stringpointer in the new buffer since we are adding a string. Null terminate it
178 //
179 PackDestination[Index] = (UINT16)(PackDestination[Index-1] +
180 StrSize((CHAR16 *)((CHAR8 *)(StringPack) + PackSource[Index-1])));
181 PackDestination[Index + 1] = (UINT16) 0;
182
183 //
184 // Index is the token value for the new string
185 //
186 *StringToken = (UINT16) Index;
187
188 //
189 // Source now points to the beginning of the old buffer strings
190 // Destination now points to the beginning of the new buffer strings
191 //
192 Source = (UINT8 *) &PackSource[Index + 1];
193 Destination = (UINT8 *) &PackDestination[Index + 2];
194
195 //
196 // This should copy all the strings from the old buffer to the new buffer
197 //
198 for (; Index != 0; Index--) {
199 //
200 // Copy Source string to destination buffer
201 //
202 StrCpy ((CHAR16 *) Destination, (CHAR16 *) Source);
203
204 //
205 // Adjust the source/destination to the next string location
206 //
207 Destination = Destination + StrSize ((CHAR16 *) Source);
208 Source = Source + StrSize ((CHAR16 *) Source);
209 }
210
211 //
212 // This copies the new string to the destination buffer
213 //
214 StrCpy ((CHAR16 *) Destination, (CHAR16 *) String);
215
216 //
217 // Adjust the size of the changed string pack by adding the size of the new string
218 // along with the size of the additional offset entry for the new string
219 //
220 StringPackBuffer->Header.Length = (UINT32) ((UINTN) StringPackBuffer->Header.Length + StrSize (String) + sizeof (RELOFST));
221
222 //
223 // Advance the buffers to point to the next spots.
224 //
225 StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPackBuffer->Header.Length);
226 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length);
227 Finished = TRUE;
228 continue;
229 }
230 //
231 // This isn't the language of the stringpack we were asked to add a string to
232 // so we need to copy it to the new buffer.
233 //
234 CopyMem (&StringPackBuffer->Header, &StringPack->Header, StringPack->Header.Length);
235
236 //
237 // Advance the buffers to point to the next spots.
238 //
239 StringPackBuffer = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPackBuffer) + StringPack->Header.Length);
240 StringPack = (EFI_HII_STRING_PACK *) ((CHAR8 *) (StringPack) + StringPack->Header.Length);
241 }
242
243 //
244 // If we didn't copy the new data to a stringpack yet
245 //
246 if (!Finished) {
247 PackDestination = (RELOFST *) (StringPackBuffer + 1);
248 //
249 // Pointing to a new string pack location
250 //
251 StringPackBuffer->Header.Length = (UINT32)
252 (
253 sizeof (EFI_HII_STRING_PACK) -
254 sizeof (EFI_STRING) +
255 sizeof (RELOFST) +
256 sizeof (RELOFST) +
257 StrSize (Language) +
258 StrSize (String)
259 );
260 StringPackBuffer->Header.Type = EFI_HII_STRING;
261 StringPackBuffer->LanguageNameString = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
262 StringPackBuffer->PrintableLanguageName = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
263 StringPackBuffer->Attributes = 0;
264 PackDestination[0] = (UINT16) ((UINTN) &PackDestination[3] - (UINTN) StringPackBuffer);
265 PackDestination[1] = (UINT16) (PackDestination[0] + StrSize (Language));
266 PackDestination[2] = (UINT16) 0;
267
268 //
269 // The first string location will be set to destination. The minimum number of strings
270 // associated with a stringpack will always be token 0 stored as the languagename (e.g. ENG, SPA, etc)
271 // and token 1 as the new string being added and and null entry for the stringpointers
272 //
273 Destination = (UINT8 *) &PackDestination[3];
274
275 //
276 // Copy the language name string to the new buffer
277 //
278 StrCpy ((CHAR16 *) Destination, Language);
279
280 //
281 // Advance the destination to the new empty spot
282 //
283 Destination = Destination + StrSize (Language);
284
285 //
286 // Copy the string to the new buffer
287 //
288 StrCpy ((CHAR16 *) Destination, String);
289
290 //
291 // Since we are starting with a new string pack - we know the new string is token 1
292 //
293 *StringToken = (UINT16) 1;
294 }
295
296 //
297 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
298 //
299 ZeroMem (StringBuffer, DEFAULT_STRING_BUFFER_SIZE);
300 CopyMem (StringBuffer, NewBuffer, DEFAULT_STRING_BUFFER_SIZE);
301
302 //
303 // Free the newly created buffer since we don't need it anymore
304 //
305 gBS->FreePool (NewBuffer);
306 return EFI_SUCCESS;
307 }
308
309
310 EFI_STATUS
311 AddOpCode (
312 IN VOID *FormBuffer,
313 IN OUT VOID *OpCodeData
314 )
315 /*++
316
317 Routine Description:
318
319 Add op-code data to the FormBuffer
320
321 Arguments:
322
323 FormBuffer - Form buffer to be inserted to
324
325 OpCodeData - Op-code data to be inserted
326
327 Returns:
328
329 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
330
331 EFI_SUCCESS - Op-code data successfully inserted
332
333 --*/
334 {
335 EFI_HII_PACK_HEADER *NewBuffer;
336 UINT8 *Source;
337 UINT8 *Destination;
338
339 //
340 // Pre-allocate a buffer sufficient for us to work on.
341 // We will use it as a destination scratch pad to build data on
342 // and when complete shift the data back to the original buffer
343 //
344 NewBuffer = AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE);
345 if (NewBuffer == NULL) {
346 return EFI_OUT_OF_RESOURCES;
347 }
348
349 Source = (UINT8 *) FormBuffer;
350 Destination = (UINT8 *) NewBuffer;
351
352 //
353 // Copy the IFR Package header to the new buffer
354 //
355 CopyMem (Destination, Source, sizeof (EFI_HII_PACK_HEADER));
356
357 //
358 // Advance Source and Destination to next op-code
359 //
360 Source = Source + sizeof (EFI_HII_PACK_HEADER);
361 Destination = Destination + sizeof (EFI_HII_PACK_HEADER);
362
363 //
364 // Copy data to the new buffer until we run into the end_form
365 //
366 for (; ((EFI_IFR_OP_HEADER *) Source)->OpCode != EFI_IFR_END_FORM_OP;) {
367 //
368 // If the this opcode is an end_form_set we better be creating and endform
369 // Nonetheless, we will add data before the end_form_set. This also provides
370 // for interesting behavior in the code we will run, but has no bad side-effects
371 // since we will possibly do a 0 byte copy in this particular end-case.
372 //
373 if (((EFI_IFR_OP_HEADER *) Source)->OpCode == EFI_IFR_END_FORM_SET_OP) {
374 break;
375 }
376
377 //
378 // Copy data to new buffer
379 //
380 CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
381
382 //
383 // Adjust Source/Destination to next op-code location
384 //
385 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
386 Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
387 }
388
389 //
390 // Prior to the end_form is where we insert the new op-code data
391 //
392 CopyMem (Destination, OpCodeData, ((EFI_IFR_OP_HEADER *) OpCodeData)->Length);
393 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
394
395 NewBuffer->Length = (UINT32) (NewBuffer->Length + (UINT32) (((EFI_IFR_OP_HEADER *) OpCodeData)->Length));
396
397 //
398 // Copy end-form data to new buffer
399 //
400 CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
401
402 //
403 // Adjust Source/Destination to next op-code location
404 //
405 Destination = Destination + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
406 Source = Source + (UINTN) ((EFI_IFR_OP_HEADER *) Source)->Length;
407
408 //
409 // Copy end-formset data to new buffer
410 //
411 CopyMem (Destination, Source, ((EFI_IFR_OP_HEADER *) Source)->Length);
412
413 //
414 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
415 //
416 ZeroMem (FormBuffer, DEFAULT_FORM_BUFFER_SIZE);
417 CopyMem (FormBuffer, NewBuffer, DEFAULT_FORM_BUFFER_SIZE);
418
419 //
420 // Free the newly created buffer since we don't need it anymore
421 //
422 gBS->FreePool (NewBuffer);
423 return EFI_SUCCESS;
424 }
425
426
427 EFI_STATUS
428 GetHiiInterface (
429 OUT EFI_HII_PROTOCOL **Hii
430 )
431 /*++
432
433 Routine Description:
434
435 Get the HII protocol interface
436
437 Arguments:
438
439 Hii - HII protocol interface
440
441 Returns:
442
443 Status code
444
445 --*/
446 {
447 EFI_STATUS Status;
448
449 //
450 // There should only be one HII protocol
451 //
452 Status = gBS->LocateProtocol (
453 &gEfiHiiProtocolGuid,
454 NULL,
455 (VOID **) Hii
456 );
457
458 return Status;;
459 }
460
461
462 EFI_STATUS
463 ExtractDataFromHiiHandle (
464 IN EFI_HII_HANDLE HiiHandle,
465 IN OUT UINT16 *ImageLength,
466 OUT UINT8 *DefaultImage,
467 OUT EFI_GUID *Guid
468 )
469 /*++
470
471 Routine Description:
472
473 Extract information pertaining to the HiiHandle
474
475 Arguments:
476
477 HiiHandle - Hii handle
478
479 ImageLength - For input, length of DefaultImage;
480 For output, length of actually required
481
482 DefaultImage - Image buffer prepared by caller
483
484 Guid - Guid information about the form
485
486 Returns:
487
488 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
489
490 EFI_BUFFER_TOO_SMALL - DefualtImage has no enough ImageLength
491
492 EFI_SUCCESS - Successfully extract data from Hii database.
493
494
495 --*/
496 {
497 EFI_STATUS Status;
498 EFI_HII_PROTOCOL *Hii;
499 UINTN DataLength;
500 UINT8 *RawData;
501 UINT8 *OldData;
502 UINTN Index;
503 UINTN Temp;
504 UINTN SizeOfNvStore;
505 UINTN CachedStart;
506
507 DataLength = DEFAULT_FORM_BUFFER_SIZE;
508 SizeOfNvStore = 0;
509 CachedStart = 0;
510
511 Status = GetHiiInterface (&Hii);
512
513 if (EFI_ERROR (Status)) {
514 return Status;
515 }
516
517 //
518 // Allocate space for retrieval of IFR data
519 //
520 RawData = AllocateZeroPool (DataLength);
521 if (RawData == NULL) {
522 return EFI_OUT_OF_RESOURCES;
523 }
524
525 //
526 // Get all the forms associated with this HiiHandle
527 //
528 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
529
530 if (EFI_ERROR (Status)) {
531 gBS->FreePool (RawData);
532
533 //
534 // Allocate space for retrieval of IFR data
535 //
536 RawData = AllocateZeroPool (DataLength);
537 if (RawData == NULL) {
538 return EFI_OUT_OF_RESOURCES;
539 }
540
541 //
542 // Get all the forms associated with this HiiHandle
543 //
544 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
545 }
546
547 OldData = RawData;
548
549 //
550 // Point RawData to the beginning of the form data
551 //
552 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
553
554 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
555 switch (RawData[Index]) {
556 case EFI_IFR_FORM_SET_OP:
557 //
558 // Copy the GUID information from this handle
559 //
560 CopyMem (Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
561 break;
562
563 case EFI_IFR_ONE_OF_OP:
564 case EFI_IFR_CHECKBOX_OP:
565 case EFI_IFR_NUMERIC_OP:
566 case EFI_IFR_DATE_OP:
567 case EFI_IFR_TIME_OP:
568 case EFI_IFR_PASSWORD_OP:
569 case EFI_IFR_STRING_OP:
570 //
571 // Remember, multiple op-codes may reference the same item, so let's keep a running
572 // marker of what the highest QuestionId that wasn't zero length. This will accurately
573 // maintain the Size of the NvStore
574 //
575 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
576 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
577 if (SizeOfNvStore < Temp) {
578 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
579 }
580 }
581 }
582
583 Index = RawData[Index + 1] + Index;
584 }
585
586 //
587 // Return an error if buffer is too small
588 //
589 if (SizeOfNvStore > *ImageLength) {
590 gBS->FreePool (OldData);
591 *ImageLength = (UINT16) SizeOfNvStore;
592 return EFI_BUFFER_TOO_SMALL;
593 }
594
595 if (DefaultImage != NULL) {
596 ZeroMem (DefaultImage, SizeOfNvStore);
597 }
598
599 //
600 // Copy the default image information to the user's buffer
601 //
602 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
603 switch (RawData[Index]) {
604 case EFI_IFR_ONE_OF_OP:
605 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
606 break;
607
608 case EFI_IFR_ONE_OF_OPTION_OP:
609 if (((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & EFI_IFR_FLAG_DEFAULT) {
610 CopyMem (&DefaultImage[CachedStart], &((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2);
611 }
612 break;
613
614 case EFI_IFR_CHECKBOX_OP:
615 DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((EFI_IFR_CHECKBOX *) &RawData[Index])->Flags;
616 break;
617
618 case EFI_IFR_NUMERIC_OP:
619 CopyMem (
620 &DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId],
621 &((EFI_IFR_NUMERIC *) &RawData[Index])->Default,
622 2
623 );
624 break;
625
626 }
627
628 Index = RawData[Index + 1] + Index;
629 }
630
631 *ImageLength = (UINT16) SizeOfNvStore;
632
633 //
634 // Free our temporary repository of form data
635 //
636 gBS->FreePool (OldData);
637
638 return EFI_SUCCESS;
639 }
640
641
642 EFI_HII_HANDLE
643 FindHiiHandle (
644 IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL
645 IN EFI_GUID *Guid
646 )
647 /*++
648
649 Routine Description:
650 Finds HII handle for given pack GUID previously registered with the HII.
651
652 Arguments:
653 HiiProtocol - pointer to pointer to HII protocol interface.
654 If NULL, the interface will be found but not returned.
655 If it points to NULL, the interface will be found and
656 written back to the pointer that is pointed to.
657 Guid - The GUID of the pack that registered with the HII.
658
659 Returns:
660 Handle to the HII pack previously registered by the memory driver.
661
662 --*/
663 {
664 EFI_STATUS Status;
665
666 EFI_HII_HANDLE *HiiHandleBuffer;
667 EFI_HII_HANDLE HiiHandle;
668 UINT16 HiiHandleBufferLength;
669 UINT32 NumberOfHiiHandles;
670 EFI_GUID HiiGuid;
671 EFI_HII_PROTOCOL *HiiProt;
672 UINT32 Index;
673 UINT16 Length;
674
675 HiiHandle = 0;
676 if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) {
677 //
678 // The protocol has been passed in
679 //
680 HiiProt = *HiiProtocol;
681 } else {
682 gBS->LocateProtocol (
683 &gEfiHiiProtocolGuid,
684 NULL,
685 (VOID **) &HiiProt
686 );
687 if (HiiProt == NULL) {
688 return HiiHandle;
689 }
690
691 if (HiiProtocol != NULL) {
692 //
693 // Return back the HII protocol for the caller as promissed
694 //
695 *HiiProtocol = HiiProt;
696 }
697 }
698 //
699 // Allocate buffer
700 //
701 HiiHandleBufferLength = 10;
702 HiiHandleBuffer = AllocatePool (HiiHandleBufferLength);
703 ASSERT (HiiHandleBuffer != NULL);
704
705 //
706 // Get the Handles of the packages that were registered with Hii
707 //
708 Status = HiiProt->FindHandles (
709 HiiProt,
710 &HiiHandleBufferLength,
711 HiiHandleBuffer
712 );
713
714 //
715 // Get a bigger bugffer if this one is to small, and try again
716 //
717 if (Status == EFI_BUFFER_TOO_SMALL) {
718
719 gBS->FreePool (HiiHandleBuffer);
720
721 HiiHandleBuffer = AllocatePool (HiiHandleBufferLength);
722 ASSERT (HiiHandleBuffer != NULL);
723
724 Status = HiiProt->FindHandles (
725 HiiProt,
726 &HiiHandleBufferLength,
727 HiiHandleBuffer
728 );
729 }
730
731 if (EFI_ERROR (Status)) {
732 goto lbl_exit;
733 }
734
735 NumberOfHiiHandles = HiiHandleBufferLength / sizeof (EFI_HII_HANDLE);
736
737 //
738 // Iterate Hii handles and look for the one that matches our Guid
739 //
740 for (Index = 0; Index < NumberOfHiiHandles; Index++) {
741
742 Length = 0;
743 ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid);
744
745 if (CompareGuid (&HiiGuid, Guid)) {
746
747 HiiHandle = HiiHandleBuffer[Index];
748 break;
749 }
750 }
751
752 lbl_exit:
753 gBS->FreePool (HiiHandleBuffer);
754 return HiiHandle;
755 }
756
757
758 EFI_STATUS
759 ValidateDataFromHiiHandle (
760 IN EFI_HII_HANDLE HiiHandle,
761 OUT BOOLEAN *Results
762 )
763 /*++
764
765 Routine Description:
766
767 Validate that the data associated with the HiiHandle in NVRAM is within
768 the reasonable parameters for that FormSet. Values for strings and passwords
769 are not verified due to their not having the equivalent of valid range settings.
770
771 Arguments:
772
773 HiiHandle - Handle of the HII database entry to query
774
775 Results - If return Status is EFI_SUCCESS, Results provides valid data
776 TRUE = NVRAM Data is within parameters
777 FALSE = NVRAM Data is NOT within parameters
778
779 Returns:
780
781 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
782
783 EFI_SUCCESS - Data successfully validated
784 --*/
785 {
786 EFI_STATUS Status;
787 EFI_HII_PROTOCOL *Hii;
788 EFI_GUID Guid;
789 UINT8 *RawData;
790 UINT8 *OldData;
791 UINTN RawDataLength;
792 UINT8 *VariableData;
793 UINTN Index;
794 UINTN Temp;
795 UINTN SizeOfNvStore;
796 UINTN CachedStart;
797 BOOLEAN GotMatch;
798
799 RawDataLength = DEFAULT_FORM_BUFFER_SIZE;
800 SizeOfNvStore = 0;
801 CachedStart = 0;
802 GotMatch = FALSE;
803 *Results = TRUE;
804
805 Status = GetHiiInterface (&Hii);
806
807 if (EFI_ERROR (Status)) {
808 return Status;
809 }
810
811 //
812 // Allocate space for retrieval of IFR data
813 //
814 RawData = AllocateZeroPool (RawDataLength);
815 if (RawData == NULL) {
816 return EFI_OUT_OF_RESOURCES;
817 }
818
819 //
820 // Get all the forms associated with this HiiHandle
821 //
822 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
823
824 if (EFI_ERROR (Status)) {
825 gBS->FreePool (RawData);
826
827 //
828 // Allocate space for retrieval of IFR data
829 //
830 RawData = AllocateZeroPool (RawDataLength);
831 if (RawData == NULL) {
832 return EFI_OUT_OF_RESOURCES;
833 }
834
835 //
836 // Get all the forms associated with this HiiHandle
837 //
838 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
839 }
840
841 OldData = RawData;
842
843 //
844 // Point RawData to the beginning of the form data
845 //
846 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
847
848 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
849 if (RawData[Index] == EFI_IFR_FORM_SET_OP) {
850 CopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
851 break;
852 }
853
854 Index = RawData[Index + 1] + Index;
855 }
856
857 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
858 switch (RawData[Index]) {
859 case EFI_IFR_FORM_SET_OP:
860 break;
861
862 case EFI_IFR_ONE_OF_OP:
863 case EFI_IFR_CHECKBOX_OP:
864 case EFI_IFR_NUMERIC_OP:
865 case EFI_IFR_DATE_OP:
866 case EFI_IFR_TIME_OP:
867 case EFI_IFR_PASSWORD_OP:
868 case EFI_IFR_STRING_OP:
869 //
870 // Remember, multiple op-codes may reference the same item, so let's keep a running
871 // marker of what the highest QuestionId that wasn't zero length. This will accurately
872 // maintain the Size of the NvStore
873 //
874 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
875 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
876 if (SizeOfNvStore < Temp) {
877 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
878 }
879 }
880 }
881
882 Index = RawData[Index + 1] + Index;
883 }
884
885 //
886 // Allocate memory for our File Form Tags
887 //
888 VariableData = AllocateZeroPool (SizeOfNvStore);
889 if (VariableData == NULL) {
890 return EFI_OUT_OF_RESOURCES;
891 }
892
893 Status = gRT->GetVariable (
894 (CHAR16 *) L"Setup",
895 &Guid,
896 NULL,
897 &SizeOfNvStore,
898 (VOID *) VariableData
899 );
900
901 if (EFI_ERROR (Status)) {
902
903 //
904 // If there is a variable that exists already and it is larger than what we calculated the
905 // storage needs to be, we must assume the variable size from GetVariable is correct and not
906 // allow the truncation of the variable. It is very possible that the user who created the IFR
907 // we are cracking is not referring to a variable that was in a previous map, however we cannot
908 // allow it's truncation.
909 //
910 if (Status == EFI_BUFFER_TOO_SMALL) {
911 //
912 // Free the buffer that was allocated that was too small
913 //
914 gBS->FreePool (VariableData);
915
916 VariableData = AllocatePool (SizeOfNvStore);
917 if (VariableData == NULL) {
918 return EFI_OUT_OF_RESOURCES;
919 }
920
921 Status = gRT->GetVariable (
922 (CHAR16 *) L"Setup",
923 &Guid,
924 NULL,
925 &SizeOfNvStore,
926 (VOID *) VariableData
927 );
928 }
929 }
930
931 //
932 // Walk through the form and see that the variable data it refers to is ok.
933 // This allows for the possibility of stale (obsoleted) data in the variable
934 // can be overlooked without causing an error
935 //
936 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
937 switch (RawData[Index]) {
938 case EFI_IFR_ONE_OF_OP:
939 //
940 // A one_of has no data, its the option that does - cache the storage Id
941 //
942 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
943 break;
944
945 case EFI_IFR_ONE_OF_OPTION_OP:
946 //
947 // A one_of_option can be any value
948 //
949 if (VariableData[CachedStart] == ((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) {
950 GotMatch = TRUE;
951 }
952 break;
953
954 case EFI_IFR_END_ONE_OF_OP:
955 //
956 // At this point lets make sure that the data value in the NVRAM matches one of the options
957 //
958 if (!GotMatch) {
959 *Results = FALSE;
960 return EFI_SUCCESS;
961 }
962 break;
963
964 case EFI_IFR_CHECKBOX_OP:
965 //
966 // A checkbox is a boolean, so 0 and 1 are valid
967 // Remember, QuestionId corresponds to the offset location of the data in the variable
968 //
969 if (VariableData[((EFI_IFR_CHECKBOX *) &RawData[Index])->QuestionId] > 1) {
970 *Results = FALSE;
971 return EFI_SUCCESS;
972 }
973 break;
974
975 case EFI_IFR_NUMERIC_OP:
976 if ((VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) ||
977 (VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) {
978 *Results = FALSE;
979 return EFI_SUCCESS;
980 }
981 break;
982
983 }
984
985 Index = RawData[Index + 1] + Index;
986 }
987
988 //
989 // Free our temporary repository of form data
990 //
991 gBS->FreePool (OldData);
992 gBS->FreePool (VariableData);
993
994 return EFI_SUCCESS;
995 }
996