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