]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/ExtendedIfrSupportLib/Form.c
793efdf87849675129f9047f2c756434bebe1983
[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 (CompareGuid((GUID *)(VOID *)&((EFI_IFR_FORM_SET *) IfrOpHdr)->Guid, FormSetGuid)) {
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 ((UINT16 *)(VOID *)&((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 //
380 // Handle is a invalid handle. Check if Handle is corrupted.
381 //
382 ASSERT (Status != EFI_NOT_FOUND);
383 //
384 // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
385 //
386 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
387 HiiPackageList = AllocatePool (BufferSize);
388 ASSERT (HiiPackageList != NULL);
389
390 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
391 if (EFI_ERROR (Status)) {
392 FreePool (HiiPackageList);
393 return Status;
394 }
395
396 //
397 // Calculate and allocate space for retrieval of IFR data
398 //
399 BufferSize += Data->Offset;
400 UpdateBuffer = AllocateZeroPool (BufferSize);
401 if (UpdateBuffer == NULL) {
402 return EFI_OUT_OF_RESOURCES;
403 }
404
405 UpdateBufferPos = (UINT8 *) UpdateBuffer;
406
407 //
408 // copy the package list header
409 //
410 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
411 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
412
413 Updated = FALSE;
414 for (Index = 0; ; Index++) {
415 Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);
416 if (Status == EFI_SUCCESS) {
417 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
418 if ((PackageHeader.Type == EFI_HII_PACKAGE_FORMS) && !Updated) {
419 Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);
420 if (!EFI_ERROR(Status)) {
421 if (FormSetGuid == NULL) {
422 Updated = TRUE;
423 }
424 CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);
425 UpdateBufferPos += TempBufferSize;
426 FreePool (TempBuffer);
427 continue;
428 }
429 }
430
431 CopyMem (UpdateBufferPos, Package, PackageLength);
432 UpdateBufferPos += PackageLength;
433 } else if (Status == EFI_NOT_FOUND) {
434 break;
435 } else {
436 FreePool (HiiPackageList);
437 return Status;
438 }
439 }
440
441 //
442 // Update package list length
443 //
444 BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;
445 WriteUnaligned32 (&UpdateBuffer->PackageLength, (UINT32)BufferSize);
446
447 FreePool (HiiPackageList);
448
449 return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);
450 }
451
452
453 /**
454 Configure the buffer accrording to ConfigBody strings in the format of
455 <Length:4 bytes>, <Offset: 2 bytes>, <Width:2 bytes>, <Data:n bytes>.
456 This ConfigBody strings is generated by UEFI VfrCompiler for the default
457 values in a Form Set. The name of the ConfigBody strings is VfrMyIfrNVDataDefault0000
458 constructed following this rule:
459 "Vfr" + varstore.name + "Default" + defaultstore.attributes.
460 Check the generated C file in Output for details.
461
462 @param Buffer The start address of buffer.
463 @param BufferSize The size of buffer.
464 @param Number The number of the strings.
465 @param ... Variable argument list for default value in <AltResp> format
466 generated by the tool.
467
468 @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate.
469 @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0.
470 @retval EFI_SUCCESS Operation successful.
471
472 **/
473 EFI_STATUS
474 EFIAPI
475 IfrLibExtractDefault(
476 IN VOID *Buffer,
477 IN UINTN *BufferSize,
478 UINTN Number,
479 ...
480 )
481 {
482 VA_LIST Args;
483 UINTN Index;
484 UINT32 TotalLen;
485 UINT8 *BufCfgArray;
486 UINT8 *BufferPos;
487 UINT16 Offset;
488 UINT16 Width;
489 UINT8 *Value;
490
491 if ((Buffer == NULL) || (BufferSize == NULL)) {
492 return EFI_INVALID_PARAMETER;
493 }
494
495 Offset = 0;
496 Width = 0;
497 Value = NULL;
498
499 VA_START (Args, Number);
500 for (Index = 0; Index < Number; Index++) {
501 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
502 TotalLen = ReadUnaligned32 ((UINT32 *)BufCfgArray);
503 BufferPos = BufCfgArray + sizeof (UINT32);
504
505 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
506 Offset = ReadUnaligned16 ((UINT16 *)BufferPos);
507 BufferPos += sizeof (UINT16);
508 Width = ReadUnaligned16 ((UINT16 *)BufferPos);
509 BufferPos += sizeof (UINT16);
510 Value = BufferPos;
511 BufferPos += Width;
512
513 if ((UINTN)(Offset + Width) > *BufferSize) {
514 return EFI_BUFFER_TOO_SMALL;
515 }
516
517 CopyMem ((UINT8 *)Buffer + Offset, Value, Width);
518 }
519 }
520 VA_END (Args);
521
522 *BufferSize = (UINTN)Offset;
523
524 return EFI_SUCCESS;
525 }
526
527