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