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