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