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