]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
IntelFrameworkModulePkg FwVolDxe: Support FFS_ATTRIB_DATA_ALIGNMENT_2
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / FwVolDxe / FwVolRead.c
1 /** @file
2 Implements functions to read firmware file.
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions
8 of the BSD License which accompanies this distribution. The
9 full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "FwVolDriver.h"
18
19 /**
20 Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in
21 (bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces
22 1 0 0 0
23 16 1 0 4
24 128 2 0 7
25 512 3 0 9
26 1 KB 4 0 10
27 4 KB 5 0 12
28 32 KB 6 0 15
29 64 KB 7 0 16
30 128 KB 0 1 17
31 256 KB 1 1 18
32 512 KB 2 1 19
33 1 MB 3 1 20
34 2 MB 4 1 21
35 4 MB 5 1 22
36 8 MB 6 1 23
37 16 MB 7 1 24
38 **/
39 UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
40 UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};
41
42 /**
43 Convert the FFS File Attributes to FV File Attributes.
44
45 @param FfsAttributes The attributes of UINT8 type.
46
47 @return The attributes of EFI_FV_FILE_ATTRIBUTES
48
49 **/
50 EFI_FV_FILE_ATTRIBUTES
51 FfsAttributes2FvFileAttributes (
52 IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
53 )
54 {
55 UINT8 DataAlignment;
56 EFI_FV_FILE_ATTRIBUTES FileAttribute;
57
58 DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
59 ASSERT (DataAlignment < 8);
60
61 if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {
62 FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];
63 } else {
64 FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
65 }
66
67 if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
68 FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
69 }
70
71 return FileAttribute;
72 }
73
74 /**
75 Given the input key, search for the next matching file in the volume.
76
77 @param This Indicates the calling context.
78 @param Key Key is a pointer to a caller allocated
79 buffer that contains implementation specific
80 data that is used to track where to begin
81 the search for the next file. The size of
82 the buffer must be at least This->KeySize
83 bytes long. To reinitialize the search and
84 begin from the beginning of the firmware
85 volume, the entire buffer must be cleared to
86 zero. Other than clearing the buffer to
87 initiate a new search, the caller must not
88 modify the data in the buffer between calls
89 to GetNextFile().
90 @param FileType FileType is a pointer to a caller allocated
91 EFI_FV_FILETYPE. The GetNextFile() API can
92 filter it's search for files based on the
93 value of *FileType input. A *FileType input
94 of 0 causes GetNextFile() to search for
95 files of all types. If a file is found, the
96 file's type is returned in *FileType.
97 *FileType is not modified if no file is
98 found.
99 @param NameGuid NameGuid is a pointer to a caller allocated
100 EFI_GUID. If a file is found, the file's
101 name is returned in *NameGuid. *NameGuid is
102 not modified if no file is found.
103 @param Attributes Attributes is a pointer to a caller
104 allocated EFI_FV_FILE_ATTRIBUTES. If a file
105 is found, the file's attributes are returned
106 in *Attributes. *Attributes is not modified
107 if no file is found.
108 @param Size Size is a pointer to a caller allocated
109 UINTN. If a file is found, the file's size
110 is returned in *Size. *Size is not modified
111 if no file is found.
112
113 @retval EFI_SUCCESS Successfully find the file.
114 @retval EFI_DEVICE_ERROR Device error.
115 @retval EFI_ACCESS_DENIED Fv could not read.
116 @retval EFI_NOT_FOUND No matching file found.
117 @retval EFI_INVALID_PARAMETER Invalid parameter
118
119 **/
120 EFI_STATUS
121 EFIAPI
122 FvGetNextFile (
123 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
124 IN OUT VOID *Key,
125 IN OUT EFI_FV_FILETYPE *FileType,
126 OUT EFI_GUID *NameGuid,
127 OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
128 OUT UINTN *Size
129 )
130 {
131 EFI_STATUS Status;
132 FV_DEVICE *FvDevice;
133 EFI_FV_ATTRIBUTES FvAttributes;
134 EFI_FFS_FILE_HEADER *FfsFileHeader;
135 UINTN *KeyValue;
136 LIST_ENTRY *Link;
137 FFS_FILE_LIST_ENTRY *FfsFileEntry;
138
139 FvDevice = FV_DEVICE_FROM_THIS (This);
140
141 Status = This->GetVolumeAttributes (This, &FvAttributes);
142 if (EFI_ERROR (Status)) {
143 return Status;
144 }
145
146 KeyValue = (UINTN *) Key;
147 FfsFileHeader = NULL;
148
149 //
150 // Check if read operation is enabled
151 //
152 if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
153 return EFI_ACCESS_DENIED;
154 }
155
156 if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
157 //
158 // File type needs to be in 0 - 0x0D
159 //
160 return EFI_NOT_FOUND;
161 }
162
163 do {
164 if (*KeyValue == 0) {
165 //
166 // Search for 1st matching file
167 //
168 Link = &FvDevice->FfsFileListHeader;
169 if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
170 return EFI_NOT_FOUND;
171 }
172
173 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
174 FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
175
176 //
177 // remember the key
178 //
179 *KeyValue = (UINTN) FfsFileEntry;
180
181 //
182 // we ignore pad files
183 //
184 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
185 continue;
186 }
187
188 if (*FileType == 0) {
189 break;
190 }
191
192 if (*FileType == FfsFileHeader->Type) {
193 break;
194 }
195
196 } else {
197 //
198 // Getting link from last Ffs
199 //
200 Link = (LIST_ENTRY *) (*KeyValue);
201 if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
202 return EFI_NOT_FOUND;
203 }
204
205 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
206 FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
207
208 //
209 // remember the key
210 //
211 *KeyValue = (UINTN) FfsFileEntry;
212
213 //
214 // we ignore pad files
215 //
216 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
217 continue;
218 }
219
220 if (*FileType == EFI_FV_FILETYPE_ALL) {
221 break;
222 }
223
224 if (*FileType == FfsFileHeader->Type) {
225 break;
226 }
227 }
228 } while (Link->ForwardLink != &FvDevice->FfsFileListHeader);
229
230 //
231 // Cache this file entry
232 //
233 FvDevice->CurrentFfsFile = FfsFileEntry;
234
235 *FileType = FfsFileHeader->Type;
236 CopyGuid (NameGuid, &FfsFileHeader->Name);
237 *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
238 if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
239 *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
240 }
241
242 //
243 // we need to substract the header size
244 //
245 if (IS_FFS_FILE2 (FfsFileHeader)) {
246 *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
247 } else {
248 *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
249 }
250
251 if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
252 //
253 // specially deal with VTF file
254 //
255 UINT8 *SrcPtr;
256 UINT32 Tmp;
257
258 if (IS_FFS_FILE2 (FfsFileHeader)) {
259 SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER2);
260 } else {
261 SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER);
262 }
263
264 while (*Size >= 4) {
265 Tmp = *(UINT32 *) SrcPtr;
266 if (Tmp == 0) {
267 SrcPtr += 4;
268 (*Size) -= 4;
269 } else {
270 break;
271 }
272 }
273 }
274
275 return EFI_SUCCESS;
276 }
277
278 /**
279 Locates a file in the firmware volume and
280 copies it to the supplied buffer.
281
282 @param This Indicates the calling context.
283 @param NameGuid Pointer to an EFI_GUID, which is the
284 filename.
285 @param Buffer Buffer is a pointer to pointer to a buffer
286 in which the file or section contents or are
287 returned.
288 @param BufferSize BufferSize is a pointer to caller allocated
289 UINTN. On input *BufferSize indicates the
290 size in bytes of the memory region pointed
291 to by Buffer. On output, *BufferSize
292 contains the number of bytes required to
293 read the file.
294 @param FoundType FoundType is a pointer to a caller allocated
295 EFI_FV_FILETYPE that on successful return
296 from Read() contains the type of file read.
297 This output reflects the file type
298 irrespective of the value of the SectionType
299 input.
300 @param FileAttributes FileAttributes is a pointer to a caller
301 allocated EFI_FV_FILE_ATTRIBUTES. On
302 successful return from Read(),
303 *FileAttributes contains the attributes of
304 the file read.
305 @param AuthenticationStatus AuthenticationStatus is a pointer to a
306 caller allocated UINTN in which the
307 authentication status is returned.
308
309 @retval EFI_SUCCESS Successfully read to memory buffer.
310 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
311 @retval EFI_NOT_FOUND Not found.
312 @retval EFI_DEVICE_ERROR Device error.
313 @retval EFI_ACCESS_DENIED Could not read.
314 @retval EFI_INVALID_PARAMETER Invalid parameter.
315 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
316
317 **/
318 EFI_STATUS
319 EFIAPI
320 FvReadFile (
321 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
322 IN CONST EFI_GUID *NameGuid,
323 IN OUT VOID **Buffer,
324 IN OUT UINTN *BufferSize,
325 OUT EFI_FV_FILETYPE *FoundType,
326 OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
327 OUT UINT32 *AuthenticationStatus
328 )
329 {
330 EFI_STATUS Status;
331 FV_DEVICE *FvDevice;
332 UINTN Key;
333 EFI_GUID SearchNameGuid;
334 EFI_FV_ATTRIBUTES FvAttributes;
335 EFI_FV_FILETYPE LocalFoundType;
336 EFI_FV_FILE_ATTRIBUTES LocalAttributes;
337 UINTN FileSize;
338 UINT8 *SrcPtr;
339 FFS_FILE_LIST_ENTRY *FfsFileEntry;
340 EFI_FFS_FILE_HEADER *FfsHeader;
341 UINT8 *FileBuffer;
342
343 if (NULL == This || NULL == NameGuid) {
344 return EFI_INVALID_PARAMETER;
345 }
346
347 FvDevice = FV_DEVICE_FROM_THIS (This);
348
349 Status = This->GetVolumeAttributes (This, &FvAttributes);
350 if (EFI_ERROR (Status)) {
351 return Status;
352 }
353 //
354 // First check to see that FV is enabled for reads...
355 //
356 if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
357 return EFI_ACCESS_DENIED;
358 }
359
360 FfsHeader = NULL;
361
362 //
363 // Check if the file was read last time.
364 //
365 FfsFileEntry = FvDevice->CurrentFfsFile;
366
367 if (FfsFileEntry != NULL) {
368 FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
369 }
370
371 if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {
372 //
373 // If not match or no file cached, search this file
374 //
375 Key = 0;
376 do {
377 LocalFoundType = 0;
378 Status = This->GetNextFile (
379 This,
380 &Key,
381 &LocalFoundType,
382 &SearchNameGuid,
383 &LocalAttributes,
384 &FileSize
385 );
386 if (EFI_ERROR (Status)) {
387 return EFI_NOT_FOUND;
388 }
389 } while (!CompareGuid (&SearchNameGuid, NameGuid));
390
391 //
392 // Get file entry
393 //
394 FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
395
396 //
397 // Update the cache
398 //
399 FvDevice->CurrentFfsFile = FfsFileEntry;
400
401 FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
402
403 } else {
404 //
405 // Get File Size of the cached file
406 //
407 if (IS_FFS_FILE2 (FfsHeader)) {
408 FileSize = FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2);
409 } else {
410 FileSize = FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER);
411 }
412 }
413 //
414 // Get file info
415 //
416 *FoundType = FfsHeader->Type;
417 *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
418 if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
419 *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
420 }
421 //
422 // Inherit the authentication status.
423 //
424 *AuthenticationStatus = FvDevice->AuthenticationStatus;
425
426 //
427 // If Buffer is NULL, we only want to get some information
428 //
429 if (Buffer == NULL) {
430 *BufferSize = FileSize;
431 return EFI_SUCCESS;
432 }
433
434 if (IS_FFS_FILE2 (FfsHeader)) {
435 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
436 } else {
437 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
438 }
439
440 if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
441 //
442 // specially deal with VTF file
443 //
444 UINT32 Tmp;
445
446 while (FileSize >= 4) {
447 Tmp = *(UINT32 *) SrcPtr;
448 if (Tmp == 0) {
449 SrcPtr += 4;
450 FileSize -= 4;
451 } else {
452 break;
453 }
454 }
455 }
456 //
457 // If we drop out of the above loop, we've found the correct file header...
458 //
459 if (*Buffer == NULL) {
460 FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
461 if (FileBuffer == NULL) {
462 return EFI_OUT_OF_RESOURCES;
463 }
464
465 *BufferSize = FileSize;
466 *Buffer = FileBuffer;
467
468 return EFI_SUCCESS;
469 }
470 //
471 // If the user's buffer is smaller than the file size, then copy as much
472 // as we can and return an appropriate status.
473 //
474 if (FileSize > *BufferSize) {
475 CopyMem (*Buffer, SrcPtr, *BufferSize);
476 *BufferSize = FileSize;
477 return EFI_WARN_BUFFER_TOO_SMALL;
478 }
479 //
480 // User's buffer size is ok, so copy the entire file to their buffer.
481 //
482 *BufferSize = FileSize;
483 CopyMem (*Buffer, SrcPtr, *BufferSize);
484
485 return EFI_SUCCESS;
486 }
487
488 /**
489 Locates a section in a given FFS File and
490 copies it to the supplied buffer (not including section header).
491
492 @param This Indicates the calling context.
493 @param NameGuid Pointer to an EFI_GUID, which is the
494 filename.
495 @param SectionType Indicates the section type to return.
496 @param SectionInstance Indicates which instance of sections with a
497 type of SectionType to return.
498 @param Buffer Buffer is a pointer to pointer to a buffer
499 in which the file or section contents or are
500 returned.
501 @param BufferSize BufferSize is a pointer to caller allocated
502 UINTN.
503 @param AuthenticationStatus AuthenticationStatus is a pointer to a
504 caller allocated UINT32 in which the
505 authentication status is returned.
506
507 @retval EFI_SUCCESS Successfully read the file section into
508 buffer.
509 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
510 @retval EFI_NOT_FOUND Section not found.
511 @retval EFI_DEVICE_ERROR Device error.
512 @retval EFI_ACCESS_DENIED Could not read.
513 @retval EFI_INVALID_PARAMETER Invalid parameter.
514
515 **/
516 EFI_STATUS
517 EFIAPI
518 FvReadFileSection (
519 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
520 IN CONST EFI_GUID *NameGuid,
521 IN EFI_SECTION_TYPE SectionType,
522 IN UINTN SectionInstance,
523 IN OUT VOID **Buffer,
524 IN OUT UINTN *BufferSize,
525 OUT UINT32 *AuthenticationStatus
526 )
527 {
528 EFI_STATUS Status;
529 FV_DEVICE *FvDevice;
530 EFI_FV_ATTRIBUTES FvAttributes;
531 EFI_FV_FILETYPE FileType;
532 EFI_FV_FILE_ATTRIBUTES FileAttributes;
533 UINTN FileSize;
534 UINT8 *FileBuffer;
535 EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
536 UINTN StreamHandle;
537
538 if (NULL == This || NULL == NameGuid || Buffer == NULL) {
539 return EFI_INVALID_PARAMETER;
540 }
541
542 FvDevice = FV_DEVICE_FROM_THIS (This);
543
544 Status = This->GetVolumeAttributes (This, &FvAttributes);
545 if (EFI_ERROR (Status)) {
546 return Status;
547 }
548 //
549 // First check to see that FV is enabled for reads...
550 //
551 if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
552 return EFI_ACCESS_DENIED;
553 }
554 //
555 // Read the whole file into buffer
556 //
557 FileBuffer = NULL;
558 Status = This->ReadFile (
559 This,
560 NameGuid,
561 (VOID **) &FileBuffer,
562 &FileSize,
563 &FileType,
564 &FileAttributes,
565 AuthenticationStatus
566 );
567
568 if (EFI_ERROR (Status)) {
569 return Status;
570 }
571 //
572 // Check to see that the file actually HAS sections before we go any further.
573 //
574 if (FileType == EFI_FV_FILETYPE_RAW) {
575 FreePool (FileBuffer);
576 return EFI_NOT_FOUND;
577 }
578 //
579 // Located the protocol
580 //
581 Status = gBS->LocateProtocol (
582 &gEfiSectionExtractionProtocolGuid,
583 NULL,
584 (VOID **) &Sep
585 );
586 if (EFI_ERROR (Status)) {
587 FreePool (FileBuffer);
588 return Status;
589 }
590
591 Status = Sep->OpenSectionStream (
592 Sep,
593 FileSize,
594 FileBuffer,
595 &StreamHandle
596 );
597
598 if (EFI_ERROR (Status)) {
599 FreePool (FileBuffer);
600 return Status;
601 }
602
603 if (SectionType == 0) {
604 //
605 // We need the whole section stream
606 //
607 Status = Sep->GetSection (
608 Sep,
609 StreamHandle,
610 NULL,
611 NULL,
612 0,
613 Buffer,
614 BufferSize,
615 AuthenticationStatus
616 );
617 } else {
618 Status = Sep->GetSection (
619 Sep,
620 StreamHandle,
621 &SectionType,
622 NULL,
623 SectionInstance,
624 Buffer,
625 BufferSize,
626 AuthenticationStatus
627 );
628 }
629
630 if (!EFI_ERROR (Status)) {
631 //
632 // Inherit the authentication status.
633 //
634 *AuthenticationStatus |= FvDevice->AuthenticationStatus;
635 }
636
637 //
638 // Handle AuthenticationStatus if necessary
639 //
640 Sep->CloseSectionStream (Sep, StreamHandle);
641
642 FreePool (FileBuffer);
643
644 return Status;
645 }