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