]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/ExtendedIfrSupportLib/Form.c
follow up the comments from code review.
[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 /**
279 This function allows the caller to update a form that has
280 previously been registered with the EFI HII database.
281
282 @param Handle Hii Handle
283 @param FormSetGuid The formset should be updated.
284 @param FormId The form should be updated.
285 @param Label Update information starting immediately after this
286 label in the IFR
287 @param Insert If TRUE and Data is not NULL, insert data after
288 Label. If FALSE, replace opcodes between two
289 labels with Data
290 @param Data The adding data; If NULL, remove opcodes between
291 two Label.
292
293 @retval EFI_SUCCESS Update success.
294 @retval Other Update fail.
295
296 **/
297 EFI_STATUS
298 EFIAPI
299 IfrLibUpdateForm (
300 IN EFI_HII_HANDLE Handle,
301 IN EFI_GUID *FormSetGuid, OPTIONAL
302 IN EFI_FORM_ID FormId,
303 IN UINT16 Label,
304 IN BOOLEAN Insert,
305 IN EFI_HII_UPDATE_DATA *Data
306 )
307 {
308 EFI_STATUS Status;
309 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
310 EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
311 UINT32 Index;
312 EFI_HII_PACKAGE_LIST_HEADER *UpdateBuffer;
313 UINTN BufferSize;
314 UINT8 *UpdateBufferPos;
315 EFI_HII_PACKAGE_HEADER PackageHeader;
316 EFI_HII_PACKAGE_HEADER *Package;
317 UINT32 PackageLength;
318 EFI_HII_PACKAGE_HEADER *TempBuffer;
319 UINT32 TempBufferSize;
320 BOOLEAN Updated;
321
322 if (Data == NULL) {
323 return EFI_INVALID_PARAMETER;
324 }
325
326 HiiDatabase = gIfrLibHiiDatabase;
327
328 //
329 // Get the orginal package list
330 //
331 BufferSize = 0;
332 HiiPackageList = NULL;
333 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
334 if (Status == EFI_BUFFER_TOO_SMALL) {
335 HiiPackageList = AllocatePool (BufferSize);
336 ASSERT (HiiPackageList != NULL);
337
338 Status = HiiDatabase->ExportPackageLists (HiiDatabase, Handle, &BufferSize, HiiPackageList);
339 if (EFI_ERROR (Status)) {
340 FreePool (HiiPackageList);
341 return Status;
342 }
343 }
344
345 //
346 // Calculate and allocate space for retrieval of IFR data
347 //
348 BufferSize += Data->Offset;
349 UpdateBuffer = AllocateZeroPool (BufferSize);
350 if (UpdateBuffer == NULL) {
351 return EFI_OUT_OF_RESOURCES;
352 }
353
354 UpdateBufferPos = (UINT8 *) UpdateBuffer;
355
356 //
357 // copy the package list header
358 //
359 CopyMem (UpdateBufferPos, HiiPackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER));
360 UpdateBufferPos += sizeof (EFI_HII_PACKAGE_LIST_HEADER);
361
362 Updated = FALSE;
363 for (Index = 0; ; Index++) {
364 Status = GetPackageDataFromPackageList (HiiPackageList, Index, &PackageLength, &Package);
365 if (Status == EFI_SUCCESS) {
366 CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
367 if ((PackageHeader.Type == EFI_HII_PACKAGE_FORM) && !Updated) {
368 Status = UpdateFormPackageData (FormSetGuid, FormId, Package, PackageLength, Label, Insert, Data, (UINT8 **)&TempBuffer, &TempBufferSize);
369 if (!EFI_ERROR(Status)) {
370 if (FormSetGuid == NULL) {
371 Updated = TRUE;
372 }
373 CopyMem (UpdateBufferPos, TempBuffer, TempBufferSize);
374 UpdateBufferPos += TempBufferSize;
375 FreePool (TempBuffer);
376 continue;
377 }
378 }
379
380 CopyMem (UpdateBufferPos, Package, PackageLength);
381 UpdateBufferPos += PackageLength;
382 } else if (Status == EFI_NOT_FOUND) {
383 break;
384 } else {
385 FreePool (HiiPackageList);
386 return Status;
387 }
388 }
389
390 //
391 // Update package list length
392 //
393 BufferSize = UpdateBufferPos - (UINT8 *) UpdateBuffer;
394 CopyMem (&UpdateBuffer->PackageLength, &BufferSize, sizeof (UINT32));
395
396 FreePool (HiiPackageList);
397
398 return HiiDatabase->UpdatePackageList (HiiDatabase, Handle, UpdateBuffer);
399 }
400
401
402 /**
403 Configure the buffer accrording to ConfigBody strings.
404
405 @param Buffer The start address of buffer.
406 @param BufferSize The size of buffer.
407 @param Number The number of the strings.
408 @param ... Variable argument list for default value in <AltResp> format
409 generated by the tool.
410
411 @retval EFI_BUFFER_TOO_SMALL the BufferSize is too small to operate.
412 @retval EFI_INVALID_PARAMETER Buffer is NULL or BufferSize is 0.
413 @retval EFI_SUCCESS Operation successful.
414
415 **/
416 EFI_STATUS
417 EFIAPI
418 IfrLibExtractDefault(
419 IN VOID *Buffer,
420 IN UINTN *BufferSize,
421 UINTN Number,
422 ...
423 )
424 {
425 VA_LIST Args;
426 UINTN Index;
427 UINT32 TotalLen;
428 UINT8 *BufCfgArray;
429 UINT8 *BufferPos;
430 UINT16 Offset;
431 UINT16 Width;
432 UINT8 *Value;
433
434 if ((Buffer == NULL) || (BufferSize == NULL)) {
435 return EFI_INVALID_PARAMETER;
436 }
437
438 Offset = 0;
439 Width = 0;
440 Value = NULL;
441
442 VA_START (Args, Number);
443 for (Index = 0; Index < Number; Index++) {
444 BufCfgArray = (UINT8 *) VA_ARG (Args, VOID *);
445 CopyMem (&TotalLen, BufCfgArray, sizeof (UINT32));
446 BufferPos = BufCfgArray + sizeof (UINT32);
447
448 while ((UINT32)(BufferPos - BufCfgArray) < TotalLen) {
449 CopyMem (&Offset, BufferPos, sizeof (UINT16));
450 BufferPos += sizeof (UINT16);
451 CopyMem (&Width, BufferPos, sizeof (UINT16));
452 BufferPos += sizeof (UINT16);
453 Value = BufferPos;
454 BufferPos += Width;
455
456 if ((UINTN)(Offset + Width) > *BufferSize) {
457 return EFI_BUFFER_TOO_SMALL;
458 }
459
460 CopyMem ((UINT8 *)Buffer + Offset, Value, Width);
461 }
462 }
463 VA_END (Args);
464
465 *BufferSize = (UINTN)Offset;
466
467 return EFI_SUCCESS;
468 }
469
470