]>
Commit | Line | Data |
---|---|---|
2ef2b01e A |
1 | /** @file |
2 | Implementation of the 6 PEI Ffs (FV) APIs in library form. | |
3 | ||
4 | This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list | |
5 | ||
6 | Copyright (c) 2008-2009, Apple Inc. All rights reserved. | |
7 | ||
8 | All rights reserved. This program and the accompanying materials | |
9 | are licensed and made available under the terms and conditions of the BSD License | |
10 | which accompanies this distribution. The full text of the license may be found at | |
11 | http://opensource.org/licenses/bsd-license.php | |
12 | ||
13 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
14 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
15 | ||
16 | **/ | |
17 | ||
18 | #include <PrePi.h> | |
19 | #include <Library/ExtractGuidedSectionLib.h> | |
20 | ||
21 | ||
22 | #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ | |
23 | (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) | |
24 | ||
25 | ||
26 | /** | |
27 | Returns the highest bit set of the State field | |
28 | ||
29 | @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY | |
30 | in the Attributes field. | |
31 | @param FfsHeader Pointer to FFS File Header | |
32 | ||
33 | ||
34 | @retval the highest bit in the State field | |
35 | ||
36 | **/ | |
37 | STATIC | |
38 | EFI_FFS_FILE_STATE | |
39 | GetFileState( | |
40 | IN UINT8 ErasePolarity, | |
41 | IN EFI_FFS_FILE_HEADER *FfsHeader | |
42 | ) | |
43 | { | |
44 | EFI_FFS_FILE_STATE FileState; | |
45 | EFI_FFS_FILE_STATE HighestBit; | |
46 | ||
47 | FileState = FfsHeader->State; | |
48 | ||
49 | if (ErasePolarity != 0) { | |
50 | FileState = (EFI_FFS_FILE_STATE)~FileState; | |
51 | } | |
52 | ||
53 | HighestBit = 0x80; | |
54 | while (HighestBit != 0 && (HighestBit & FileState) == 0) { | |
55 | HighestBit >>= 1; | |
56 | } | |
57 | ||
58 | return HighestBit; | |
59 | } | |
60 | ||
61 | ||
62 | /** | |
63 | Calculates the checksum of the header of a file. | |
64 | The header is a zero byte checksum, so zero means header is good | |
65 | ||
66 | @param FfsHeader Pointer to FFS File Header | |
67 | ||
68 | @retval Checksum of the header | |
69 | ||
70 | **/ | |
71 | STATIC | |
72 | UINT8 | |
73 | CalculateHeaderChecksum ( | |
74 | IN EFI_FFS_FILE_HEADER *FileHeader | |
75 | ) | |
76 | { | |
77 | UINT8 *Ptr; | |
78 | UINTN Index; | |
79 | UINT8 Sum; | |
80 | ||
81 | Sum = 0; | |
82 | Ptr = (UINT8 *)FileHeader; | |
83 | ||
84 | for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { | |
85 | Sum = (UINT8)(Sum + Ptr[Index]); | |
86 | Sum = (UINT8)(Sum + Ptr[Index+1]); | |
87 | Sum = (UINT8)(Sum + Ptr[Index+2]); | |
88 | Sum = (UINT8)(Sum + Ptr[Index+3]); | |
89 | } | |
90 | ||
91 | for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { | |
92 | Sum = (UINT8)(Sum + Ptr[Index]); | |
93 | } | |
94 | ||
95 | // | |
96 | // State field (since this indicates the different state of file). | |
97 | // | |
98 | Sum = (UINT8)(Sum - FileHeader->State); | |
99 | // | |
100 | // Checksum field of the file is not part of the header checksum. | |
101 | // | |
102 | Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); | |
103 | ||
104 | return Sum; | |
105 | } | |
106 | ||
107 | ||
108 | /** | |
109 | Given a FileHandle return the VolumeHandle | |
110 | ||
111 | @param FileHandle File handle to look up | |
112 | @param VolumeHandle Match for FileHandle | |
113 | ||
114 | @retval TRUE VolumeHandle is valid | |
115 | ||
116 | **/ | |
117 | STATIC | |
118 | BOOLEAN | |
119 | EFIAPI | |
120 | FileHandleToVolume ( | |
121 | IN EFI_PEI_FILE_HANDLE FileHandle, | |
122 | OUT EFI_PEI_FV_HANDLE *VolumeHandle | |
123 | ) | |
124 | { | |
125 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
126 | EFI_PEI_HOB_POINTERS Hob; | |
127 | ||
128 | Hob.Raw = GetHobList (); | |
129 | if (Hob.Raw == NULL) { | |
130 | return FALSE; | |
131 | } | |
132 | ||
133 | do { | |
134 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); | |
135 | if (Hob.Raw != NULL) { | |
136 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); | |
137 | if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ | |
138 | ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { | |
139 | *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; | |
140 | return TRUE; | |
141 | } | |
142 | ||
143 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); | |
144 | } | |
145 | } while (Hob.Raw != NULL); | |
146 | ||
147 | return FALSE; | |
148 | } | |
149 | ||
150 | ||
151 | ||
152 | /** | |
153 | Given the input file pointer, search for the next matching file in the | |
154 | FFS volume as defined by SearchType. The search starts from FileHeader inside | |
155 | the Firmware Volume defined by FwVolHeader. | |
156 | ||
157 | @param FileHandle File handle to look up | |
158 | @param VolumeHandle Match for FileHandle | |
159 | ||
160 | ||
161 | **/ | |
162 | EFI_STATUS | |
163 | FindFileEx ( | |
164 | IN CONST EFI_PEI_FV_HANDLE FvHandle, | |
165 | IN CONST EFI_GUID *FileName, OPTIONAL | |
166 | IN EFI_FV_FILETYPE SearchType, | |
167 | IN OUT EFI_PEI_FILE_HANDLE *FileHandle | |
168 | ) | |
169 | { | |
170 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; | |
171 | EFI_FFS_FILE_HEADER **FileHeader; | |
172 | EFI_FFS_FILE_HEADER *FfsFileHeader; | |
173 | EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; | |
174 | UINT32 FileLength; | |
175 | UINT32 FileOccupiedSize; | |
176 | UINT32 FileOffset; | |
177 | UINT64 FvLength; | |
178 | UINT8 ErasePolarity; | |
179 | UINT8 FileState; | |
180 | ||
181 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; | |
182 | FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; | |
183 | ||
184 | FvLength = FwVolHeader->FvLength; | |
185 | if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { | |
186 | ErasePolarity = 1; | |
187 | } else { | |
188 | ErasePolarity = 0; | |
189 | } | |
190 | ||
191 | // | |
192 | // If FileHeader is not specified (NULL) or FileName is not NULL, | |
193 | // start with the first file in the firmware volume. Otherwise, | |
194 | // start from the FileHeader. | |
195 | // | |
196 | if ((*FileHeader == NULL) || (FileName != NULL)) { | |
197 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); | |
198 | if (FwVolHeader->ExtHeaderOffset != 0) { | |
199 | FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); | |
200 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); | |
201 | } | |
202 | } else { | |
203 | // | |
204 | // Length is 24 bits wide so mask upper 8 bits | |
205 | // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. | |
206 | // | |
207 | FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; | |
208 | FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); | |
209 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); | |
210 | } | |
211 | ||
212 | FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); | |
213 | ASSERT (FileOffset <= 0xFFFFFFFF); | |
214 | ||
215 | while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { | |
216 | // | |
217 | // Get FileState which is the highest bit of the State | |
218 | // | |
219 | FileState = GetFileState (ErasePolarity, FfsFileHeader); | |
220 | ||
221 | switch (FileState) { | |
222 | ||
223 | case EFI_FILE_HEADER_INVALID: | |
224 | FileOffset += sizeof(EFI_FFS_FILE_HEADER); | |
225 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); | |
226 | break; | |
227 | ||
228 | case EFI_FILE_DATA_VALID: | |
229 | case EFI_FILE_MARKED_FOR_UPDATE: | |
230 | if (CalculateHeaderChecksum (FfsFileHeader) != 0) { | |
231 | ASSERT (FALSE); | |
232 | *FileHeader = NULL; | |
233 | return EFI_NOT_FOUND; | |
234 | } | |
235 | ||
236 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; | |
237 | FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); | |
238 | ||
239 | if (FileName != NULL) { | |
240 | if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { | |
241 | *FileHeader = FfsFileHeader; | |
242 | return EFI_SUCCESS; | |
243 | } | |
244 | } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && | |
245 | (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { | |
246 | *FileHeader = FfsFileHeader; | |
247 | return EFI_SUCCESS; | |
248 | } | |
249 | ||
250 | FileOffset += FileOccupiedSize; | |
251 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); | |
252 | break; | |
253 | ||
254 | case EFI_FILE_DELETED: | |
255 | FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; | |
256 | FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); | |
257 | FileOffset += FileOccupiedSize; | |
258 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); | |
259 | break; | |
260 | ||
261 | default: | |
262 | *FileHeader = NULL; | |
263 | return EFI_NOT_FOUND; | |
264 | } | |
265 | } | |
266 | ||
267 | ||
268 | *FileHeader = NULL; | |
269 | return EFI_NOT_FOUND; | |
270 | } | |
271 | ||
272 | ||
273 | /** | |
274 | Go through the file to search SectionType section, | |
275 | when meeting an encapsuled section. | |
276 | ||
277 | @param SectionType - Filter to find only section of this type. | |
278 | @param Section - From where to search. | |
279 | @param SectionSize - The file size to search. | |
280 | @param OutputBuffer - Pointer to the section to search. | |
281 | ||
282 | @retval EFI_SUCCESS | |
283 | **/ | |
284 | EFI_STATUS | |
285 | FfsProcessSection ( | |
286 | IN EFI_SECTION_TYPE SectionType, | |
287 | IN EFI_COMMON_SECTION_HEADER *Section, | |
288 | IN UINTN SectionSize, | |
289 | OUT VOID **OutputBuffer | |
290 | ) | |
291 | { | |
292 | EFI_STATUS Status; | |
293 | UINT32 SectionLength; | |
294 | UINT32 ParsedLength; | |
295 | EFI_COMPRESSION_SECTION *CompressionSection; | |
296 | UINTN DstBufferSize; | |
297 | VOID *ScratchBuffer; | |
298 | UINT32 ScratchBufferSize; | |
299 | VOID *DstBuffer; | |
300 | UINT16 SectionAttribute; | |
301 | UINT32 AuthenticationStatus; | |
302 | ||
303 | ||
304 | *OutputBuffer = NULL; | |
305 | ParsedLength = 0; | |
306 | Status = EFI_NOT_FOUND; | |
307 | while (ParsedLength < SectionSize) { | |
308 | if (Section->Type == SectionType) { | |
309 | *OutputBuffer = (VOID *)(Section + 1); | |
310 | ||
311 | return EFI_SUCCESS; | |
312 | } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { | |
313 | ||
314 | if (Section->Type == EFI_SECTION_COMPRESSION) { | |
315 | CompressionSection = (EFI_COMPRESSION_SECTION *) Section; | |
316 | SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; | |
317 | ||
318 | if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { | |
319 | return EFI_UNSUPPORTED; | |
320 | } | |
321 | ||
322 | Status = UefiDecompressGetInfo ( | |
323 | (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), | |
324 | (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), | |
325 | (UINT32 *) &DstBufferSize, | |
326 | &ScratchBufferSize | |
327 | ); | |
328 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { | |
329 | Status = ExtractGuidedSectionGetInfo ( | |
330 | Section, | |
331 | (UINT32 *) &DstBufferSize, | |
332 | &ScratchBufferSize, | |
333 | &SectionAttribute | |
334 | ); | |
335 | } | |
336 | ||
337 | if (EFI_ERROR (Status)) { | |
338 | // | |
339 | // GetInfo failed | |
340 | // | |
341 | DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); | |
342 | return EFI_NOT_FOUND; | |
343 | } | |
344 | // | |
345 | // Allocate scratch buffer | |
346 | // | |
347 | ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); | |
348 | if (ScratchBuffer == NULL) { | |
349 | return EFI_OUT_OF_RESOURCES; | |
350 | } | |
351 | // | |
352 | // Allocate destination buffer, extra one page for adjustment | |
353 | // | |
354 | DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); | |
355 | if (DstBuffer == NULL) { | |
356 | return EFI_OUT_OF_RESOURCES; | |
357 | } | |
358 | // | |
359 | // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header | |
360 | // to make section data at page alignment. | |
361 | // | |
362 | DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); | |
363 | // | |
364 | // Call decompress function | |
365 | // | |
366 | if (Section->Type == EFI_SECTION_COMPRESSION) { | |
367 | Status = UefiDecompress ( | |
368 | (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), | |
369 | DstBuffer, | |
370 | ScratchBuffer | |
371 | ); | |
372 | } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { | |
373 | Status = ExtractGuidedSectionDecode ( | |
374 | Section, | |
375 | &DstBuffer, | |
376 | ScratchBuffer, | |
377 | &AuthenticationStatus | |
378 | ); | |
379 | } | |
380 | ||
381 | if (EFI_ERROR (Status)) { | |
382 | // | |
383 | // Decompress failed | |
384 | // | |
385 | DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); | |
386 | return EFI_NOT_FOUND; | |
387 | } else { | |
388 | return FfsProcessSection ( | |
389 | SectionType, | |
390 | DstBuffer, | |
391 | DstBufferSize, | |
392 | OutputBuffer | |
393 | ); | |
394 | } | |
395 | } | |
396 | ||
397 | // | |
398 | // Size is 24 bits wide so mask upper 8 bits. | |
399 | // SectionLength is adjusted it is 4 byte aligned. | |
400 | // Go to the next section | |
401 | // | |
402 | SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; | |
403 | SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); | |
404 | ASSERT (SectionLength != 0); | |
405 | ParsedLength += SectionLength; | |
406 | Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); | |
407 | } | |
408 | ||
409 | return EFI_NOT_FOUND; | |
410 | } | |
411 | ||
412 | ||
413 | ||
414 | /** | |
415 | This service enables discovery sections of a given type within a valid FFS file. | |
416 | ||
417 | @param SearchType The value of the section type to find. | |
418 | @param FfsFileHeader A pointer to the file header that contains the set of sections to | |
419 | be searched. | |
420 | @param SectionData A pointer to the discovered section, if successful. | |
421 | ||
422 | @retval EFI_SUCCESS The section was found. | |
423 | @retval EFI_NOT_FOUND The section was not found. | |
424 | ||
425 | **/ | |
426 | EFI_STATUS | |
427 | EFIAPI | |
428 | FfsFindSectionData ( | |
429 | IN EFI_SECTION_TYPE SectionType, | |
430 | IN EFI_PEI_FILE_HANDLE FileHandle, | |
431 | OUT VOID **SectionData | |
432 | ) | |
433 | { | |
434 | EFI_FFS_FILE_HEADER *FfsFileHeader; | |
435 | UINT32 FileSize; | |
436 | EFI_COMMON_SECTION_HEADER *Section; | |
437 | ||
438 | FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); | |
439 | ||
440 | // | |
441 | // Size is 24 bits wide so mask upper 8 bits. | |
442 | // Does not include FfsFileHeader header size | |
443 | // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. | |
444 | // | |
445 | Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); | |
446 | FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; | |
447 | FileSize -= sizeof (EFI_FFS_FILE_HEADER); | |
448 | ||
449 | return FfsProcessSection ( | |
450 | SectionType, | |
451 | Section, | |
452 | FileSize, | |
453 | SectionData | |
454 | ); | |
455 | } | |
456 | ||
457 | ||
458 | ||
459 | ||
460 | ||
461 | ||
462 | /** | |
463 | This service enables discovery of additional firmware files. | |
464 | ||
465 | @param SearchType A filter to find files only of this type. | |
466 | @param FwVolHeader Pointer to the firmware volume header of the volume to search. | |
467 | This parameter must point to a valid FFS volume. | |
468 | @param FileHeader Pointer to the current file from which to begin searching. | |
469 | ||
470 | @retval EFI_SUCCESS The file was found. | |
471 | @retval EFI_NOT_FOUND The file was not found. | |
472 | @retval EFI_NOT_FOUND The header checksum was not zero. | |
473 | ||
474 | **/ | |
475 | EFI_STATUS | |
476 | EFIAPI | |
477 | FfsFindNextFile ( | |
478 | IN UINT8 SearchType, | |
479 | IN EFI_PEI_FV_HANDLE VolumeHandle, | |
480 | IN OUT EFI_PEI_FILE_HANDLE *FileHandle | |
481 | ) | |
482 | { | |
483 | return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); | |
484 | } | |
485 | ||
486 | ||
487 | /** | |
488 | This service enables discovery of additional firmware volumes. | |
489 | ||
490 | @param Instance This instance of the firmware volume to find. The value 0 is the | |
491 | Boot Firmware Volume (BFV). | |
492 | @param FwVolHeader Pointer to the firmware volume header of the volume to return. | |
493 | ||
494 | @retval EFI_SUCCESS The volume was found. | |
495 | @retval EFI_NOT_FOUND The volume was not found. | |
496 | ||
497 | **/ | |
498 | EFI_STATUS | |
499 | EFIAPI | |
500 | FfsFindNextVolume ( | |
501 | IN UINTN Instance, | |
502 | IN OUT EFI_PEI_FV_HANDLE *VolumeHandle | |
503 | ) | |
504 | { | |
505 | EFI_PEI_HOB_POINTERS Hob; | |
506 | ||
507 | ||
508 | Hob.Raw = GetHobList (); | |
509 | if (Hob.Raw == NULL) { | |
510 | return EFI_NOT_FOUND; | |
511 | } | |
512 | ||
513 | do { | |
514 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); | |
515 | if (Hob.Raw != NULL) { | |
516 | if (Instance-- == 0) { | |
517 | *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); | |
518 | return EFI_SUCCESS; | |
519 | } | |
520 | ||
521 | Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); | |
522 | } | |
523 | } while (Hob.Raw != NULL); | |
524 | ||
525 | return EFI_NOT_FOUND; | |
526 | ||
527 | } | |
528 | ||
529 | ||
530 | /** | |
531 | Find a file in the volume by name | |
532 | ||
533 | @param FileName A pointer to the name of the file to | |
534 | find within the firmware volume. | |
535 | ||
536 | @param VolumeHandle The firmware volume to search FileHandle | |
537 | Upon exit, points to the found file's | |
538 | handle or NULL if it could not be found. | |
539 | ||
540 | @retval EFI_SUCCESS File was found. | |
541 | ||
542 | @retval EFI_NOT_FOUND File was not found. | |
543 | ||
544 | @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or | |
545 | FileName was NULL. | |
546 | ||
547 | **/ | |
548 | EFI_STATUS | |
549 | EFIAPI | |
550 | FfsFindFileByName ( | |
551 | IN CONST EFI_GUID *FileName, | |
552 | IN EFI_PEI_FV_HANDLE VolumeHandle, | |
553 | OUT EFI_PEI_FILE_HANDLE *FileHandle | |
554 | ) | |
555 | { | |
556 | EFI_STATUS Status; | |
557 | if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { | |
558 | return EFI_INVALID_PARAMETER; | |
559 | } | |
560 | Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); | |
561 | if (Status == EFI_NOT_FOUND) { | |
562 | *FileHandle = NULL; | |
563 | } | |
564 | return Status; | |
565 | } | |
566 | ||
567 | ||
568 | ||
569 | ||
570 | /** | |
571 | Get information about the file by name. | |
572 | ||
573 | @param FileHandle Handle of the file. | |
574 | ||
575 | @param FileInfo Upon exit, points to the file's | |
576 | information. | |
577 | ||
578 | @retval EFI_SUCCESS File information returned. | |
579 | ||
580 | @retval EFI_INVALID_PARAMETER If FileHandle does not | |
581 | represent a valid file. | |
582 | ||
583 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL. | |
584 | ||
585 | **/ | |
586 | EFI_STATUS | |
587 | EFIAPI | |
588 | FfsGetFileInfo ( | |
589 | IN EFI_PEI_FILE_HANDLE FileHandle, | |
590 | OUT EFI_FV_FILE_INFO *FileInfo | |
591 | ) | |
592 | { | |
593 | UINT8 FileState; | |
594 | UINT8 ErasePolarity; | |
595 | EFI_FFS_FILE_HEADER *FileHeader; | |
596 | EFI_PEI_FV_HANDLE VolumeHandle; | |
597 | ||
598 | if ((FileHandle == NULL) || (FileInfo == NULL)) { | |
599 | return EFI_INVALID_PARAMETER; | |
600 | } | |
601 | ||
602 | VolumeHandle = 0; | |
603 | // | |
604 | // Retrieve the FirmwareVolume which the file resides in. | |
605 | // | |
606 | if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { | |
607 | return EFI_INVALID_PARAMETER; | |
608 | } | |
609 | ||
610 | if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { | |
611 | ErasePolarity = 1; | |
612 | } else { | |
613 | ErasePolarity = 0; | |
614 | } | |
615 | ||
616 | // | |
617 | // Get FileState which is the highest bit of the State | |
618 | // | |
619 | FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); | |
620 | ||
621 | switch (FileState) { | |
622 | case EFI_FILE_DATA_VALID: | |
623 | case EFI_FILE_MARKED_FOR_UPDATE: | |
624 | break; | |
625 | default: | |
626 | return EFI_INVALID_PARAMETER; | |
627 | } | |
628 | ||
629 | FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; | |
630 | CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); | |
631 | FileInfo->FileType = FileHeader->Type; | |
632 | FileInfo->FileAttributes = FileHeader->Attributes; | |
633 | FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); | |
634 | FileInfo->Buffer = (FileHeader + 1); | |
635 | return EFI_SUCCESS; | |
636 | } | |
637 | ||
638 | ||
639 | /** | |
640 | Get Information about the volume by name | |
641 | ||
642 | @param VolumeHandle Handle of the volume. | |
643 | ||
644 | @param VolumeInfo Upon exit, points to the volume's | |
645 | information. | |
646 | ||
647 | @retval EFI_SUCCESS File information returned. | |
648 | ||
649 | @retval EFI_INVALID_PARAMETER If FileHandle does not | |
650 | represent a valid file. | |
651 | ||
652 | @retval EFI_INVALID_PARAMETER If FileInfo is NULL. | |
653 | ||
654 | **/ | |
655 | EFI_STATUS | |
656 | EFIAPI | |
657 | FfsGetVolumeInfo ( | |
658 | IN EFI_PEI_FV_HANDLE VolumeHandle, | |
659 | OUT EFI_FV_INFO *VolumeInfo | |
660 | ) | |
661 | { | |
662 | EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; | |
663 | EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; | |
664 | ||
665 | if (VolumeInfo == NULL) { | |
666 | return EFI_INVALID_PARAMETER; | |
667 | } | |
668 | ||
669 | // | |
670 | // VolumeHandle may not align at 8 byte, | |
671 | // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. | |
672 | // So, Copy FvHeader into the local FvHeader structure. | |
673 | // | |
674 | CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); | |
675 | // | |
676 | // Check Fv Image Signature | |
677 | // | |
678 | if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { | |
679 | return EFI_INVALID_PARAMETER; | |
680 | } | |
681 | VolumeInfo->FvAttributes = FwVolHeader.Attributes; | |
682 | VolumeInfo->FvStart = (VOID *) VolumeHandle; | |
683 | VolumeInfo->FvSize = FwVolHeader.FvLength; | |
684 | CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); | |
685 | ||
686 | if (FwVolHeader.ExtHeaderOffset != 0) { | |
687 | FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); | |
688 | CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); | |
689 | } | |
690 | return EFI_SUCCESS; | |
691 | } | |
692 | ||
693 | ||
694 | ||
695 | /** | |
696 | Search through every FV until you find a file of type FileType | |
697 | ||
698 | @param FileType File handle of a Fv type file. | |
699 | @param Volumehandle On succes Volume Handle of the match | |
700 | @param FileHandle On success File Handle of the match | |
701 | ||
702 | @retval EFI_NOT_FOUND FV image can't be found. | |
703 | @retval EFI_SUCCESS Successfully found FileType | |
704 | ||
705 | **/ | |
706 | EFI_STATUS | |
707 | EFIAPI | |
708 | FfsAnyFvFindFirstFile ( | |
709 | IN EFI_FV_FILETYPE FileType, | |
710 | OUT EFI_PEI_FV_HANDLE *VolumeHandle, | |
711 | OUT EFI_PEI_FILE_HANDLE *FileHandle | |
712 | ) | |
713 | { | |
714 | EFI_STATUS Status; | |
715 | UINTN Instance; | |
716 | ||
717 | // | |
718 | // Search every FV for the DXE Core | |
719 | // | |
720 | Instance = 0; | |
721 | *FileHandle = NULL; | |
722 | ||
723 | while (1) | |
724 | { | |
725 | Status = FfsFindNextVolume (Instance++, VolumeHandle); | |
726 | if (EFI_ERROR (Status)) | |
727 | { | |
728 | break; | |
729 | } | |
730 | ||
731 | Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); | |
732 | if (!EFI_ERROR (Status)) | |
733 | { | |
734 | break; | |
735 | } | |
736 | } | |
737 | ||
738 | return Status; | |
739 | } | |
740 | ||
741 | ||
742 | ||
743 | /** | |
744 | Get Fv image from the FV type file, then add FV & FV2 Hob. | |
745 | ||
746 | @param FileHandle File handle of a Fv type file. | |
747 | ||
748 | ||
749 | @retval EFI_NOT_FOUND FV image can't be found. | |
750 | @retval EFI_SUCCESS Successfully to process it. | |
751 | ||
752 | **/ | |
753 | EFI_STATUS | |
754 | EFIAPI | |
755 | FfsProcessFvFile ( | |
756 | IN EFI_PEI_FILE_HANDLE FvFileHandle | |
757 | ) | |
758 | { | |
759 | EFI_STATUS Status; | |
760 | EFI_PEI_FV_HANDLE FvImageHandle; | |
761 | EFI_FV_INFO FvImageInfo; | |
762 | UINT32 FvAlignment; | |
763 | VOID *FvBuffer; | |
764 | EFI_PEI_HOB_POINTERS HobFv2; | |
765 | ||
766 | FvBuffer = NULL; | |
767 | ||
768 | ||
769 | // | |
770 | // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already | |
771 | // been extracted. | |
772 | // | |
773 | HobFv2.Raw = GetHobList (); | |
774 | while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { | |
775 | if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { | |
776 | // | |
777 | // this FILE has been dispatched, it will not be dispatched again. | |
778 | // | |
779 | return EFI_SUCCESS; | |
780 | } | |
781 | HobFv2.Raw = GET_NEXT_HOB (HobFv2); | |
782 | } | |
783 | ||
784 | // | |
785 | // Find FvImage in FvFile | |
786 | // | |
787 | Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); | |
788 | if (EFI_ERROR (Status)) { | |
789 | return Status; | |
790 | } | |
791 | ||
792 | // | |
793 | // Collect FvImage Info. | |
794 | // | |
795 | Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); | |
796 | ASSERT_EFI_ERROR (Status); | |
797 | ||
798 | // | |
799 | // FvAlignment must be more than 8 bytes required by FvHeader structure. | |
800 | // | |
801 | FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); | |
802 | if (FvAlignment < 8) { | |
803 | FvAlignment = 8; | |
804 | } | |
805 | ||
806 | // | |
807 | // Check FvImage | |
808 | // | |
809 | if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { | |
810 | FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); | |
811 | if (FvBuffer == NULL) { | |
812 | return EFI_OUT_OF_RESOURCES; | |
813 | } | |
814 | CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); | |
815 | // | |
816 | // Update FvImageInfo after reload FvImage to new aligned memory | |
817 | // | |
818 | FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); | |
819 | } | |
820 | ||
821 | ||
822 | // | |
823 | // Inform HOB consumer phase, i.e. DXE core, the existance of this FV | |
824 | // | |
825 | BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); | |
826 | ||
827 | // | |
828 | // Makes the encapsulated volume show up in DXE phase to skip processing of | |
829 | // encapsulated file again. | |
830 | // | |
831 | BuildFv2Hob ( | |
832 | (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, | |
833 | FvImageInfo.FvSize, | |
834 | &FvImageInfo.FvName, | |
835 | &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) | |
836 | ); | |
837 | ||
838 | return EFI_SUCCESS; | |
839 | } | |
840 | ||
841 |