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