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