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