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