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