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