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