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