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