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