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