]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/ExtendedIfrSupportLib/Form.c
Replace CopyMem() which can be replaced by BaseLib's Read/WriteUnalianedXX() as these...
[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
53dff899 50 ASSERT (HiiPackageList != NULL);\r
8dbae30d 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
3a306c10 59 PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);\r
8dbae30d 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
53dff899 86 @param FormId The Form ID.\r
6ca46b63 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
3a306c10 181 LabelNumber = ReadUnaligned16 (&((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Number);\r
3597bcbe 182 if ((ExtendOpCode != EFI_IFR_EXTEND_OP_LABEL) || (LabelNumber != Label) \r
5cd6c13b 183 || !CompareGuid ((EFI_GUID *)(UINTN)(&((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Guid), &mIfrVendorGuid)) {\r
8dbae30d 184 //\r
185 // Go to the next Op-Code\r
186 //\r
187 Offset += IfrOpHdr->Length;\r
188 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
189 continue;\r
190 }\r
191\r
192 if (Insert && (Data != NULL)) {\r
193 //\r
194 // insert the DataCount amount of opcodes to TempBuffer if Data is NULL remove\r
195 // DataCount amount of opcodes unless runing into a label.\r
196 //\r
197 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;\r
198 AddSize = 0;\r
199 while (AddSize < Data->Offset) {\r
200 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);\r
201 BufferPos += AddOpCode->Length;\r
202 *TempBufferSize += AddOpCode->Length;\r
203\r
204 AddSize += AddOpCode->Length;\r
205 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);\r
206 }\r
207 } else {\r
208 //\r
209 // Search the next Label.\r
210 //\r
211 while (TRUE) {\r
212 Offset += IfrOpHdr->Length;\r
213 //\r
214 // Search the next label and Fail if not label found.\r
215 //\r
216 if (Offset >= PackageHeader.Length) {\r
217 goto Fail;\r
218 }\r
219 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
220 if (IfrOpHdr->OpCode == EFI_IFR_GUID_OP) {\r
221 ExtendOpCode = ((EFI_IFR_GUID_LABEL *) IfrOpHdr)->ExtendOpCode;\r
5cd6c13b 222 if ((ExtendOpCode == EFI_IFR_EXTEND_OP_LABEL) && CompareGuid ((EFI_GUID *)(UINTN)(&((EFI_IFR_GUID_LABEL *)IfrOpHdr)->Guid), &mIfrVendorGuid)) {\r
8dbae30d 223 break;\r
224 }\r
225 }\r
226 }\r
227\r
228 if (Data != NULL) {\r
229 AddOpCode = (EFI_IFR_OP_HEADER *)Data->Data;\r
230 AddSize = 0;\r
231 while (AddSize < Data->Offset) {\r
232 CopyMem (BufferPos, AddOpCode, AddOpCode->Length);\r
233 BufferPos += AddOpCode->Length;\r
234 *TempBufferSize += AddOpCode->Length;\r
235\r
236 AddSize += AddOpCode->Length;\r
237 AddOpCode = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (AddOpCode) + AddOpCode->Length);\r
238 }\r
239 }\r
240\r
241 //\r
242 // copy the next label\r
243 //\r
244 CopyMem (BufferPos, IfrOpHdr, IfrOpHdr->Length);\r
245 BufferPos += IfrOpHdr->Length;\r
246 *TempBufferSize += IfrOpHdr->Length;\r
247 }\r
248\r
249 Updated = TRUE;\r
250 break;\r
251 default :\r
252 break;\r
253 }\r
254\r
255 //\r
256 // Go to the next Op-Code\r
257 //\r
258 Offset += IfrOpHdr->Length;\r
259 IfrOpHdr = (EFI_IFR_OP_HEADER *) ((CHAR8 *) (IfrOpHdr) + IfrOpHdr->Length);\r
260 }\r
261\r
262 //\r
263 // Update the package length.\r
264 //\r
265 PackageHeader.Length = *TempBufferSize;\r
266 CopyMem (*TempBuffer, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER));\r
267\r
268Fail:\r
269 if (!Updated) {\r
cfb9b643 270 FreePool (*TempBuffer);\r
8dbae30d 271 *TempBufferSize = 0;\r
272 return EFI_NOT_FOUND;\r
273 }\r
274\r
275 return EFI_SUCCESS;\r
276}\r
277\r
8d00a0f1 278/**\r
279 This function initialize the data structure for dynamic opcode.\r
280\r
281 @param UpdateData The adding data;\r
282 @param BufferSize Length of the buffer to fill dynamic opcodes.\r
283\r
284 @retval EFI_SUCCESS Update data is initialized.\r
285 @retval EFI_INVALID_PARAMETER UpdateData is NULL.\r
286 @retval EFI_OUT_OF_RESOURCES No enough memory to allocate.\r
287\r
288**/\r
289EFI_STATUS\r
290IfrLibInitUpdateData (\r
291 IN OUT EFI_HII_UPDATE_DATA *UpdateData,\r
292 IN UINT32 BufferSize\r
293 )\r
294{\r
295 ASSERT (UpdateData != NULL);\r
296\r
297 UpdateData->BufferSize = BufferSize;\r
298 UpdateData->Offset = 0;\r
299 UpdateData->Data = AllocatePool (BufferSize);\r
300\r
301 return (UpdateData->Data != NULL) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;\r
302}\r
303\r
304/**\r
305\r
306 This function free the resource of update data.\r
307\r
308 @param UpdateData The adding data;\r
309\r
8d00a0f1 310**/\r
f875a4f1 311VOID\r
8d00a0f1 312IfrLibFreeUpdateData (\r
313 IN EFI_HII_UPDATE_DATA *UpdateData\r
314 )\r
315{\r
f875a4f1 316 ASSERT (UpdateData != NULL);\r
317 \r
318 FreePool (UpdateData->Data);\r
8d00a0f1 319 UpdateData->Data = NULL;\r
320\r
8d00a0f1 321}\r
8dbae30d 322\r
323/**\r
324 This function allows the caller to update a form that has\r
325 previously been registered with the EFI HII database.\r
326\r
327 @param Handle Hii Handle\r
328 @param FormSetGuid The formset should be updated.\r
329 @param FormId The form should be updated.\r
330 @param Label Update information starting immediately after this\r
331 label in the IFR\r
332 @param Insert If TRUE and Data is not NULL, insert data after\r
333 Label. If FALSE, replace opcodes between two\r
334 labels with Data\r
335 @param Data The adding data; If NULL, remove opcodes between\r
336 two Label.\r
337\r
338 @retval EFI_SUCCESS Update success.\r
339 @retval Other Update fail.\r
340\r
341**/\r
342EFI_STATUS\r
343EFIAPI\r
344IfrLibUpdateForm (\r
345 IN EFI_HII_HANDLE Handle,\r
346 IN EFI_GUID *FormSetGuid, OPTIONAL\r
347 IN EFI_FORM_ID FormId,\r
348 IN UINT16 Label,\r
349 IN BOOLEAN Insert,\r
350 IN EFI_HII_UPDATE_DATA *Data\r
351 )\r
352{\r
353 EFI_STATUS Status;\r
354 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;\r
355 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;\r
356 UINT32 Index;\r
357 EFI_HII_PACKAGE_LIST_HEADER *UpdateBuffer;\r
358 UINTN BufferSize;\r
359 UINT8 *UpdateBufferPos;\r
360 EFI_HII_PACKAGE_HEADER PackageHeader;\r
361 EFI_HII_PACKAGE_HEADER *Package;\r
362 UINT32 PackageLength;\r
363 EFI_HII_PACKAGE_HEADER *TempBuffer;\r
364 UINT32 TempBufferSize;\r
365 BOOLEAN Updated;\r
366\r
367 if (Data == NULL) {\r
368 return EFI_INVALID_PARAMETER;\r
369 }\r
370\r
371 HiiDatabase = gIfrLibHiiDatabase;\r
372\r
373 //\r
374 // Get the orginal package list\r
375 //\r
376 BufferSize = 0;\r
377 HiiPackageList = NULL;\r
378 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
379 if (Status == EFI_BUFFER_TOO_SMALL) {\r
380 HiiPackageList = AllocatePool (BufferSize);\r
381 ASSERT (HiiPackageList != NULL);\r
382\r
383 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);\r
384 if (EFI_ERROR (Status)) {\r
cfb9b643 385 FreePool (HiiPackageList);\r
8dbae30d 386 return Status;\r
387 }\r
388 }\r
389\r
390 //\r
391 // Calculate and allocate space for retrieval of IFR data\r
392 //\r
393 BufferSize += Data->Offset;\r
394 UpdateBuffer = AllocateZeroPool (BufferSize);\r
395 if (UpdateBuffer == NULL) {\r
396 return EFI_OUT_OF_RESOURCES;\r
397 }\r
398\r
399 UpdateBufferPos = (UINT8 *) UpdateBuffer;\r
400\r
401 //\r
402 // copy the package list header\r
403 //\r
404 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));\r
405 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);\r
406\r
407 Updated = FALSE;\r
408 for (Index = 0; ; Index++) {\r
409 Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);\r
410 if (Status == EFI_SUCCESS) {\r
411 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));\r
8d00a0f1 412 if ((PackageHeader.Type == EFI_HII_PACKAGE_FORMS) && !Updated) {\r
8dbae30d 413 Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);\r
414 if (!EFI_ERROR(Status)) {\r
415 if (FormSetGuid == NULL) {\r
416 Updated = TRUE;\r
417 }\r
418 CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);\r
419 UpdateBufferPos += TempBufferSize;\r
cfb9b643 420 FreePool (TempBuffer);\r
8dbae30d 421 continue;\r
422 }\r
423 }\r
424\r
425 CopyMem (UpdateBufferPos, Package, PackageLength);\r
426 UpdateBufferPos += PackageLength;\r
427 } else if (Status == EFI_NOT_FOUND) {\r
428 break;\r
429 } else {\r
cfb9b643 430 FreePool (HiiPackageList);\r
8dbae30d 431 return Status;\r
432 }\r
433 }\r
434\r
435 //\r
436 // Update package list length\r
437 //\r
438 BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;\r
3a306c10 439 WriteUnaligned32 (&UpdateBuffer->PackageLength, (UINT32)BufferSize);\r
8dbae30d 440\r
cfb9b643 441 FreePool (HiiPackageList);\r
8dbae30d 442\r
443 return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);\r
444}\r
445\r
446\r
447/**\r
53dff899 448 Configure the buffer accrording to ConfigBody strings in the format of\r
449 <Length:4 bytes>, <Offset: 2 bytes>, <Width:2 bytes>, <Data:n bytes>.\r
450 This ConfigBody strings is generated by UEFI VfrCompiler for the default\r
451 values in a Form Set. The name of the ConfigBody strings is VfrMyIfrNVDataDefault0000\r
452 constructed following this rule: \r
453 "Vfr" + varstore.name + "Default" + defaultstore.attributes.\r
454 Check the generated C file in Output for details.\r
8dbae30d 455\r
6ca46b63 456 @param Buffer The start address of buffer.\r
457 @param BufferSize The size of buffer.\r
458 @param Number The number of the strings.\r
459 @param ... Variable argument list for default value in <AltResp> format \r
460 generated by the tool.\r
8dbae30d 461\r
462 @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate.\r
463 @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0.\r
464 @retval EFI_SUCCESS Operation successful.\r
465\r
466**/\r
467EFI_STATUS\r
468EFIAPI\r
469IfrLibExtractDefault(\r
470 IN VOID *Buffer,\r
471 IN UINTN *BufferSize,\r
472 UINTN Number,\r
473 ...\r
474 )\r
475{\r
476 VA_LIST Args;\r
477 UINTN Index;\r
478 UINT32 TotalLen;\r
479 UINT8 *BufCfgArray;\r
480 UINT8 *BufferPos;\r
481 UINT16 Offset;\r
482 UINT16 Width;\r
483 UINT8 *Value;\r
484\r
485 if ((Buffer == NULL) || (BufferSize == NULL)) {\r
486 return EFI_INVALID_PARAMETER;\r
487 }\r
488\r
489 Offset = 0;\r
490 Width = 0;\r
491 Value = NULL;\r
492\r
493 VA_START (Args, Number);\r
494 for (Index = 0; Index < Number; Index++) {\r
495 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);\r
3a306c10 496 TotalLen = ReadUnaligned32 ((UINT32 *)BufCfgArray);\r
8dbae30d 497 BufferPos = BufCfgArray + sizeof (UINT32);\r
498\r
499 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {\r
3a306c10 500 Offset = ReadUnaligned16 ((UINT16 *)BufferPos);\r
8dbae30d 501 BufferPos += sizeof (UINT16);\r
3a306c10 502 Width = ReadUnaligned16 ((UINT16 *)BufferPos);\r
8dbae30d 503 BufferPos += sizeof (UINT16);\r
504 Value = BufferPos;\r
505 BufferPos += Width;\r
506\r
507 if ((UINTN)(Offset + Width) > *BufferSize) {\r
508 return EFI_BUFFER_TOO_SMALL;\r
509 }\r
510\r
511 CopyMem ((UINT8 *)Buffer + Offset, Value, Width);\r
512 }\r
513 }\r
514 VA_END (Args);\r
515\r
516 *BufferSize = (UINTN)Offset;\r
517\r
518 return EFI_SUCCESS;\r
519}\r
520\r
521\r