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