]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkPkg/Library/FrameworkIfrSupportLib/IfrCommon.c
Fix VS2005 build error
[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 EFIAPI
30 GetCurrentLanguage (
31 OUT CHAR16 *Lang
32 )
33 {
34 EFI_STATUS Status;
35 UINTN Size;
36 UINTN Index;
37 CHAR8 Language[4];
38
39 //
40 // Getting the system language and placing it into our Global Data
41 //
42 Size = sizeof (Language);
43 Status = gRT->GetVariable (
44 (CHAR16 *) L"Lang",
45 &gEfiGlobalVariableGuid,
46 NULL,
47 &Size,
48 Language
49 );
50 if (EFI_ERROR (Status)) {
51 AsciiStrCpy (Language, "eng");
52 }
53
54 for (Index = 0; Index < 3; Index++) {
55 //
56 // Bitwise AND ascii value with 0xDF yields an uppercase value.
57 // Sign extend into a unicode value
58 //
59 Lang[Index] = (CHAR16) (Language[Index] & 0xDF);
60 }
61
62 //
63 // Null-terminate the value
64 //
65 Lang[3] = (CHAR16) 0;
66
67 return Status;
68 }
69
70 /**
71 Add a string to the incoming buffer and return the token and offset data.
72
73 @param StringBuffer The incoming buffer
74 @param Language Currrent language
75 @param String The string to be added
76 @param StringToken The index where the string placed
77
78 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
79 @retval EFI_SUCCESS String successfully added to the incoming buffer
80 **/
81 EFI_STATUS
82 EFIAPI
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 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 EFIAPI
292 AddOpCode (
293 IN VOID *FormBuffer,
294 IN OUT VOID *OpCodeData
295 )
296 {
297 EFI_HII_PACK_HEADER *NewBuffer;
298 UINT8 *Source;
299 UINT8 *Destination;
300
301 //
302 // Pre-allocate a buffer sufficient for us to work on.
303 // We will use it as a destination scratch pad to build data on
304 // and when complete shift the data back to the original buffer
305 //
306 NewBuffer = AllocateZeroPool (DEFAULT_FORM_BUFFER_SIZE);
307 if (NewBuffer == NULL) {
308 return EFI_OUT_OF_RESOURCES;
309 }
310
311 //
312 // Copy the IFR Package header to the new buffer
313 //
314 Source = (UINT8 *) FormBuffer;
315 Destination = (UINT8 *) NewBuffer;
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 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
355 Destination = Destination + (UINTN) ((FRAMEWORK_EFI_IFR_OP_HEADER *) OpCodeData)->Length;
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 // Copy end-formset data to new buffer
365 //
366 Destination = Destination + (UINTN) ((FRAMEWORK_EFI_IFR_OP_HEADER *) Source)->Length;
367 Source = Source + (UINTN) ((FRAMEWORK_EFI_IFR_OP_HEADER *) Source)->Length;
368 CopyMem (Destination, Source, ((FRAMEWORK_EFI_IFR_OP_HEADER *) Source)->Length);
369
370 //
371 // Zero out the original buffer and copy the updated data in the new buffer to the old buffer
372 //
373 ZeroMem (FormBuffer, DEFAULT_FORM_BUFFER_SIZE);
374 CopyMem (FormBuffer, NewBuffer, DEFAULT_FORM_BUFFER_SIZE);
375
376 //
377 // Free the newly created buffer since we don't need it anymore
378 //
379 FreePool (NewBuffer);
380 return EFI_SUCCESS;
381 }
382
383 /**
384 Get the HII protocol interface.
385
386 @param Hii HII protocol interface
387
388 @return the statue of locating HII protocol
389 **/
390 EFI_STATUS
391 EFIAPI
392 GetHiiInterface (
393 OUT EFI_HII_PROTOCOL **Hii
394 )
395 {
396 EFI_STATUS Status;
397
398 //
399 // There should only be one HII protocol
400 //
401 Status = gBS->LocateProtocol (
402 &gEfiHiiProtocolGuid,
403 NULL,
404 (VOID **) Hii
405 );
406
407 return Status;;
408 }
409
410 /**
411 Extract information pertaining to the HiiHandle.
412
413 @param HiiHandle Hii handle
414 @param ImageLength For input, length of DefaultImage;
415 For output, length of actually required
416 @param DefaultImage Image buffer prepared by caller
417 @param Guid Guid information about the form
418
419 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
420 @retval EFI_BUFFER_TOO_SMALL DefualtImage has no enough ImageLength
421 @retval EFI_SUCCESS Successfully extract data from Hii database.
422 **/
423 EFI_STATUS
424 EFIAPI
425 ExtractDataFromHiiHandle (
426 IN FRAMEWORK_EFI_HII_HANDLE HiiHandle,
427 IN OUT UINT16 *ImageLength,
428 OUT UINT8 *DefaultImage,
429 OUT EFI_GUID *Guid
430 )
431 {
432 EFI_STATUS Status;
433 EFI_HII_PROTOCOL *Hii;
434 UINTN DataLength;
435 UINT8 *RawData;
436 UINT8 *OldData;
437 UINTN Index;
438 UINTN Temp;
439 UINTN SizeOfNvStore;
440 UINTN CachedStart;
441
442 DataLength = DEFAULT_FORM_BUFFER_SIZE;
443 SizeOfNvStore = 0;
444 CachedStart = 0;
445
446 Status = GetHiiInterface (&Hii);
447 if (EFI_ERROR (Status)) {
448 return Status;
449 }
450
451 //
452 // Allocate space for retrieval of IFR data
453 //
454 RawData = AllocateZeroPool (DataLength);
455 if (RawData == NULL) {
456 return EFI_OUT_OF_RESOURCES;
457 }
458
459 //
460 // Get all the forms associated with this HiiHandle
461 //
462 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
463 if (EFI_ERROR (Status)) {
464 FreePool (RawData);
465
466 //
467 // Allocate space for retrieval of IFR data
468 //
469 RawData = AllocateZeroPool (DataLength);
470 if (RawData == NULL) {
471 return EFI_OUT_OF_RESOURCES;
472 }
473
474 //
475 // Get all the forms associated with this HiiHandle
476 //
477 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
478 }
479
480 OldData = RawData;
481
482 //
483 // Point RawData to the beginning of the form data
484 //
485 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
486
487 for (Index = 0; RawData[Index] != FRAMEWORK_EFI_IFR_END_FORM_SET_OP;) {
488 switch (RawData[Index]) {
489
490 case FRAMEWORK_EFI_IFR_FORM_SET_OP:
491 //
492 // Copy the GUID information from this handle
493 //
494 CopyGuid (Guid, (GUID *)(VOID *)&((FRAMEWORK_EFI_IFR_FORM_SET *) &RawData[Index])->Guid);
495 break;
496
497 case FRAMEWORK_EFI_IFR_ONE_OF_OP:
498 case FRAMEWORK_EFI_IFR_CHECKBOX_OP:
499 case FRAMEWORK_EFI_IFR_NUMERIC_OP:
500 case FRAMEWORK_EFI_IFR_DATE_OP:
501 case FRAMEWORK_EFI_IFR_TIME_OP:
502 case FRAMEWORK_EFI_IFR_PASSWORD_OP:
503 case FRAMEWORK_EFI_IFR_STRING_OP:
504 //
505 // Remember, multiple op-codes may reference the same item, so let's keep a running
506 // marker of what the highest QuestionId that wasn't zero length. This will accurately
507 // maintain the Size of the NvStore
508 //
509 if (((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
510 Temp = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width;
511 if (SizeOfNvStore < Temp) {
512 SizeOfNvStore = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width;
513 }
514 }
515 }
516
517 Index = RawData[Index + 1] + Index;
518 }
519
520 //
521 // Return an error if buffer is too small
522 //
523 if (SizeOfNvStore > *ImageLength) {
524 FreePool (OldData);
525 *ImageLength = (UINT16) SizeOfNvStore;
526 return EFI_BUFFER_TOO_SMALL;
527 }
528
529 if (DefaultImage != NULL) {
530 ZeroMem (DefaultImage, SizeOfNvStore);
531 }
532
533 //
534 // Copy the default image information to the user's buffer
535 //
536 for (Index = 0; RawData[Index] != FRAMEWORK_EFI_IFR_END_FORM_SET_OP;) {
537 switch (RawData[Index]) {
538
539 case FRAMEWORK_EFI_IFR_ONE_OF_OP:
540 CachedStart = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
541 break;
542
543 case FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP:
544 if (((FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & FRAMEWORK_EFI_IFR_FLAG_DEFAULT) {
545 CopyMem (&DefaultImage[CachedStart], &((FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2);
546 }
547 break;
548
549 case FRAMEWORK_EFI_IFR_CHECKBOX_OP:
550 DefaultImage[((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((FRAMEWORK_EFI_IFR_CHECKBOX *) &RawData[Index])->Flags;
551 break;
552
553 case FRAMEWORK_EFI_IFR_NUMERIC_OP:
554 CopyMem (
555 &DefaultImage[((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId],
556 &((FRAMEWORK_EFI_IFR_NUMERIC *) &RawData[Index])->Default,
557 2
558 );
559 break;
560
561 }
562
563 Index = RawData[Index + 1] + Index;
564 }
565
566 *ImageLength = (UINT16) SizeOfNvStore;
567
568 //
569 // Free our temporary repository of form data
570 //
571 FreePool (OldData);
572
573 return EFI_SUCCESS;
574 }
575
576 /**
577 Finds HII handle for given pack GUID previously registered with the HII.
578
579 @param HiiProtocol pointer to pointer to HII protocol interface.
580 If NULL, the interface will be found but not returned.
581 If it points to NULL, the interface will be found and
582 written back to the pointer that is pointed to.
583 @param Guid The GUID of the pack that registered with the HII.
584
585 @return Handle to the HII pack previously registered by the memory driver.
586 **/
587 FRAMEWORK_EFI_HII_HANDLE
588 EFIAPI
589 FindHiiHandle (
590 IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL
591 IN EFI_GUID *Guid
592 )
593 {
594 EFI_STATUS Status;
595 FRAMEWORK_EFI_HII_HANDLE *HiiHandleBuffer;
596 FRAMEWORK_EFI_HII_HANDLE HiiHandle;
597 UINT16 HiiHandleBufferLength;
598 UINT32 NumberOfHiiHandles;
599 EFI_GUID HiiGuid;
600 EFI_HII_PROTOCOL *HiiProt;
601 UINT32 Index;
602 UINT16 Length;
603
604 HiiHandle = 0;
605 if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) {
606 //
607 // The protocol has been passed in
608 //
609 HiiProt = *HiiProtocol;
610 } else {
611 gBS->LocateProtocol (
612 &gEfiHiiProtocolGuid,
613 NULL,
614 (VOID **) &HiiProt
615 );
616 if (HiiProt == NULL) {
617 return HiiHandle;
618 }
619
620 if (HiiProtocol != NULL) {
621 //
622 // Return back the HII protocol for the caller as promissed
623 //
624 *HiiProtocol = HiiProt;
625 }
626 }
627 //
628 // Allocate buffer
629 //
630 HiiHandleBufferLength = 10;
631 HiiHandleBuffer = AllocatePool (HiiHandleBufferLength);
632 ASSERT (HiiHandleBuffer != NULL);
633
634 //
635 // Get the Handles of the packages that were registered with Hii
636 //
637 Status = HiiProt->FindHandles (
638 HiiProt,
639 &HiiHandleBufferLength,
640 HiiHandleBuffer
641 );
642
643 //
644 // Get a bigger bugffer if this one is to small, and try again
645 //
646 if (Status == EFI_BUFFER_TOO_SMALL) {
647
648 FreePool (HiiHandleBuffer);
649
650 HiiHandleBuffer = AllocatePool (HiiHandleBufferLength);
651 ASSERT (HiiHandleBuffer != NULL);
652
653 Status = HiiProt->FindHandles (
654 HiiProt,
655 &HiiHandleBufferLength,
656 HiiHandleBuffer
657 );
658 }
659
660 if (EFI_ERROR (Status)) {
661 goto lbl_exit;
662 }
663
664 NumberOfHiiHandles = HiiHandleBufferLength / sizeof (FRAMEWORK_EFI_HII_HANDLE );
665
666 //
667 // Iterate Hii handles and look for the one that matches our Guid
668 //
669 for (Index = 0; Index < NumberOfHiiHandles; Index++) {
670
671 Length = 0;
672 ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid);
673
674 if (CompareGuid (&HiiGuid, Guid)) {
675 HiiHandle = HiiHandleBuffer[Index];
676 break;
677 }
678 }
679
680 lbl_exit:
681 FreePool (HiiHandleBuffer);
682 return HiiHandle;
683 }
684
685 /**
686 Validate that the data associated with the HiiHandle in NVRAM is within
687 the reasonable parameters for that FormSet. Values for strings and passwords
688 are not verified due to their not having the equivalent of valid range settings.
689
690 @param HiiHandle Handle of the HII database entry to query
691 @param Results If return Status is EFI_SUCCESS, Results provides valid data
692 TRUE = NVRAM Data is within parameters
693 FALSE = NVRAM Data is NOT within parameters
694
695 @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
696 @retval EFI_SUCCESS Data successfully validated
697 **/
698 EFI_STATUS
699 EFIAPI
700 ValidateDataFromHiiHandle (
701 IN FRAMEWORK_EFI_HII_HANDLE HiiHandle,
702 OUT BOOLEAN *Results
703 )
704 {
705 EFI_STATUS Status;
706 EFI_HII_PROTOCOL *Hii;
707 EFI_GUID Guid;
708 UINT8 *RawData;
709 UINT8 *OldData;
710 UINTN RawDataLength;
711 UINT8 *VariableData;
712 UINTN Index;
713 UINTN Temp;
714 UINTN SizeOfNvStore;
715 UINTN CachedStart;
716 BOOLEAN GotMatch;
717
718 RawDataLength = DEFAULT_FORM_BUFFER_SIZE;
719 SizeOfNvStore = 0;
720 CachedStart = 0;
721 GotMatch = FALSE;
722 *Results = TRUE;
723
724 Status = GetHiiInterface (&Hii);
725 if (EFI_ERROR (Status)) {
726 return Status;
727 }
728
729 //
730 // Allocate space for retrieval of IFR data
731 //
732 RawData = AllocateZeroPool (RawDataLength);
733 if (RawData == NULL) {
734 return EFI_OUT_OF_RESOURCES;
735 }
736
737 //
738 // Get all the forms associated with this HiiHandle
739 //
740 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
741 if (EFI_ERROR (Status)) {
742 FreePool (RawData);
743
744 //
745 // Allocate space for retrieval of IFR data
746 //
747 RawData = AllocateZeroPool (RawDataLength);
748 if (RawData == NULL) {
749 return EFI_OUT_OF_RESOURCES;
750 }
751
752 //
753 // Get all the forms associated with this HiiHandle
754 //
755 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
756 }
757
758 OldData = RawData;
759
760 //
761 // Point RawData to the beginning of the form data
762 //
763 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
764
765 for (Index = 0; RawData[Index] != FRAMEWORK_EFI_IFR_END_FORM_SET_OP;) {
766 if (RawData[Index] == FRAMEWORK_EFI_IFR_FORM_SET_OP) {
767 CopyGuid (&Guid, (GUID *)(VOID *)&((FRAMEWORK_EFI_IFR_FORM_SET *) &RawData[Index])->Guid);
768 break;
769 }
770 Index = RawData[Index + 1] + Index;
771 }
772
773 for (Index = 0; RawData[Index] != FRAMEWORK_EFI_IFR_END_FORM_SET_OP;) {
774 switch (RawData[Index]) {
775
776 case FRAMEWORK_EFI_IFR_FORM_SET_OP:
777 break;
778
779 case FRAMEWORK_EFI_IFR_ONE_OF_OP:
780 case FRAMEWORK_EFI_IFR_CHECKBOX_OP:
781 case FRAMEWORK_EFI_IFR_NUMERIC_OP:
782 case FRAMEWORK_EFI_IFR_DATE_OP:
783 case FRAMEWORK_EFI_IFR_TIME_OP:
784 case FRAMEWORK_EFI_IFR_PASSWORD_OP:
785 case FRAMEWORK_EFI_IFR_STRING_OP:
786 //
787 // Remember, multiple op-codes may reference the same item, so let's keep a running
788 // marker of what the highest QuestionId that wasn't zero length. This will accurately
789 // maintain the Size of the NvStore
790 //
791 if (((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
792 Temp = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width;
793 if (SizeOfNvStore < Temp) {
794 SizeOfNvStore = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->Width;
795 }
796 }
797 }
798
799 Index = RawData[Index + 1] + Index;
800 }
801
802 //
803 // Allocate memory for our File Form Tags
804 //
805 VariableData = AllocateZeroPool (SizeOfNvStore);
806 if (VariableData == NULL) {
807 return EFI_OUT_OF_RESOURCES;
808 }
809
810 Status = gRT->GetVariable (
811 (CHAR16 *) L"Setup",
812 &Guid,
813 NULL,
814 &SizeOfNvStore,
815 (VOID *) VariableData
816 );
817
818 if (EFI_ERROR (Status)) {
819
820 //
821 // If there is a variable that exists already and it is larger than what we calculated the
822 // storage needs to be, we must assume the variable size from GetVariable is correct and not
823 // allow the truncation of the variable. It is very possible that the user who created the IFR
824 // we are cracking is not referring to a variable that was in a previous map, however we cannot
825 // allow it's truncation.
826 //
827 if (Status == EFI_BUFFER_TOO_SMALL) {
828 //
829 // Free the buffer that was allocated that was too small
830 //
831 FreePool (VariableData);
832
833 VariableData = AllocatePool (SizeOfNvStore);
834 if (VariableData == NULL) {
835 return EFI_OUT_OF_RESOURCES;
836 }
837
838 Status = gRT->GetVariable (
839 (CHAR16 *) L"Setup",
840 &Guid,
841 NULL,
842 &SizeOfNvStore,
843 (VOID *) VariableData
844 );
845 }
846 }
847
848 //
849 // Walk through the form and see that the variable data it refers to is ok.
850 // This allows for the possibility of stale (obsoleted) data in the variable
851 // can be overlooked without causing an error
852 //
853 for (Index = 0; RawData[Index] != FRAMEWORK_EFI_IFR_END_FORM_SET_OP;) {
854 switch (RawData[Index]) {
855
856 case FRAMEWORK_EFI_IFR_ONE_OF_OP:
857 //
858 // A one_of has no data, its the option that does - cache the storage Id
859 //
860 CachedStart = ((FRAMEWORK_EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
861 break;
862
863 case FRAMEWORK_EFI_IFR_ONE_OF_OPTION_OP:
864 //
865 // A one_of_option can be any value
866 //
867 if (VariableData[CachedStart] == ((FRAMEWORK_EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) {
868 GotMatch = TRUE;
869 }
870 break;
871
872 case FRAMEWORK_EFI_IFR_END_ONE_OF_OP:
873 //
874 // At this point lets make sure that the data value in the NVRAM matches one of the options
875 //
876 if (!GotMatch) {
877 *Results = FALSE;
878 return EFI_SUCCESS;
879 }
880 break;
881
882 case FRAMEWORK_EFI_IFR_CHECKBOX_OP:
883 //
884 // A checkbox is a boolean, so 0 and 1 are valid
885 // Remember, QuestionId corresponds to the offset location of the data in the variable
886 //
887 if (VariableData[((FRAMEWORK_EFI_IFR_CHECKBOX *) &RawData[Index])->QuestionId] > 1) {
888 *Results = FALSE;
889 return EFI_SUCCESS;
890 }
891 break;
892
893 case FRAMEWORK_EFI_IFR_NUMERIC_OP:
894 if ((VariableData[((FRAMEWORK_EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((FRAMEWORK_EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) ||
895 (VariableData[((FRAMEWORK_EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((FRAMEWORK_EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) {
896 *Results = FALSE;
897 return EFI_SUCCESS;
898 }
899 break;
900
901 }
902
903 Index = RawData[Index + 1] + Index;
904 }
905
906 //
907 // Free our temporary repository of form data
908 //
909 gBS->FreePool (OldData);
910 gBS->FreePool (VariableData);
911
912 return EFI_SUCCESS;
913 }
914
915