]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/Dxe/EfiIfrSupportLib/IfrCommon.c
Fix various warnings with the Intel C compiler.
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / Dxe / EfiIfrSupportLib / IfrCommon.c
1 /*++
2 Copyright (c) 2004 - 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 Module Name:
12 IfrCommon.c
13
14 Abstract:
15
16 Common Library Routines to assist in IFR creation on-the-fly
17
18 --*/
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 #ifdef SUPPORT_DEPRECATED_IFRSUPPORTLIB_API
494
495 EFI_STATUS Status;
496 EFI_HII_PROTOCOL *Hii;
497 UINTN DataLength;
498 UINT8 *RawData;
499 UINT8 *OldData;
500 UINTN Index;
501 UINTN Temp;
502 UINTN SizeOfNvStore;
503 UINTN CachedStart;
504
505 DataLength = DEFAULT_FORM_BUFFER_SIZE;
506 SizeOfNvStore = 0;
507 CachedStart = 0;
508
509 Status = GetHiiInterface (&Hii);
510
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 //
516 // Allocate space for retrieval of IFR data
517 //
518 RawData = EfiLibAllocateZeroPool ((UINTN) DataLength);
519 if (RawData == NULL) {
520 return EFI_OUT_OF_RESOURCES;
521 }
522
523 //
524 // Get all the forms associated with this HiiHandle
525 //
526 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
527
528 if (EFI_ERROR (Status)) {
529 gBS->FreePool (RawData);
530
531 //
532 // Allocate space for retrieval of IFR data
533 //
534 RawData = EfiLibAllocateZeroPool ((UINTN) DataLength);
535 if (RawData == NULL) {
536 return EFI_OUT_OF_RESOURCES;
537 }
538
539 //
540 // Get all the forms associated with this HiiHandle
541 //
542 Status = Hii->GetForms (Hii, HiiHandle, 0, &DataLength, RawData);
543 }
544
545 OldData = RawData;
546
547 //
548 // Point RawData to the beginning of the form data
549 //
550 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
551
552 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
553 switch (RawData[Index]) {
554 case EFI_IFR_FORM_SET_OP:
555 //
556 // Copy the GUID information from this handle
557 //
558 EfiCopyMem (Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
559 break;
560
561 case EFI_IFR_ONE_OF_OP:
562 case EFI_IFR_CHECKBOX_OP:
563 case EFI_IFR_NUMERIC_OP:
564 case EFI_IFR_DATE_OP:
565 case EFI_IFR_TIME_OP:
566 case EFI_IFR_PASSWORD_OP:
567 case EFI_IFR_STRING_OP:
568 //
569 // Remember, multiple op-codes may reference the same item, so let's keep a running
570 // marker of what the highest QuestionId that wasn't zero length. This will accurately
571 // maintain the Size of the NvStore
572 //
573 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
574 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
575 if (SizeOfNvStore < Temp) {
576 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
577 }
578 }
579 }
580
581 Index = RawData[Index + 1] + Index;
582 }
583
584 //
585 // Return an error if buffer is too small
586 //
587 if (SizeOfNvStore > *ImageLength) {
588 gBS->FreePool (OldData);
589 *ImageLength = (UINT16) SizeOfNvStore;
590 return EFI_BUFFER_TOO_SMALL;
591 }
592
593 EfiZeroMem (DefaultImage, SizeOfNvStore);
594
595 //
596 // Copy the default image information to the user's buffer
597 //
598 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
599 switch (RawData[Index]) {
600 case EFI_IFR_ONE_OF_OP:
601 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
602 break;
603
604 case EFI_IFR_ONE_OF_OPTION_OP:
605 if (((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Flags & EFI_IFR_FLAG_DEFAULT) {
606 EfiCopyMem (&DefaultImage[CachedStart], &((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value, 2);
607 }
608 break;
609
610 case EFI_IFR_CHECKBOX_OP:
611 DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId] = ((EFI_IFR_CHECK_BOX *) &RawData[Index])->Flags;
612 break;
613
614 case EFI_IFR_NUMERIC_OP:
615 EfiCopyMem (
616 &DefaultImage[((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId],
617 &((EFI_IFR_NUMERIC *) &RawData[Index])->Default,
618 2
619 );
620 break;
621
622 }
623
624 Index = RawData[Index + 1] + Index;
625 }
626
627 *ImageLength = (UINT16) SizeOfNvStore;
628
629 //
630 // Free our temporary repository of form data
631 //
632 gBS->FreePool (OldData);
633
634 return EFI_SUCCESS;
635 #else
636 //
637 // The implementation will be added later.
638 //
639 ASSERT (FALSE);
640 return EFI_UNSUPPORTED;
641 #endif
642 }
643
644
645 EFI_HII_HANDLE
646 FindHiiHandle (
647 IN OUT EFI_HII_PROTOCOL **HiiProtocol, OPTIONAL
648 IN EFI_GUID *Guid
649 )
650 /*++
651
652 Routine Description:
653 Finds HII handle for given pack GUID previously registered with the HII.
654
655 Arguments:
656 HiiProtocol - pointer to pointer to HII protocol interface.
657 If NULL, the interface will be found but not returned.
658 If it points to NULL, the interface will be found and
659 written back to the pointer that is pointed to.
660 Guid - The GUID of the pack that registered with the HII.
661
662 Returns:
663 Handle to the HII pack previously registered by the memory driver.
664
665 --*/
666 {
667 #ifdef SUPPORT_DEPRECATED_IFRSUPPORTLIB_API
668 EFI_STATUS Status;
669
670 EFI_HII_HANDLE *HiiHandleBuffer;
671 EFI_HII_HANDLE HiiHandle;
672 UINT16 HiiHandleBufferLength;
673 UINT32 NumberOfHiiHandles;
674 EFI_GUID HiiGuid;
675 EFI_HII_PROTOCOL *HiiProt;
676 UINT32 Index;
677 UINT16 Length;
678
679 HiiHandle = 0;
680 if ((HiiProtocol != NULL) && (*HiiProtocol != NULL)) {
681 //
682 // The protocol has been passed in
683 //
684 HiiProt = *HiiProtocol;
685 } else {
686 gBS->LocateProtocol (
687 &gEfiHiiProtocolGuid,
688 NULL,
689 (VOID **) &HiiProt
690 );
691 if (HiiProt == NULL) {
692 return HiiHandle;
693 }
694
695 if (HiiProtocol != NULL) {
696 //
697 // Return back the HII protocol for the caller as promissed
698 //
699 *HiiProtocol = HiiProt;
700 }
701 }
702 //
703 // Allocate buffer
704 //
705 HiiHandleBufferLength = 10;
706 HiiHandleBuffer = EfiLibAllocatePool (HiiHandleBufferLength);
707 ASSERT (HiiHandleBuffer != NULL);
708
709 //
710 // Get the Handles of the packages that were registered with Hii
711 //
712 Status = HiiProt->FindHandles (
713 HiiProt,
714 &HiiHandleBufferLength,
715 HiiHandleBuffer
716 );
717
718 //
719 // Get a bigger bugffer if this one is to small, and try again
720 //
721 if (Status == EFI_BUFFER_TOO_SMALL) {
722
723 gBS->FreePool (HiiHandleBuffer);
724
725 HiiHandleBuffer = EfiLibAllocatePool (HiiHandleBufferLength);
726 ASSERT (HiiHandleBuffer != NULL);
727
728 Status = HiiProt->FindHandles (
729 HiiProt,
730 &HiiHandleBufferLength,
731 HiiHandleBuffer
732 );
733 }
734
735 if (EFI_ERROR (Status)) {
736 goto lbl_exit;
737 }
738
739 NumberOfHiiHandles = HiiHandleBufferLength / sizeof (EFI_HII_HANDLE);
740
741 //
742 // Iterate Hii handles and look for the one that matches our Guid
743 //
744 for (Index = 0; Index < NumberOfHiiHandles; Index++) {
745
746 Length = 0;
747 ExtractDataFromHiiHandle (HiiHandleBuffer[Index], &Length, NULL, &HiiGuid);
748
749 if (EfiCompareGuid (&HiiGuid, Guid)) {
750
751 HiiHandle = HiiHandleBuffer[Index];
752 break;
753 }
754 }
755
756 lbl_exit:
757 gBS->FreePool (HiiHandleBuffer);
758 return HiiHandle;
759 #else
760 //
761 // The implementation will be added later.
762 //
763 ASSERT (FALSE);
764 return (EFI_HII_HANDLE) 0;
765 #endif
766 }
767
768 #ifdef SUPPORT_DEPRECATED_IFRSUPPORTLIB_API
769 EFI_STATUS
770 ValidateDataFromHiiHandle (
771 IN EFI_HII_HANDLE HiiHandle,
772 OUT BOOLEAN *Results
773 )
774 /*++
775
776 Routine Description:
777
778 Validate that the data associated with the HiiHandle in NVRAM is within
779 the reasonable parameters for that FormSet. Values for strings and passwords
780 are not verified due to their not having the equivalent of valid range settings.
781
782 Arguments:
783
784 HiiHandle - Handle of the HII database entry to query
785
786 Results - If return Status is EFI_SUCCESS, Results provides valid data
787 TRUE = NVRAM Data is within parameters
788 FALSE = NVRAM Data is NOT within parameters
789
790 Returns:
791
792 EFI_OUT_OF_RESOURCES - No enough buffer to allocate
793
794 EFI_SUCCESS - Data successfully validated
795 --*/
796 {
797 EFI_STATUS Status;
798 EFI_HII_PROTOCOL *Hii;
799 EFI_GUID Guid;
800 UINT8 *RawData;
801 UINT8 *OldData;
802 UINTN RawDataLength;
803 UINT8 *VariableData;
804 UINTN Index;
805 UINTN Temp;
806 UINTN SizeOfNvStore;
807 UINTN CachedStart;
808 BOOLEAN GotMatch;
809
810 RawDataLength = DEFAULT_FORM_BUFFER_SIZE;
811 SizeOfNvStore = 0;
812 CachedStart = 0;
813 GotMatch = FALSE;
814 *Results = TRUE;
815
816 Status = GetHiiInterface (&Hii);
817
818 if (EFI_ERROR (Status)) {
819 return Status;
820 }
821
822 //
823 // Allocate space for retrieval of IFR data
824 //
825 RawData = EfiLibAllocateZeroPool (RawDataLength);
826 if (RawData == NULL) {
827 return EFI_OUT_OF_RESOURCES;
828 }
829
830 //
831 // Get all the forms associated with this HiiHandle
832 //
833 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
834
835 if (EFI_ERROR (Status)) {
836 gBS->FreePool (RawData);
837
838 //
839 // Allocate space for retrieval of IFR data
840 //
841 RawData = EfiLibAllocateZeroPool (RawDataLength);
842 if (RawData == NULL) {
843 return EFI_OUT_OF_RESOURCES;
844 }
845
846 //
847 // Get all the forms associated with this HiiHandle
848 //
849 Status = Hii->GetForms (Hii, HiiHandle, 0, &RawDataLength, RawData);
850 }
851
852 OldData = RawData;
853
854 //
855 // Point RawData to the beginning of the form data
856 //
857 RawData = (UINT8 *) ((UINTN) RawData + sizeof (EFI_HII_PACK_HEADER));
858
859 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
860 if (RawData[Index] == EFI_IFR_FORM_SET_OP) {
861 EfiCopyMem (&Guid, &((EFI_IFR_FORM_SET *) &RawData[Index])->Guid, sizeof (EFI_GUID));
862 break;
863 }
864
865 Index = RawData[Index + 1] + Index;
866 }
867
868 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
869 switch (RawData[Index]) {
870 case EFI_IFR_FORM_SET_OP:
871 break;
872
873 case EFI_IFR_ONE_OF_OP:
874 case EFI_IFR_CHECKBOX_OP:
875 case EFI_IFR_NUMERIC_OP:
876 case EFI_IFR_DATE_OP:
877 case EFI_IFR_TIME_OP:
878 case EFI_IFR_PASSWORD_OP:
879 case EFI_IFR_STRING_OP:
880 //
881 // Remember, multiple op-codes may reference the same item, so let's keep a running
882 // marker of what the highest QuestionId that wasn't zero length. This will accurately
883 // maintain the Size of the NvStore
884 //
885 if (((EFI_IFR_ONE_OF *) &RawData[Index])->Width != 0) {
886 Temp = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
887 if (SizeOfNvStore < Temp) {
888 SizeOfNvStore = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId + ((EFI_IFR_ONE_OF *) &RawData[Index])->Width;
889 }
890 }
891 }
892
893 Index = RawData[Index + 1] + Index;
894 }
895
896 //
897 // Allocate memory for our File Form Tags
898 //
899 VariableData = EfiLibAllocateZeroPool (SizeOfNvStore);
900 if (VariableData == NULL) {
901 return EFI_OUT_OF_RESOURCES;
902 }
903
904 Status = gRT->GetVariable (
905 L"Setup",
906 &Guid,
907 NULL,
908 &SizeOfNvStore,
909 (VOID *) VariableData
910 );
911
912 if (EFI_ERROR (Status)) {
913
914 //
915 // If there is a variable that exists already and it is larger than what we calculated the
916 // storage needs to be, we must assume the variable size from GetVariable is correct and not
917 // allow the truncation of the variable. It is very possible that the user who created the IFR
918 // we are cracking is not referring to a variable that was in a previous map, however we cannot
919 // allow it's truncation.
920 //
921 if (Status == EFI_BUFFER_TOO_SMALL) {
922 //
923 // Free the buffer that was allocated that was too small
924 //
925 gBS->FreePool (VariableData);
926
927 VariableData = EfiLibAllocatePool (SizeOfNvStore);
928 if (VariableData == NULL) {
929 return EFI_OUT_OF_RESOURCES;
930 }
931
932 Status = gRT->GetVariable (
933 L"Setup",
934 &Guid,
935 NULL,
936 &SizeOfNvStore,
937 (VOID *) VariableData
938 );
939 }
940 }
941
942 //
943 // Walk through the form and see that the variable data it refers to is ok.
944 // This allows for the possibility of stale (obsoleted) data in the variable
945 // can be overlooked without causing an error
946 //
947 for (Index = 0; RawData[Index] != EFI_IFR_END_FORM_SET_OP;) {
948 switch (RawData[Index]) {
949 case EFI_IFR_ONE_OF_OP:
950 //
951 // A one_of has no data, its the option that does - cache the storage Id
952 //
953 CachedStart = ((EFI_IFR_ONE_OF *) &RawData[Index])->QuestionId;
954 break;
955
956 case EFI_IFR_ONE_OF_OPTION_OP:
957 //
958 // A one_of_option can be any value
959 //
960 if (VariableData[CachedStart] == ((EFI_IFR_ONE_OF_OPTION *) &RawData[Index])->Value) {
961 GotMatch = TRUE;
962 }
963 break;
964
965 case EFI_IFR_END_ONE_OF_OP:
966 //
967 // At this point lets make sure that the data value in the NVRAM matches one of the options
968 //
969 if (!GotMatch) {
970 *Results = FALSE;
971 return EFI_SUCCESS;
972 }
973 break;
974
975 case EFI_IFR_CHECKBOX_OP:
976 //
977 // A checkbox is a boolean, so 0 and 1 are valid
978 // Remember, QuestionId corresponds to the offset location of the data in the variable
979 //
980 if (VariableData[((EFI_IFR_CHECK_BOX *) &RawData[Index])->QuestionId] > 1) {
981 *Results = FALSE;
982 return EFI_SUCCESS;
983 }
984 break;
985
986 case EFI_IFR_NUMERIC_OP:
987 if ((VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] < ((EFI_IFR_NUMERIC *)&RawData[Index])->Minimum) ||
988 (VariableData[((EFI_IFR_NUMERIC *)&RawData[Index])->QuestionId] > ((EFI_IFR_NUMERIC *)&RawData[Index])->Maximum)) {
989 *Results = FALSE;
990 return EFI_SUCCESS;
991 }
992 break;
993
994 }
995
996 Index = RawData[Index + 1] + Index;
997 }
998
999 //
1000 // Free our temporary repository of form data
1001 //
1002 gBS->FreePool (OldData);
1003 gBS->FreePool (VariableData);
1004
1005 return EFI_SUCCESS;
1006 }
1007 #endif
1008
1009 EFI_HII_PACKAGES *
1010 PreparePackages (
1011 IN UINTN NumberOfPackages,
1012 IN EFI_GUID *GuidId,
1013 ...
1014 )
1015 /*++
1016
1017 Routine Description:
1018
1019 Assemble EFI_HII_PACKAGES according to the passed in packages.
1020
1021 Arguments:
1022
1023 NumberOfPackages - Number of packages.
1024 GuidId - Package GUID.
1025
1026 Returns:
1027
1028 Pointer of EFI_HII_PACKAGES.
1029
1030 --*/
1031 {
1032 VA_LIST args;
1033 EFI_HII_PACKAGES *HiiPackages;
1034 VOID **Package;
1035 UINTN Index;
1036
1037 ASSERT (NumberOfPackages > 0);
1038
1039 HiiPackages = EfiLibAllocateZeroPool (sizeof (EFI_HII_PACKAGES) + NumberOfPackages * sizeof (VOID *));
1040
1041 HiiPackages->GuidId = GuidId;
1042 HiiPackages->NumberOfPackages = NumberOfPackages;
1043 Package = (VOID **) (((UINT8 *) HiiPackages) + sizeof (EFI_HII_PACKAGES));
1044
1045 VA_START (args, GuidId);
1046
1047 for (Index = 0; Index < NumberOfPackages; Index++) {
1048 *Package = VA_ARG (args, VOID *);
1049 Package++;
1050 }
1051
1052 VA_END (args);
1053
1054 return HiiPackages;
1055 }