]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
Add core FFS3 support, DxeCore.
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVolRead.c
1 /** @file
2 Implements functions to read firmware file
3
4 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "DxeMain.h"
16 #include "FwVolDriver.h"
17
18 /**
19 Required Alignment Alignment Value in FFS Alignment Value in
20 (bytes) Attributes Field Firmware Volume Interfaces
21 1 0 0
22 2 0 1
23 4 0 2
24 8 0 3
25 16 1 4
26 128 2 7
27 512 3 9
28 1 KB 4 10
29 4 KB 5 12
30 32 KB 6 15
31 64 KB 7 16
32 **/
33 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
34
35
36
37 /**
38 Convert the FFS File Attributes to FV File Attributes
39
40 @param FfsAttributes The attributes of UINT8 type.
41
42 @return The attributes of EFI_FV_FILE_ATTRIBUTES
43
44 **/
45 EFI_FV_FILE_ATTRIBUTES
46 FfsAttributes2FvFileAttributes (
47 IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
48 )
49 {
50 FfsAttributes = (EFI_FFS_FILE_ATTRIBUTES)((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
51 ASSERT (FfsAttributes < 8);
52
53 return (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[FfsAttributes];
54 }
55
56
57
58 /**
59 Given the input key, search for the next matching file in the volume.
60
61 @param This Indicates the calling context.
62 @param Key Key is a pointer to a caller allocated
63 buffer that contains implementation specific
64 data that is used to track where to begin
65 the search for the next file. The size of
66 the buffer must be at least This->KeySize
67 bytes long. To reinitialize the search and
68 begin from the beginning of the firmware
69 volume, the entire buffer must be cleared to
70 zero. Other than clearing the buffer to
71 initiate a new search, the caller must not
72 modify the data in the buffer between calls
73 to GetNextFile().
74 @param FileType FileType is a pointer to a caller allocated
75 EFI_FV_FILETYPE. The GetNextFile() API can
76 filter it's search for files based on the
77 value of *FileType input. A *FileType input
78 of 0 causes GetNextFile() to search for
79 files of all types. If a file is found, the
80 file's type is returned in *FileType.
81 *FileType is not modified if no file is
82 found.
83 @param NameGuid NameGuid is a pointer to a caller allocated
84 EFI_GUID. If a file is found, the file's
85 name is returned in *NameGuid. *NameGuid is
86 not modified if no file is found.
87 @param Attributes Attributes is a pointer to a caller
88 allocated EFI_FV_FILE_ATTRIBUTES. If a file
89 is found, the file's attributes are returned
90 in *Attributes. *Attributes is not modified
91 if no file is found.
92 @param Size Size is a pointer to a caller allocated
93 UINTN. If a file is found, the file's size
94 is returned in *Size. *Size is not modified
95 if no file is found.
96
97 @retval EFI_SUCCESS Successfully find the file.
98 @retval EFI_DEVICE_ERROR Device error.
99 @retval EFI_ACCESS_DENIED Fv could not read.
100 @retval EFI_NOT_FOUND No matching file found.
101 @retval EFI_INVALID_PARAMETER Invalid parameter
102
103 **/
104 EFI_STATUS
105 EFIAPI
106 FvGetNextFile (
107 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
108 IN OUT VOID *Key,
109 IN OUT EFI_FV_FILETYPE *FileType,
110 OUT EFI_GUID *NameGuid,
111 OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
112 OUT UINTN *Size
113 )
114 {
115 EFI_STATUS Status;
116 FV_DEVICE *FvDevice;
117 EFI_FV_ATTRIBUTES FvAttributes;
118 EFI_FFS_FILE_HEADER *FfsFileHeader;
119 UINTN *KeyValue;
120 LIST_ENTRY *Link;
121 FFS_FILE_LIST_ENTRY *FfsFileEntry;
122
123 FvDevice = FV_DEVICE_FROM_THIS (This);
124
125 Status = FvGetVolumeAttributes (This, &FvAttributes);
126 if (EFI_ERROR (Status)){
127 return Status;
128 }
129
130 //
131 // Check if read operation is enabled
132 //
133 if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
134 return EFI_ACCESS_DENIED;
135 }
136
137 if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
138 //
139 // File type needs to be in 0 - 0x0D
140 //
141 return EFI_NOT_FOUND;
142 }
143
144 KeyValue = (UINTN *)Key;
145 for (;;) {
146 if (*KeyValue == 0) {
147 //
148 // Search for 1st matching file
149 //
150 Link = &FvDevice->FfsFileListHeader;
151 } else {
152 //
153 // Key is pointer to FFsFileEntry, so get next one
154 //
155 Link = (LIST_ENTRY *)(*KeyValue);
156 }
157
158 if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
159 //
160 // Next is end of list so we did not find data
161 //
162 return EFI_NOT_FOUND;
163 }
164
165 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;
166 FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;
167
168 //
169 // remember the key
170 //
171 *KeyValue = (UINTN)FfsFileEntry;
172
173 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
174 //
175 // we ignore pad files
176 //
177 continue;
178 }
179
180 if (*FileType == EFI_FV_FILETYPE_ALL) {
181 //
182 // Process all file types so we have a match
183 //
184 break;
185 }
186
187 if (*FileType == FfsFileHeader->Type) {
188 //
189 // Found a matching file type
190 //
191 break;
192 }
193
194 }
195
196 //
197 // Return FileType, NameGuid, and Attributes
198 //
199 *FileType = FfsFileHeader->Type;
200 CopyGuid (NameGuid, &FfsFileHeader->Name);
201 *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
202
203 //
204 // we need to substract the header size
205 //
206 if (IS_FFS_FILE2 (FfsFileHeader)) {
207 *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
208 } else {
209 *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
210 }
211
212 return EFI_SUCCESS;
213 }
214
215
216
217 /**
218 Locates a file in the firmware volume and
219 copies it to the supplied buffer.
220
221 @param This Indicates the calling context.
222 @param NameGuid Pointer to an EFI_GUID, which is the
223 filename.
224 @param Buffer Buffer is a pointer to pointer to a buffer
225 in which the file or section contents or are
226 returned.
227 @param BufferSize BufferSize is a pointer to caller allocated
228 UINTN. On input *BufferSize indicates the
229 size in bytes of the memory region pointed
230 to by Buffer. On output, *BufferSize
231 contains the number of bytes required to
232 read the file.
233 @param FoundType FoundType is a pointer to a caller allocated
234 EFI_FV_FILETYPE that on successful return
235 from Read() contains the type of file read.
236 This output reflects the file type
237 irrespective of the value of the SectionType
238 input.
239 @param FileAttributes FileAttributes is a pointer to a caller
240 allocated EFI_FV_FILE_ATTRIBUTES. On
241 successful return from Read(),
242 *FileAttributes contains the attributes of
243 the file read.
244 @param AuthenticationStatus AuthenticationStatus is a pointer to a
245 caller allocated UINTN in which the
246 authentication status is returned.
247
248 @retval EFI_SUCCESS Successfully read to memory buffer.
249 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
250 @retval EFI_NOT_FOUND Not found.
251 @retval EFI_DEVICE_ERROR Device error.
252 @retval EFI_ACCESS_DENIED Could not read.
253 @retval EFI_INVALID_PARAMETER Invalid parameter.
254 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
255
256 **/
257 EFI_STATUS
258 EFIAPI
259 FvReadFile (
260 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
261 IN CONST EFI_GUID *NameGuid,
262 IN OUT VOID **Buffer,
263 IN OUT UINTN *BufferSize,
264 OUT EFI_FV_FILETYPE *FoundType,
265 OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
266 OUT UINT32 *AuthenticationStatus
267 )
268 {
269 EFI_STATUS Status;
270 FV_DEVICE *FvDevice;
271 EFI_GUID SearchNameGuid;
272 EFI_FV_FILETYPE LocalFoundType;
273 EFI_FV_FILE_ATTRIBUTES LocalAttributes;
274 UINTN FileSize;
275 UINT8 *SrcPtr;
276 EFI_FFS_FILE_HEADER *FfsHeader;
277 UINTN InputBufferSize;
278
279 if (NameGuid == NULL) {
280 return EFI_INVALID_PARAMETER;
281 }
282
283 FvDevice = FV_DEVICE_FROM_THIS (This);
284
285
286 //
287 // Keep looking until we find the matching NameGuid.
288 // The Key is really an FfsFileEntry
289 //
290 FvDevice->LastKey = 0;
291 do {
292 LocalFoundType = 0;
293 Status = FvGetNextFile (
294 This,
295 &FvDevice->LastKey,
296 &LocalFoundType,
297 &SearchNameGuid,
298 &LocalAttributes,
299 &FileSize
300 );
301 if (EFI_ERROR (Status)) {
302 return EFI_NOT_FOUND;
303 }
304 } while (!CompareGuid (&SearchNameGuid, NameGuid));
305
306 //
307 // Get a pointer to the header
308 //
309 FfsHeader = FvDevice->LastKey->FfsHeader;
310
311 //
312 // Remember callers buffer size
313 //
314 InputBufferSize = *BufferSize;
315
316 //
317 // Calculate return values
318 //
319 *FoundType = FfsHeader->Type;
320 *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
321 *AuthenticationStatus = 0;
322 *BufferSize = FileSize;
323
324 if (Buffer == NULL) {
325 //
326 // If Buffer is NULL, we only want to get the information collected so far
327 //
328 return EFI_SUCCESS;
329 }
330
331 //
332 // Skip over file header
333 //
334 if (IS_FFS_FILE2 (FfsHeader)) {
335 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
336 } else {
337 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
338 }
339
340 Status = EFI_SUCCESS;
341 if (*Buffer == NULL) {
342 //
343 // Caller passed in a pointer so allocate buffer for them
344 //
345 *Buffer = AllocatePool (FileSize);
346 if (*Buffer == NULL) {
347 return EFI_OUT_OF_RESOURCES;
348 }
349 } else if (FileSize > InputBufferSize) {
350 //
351 // Callers buffer was not big enough
352 //
353 Status = EFI_WARN_BUFFER_TOO_SMALL;
354 FileSize = InputBufferSize;
355 }
356
357 //
358 // Copy data into callers buffer
359 //
360 CopyMem (*Buffer, SrcPtr, FileSize);
361
362 return Status;
363 }
364
365
366
367 /**
368 Locates a section in a given FFS File and
369 copies it to the supplied buffer (not including section header).
370
371 @param This Indicates the calling context.
372 @param NameGuid Pointer to an EFI_GUID, which is the
373 filename.
374 @param SectionType Indicates the section type to return.
375 @param SectionInstance Indicates which instance of sections with a
376 type of SectionType to return.
377 @param Buffer Buffer is a pointer to pointer to a buffer
378 in which the file or section contents or are
379 returned.
380 @param BufferSize BufferSize is a pointer to caller allocated
381 UINTN.
382 @param AuthenticationStatus AuthenticationStatus is a pointer to a
383 caller allocated UINT32 in which the
384 authentication status is returned.
385
386 @retval EFI_SUCCESS Successfully read the file section into
387 buffer.
388 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
389 @retval EFI_NOT_FOUND Section not found.
390 @retval EFI_DEVICE_ERROR Device error.
391 @retval EFI_ACCESS_DENIED Could not read.
392 @retval EFI_INVALID_PARAMETER Invalid parameter.
393
394 **/
395 EFI_STATUS
396 EFIAPI
397 FvReadFileSection (
398 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
399 IN CONST EFI_GUID *NameGuid,
400 IN EFI_SECTION_TYPE SectionType,
401 IN UINTN SectionInstance,
402 IN OUT VOID **Buffer,
403 IN OUT UINTN *BufferSize,
404 OUT UINT32 *AuthenticationStatus
405 )
406 {
407 EFI_STATUS Status;
408 FV_DEVICE *FvDevice;
409 EFI_FV_FILETYPE FileType;
410 EFI_FV_FILE_ATTRIBUTES FileAttributes;
411 UINTN FileSize;
412 UINT8 *FileBuffer;
413 FFS_FILE_LIST_ENTRY *FfsEntry;
414
415 if (NameGuid == NULL || Buffer == NULL) {
416 return EFI_INVALID_PARAMETER;
417 }
418
419 FvDevice = FV_DEVICE_FROM_THIS (This);
420
421 //
422 // Read the whole file into buffer
423 //
424 FileBuffer = NULL;
425 Status = FvReadFile (
426 This,
427 NameGuid,
428 (VOID **)&FileBuffer,
429 &FileSize,
430 &FileType,
431 &FileAttributes,
432 AuthenticationStatus
433 );
434 //
435 // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.
436 //
437 FfsEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->LastKey;
438
439 if (EFI_ERROR (Status)) {
440 return Status;
441 }
442
443 //
444 // Check to see that the file actually HAS sections before we go any further.
445 //
446 if (FileType == EFI_FV_FILETYPE_RAW) {
447 Status = EFI_NOT_FOUND;
448 goto Done;
449 }
450
451 //
452 // Use FfsEntry to cache Section Extraction Protocol Information
453 //
454 if (FfsEntry->StreamHandle == 0) {
455 Status = OpenSectionStream (
456 FileSize,
457 FileBuffer,
458 &FfsEntry->StreamHandle
459 );
460 if (EFI_ERROR (Status)) {
461 goto Done;
462 }
463 }
464
465 //
466 // If SectionType == 0 We need the whole section stream
467 //
468 Status = GetSection (
469 FfsEntry->StreamHandle,
470 (SectionType == 0) ? NULL : &SectionType,
471 NULL,
472 (SectionType == 0) ? 0 : SectionInstance,
473 Buffer,
474 BufferSize,
475 AuthenticationStatus,
476 FvDevice->IsFfs3Fv
477 );
478
479 //
480 // Close of stream defered to close of FfsHeader list to allow SEP to cache data
481 //
482
483 Done:
484 CoreFreePool (FileBuffer);
485
486 return Status;
487 }
488
489