]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVol/FwVolRead.c
MdeModulePkg Core: Support FFS_ATTRIB_DATA_ALIGNMENT_2
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVol / FwVolRead.c
CommitLineData
23c98c94 1/** @file\r
504214c4 2 Implements functions to read firmware file\r
28a00297 3\r
e411f8ca 4Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
23c98c94 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
28a00297 12\r
504214c4 13**/\r
28a00297 14\r
9c4ac31c 15#include "DxeMain.h"\r
ec90508b 16#include "FwVolDriver.h"\r
28a00297 17\r
ec90508b 18/**\r
e411f8ca
SZ
19Required Alignment Alignment Value in FFS FFS_ATTRIB_DATA_ALIGNMENT2 Alignment Value in\r
20(bytes) Attributes Field in FFS Attributes Field Firmware Volume Interfaces\r
211 0 0 0\r
2216 1 0 4\r
23128 2 0 7\r
24512 3 0 9\r
251 KB 4 0 10\r
264 KB 5 0 12\r
2732 KB 6 0 15\r
2864 KB 7 0 16\r
29128 KB 0 1 17\r
30256 KB 1 1 18\r
31512 KB 2 1 19\r
321 MB 3 1 20\r
332 MB 4 1 21\r
344 MB 5 1 22\r
358 MB 6 1 23\r
3616 MB 7 1 24\r
ec90508b 37**/\r
022c6d45 38UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};\r
e411f8ca 39UINT8 mFvAttributes2[] = {17, 18, 19, 20, 21, 22, 23, 24};\r
28a00297 40\r
162ed594 41/**\r
42 Convert the FFS File Attributes to FV File Attributes\r
43\r
022c6d45 44 @param FfsAttributes The attributes of UINT8 type.\r
162ed594 45\r
46 @return The attributes of EFI_FV_FILE_ATTRIBUTES\r
47\r
48**/\r
28a00297 49EFI_FV_FILE_ATTRIBUTES\r
50FfsAttributes2FvFileAttributes (\r
51 IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes\r
52 )\r
28a00297 53{\r
795bb9b6
SZ
54 UINT8 DataAlignment;\r
55 EFI_FV_FILE_ATTRIBUTES FileAttribute;\r
28a00297 56\r
795bb9b6
SZ
57 DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);\r
58 ASSERT (DataAlignment < 8);\r
28a00297 59\r
e411f8ca
SZ
60 if ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT_2) != 0) {\r
61 FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes2[DataAlignment];\r
62 } else {\r
63 FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];\r
64 }\r
28a00297 65\r
795bb9b6
SZ
66 if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {\r
67 FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;\r
68 }\r
69\r
70 return FileAttribute;\r
71}\r
162ed594 72\r
73/**\r
74 Given the input key, search for the next matching file in the volume.\r
75\r
022c6d45 76 @param This Indicates the calling context.\r
77 @param Key Key is a pointer to a caller allocated\r
78 buffer that contains implementation specific\r
79 data that is used to track where to begin\r
80 the search for the next file. The size of\r
81 the buffer must be at least This->KeySize\r
82 bytes long. To reinitialize the search and\r
83 begin from the beginning of the firmware\r
84 volume, the entire buffer must be cleared to\r
85 zero. Other than clearing the buffer to\r
86 initiate a new search, the caller must not\r
87 modify the data in the buffer between calls\r
88 to GetNextFile().\r
89 @param FileType FileType is a pointer to a caller allocated\r
90 EFI_FV_FILETYPE. The GetNextFile() API can\r
91 filter it's search for files based on the\r
92 value of *FileType input. A *FileType input\r
93 of 0 causes GetNextFile() to search for\r
94 files of all types. If a file is found, the\r
95 file's type is returned in *FileType.\r
96 *FileType is not modified if no file is\r
97 found.\r
98 @param NameGuid NameGuid is a pointer to a caller allocated\r
99 EFI_GUID. If a file is found, the file's\r
100 name is returned in *NameGuid. *NameGuid is\r
101 not modified if no file is found.\r
102 @param Attributes Attributes is a pointer to a caller\r
103 allocated EFI_FV_FILE_ATTRIBUTES. If a file\r
104 is found, the file's attributes are returned\r
105 in *Attributes. *Attributes is not modified\r
106 if no file is found.\r
107 @param Size Size is a pointer to a caller allocated\r
108 UINTN. If a file is found, the file's size\r
109 is returned in *Size. *Size is not modified\r
110 if no file is found.\r
111\r
112 @retval EFI_SUCCESS Successfully find the file.\r
113 @retval EFI_DEVICE_ERROR Device error.\r
114 @retval EFI_ACCESS_DENIED Fv could not read.\r
115 @retval EFI_NOT_FOUND No matching file found.\r
162ed594 116 @retval EFI_INVALID_PARAMETER Invalid parameter\r
117\r
118**/\r
28a00297 119EFI_STATUS\r
120EFIAPI\r
121FvGetNextFile (\r
0c2b5da8 122 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
123 IN OUT VOID *Key,\r
124 IN OUT EFI_FV_FILETYPE *FileType,\r
28a00297 125 OUT EFI_GUID *NameGuid,\r
126 OUT EFI_FV_FILE_ATTRIBUTES *Attributes,\r
162ed594 127 OUT UINTN *Size\r
28a00297 128 )\r
28a00297 129{\r
130 EFI_STATUS Status;\r
131 FV_DEVICE *FvDevice;\r
132 EFI_FV_ATTRIBUTES FvAttributes;\r
133 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
134 UINTN *KeyValue;\r
135 LIST_ENTRY *Link;\r
136 FFS_FILE_LIST_ENTRY *FfsFileEntry;\r
28a00297 137\r
138 FvDevice = FV_DEVICE_FROM_THIS (This);\r
139\r
140 Status = FvGetVolumeAttributes (This, &FvAttributes);\r
141 if (EFI_ERROR (Status)){\r
142 return Status;\r
143 }\r
144\r
145 //\r
146 // Check if read operation is enabled\r
147 //\r
0c2b5da8 148 if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {\r
28a00297 149 return EFI_ACCESS_DENIED;\r
150 }\r
151\r
202c3279 152 if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {\r
28a00297 153 //\r
202c3279 154 // File type needs to be in 0 - 0x0D\r
28a00297 155 //\r
26fa3b49 156 return EFI_NOT_FOUND;\r
28a00297 157 }\r
158\r
159 KeyValue = (UINTN *)Key;\r
160 for (;;) {\r
161 if (*KeyValue == 0) {\r
162 //\r
163 // Search for 1st matching file\r
164 //\r
165 Link = &FvDevice->FfsFileListHeader;\r
166 } else {\r
167 //\r
168 // Key is pointer to FFsFileEntry, so get next one\r
169 //\r
170 Link = (LIST_ENTRY *)(*KeyValue);\r
171 }\r
172\r
173 if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {\r
174 //\r
175 // Next is end of list so we did not find data\r
176 //\r
177 return EFI_NOT_FOUND;\r
178 }\r
179\r
180 FfsFileEntry = (FFS_FILE_LIST_ENTRY *)Link->ForwardLink;\r
181 FfsFileHeader = (EFI_FFS_FILE_HEADER *)FfsFileEntry->FfsHeader;\r
182\r
183 //\r
184 // remember the key\r
185 //\r
186 *KeyValue = (UINTN)FfsFileEntry;\r
187\r
188 if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {\r
189 //\r
190 // we ignore pad files\r
191 //\r
192 continue;\r
193 }\r
194\r
ef816997 195 if (*FileType == EFI_FV_FILETYPE_ALL) {\r
28a00297 196 //\r
197 // Process all file types so we have a match\r
198 //\r
199 break;\r
200 }\r
201\r
202 if (*FileType == FfsFileHeader->Type) {\r
203 //\r
204 // Found a matching file type\r
205 //\r
206 break;\r
207 }\r
208\r
022c6d45 209 }\r
28a00297 210\r
211 //\r
212 // Return FileType, NameGuid, and Attributes\r
213 //\r
214 *FileType = FfsFileHeader->Type;\r
e94a9ff7 215 CopyGuid (NameGuid, &FfsFileHeader->Name);\r
28a00297 216 *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);\r
795bb9b6
SZ
217 if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {\r
218 *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;\r
219 }\r
28a00297 220\r
28a00297 221 //\r
222 // we need to substract the header size\r
223 //\r
6c85d162
SZ
224 if (IS_FFS_FILE2 (FfsFileHeader)) {\r
225 *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);\r
226 } else {\r
227 *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);\r
228 }\r
28a00297 229\r
28a00297 230 return EFI_SUCCESS;\r
231}\r
232\r
233\r
162ed594 234\r
235/**\r
236 Locates a file in the firmware volume and\r
237 copies it to the supplied buffer.\r
238\r
022c6d45 239 @param This Indicates the calling context.\r
240 @param NameGuid Pointer to an EFI_GUID, which is the\r
241 filename.\r
242 @param Buffer Buffer is a pointer to pointer to a buffer\r
243 in which the file or section contents or are\r
244 returned.\r
245 @param BufferSize BufferSize is a pointer to caller allocated\r
246 UINTN. On input *BufferSize indicates the\r
247 size in bytes of the memory region pointed\r
248 to by Buffer. On output, *BufferSize\r
249 contains the number of bytes required to\r
250 read the file.\r
251 @param FoundType FoundType is a pointer to a caller allocated\r
252 EFI_FV_FILETYPE that on successful return\r
253 from Read() contains the type of file read.\r
254 This output reflects the file type\r
255 irrespective of the value of the SectionType\r
256 input.\r
257 @param FileAttributes FileAttributes is a pointer to a caller\r
258 allocated EFI_FV_FILE_ATTRIBUTES. On\r
259 successful return from Read(),\r
260 *FileAttributes contains the attributes of\r
261 the file read.\r
262 @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
263 caller allocated UINTN in which the\r
264 authentication status is returned.\r
265\r
266 @retval EFI_SUCCESS Successfully read to memory buffer.\r
267 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
268 @retval EFI_NOT_FOUND Not found.\r
269 @retval EFI_DEVICE_ERROR Device error.\r
270 @retval EFI_ACCESS_DENIED Could not read.\r
271 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
162ed594 272 @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.\r
273\r
274**/\r
28a00297 275EFI_STATUS\r
276EFIAPI\r
277FvReadFile (\r
0c2b5da8 278 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
279 IN CONST EFI_GUID *NameGuid,\r
280 IN OUT VOID **Buffer,\r
281 IN OUT UINTN *BufferSize,\r
282 OUT EFI_FV_FILETYPE *FoundType,\r
283 OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,\r
284 OUT UINT32 *AuthenticationStatus\r
28a00297 285 )\r
28a00297 286{\r
287 EFI_STATUS Status;\r
288 FV_DEVICE *FvDevice;\r
289 EFI_GUID SearchNameGuid;\r
290 EFI_FV_FILETYPE LocalFoundType;\r
291 EFI_FV_FILE_ATTRIBUTES LocalAttributes;\r
292 UINTN FileSize;\r
293 UINT8 *SrcPtr;\r
294 EFI_FFS_FILE_HEADER *FfsHeader;\r
295 UINTN InputBufferSize;\r
eb1cace2 296 UINTN WholeFileSize;\r
022c6d45 297\r
e94a9ff7 298 if (NameGuid == NULL) {\r
28a00297 299 return EFI_INVALID_PARAMETER;\r
300 }\r
301\r
302 FvDevice = FV_DEVICE_FROM_THIS (This);\r
022c6d45 303\r
28a00297 304\r
305 //\r
306 // Keep looking until we find the matching NameGuid.\r
eb1cace2 307 // The Key is really a FfsFileEntry\r
28a00297 308 //\r
309 FvDevice->LastKey = 0;\r
310 do {\r
311 LocalFoundType = 0;\r
312 Status = FvGetNextFile (\r
313 This,\r
314 &FvDevice->LastKey,\r
315 &LocalFoundType,\r
316 &SearchNameGuid,\r
317 &LocalAttributes,\r
318 &FileSize\r
319 );\r
320 if (EFI_ERROR (Status)) {\r
321 return EFI_NOT_FOUND;\r
322 }\r
323 } while (!CompareGuid (&SearchNameGuid, NameGuid));\r
324\r
325 //\r
326 // Get a pointer to the header\r
327 //\r
328 FfsHeader = FvDevice->LastKey->FfsHeader;\r
eb1cace2
SZ
329 if (FvDevice->IsMemoryMapped) {\r
330 //\r
331 // Memory mapped FV has not been cached, so here is to cache by file.\r
332 //\r
333 if (!FvDevice->LastKey->FileCached) {\r
334 //\r
335 // Cache FFS file to memory buffer.\r
336 //\r
337 WholeFileSize = IS_FFS_FILE2 (FfsHeader) ? FFS_FILE2_SIZE (FfsHeader): FFS_FILE_SIZE (FfsHeader);\r
338 FfsHeader = AllocateCopyPool (WholeFileSize, FfsHeader);\r
339 if (FfsHeader == NULL) {\r
340 return EFI_OUT_OF_RESOURCES;\r
341 }\r
342 //\r
343 // Let FfsHeader in FfsFileEntry point to the cached file buffer.\r
344 //\r
345 FvDevice->LastKey->FfsHeader = FfsHeader;\r
346 FvDevice->LastKey->FileCached = TRUE;\r
347 }\r
348 }\r
28a00297 349\r
350 //\r
351 // Remember callers buffer size\r
352 //\r
353 InputBufferSize = *BufferSize;\r
354\r
355 //\r
356 // Calculate return values\r
357 //\r
358 *FoundType = FfsHeader->Type;\r
359 *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);\r
795bb9b6
SZ
360 if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {\r
361 *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;\r
362 }\r
2bc08e8c
SZ
363 //\r
364 // Inherit the authentication status.\r
365 //\r
366 *AuthenticationStatus = FvDevice->AuthenticationStatus;\r
28a00297 367 *BufferSize = FileSize;\r
368\r
369 if (Buffer == NULL) {\r
370 //\r
d613c2a8 371 // If Buffer is NULL, we only want to get the information collected so far\r
28a00297 372 //\r
373 return EFI_SUCCESS;\r
374 }\r
375\r
376 //\r
377 // Skip over file header\r
378 //\r
6c85d162
SZ
379 if (IS_FFS_FILE2 (FfsHeader)) {\r
380 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);\r
381 } else {\r
382 SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);\r
383 }\r
28a00297 384\r
385 Status = EFI_SUCCESS;\r
386 if (*Buffer == NULL) {\r
387 //\r
388 // Caller passed in a pointer so allocate buffer for them\r
389 //\r
9c4ac31c 390 *Buffer = AllocatePool (FileSize);\r
28a00297 391 if (*Buffer == NULL) {\r
392 return EFI_OUT_OF_RESOURCES;\r
393 }\r
394 } else if (FileSize > InputBufferSize) {\r
395 //\r
396 // Callers buffer was not big enough\r
022c6d45 397 //\r
28a00297 398 Status = EFI_WARN_BUFFER_TOO_SMALL;\r
399 FileSize = InputBufferSize;\r
400 }\r
022c6d45 401\r
28a00297 402 //\r
022c6d45 403 // Copy data into callers buffer\r
28a00297 404 //\r
405 CopyMem (*Buffer, SrcPtr, FileSize);\r
406\r
407 return Status;\r
408}\r
409\r
410\r
162ed594 411\r
412/**\r
413 Locates a section in a given FFS File and\r
414 copies it to the supplied buffer (not including section header).\r
415\r
022c6d45 416 @param This Indicates the calling context.\r
417 @param NameGuid Pointer to an EFI_GUID, which is the\r
418 filename.\r
419 @param SectionType Indicates the section type to return.\r
420 @param SectionInstance Indicates which instance of sections with a\r
421 type of SectionType to return.\r
422 @param Buffer Buffer is a pointer to pointer to a buffer\r
423 in which the file or section contents or are\r
424 returned.\r
425 @param BufferSize BufferSize is a pointer to caller allocated\r
162ed594 426 UINTN.\r
022c6d45 427 @param AuthenticationStatus AuthenticationStatus is a pointer to a\r
428 caller allocated UINT32 in which the\r
429 authentication status is returned.\r
430\r
431 @retval EFI_SUCCESS Successfully read the file section into\r
432 buffer.\r
433 @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.\r
434 @retval EFI_NOT_FOUND Section not found.\r
435 @retval EFI_DEVICE_ERROR Device error.\r
436 @retval EFI_ACCESS_DENIED Could not read.\r
162ed594 437 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
438\r
439**/\r
28a00297 440EFI_STATUS\r
441EFIAPI\r
442FvReadFileSection (\r
0c2b5da8 443 IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,\r
444 IN CONST EFI_GUID *NameGuid,\r
445 IN EFI_SECTION_TYPE SectionType,\r
446 IN UINTN SectionInstance,\r
447 IN OUT VOID **Buffer,\r
448 IN OUT UINTN *BufferSize,\r
449 OUT UINT32 *AuthenticationStatus\r
28a00297 450 )\r
28a00297 451{\r
452 EFI_STATUS Status;\r
453 FV_DEVICE *FvDevice;\r
454 EFI_FV_FILETYPE FileType;\r
455 EFI_FV_FILE_ATTRIBUTES FileAttributes;\r
456 UINTN FileSize;\r
457 UINT8 *FileBuffer;\r
28a00297 458 FFS_FILE_LIST_ENTRY *FfsEntry;\r
022c6d45 459\r
e94a9ff7 460 if (NameGuid == NULL || Buffer == NULL) {\r
28a00297 461 return EFI_INVALID_PARAMETER;\r
462 }\r
463\r
464 FvDevice = FV_DEVICE_FROM_THIS (This);\r
465\r
466 //\r
eb1cace2 467 // Read the file\r
28a00297 468 //\r
28a00297 469 Status = FvReadFile (\r
470 This,\r
471 NameGuid,\r
eb1cace2 472 NULL,\r
28a00297 473 &FileSize,\r
474 &FileType,\r
475 &FileAttributes,\r
476 AuthenticationStatus\r
022c6d45 477 );\r
28a00297 478 //\r
479 // Get the last key used by our call to FvReadFile as it is the FfsEntry for this file.\r
022c6d45 480 //\r
e94a9ff7 481 FfsEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->LastKey;\r
28a00297 482\r
483 if (EFI_ERROR (Status)) {\r
484 return Status;\r
485 }\r
eb1cace2
SZ
486 if (IS_FFS_FILE2 (FfsEntry->FfsHeader)) {\r
487 FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);\r
488 } else {\r
489 FileBuffer = ((UINT8 *) FfsEntry->FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);\r
490 }\r
28a00297 491 //\r
492 // Check to see that the file actually HAS sections before we go any further.\r
493 //\r
494 if (FileType == EFI_FV_FILETYPE_RAW) {\r
495 Status = EFI_NOT_FOUND;\r
496 goto Done;\r
497 }\r
498\r
499 //\r
6c85d162 500 // Use FfsEntry to cache Section Extraction Protocol Information\r
28a00297 501 //\r
502 if (FfsEntry->StreamHandle == 0) {\r
797a9d67 503 Status = OpenSectionStream (\r
e94a9ff7 504 FileSize,\r
505 FileBuffer,\r
506 &FfsEntry->StreamHandle\r
507 );\r
28a00297 508 if (EFI_ERROR (Status)) {\r
509 goto Done;\r
510 }\r
28a00297 511 }\r
512\r
513 //\r
514 // If SectionType == 0 We need the whole section stream\r
515 //\r
797a9d67 516 Status = GetSection (\r
517 FfsEntry->StreamHandle,\r
518 (SectionType == 0) ? NULL : &SectionType,\r
519 NULL,\r
520 (SectionType == 0) ? 0 : SectionInstance,\r
521 Buffer,\r
522 BufferSize,\r
6c85d162
SZ
523 AuthenticationStatus,\r
524 FvDevice->IsFfs3Fv\r
797a9d67 525 );\r
28a00297 526\r
0c3a1db4
SZ
527 if (!EFI_ERROR (Status)) {\r
528 //\r
529 // Inherit the authentication status.\r
530 //\r
531 *AuthenticationStatus |= FvDevice->AuthenticationStatus;\r
532 }\r
533\r
28a00297 534 //\r
535 // Close of stream defered to close of FfsHeader list to allow SEP to cache data\r
536 //\r
537\r
538Done:\r
28a00297 539 return Status;\r
540}\r
541\r
162ed594 542\r