]> git.proxmox.com Git - mirror_edk2.git/blob - StandaloneMmPkg/Library/FvLib/FvLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / StandaloneMmPkg / Library / FvLib / FvLib.c
1 /** @file
2
3 Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
4 Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include <Library/FvLib.h>
11
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15
16 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
17 (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
18
19 /**
20 Returns the highest bit set of the State field
21
22 @param ErasePolarity Erase Polarity as defined by EFI_FVB_ERASE_POLARITY
23 in the Attributes field.
24 @param FfsHeader Pointer to FFS File Header.
25
26 @return the highest bit in the State field
27 **/
28 EFI_FFS_FILE_STATE
29 GetFileState (
30 IN UINT8 ErasePolarity,
31 IN EFI_FFS_FILE_HEADER *FfsHeader
32 )
33 {
34 EFI_FFS_FILE_STATE FileState;
35 EFI_FFS_FILE_STATE HighestBit;
36
37 FileState = FfsHeader->State;
38
39 if (ErasePolarity != 0) {
40 FileState = (EFI_FFS_FILE_STATE) ~FileState;
41 }
42
43 HighestBit = 0x80;
44 while (HighestBit != 0 && (HighestBit & FileState) == 0) {
45 HighestBit >>= 1;
46 }
47
48 return HighestBit;
49 }
50
51 /**
52 Calculates the checksum of the header of a file.
53
54 @param FileHeader Pointer to FFS File Header.
55
56 @return Checksum of the header.
57 **/
58 UINT8
59 CalculateHeaderChecksum (
60 IN EFI_FFS_FILE_HEADER *FileHeader
61 )
62 {
63 UINT8 *ptr;
64 UINTN Index;
65 UINT8 Sum;
66 UINTN Size;
67
68 Sum = 0;
69 ptr = (UINT8 *)FileHeader;
70 Size = IS_FFS_FILE2 (FileHeader) ? sizeof (EFI_FFS_FILE_HEADER2) : sizeof (EFI_FFS_FILE_HEADER);
71
72 for (Index = 0; Index < Size - 3; Index += 4) {
73 Sum = (UINT8)(Sum + ptr[Index]);
74 Sum = (UINT8)(Sum + ptr[Index + 1]);
75 Sum = (UINT8)(Sum + ptr[Index + 2]);
76 Sum = (UINT8)(Sum + ptr[Index + 3]);
77 }
78
79 for ( ; Index < Size; Index++) {
80 Sum = (UINT8)(Sum + ptr[Index]);
81 }
82
83 //
84 // State field (since this indicates the different state of file).
85 //
86 Sum = (UINT8)(Sum - FileHeader->State);
87 //
88 // Checksum field of the file is not part of the header checksum.
89 //
90 Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File);
91
92 return Sum;
93 }
94
95 /**
96 Given the input file pointer, search for the next matching file in the
97 FFS volume as defined by SearchType. The search starts from FileHeader inside
98 the Firmware Volume defined by FwVolHeader.
99
100 @param SearchType Filter to find only files of this type.
101 Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
102 @param FwVolHeader Pointer to the FV header of the volume to search.
103 This parameter must point to a valid FFS volume.
104 @param FileHeader Pointer to the current file from which to begin searching.
105 This pointer will be updated upon return to reflect the file found.
106
107 @retval EFI_NOT_FOUND No files matching the search criteria were found
108 @retval EFI_SUCCESS
109 **/
110 EFI_STATUS
111 EFIAPI
112 FfsFindNextFile (
113 IN EFI_FV_FILETYPE SearchType,
114 IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
115 IN OUT EFI_FFS_FILE_HEADER **FileHeader
116 )
117 {
118 EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
119
120 EFI_FFS_FILE_HEADER *FfsFileHeader;
121 UINT32 FileLength;
122 UINT32 FileOccupiedSize;
123 UINT32 FileOffset;
124 UINT64 FvLength;
125 UINT8 ErasePolarity;
126 UINT8 FileState;
127
128 FvLength = FwVolHeader->FvLength;
129 if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
130 ErasePolarity = 1;
131 } else {
132 ErasePolarity = 0;
133 }
134
135 //
136 // If FileHeader is not specified (NULL) start with the first file in the
137 // firmware volume. Otherwise, start from the FileHeader.
138 //
139 if (*FileHeader == NULL) {
140 if (FwVolHeader->ExtHeaderOffset != 0) {
141 FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FwVolHeader +
142 FwVolHeader->ExtHeaderOffset);
143
144 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader +
145 FvExtHeader->ExtHeaderSize);
146 } else {
147 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader +
148 FwVolHeader->HeaderLength);
149 }
150
151 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FwVolHeader +
152 ALIGN_VALUE (
153 (UINTN)FfsFileHeader -
154 (UINTN)FwVolHeader,
155 8
156 ));
157 } else {
158 //
159 // Length is 24 bits wide so mask upper 8 bits
160 // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
161 //
162 FileLength = IS_FFS_FILE2 (*FileHeader) ?
163 FFS_FILE2_SIZE (*FileHeader) : FFS_FILE_SIZE (*FileHeader);
164 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
165 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize);
166 }
167
168 FileOffset = (UINT32)((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader);
169
170 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
171 //
172 // Get FileState which is the highest bit of the State
173 //
174 FileState = GetFileState (ErasePolarity, FfsFileHeader);
175
176 switch (FileState) {
177 case EFI_FILE_HEADER_INVALID:
178 if (IS_FFS_FILE2 (FfsFileHeader)) {
179 FileOffset += sizeof (EFI_FFS_FILE_HEADER2);
180 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
181 } else {
182 FileOffset += sizeof (EFI_FFS_FILE_HEADER);
183 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
184 }
185
186 break;
187
188 case EFI_FILE_DATA_VALID:
189 case EFI_FILE_MARKED_FOR_UPDATE:
190 if (CalculateHeaderChecksum (FfsFileHeader) == 0) {
191 FileLength = IS_FFS_FILE2 (FfsFileHeader) ?
192 FFS_FILE2_SIZE (FfsFileHeader) : FFS_FILE_SIZE (FfsFileHeader);
193 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
194
195 if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) {
196 *FileHeader = FfsFileHeader;
197
198 return EFI_SUCCESS;
199 }
200
201 FileOffset += FileOccupiedSize;
202 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
203 } else {
204 return EFI_NOT_FOUND;
205 }
206
207 break;
208
209 case EFI_FILE_DELETED:
210 FileLength = IS_FFS_FILE2 (FfsFileHeader) ?
211 FFS_FILE2_SIZE (FfsFileHeader) : FFS_FILE_SIZE (FfsFileHeader);
212 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
213 FileOffset += FileOccupiedSize;
214 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize);
215 break;
216
217 default:
218 return EFI_NOT_FOUND;
219 }
220 }
221
222 return EFI_NOT_FOUND;
223 }
224
225 /**
226 Locates a section within a series of sections
227 with the specified section type.
228
229 @param[in] Sections The sections to search
230 @param[in] SizeOfSections Total size of all sections
231 @param[in] SectionType The section type to locate
232 @param[out] FoundSection The FFS section if found
233
234 @retval EFI_SUCCESS The file and section was found
235 @retval EFI_NOT_FOUND The file and section was not found
236 @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted
237 **/
238 EFI_STATUS
239 EFIAPI
240 FindFfsSectionInSections (
241 IN VOID *Sections,
242 IN UINTN SizeOfSections,
243 IN EFI_SECTION_TYPE SectionType,
244 OUT EFI_COMMON_SECTION_HEADER **FoundSection
245 )
246 {
247 EFI_PHYSICAL_ADDRESS CurrentAddress;
248 UINT32 Size;
249 EFI_PHYSICAL_ADDRESS EndOfSections;
250 EFI_COMMON_SECTION_HEADER *Section;
251 EFI_PHYSICAL_ADDRESS EndOfSection;
252
253 //
254 // Loop through the FFS file sections
255 //
256 EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN)Sections;
257 EndOfSections = EndOfSection + SizeOfSections;
258 for ( ; ;) {
259 if (EndOfSection == EndOfSections) {
260 break;
261 }
262
263 CurrentAddress = EndOfSection;
264
265 Section = (EFI_COMMON_SECTION_HEADER *)(UINTN)CurrentAddress;
266
267 Size = IS_SECTION2 (Section) ? SECTION2_SIZE (Section) : SECTION_SIZE (Section);
268 if (Size < sizeof (*Section)) {
269 return EFI_VOLUME_CORRUPTED;
270 }
271
272 EndOfSection = CurrentAddress + Size;
273 if (EndOfSection > EndOfSections) {
274 return EFI_VOLUME_CORRUPTED;
275 }
276
277 Size = GET_OCCUPIED_SIZE (Size, 4);
278
279 //
280 // Look for the requested section type
281 //
282 if (Section->Type == SectionType) {
283 *FoundSection = Section;
284 return EFI_SUCCESS;
285 }
286 }
287
288 return EFI_NOT_FOUND;
289 }
290
291 /**
292 Given the input file pointer, search for the next matching section in the
293 FFS volume.
294
295 @param SearchType Filter to find only sections of this type.
296 @param FfsFileHeader Pointer to the current file to search.
297 @param SectionHeader Pointer to the Section matching SectionType in FfsFileHeader.
298 NULL if section not found
299
300 @retval EFI_NOT_FOUND No files matching the search criteria were found
301 @retval EFI_SUCCESS
302 **/
303 EFI_STATUS
304 EFIAPI
305 FfsFindSection (
306 IN EFI_SECTION_TYPE SectionType,
307 IN EFI_FFS_FILE_HEADER *FfsFileHeader,
308 IN OUT EFI_COMMON_SECTION_HEADER **SectionHeader
309 )
310 {
311 UINT32 FileSize;
312 EFI_COMMON_SECTION_HEADER *Section;
313 EFI_STATUS Status;
314
315 //
316 // Size is 24 bits wide so mask upper 8 bits.
317 // Does not include FfsFileHeader header size
318 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
319 //
320 if (IS_FFS_FILE2 (FfsFileHeader)) {
321 Section = (EFI_COMMON_SECTION_HEADER *)((EFI_FFS_FILE_HEADER2 *)FfsFileHeader + 1);
322 FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
323 } else {
324 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
325 FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
326 }
327
328 Status = FindFfsSectionInSections (
329 Section,
330 FileSize,
331 SectionType,
332 SectionHeader
333 );
334 return Status;
335 }
336
337 /**
338 Given the input file pointer, search for the next matching section in the
339 FFS volume.
340
341 @param SearchType Filter to find only sections of this type.
342 @param FfsFileHeader Pointer to the current file to search.
343 @param SectionData Pointer to the Section matching SectionType in FfsFileHeader.
344 NULL if section not found
345 @param SectionDataSize The size of SectionData
346
347 @retval EFI_NOT_FOUND No files matching the search criteria were found
348 @retval EFI_SUCCESS
349 **/
350 EFI_STATUS
351 EFIAPI
352 FfsFindSectionData (
353 IN EFI_SECTION_TYPE SectionType,
354 IN EFI_FFS_FILE_HEADER *FfsFileHeader,
355 IN OUT VOID **SectionData,
356 IN OUT UINTN *SectionDataSize
357 )
358 {
359 UINT32 FileSize;
360 EFI_COMMON_SECTION_HEADER *Section;
361 UINT32 SectionLength;
362 UINT32 ParsedLength;
363
364 //
365 // Size is 24 bits wide so mask upper 8 bits.
366 // Does not include FfsFileHeader header size
367 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
368 //
369 if (IS_FFS_FILE2 (FfsFileHeader)) {
370 Section = (EFI_COMMON_SECTION_HEADER *)((EFI_FFS_FILE_HEADER2 *)FfsFileHeader + 1);
371 FileSize = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
372 } else {
373 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1);
374 FileSize = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
375 }
376
377 *SectionData = NULL;
378 ParsedLength = 0;
379 while (ParsedLength < FileSize) {
380 if (Section->Type == SectionType) {
381 if (IS_SECTION2 (Section)) {
382 *SectionData = (VOID *)((EFI_COMMON_SECTION_HEADER2 *)Section + 1);
383 *SectionDataSize = SECTION2_SIZE (Section);
384 } else {
385 *SectionData = (VOID *)(Section + 1);
386 *SectionDataSize = SECTION_SIZE (Section);
387 }
388
389 return EFI_SUCCESS;
390 }
391
392 //
393 // Size is 24 bits wide so mask upper 8 bits.
394 // SectionLength is adjusted it is 4 byte aligned.
395 // Go to the next section
396 //
397 SectionLength = IS_SECTION2 (Section) ? SECTION2_SIZE (Section) : SECTION_SIZE (Section);
398 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
399
400 ParsedLength += SectionLength;
401 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength);
402 }
403
404 return EFI_NOT_FOUND;
405 }