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