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