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