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