]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/ExtendedIfrSupportLib/Form.c
Sync in bug fix from EDK I:
[mirror_edk2.git] / MdeModulePkg / Library / ExtendedIfrSupportLib / Form.c
CommitLineData
8dbae30d 1/** @file\r
2 Common Library Routines to assist handle HII elements.\r
3\r
4Copyright (c) 2007 - 2008, Intel Corporation. <BR>\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "LibraryInternal.h"\r
16\r
13492369 17extern EFI_HII_DATABASE_PROTOCOL *gIfrLibHiiDatabase;\r
18\r
6ca46b63 19/**\r
20 Get the specified package from a package list based on an index.\r
21 The Buffer on output is updated to point to a package header in\r
22 the HiiPackageList. This is an internal function.\r
23\r
24 @param HiiPackageList The Package List Header.\r
25 @param PackageIndex The index of the package to get.\r
26 @param BufferLen The length of the package.\r
27 @param Buffer The starting address of package.\r
28\r
29 @retval EFI_SUCCESS This function completes successfully.\r
30 @retval EFI_NOT_FOUND The package is not found.\r
31\r
32**/\r
8dbae30d 33EFI_STATUS\r
34GetPackageDataFromPackageList (\r
35 IN EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList,\r
36 IN UINT32 PackageIndex,\r
37 OUT UINT32 *BufferLen,\r
38 OUT EFI_HII_PACKAGE_HEADER **Buffer\r
39 )\r
40{\r
41 UINT32 Index;\r
42 EFI_HII_PACKAGE_HEADER *Package;\r
43 UINT32 Offset;\r
44 UINT32 PackageListLength;\r
6ca46b63 45 EFI_HII_PACKAGE_HEADER PackageHeader;\r
46\r
47 PackageHeader.Length = 0;\r
48 PackageHeader.Type = 0;\r
8dbae30d 49\r
50 ASSERT(HiiPackageList != NULL);\r
51\r
52 if ((BufferLen == NULL) || (Buffer == NULL)) {\r
53 return EFI_INVALID_PARAMETER;\r
54 }\r
55\r
56 Package = NULL;\r
57 Index = 0;\r
58 Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
59 CopyMem (&PackageListLength, &HiiPackageList->PackageLength, sizeof (UINT32));\r
60 while (Offset < PackageListLength) {\r
61 Package = (EFI_HII_PACKAGE_HEADER *) (((UINT8 *) HiiPackageList) + Offset);\r
62 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
63 if (Index == PackageIndex) {\r
64 break;\r
65 }\r
66 Offset += PackageHeader.Length;\r
67 Index++;\r
68 }\r
69 if (Offset >= PackageListLength) {\r
70 //\r
71 // no package found in this Package List\r
72 //\r
73 return EFI_NOT_FOUND;\r
74 }\r
75\r
76 *BufferLen = PackageHeader.Length;\r
77 *Buffer = Package;\r
78 return EFI_SUCCESS;\r
79}\r
80\r
6ca46b63 81/**\r
82 This is the internal worker function to update the data in\r
5df74ff8 83 a form specified by FormSetGuid, FormId and Label.\r
6ca46b63 84\r
85 @param FormSetGuid The optional Formset GUID.\r
86 @param FormId The form ID>\r
87 @param Package The package header.\r
88 @param PackageLength The package length.\r
89 @param Label The label for the update.\r
90 @param Insert True if inserting opcode to the form.\r
91 @param Data The data payload.\r
92 @param TempBuffer The resultant package.\r
93 @param TempBufferSize The length of the resultant package.\r
94\r
95 @retval EFI_OUT_OF_RESOURCES If there is not enough memory to complete the operation.\r
96 @retval EFI_INVALID_PARAMETER If TempBuffer or TempBufferSize is NULL.\r
97 @retval EFI_SUCCESS The function completes successfully.\r
98\r
99**/\r
8dbae30d 100EFI_STATUS\r
101EFIAPI\r
102UpdateFormPackageData (\r
6ca46b63 103 IN EFI_GUID *FormSetGuid, OPTIONAL\r
8dbae30d 104 IN EFI_FORM_ID FormId,\r
105 IN EFI_HII_PACKAGE_HEADER *Package,\r
106 IN UINT32 PackageLength,\r
107 IN UINT16 Label,\r
108 IN BOOLEAN Insert,\r
109 IN EFI_HII_UPDATE_DATA *Data,\r
110 OUT UINT8 **TempBuffer,\r
111 OUT UINT32 *TempBufferSize\r
112 )\r
113{\r
114 UINTN AddSize;\r
115 UINT8 *BufferPos;\r
116 EFI_HII_PACKAGE_HEADER PackageHeader;\r
117 UINTN Offset;\r
118 EFI_IFR_OP_HEADER *IfrOpHdr;\r
119 BOOLEAN GetFormSet;\r
120 BOOLEAN GetForm;\r
121 UINT8 ExtendOpCode;\r
122 UINT16 LabelNumber;\r
123 BOOLEAN Updated;\r
124 EFI_IFR_OP_HEADER *AddOpCode;\r
125\r
126 if ((TempBuffer == NULL) || (TempBufferSize == NULL)) {\r
127 return EFI_INVALID_PARAMETER;\r
128 }\r
129\r
130 *TempBufferSize = PackageLength;\r
131 if (Data != NULL) {\r
132 *TempBufferSize += Data->Offset;\r
133 }\r
134 *TempBuffer = AllocateZeroPool (*TempBufferSize);\r
135 if (*TempBuffer == NULL) {\r
136 return EFI_OUT_OF_RESOURCES;\r
137 }\r
138\r
139 CopyMem (*TempBuffer, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
140 *TempBufferSize = sizeof (EFI_HII_PACKAGE_HEADER);\r
141 BufferPos = *TempBuffer + sizeof (EFI_HII_PACKAGE_HEADER);\r
142\r
143 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
144 IfrOpHdr = (EFI_IFR_OP_HEADER *)((UINT8 *) Package + sizeof (EFI_HII_PACKAGE_HEADER));\r
145 Offset = sizeof (EFI_HII_PACKAGE_HEADER);\r
146 GetFormSet = (BOOLEAN) ((FormSetGuid == NULL) ? TRUE : FALSE);\r
147 GetForm = FALSE;\r
148 Updated = FALSE;\r
149\r
150 while (Offset < PackageHeader.Length) {\r
151 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);\r
152 BufferPos += IfrOpHdr->Length;\r
153 *TempBufferSize += IfrOpHdr->Length;\r
154\r
155 switch (IfrOpHdr->OpCode) {\r
156 case EFI_IFR_FORM_SET_OP :\r
157 if (FormSetGuid != NULL) {\r
158 if (CompareMem (&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid, sizeof (EFI_GUID)) == 0) {\r
159 GetFormSet = TRUE;\r
160 }\r
161 }\r
162 break;\r
163\r
164 case EFI_IFR_FORM_OP:\r
165 if (CompareMem (&((EFI_IFR_FORM *) IfrOpHdr)->FormId, &FormId, sizeof (EFI_FORM_ID)) == 0) {\r
166 GetForm = TRUE;\r
167 }\r
168 break;\r
169\r
170 case EFI_IFR_GUID_OP :\r
171 if (!GetFormSet || !GetForm || Updated) {\r
172 //\r
173 // Go to the next Op-Code\r
174 //\r
175 Offset += IfrOpHdr->Length;\r
176 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
177 continue;\r
178 }\r
179\r
180 ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;\r
181 CopyMem (&LabelNumber, &((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number, sizeof (UINT16));\r
182 if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label)) {\r
183 //\r
184 // Go to the next Op-Code\r
185 //\r
186 Offset += IfrOpHdr->Length;\r
187 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
188 continue;\r
189 }\r
190\r
191 if (Insert && (Data != NULL)) {\r
192 //\r
193 // insert the DataCount amount of opcodes to TempBuffer if Data is NULL remove\r
194 // DataCount amount of opcodes unless runing into a label.\r
195 //\r
196 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;\r
197 AddSize = 0;\r
198 while (AddSize < Data->Offset) {\r
199 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);\r
200 BufferPos += AddOpCode->Length;\r
201 *TempBufferSize += AddOpCode->Length;\r
202\r
203 AddSize += AddOpCode->Length;\r
204 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);\r
205 }\r
206 } else {\r
207 //\r
208 // Search the next Label.\r
209 //\r
210 while (TRUE) {\r
211 Offset += IfrOpHdr->Length;\r
212 //\r
213 // Search the next label and Fail if not label found.\r
214 //\r
215 if (Offset >= PackageHeader.Length) {\r
216 goto Fail;\r
217 }\r
218 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
219 if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) {\r
220 ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;\r
221 if (ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) {\r
222 break;\r
223 }\r
224 }\r
225 }\r
226\r
227 if (Data != NULL) {\r
228 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;\r
229 AddSize = 0;\r
230 while (AddSize < Data->Offset) {\r
231 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);\r
232 BufferPos += AddOpCode->Length;\r
233 *TempBufferSize += AddOpCode->Length;\r
234\r
235 AddSize += AddOpCode->Length;\r
236 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);\r
237 }\r
238 }\r
239\r
240 //\r
241 // copy the next label\r
242 //\r
243 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);\r
244 BufferPos += IfrOpHdr->Length;\r
245 *TempBufferSize += IfrOpHdr->Length;\r
246 }\r
247\r
248 Updated = TRUE;\r
249 break;\r
250 default :\r
251 break;\r
252 }\r
253\r
254 //\r
255 // Go to the next Op-Code\r
256 //\r
257 Offset += IfrOpHdr->Length;\r
258 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
259 }\r
260\r
261 //\r
262 // Update the package length.\r
263 //\r
264 PackageHeader.Length = *TempBufferSize;\r
265 CopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
266\r
267Fail:\r
268 if (!Updated) {\r
cfb9b643 269 FreePool (*TempBuffer);\r
8dbae30d 270 *TempBufferSize = 0;\r
271 return EFI_NOT_FOUND;\r
272 }\r
273\r
274 return EFI_SUCCESS;\r
275}\r
276\r
8d00a0f1 277/**\r
278 This function initialize the data structure for dynamic opcode.\r
279\r
280 @param UpdateData The adding data;\r
281 @param BufferSize Length of the buffer to fill dynamic opcodes.\r
282\r
283 @retval EFI_SUCCESS Update data is initialized.\r
284 @retval EFI_INVALID_PARAMETER UpdateData is NULL.\r
285 @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.\r
286\r
287**/\r
288EFI_STATUS\r
289IfrLibInitUpdateData (\r
290 IN OUT EFI_HII_UPDATE_DATA *UpdateData,\r
291 IN UINT32 BufferSize\r
292 )\r
293{\r
294 ASSERT (UpdateData != NULL);\r
295\r
296 UpdateData->BufferSize = BufferSize;\r
297 UpdateData->Offset = 0;\r
298 UpdateData->Data = AllocatePool (BufferSize);\r
299\r
300 return (UpdateData->Data != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
301}\r
302\r
303/**\r
304\r
305 This function free the resource of update data.\r
306\r
307 @param UpdateData The adding data;\r
308\r
309 @retval EFI_SUCCESS Resource in UpdateData is released.\r
310 @retval EFI_INVALID_PARAMETER UpdateData is NULL.\r
311\r
312**/\r
313EFI_STATUS\r
314IfrLibFreeUpdateData (\r
315 IN EFI_HII_UPDATE_DATA *UpdateData\r
316 )\r
317{\r
318 EFI_STATUS Status;\r
319\r
320 if (UpdateData == NULL) {\r
321 return EFI_INVALID_PARAMETER;\r
322 }\r
323\r
324 Status = gBS->FreePool (UpdateData->Data);\r
325 UpdateData->Data = NULL;\r
326\r
327 return Status;\r
328}\r
8dbae30d 329\r
330/**\r
331 This function allows the caller to update a form that has\r
332 previously been registered with the EFI HII database.\r
333\r
334 @param Handle Hii Handle\r
335 @param FormSetGuid The formset should be updated.\r
336 @param FormId The form should be updated.\r
337 @param Label Update information starting immediately after this\r
338 label in the IFR\r
339 @param Insert If TRUE and Data is not NULL, insert data after\r
340 Label. If FALSE, replace opcodes between two\r
341 labels with Data\r
342 @param Data The adding data; If NULL, remove opcodes between\r
343 two Label.\r
344\r
345 @retval EFI_SUCCESS Update success.\r
346 @retval Other Update fail.\r
347\r
348**/\r
349EFI_STATUS\r
350EFIAPI\r
351IfrLibUpdateForm (\r
352 IN EFI_HII_HANDLE Handle,\r
353 IN EFI_GUID *FormSetGuid, OPTIONAL\r
354 IN EFI_FORM_ID FormId,\r
355 IN UINT16 Label,\r
356 IN BOOLEAN Insert,\r
357 IN EFI_HII_UPDATE_DATA *Data\r
358 )\r
359{\r
360 EFI_STATUS Status;\r
361 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;\r
362 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
363 UINT32 Index;\r
364 EFI_HII_PACKAGE_LIST_HEADER *UpdateBuffer;\r
365 UINTN BufferSize;\r
366 UINT8 *UpdateBufferPos;\r
367 EFI_HII_PACKAGE_HEADER PackageHeader;\r
368 EFI_HII_PACKAGE_HEADER *Package;\r
369 UINT32 PackageLength;\r
370 EFI_HII_PACKAGE_HEADER *TempBuffer;\r
371 UINT32 TempBufferSize;\r
372 BOOLEAN Updated;\r
373\r
374 if (Data == NULL) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377\r
378 HiiDatabase = gIfrLibHiiDatabase;\r
379\r
380 //\r
381 // Get the orginal package list\r
382 //\r
383 BufferSize = 0;\r
384 HiiPackageList = NULL;\r
385 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
386 if (Status == EFI_BUFFER_TOO_SMALL) {\r
387 HiiPackageList = AllocatePool (BufferSize);\r
388 ASSERT (HiiPackageList != NULL);\r
389\r
390 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
391 if (EFI_ERROR (Status)) {\r
cfb9b643 392 FreePool (HiiPackageList);\r
8dbae30d 393 return Status;\r
394 }\r
395 }\r
396\r
397 //\r
398 // Calculate and allocate space for retrieval of IFR data\r
399 //\r
400 BufferSize += Data->Offset;\r
401 UpdateBuffer = AllocateZeroPool (BufferSize);\r
402 if (UpdateBuffer == NULL) {\r
403 return EFI_OUT_OF_RESOURCES;\r
404 }\r
405\r
406 UpdateBufferPos = (UINT8 *) UpdateBuffer;\r
407\r
408 //\r
409 // copy the package list header\r
410 //\r
411 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));\r
412 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
413\r
414 Updated = FALSE;\r
415 for (Index = 0; ; Index++) {\r
416 Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);\r
417 if (Status == EFI_SUCCESS) {\r
418 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
8d00a0f1 419 if ((PackageHeader.Type == EFI_HII_PACKAGE_FORMS) && !Updated) {\r
8dbae30d 420 Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);\r
421 if (!EFI_ERROR(Status)) {\r
422 if (FormSetGuid == NULL) {\r
423 Updated = TRUE;\r
424 }\r
425 CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);\r
426 UpdateBufferPos += TempBufferSize;\r
cfb9b643 427 FreePool (TempBuffer);\r
8dbae30d 428 continue;\r
429 }\r
430 }\r
431\r
432 CopyMem (UpdateBufferPos, Package, PackageLength);\r
433 UpdateBufferPos += PackageLength;\r
434 } else if (Status == EFI_NOT_FOUND) {\r
435 break;\r
436 } else {\r
cfb9b643 437 FreePool (HiiPackageList);\r
8dbae30d 438 return Status;\r
439 }\r
440 }\r
441\r
442 //\r
443 // Update package list length\r
444 //\r
445 BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;\r
446 CopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32));\r
447\r
cfb9b643 448 FreePool (HiiPackageList);\r
8dbae30d 449\r
450 return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);\r
451}\r
452\r
453\r
454/**\r
455 Configure the buffer accrording to ConfigBody strings.\r
456\r
6ca46b63 457 @param Buffer The start address of buffer.\r
458 @param BufferSize The size of buffer.\r
459 @param Number The number of the strings.\r
460 @param ... Variable argument list for default value in <AltResp> format \r
461 generated by the tool.\r
8dbae30d 462\r
463 @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate.\r
464 @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0.\r
465 @retval EFI_SUCCESS Operation successful.\r
466\r
467**/\r
468EFI_STATUS\r
469EFIAPI\r
470IfrLibExtractDefault(\r
471 IN VOID *Buffer,\r
472 IN UINTN *BufferSize,\r
473 UINTN Number,\r
474 ...\r
475 )\r
476{\r
477 VA_LIST Args;\r
478 UINTN Index;\r
479 UINT32 TotalLen;\r
480 UINT8 *BufCfgArray;\r
481 UINT8 *BufferPos;\r
482 UINT16 Offset;\r
483 UINT16 Width;\r
484 UINT8 *Value;\r
485\r
486 if ((Buffer == NULL) || (BufferSize == NULL)) {\r
487 return EFI_INVALID_PARAMETER;\r
488 }\r
489\r
490 Offset = 0;\r
491 Width = 0;\r
492 Value = NULL;\r
493\r
494 VA_START (Args, Number);\r
495 for (Index = 0; Index < Number; Index++) {\r
496 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);\r
497 CopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));\r
498 BufferPos = BufCfgArray + sizeof (UINT32);\r
499\r
500 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {\r
501 CopyMem (&Offset, BufferPos, sizeof (UINT16));\r
502 BufferPos += sizeof (UINT16);\r
503 CopyMem (&Width, BufferPos, sizeof (UINT16));\r
504 BufferPos += sizeof (UINT16);\r
505 Value = BufferPos;\r
506 BufferPos += Width;\r
507\r
508 if ((UINTN)(Offset + Width) > *BufferSize) {\r
509 return EFI_BUFFER_TOO_SMALL;\r
510 }\r
511\r
512 CopyMem ((UINT8 *)Buffer + Offset, Value, Width);\r
513 }\r
514 }\r
515 VA_END (Args);\r
516\r
517 *BufferSize = (UINTN)Offset;\r
518\r
519 return EFI_SUCCESS;\r
520}\r
521\r
522\r