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