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