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