]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/FwVolBlock/FwVolBlock.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / FwVolBlock / FwVolBlock.c
CommitLineData
162ed594 1/** @file\r
022c6d45 2 Implementations for Firmware Volume Block protocol.\r
3\r
d613c2a8 4 It consumes FV HOBs and creates read-only Firmare Volume Block protocol\r
e94a9ff7 5 instances for each of them.\r
23c98c94 6\r
d1102dba 7Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 8SPDX-License-Identifier: BSD-2-Clause-Patent\r
28a00297 9\r
797a9d67 10**/\r
28a00297 11\r
9c4ac31c 12#include "DxeMain.h"\r
ec90508b 13#include "FwVolBlock.h"\r
28a00297 14\r
1436aea4 15FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {\r
28a00297 16 {\r
17 {\r
84266565 18 HARDWARE_DEVICE_PATH,\r
19 HW_MEMMAP_DP,\r
28a00297 20 {\r
84266565 21 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
22 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)\r
23 }\r
28a00297 24 },\r
84266565 25 EfiMemoryMappedIO,\r
1436aea4
MK
26 (EFI_PHYSICAL_ADDRESS)0,\r
27 (EFI_PHYSICAL_ADDRESS)0,\r
84266565 28 },\r
29 {\r
30 END_DEVICE_PATH_TYPE,\r
31 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
28a00297 32 {\r
84266565 33 END_DEVICE_PATH_LENGTH,\r
34 0\r
35 }\r
36 }\r
37};\r
38\r
1436aea4 39FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {\r
84266565 40 {\r
41 {\r
42 MEDIA_DEVICE_PATH,\r
43 MEDIA_PIWG_FW_VOL_DP,\r
022c6d45 44 {\r
84266565 45 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),\r
46 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)\r
022c6d45 47 }\r
28a00297 48 },\r
84266565 49 { 0 }\r
28a00297 50 },\r
84266565 51 {\r
52 END_DEVICE_PATH_TYPE,\r
53 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
54 {\r
55 END_DEVICE_PATH_LENGTH,\r
56 0\r
57 }\r
58 }\r
59};\r
60\r
61EFI_FW_VOL_BLOCK_DEVICE mFwVolBlock = {\r
62 FVB_DEVICE_SIGNATURE,\r
63 NULL,\r
64 NULL,\r
28a00297 65 {\r
66 FwVolBlockGetAttributes,\r
67 (EFI_FVB_SET_ATTRIBUTES)FwVolBlockSetAttributes,\r
68 FwVolBlockGetPhysicalAddress,\r
69 FwVolBlockGetBlockSize,\r
70 FwVolBlockReadBlock,\r
71 (EFI_FVB_WRITE)FwVolBlockWriteBlock,\r
72 (EFI_FVB_ERASE_BLOCKS)FwVolBlockEraseBlock,\r
022c6d45 73 NULL\r
28a00297 74 },\r
75 0,\r
76 NULL,\r
77 0,\r
0c3a1db4 78 0,\r
28a00297 79 0\r
80};\r
81\r
162ed594 82/**\r
83 Retrieves Volume attributes. No polarity translations are done.\r
84\r
022c6d45 85 @param This Calling context\r
86 @param Attributes output buffer which contains attributes\r
162ed594 87\r
88 @retval EFI_SUCCESS The firmware volume attributes were returned.\r
89\r
90**/\r
28a00297 91EFI_STATUS\r
92EFIAPI\r
93FwVolBlockGetAttributes (\r
94 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 95 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
28a00297 96 )\r
28a00297 97{\r
1436aea4 98 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
022c6d45 99\r
28a00297 100 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
101\r
102 //\r
103 // Since we are read only, it's safe to get attributes data from our in-memory copy.\r
104 //\r
8a9e0b72 105 *Attributes = FvbDevice->FvbAttributes & ~EFI_FVB2_WRITE_STATUS;\r
28a00297 106\r
107 return EFI_SUCCESS;\r
108}\r
109\r
162ed594 110/**\r
111 Modifies the current settings of the firmware volume according to the input parameter.\r
112\r
022c6d45 113 @param This Calling context\r
114 @param Attributes input buffer which contains attributes\r
162ed594 115\r
022c6d45 116 @retval EFI_SUCCESS The firmware volume attributes were returned.\r
117 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with\r
118 the capabilities as declared in the firmware\r
119 volume header.\r
162ed594 120 @retval EFI_UNSUPPORTED Not supported.\r
121\r
122**/\r
28a00297 123EFI_STATUS\r
124EFIAPI\r
125FwVolBlockSetAttributes (\r
126 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 127 IN CONST EFI_FVB_ATTRIBUTES_2 *Attributes\r
28a00297 128 )\r
28a00297 129{\r
130 return EFI_UNSUPPORTED;\r
131}\r
132\r
162ed594 133/**\r
134 The EraseBlock() function erases one or more blocks as denoted by the\r
135 variable argument list. The entire parameter list of blocks must be verified\r
136 prior to erasing any blocks. If a block is requested that does not exist\r
137 within the associated firmware volume (it has a larger index than the last\r
138 block of the firmware volume), the EraseBlock() function must return\r
139 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
140\r
022c6d45 141 @param This Calling context\r
142 @param ... Starting LBA followed by Number of Lba to erase.\r
143 a -1 to terminate the list.\r
144\r
145 @retval EFI_SUCCESS The erase request was successfully completed.\r
146 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled\r
147 state.\r
148 @retval EFI_DEVICE_ERROR The block device is not functioning correctly\r
149 and could not be written. The firmware device\r
150 may have been partially erased.\r
151 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable\r
152 argument list do\r
162ed594 153 @retval EFI_UNSUPPORTED Not supported.\r
154\r
155**/\r
28a00297 156EFI_STATUS\r
157EFIAPI\r
158FwVolBlockEraseBlock (\r
1436aea4 159 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
28a00297 160 ...\r
161 )\r
28a00297 162{\r
163 return EFI_UNSUPPORTED;\r
164}\r
165\r
162ed594 166/**\r
167 Read the specified number of bytes from the block to the input buffer.\r
168\r
022c6d45 169 @param This Indicates the calling context.\r
170 @param Lba The starting logical block index to read.\r
171 @param Offset Offset into the block at which to begin reading.\r
172 @param NumBytes Pointer to a UINT32. At entry, *NumBytes\r
173 contains the total size of the buffer. At exit,\r
174 *NumBytes contains the total number of bytes\r
175 actually read.\r
176 @param Buffer Pinter to a caller-allocated buffer that\r
177 contains the destine for the read.\r
178\r
179 @retval EFI_SUCCESS The firmware volume was read successfully.\r
180 @retval EFI_BAD_BUFFER_SIZE The read was attempted across an LBA boundary.\r
181 @retval EFI_ACCESS_DENIED Access denied.\r
182 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not\r
162ed594 183 be read.\r
184\r
185**/\r
28a00297 186EFI_STATUS\r
187EFIAPI\r
188FwVolBlockReadBlock (\r
1436aea4
MK
189 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
190 IN CONST EFI_LBA Lba,\r
191 IN CONST UINTN Offset,\r
192 IN OUT UINTN *NumBytes,\r
193 IN OUT UINT8 *Buffer\r
28a00297 194 )\r
28a00297 195{\r
1436aea4
MK
196 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
197 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
198 UINT8 *LbaOffset;\r
199 UINTN LbaStart;\r
200 UINTN NumOfBytesRead;\r
201 UINTN LbaIndex;\r
022c6d45 202\r
28a00297 203 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
204\r
205 //\r
206 // Check if This FW can be read\r
207 //\r
797a9d67 208 if ((FvbDevice->FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {\r
28a00297 209 return EFI_ACCESS_DENIED;\r
210 }\r
022c6d45 211\r
1436aea4 212 LbaIndex = (UINTN)Lba;\r
28a00297 213 if (LbaIndex >= FvbDevice->NumBlocks) {\r
214 //\r
215 // Invalid Lba, read nothing.\r
216 //\r
217 *NumBytes = 0;\r
218 return EFI_BAD_BUFFER_SIZE;\r
219 }\r
022c6d45 220\r
28a00297 221 if (Offset > FvbDevice->LbaCache[LbaIndex].Length) {\r
222 //\r
6393d9c8 223 // all exceed boundary, read nothing.\r
28a00297 224 //\r
225 *NumBytes = 0;\r
226 return EFI_BAD_BUFFER_SIZE;\r
227 }\r
022c6d45 228\r
28a00297 229 NumOfBytesRead = *NumBytes;\r
230 if (Offset + NumOfBytesRead > FvbDevice->LbaCache[LbaIndex].Length) {\r
231 //\r
6393d9c8 232 // partial exceed boundary, read data from current postion to end.\r
28a00297 233 //\r
234 NumOfBytesRead = FvbDevice->LbaCache[LbaIndex].Length - Offset;\r
235 }\r
022c6d45 236\r
1436aea4
MK
237 LbaStart = FvbDevice->LbaCache[LbaIndex].Base;\r
238 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
239 LbaOffset = (UINT8 *)FwVolHeader + LbaStart + Offset;\r
28a00297 240\r
241 //\r
242 // Perform read operation\r
243 //\r
244 CopyMem (Buffer, LbaOffset, NumOfBytesRead);\r
022c6d45 245\r
28a00297 246 if (NumOfBytesRead == *NumBytes) {\r
247 return EFI_SUCCESS;\r
248 }\r
022c6d45 249\r
28a00297 250 *NumBytes = NumOfBytesRead;\r
251 return EFI_BAD_BUFFER_SIZE;\r
252}\r
022c6d45 253\r
162ed594 254/**\r
255 Writes the specified number of bytes from the input buffer to the block.\r
256\r
022c6d45 257 @param This Indicates the calling context.\r
258 @param Lba The starting logical block index to write to.\r
259 @param Offset Offset into the block at which to begin writing.\r
260 @param NumBytes Pointer to a UINT32. At entry, *NumBytes\r
261 contains the total size of the buffer. At exit,\r
262 *NumBytes contains the total number of bytes\r
263 actually written.\r
264 @param Buffer Pinter to a caller-allocated buffer that\r
265 contains the source for the write.\r
266\r
267 @retval EFI_SUCCESS The firmware volume was written successfully.\r
268 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.\r
269 On output, NumBytes contains the total number of\r
270 bytes actually written.\r
271 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled\r
272 state.\r
273 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not\r
274 be written.\r
162ed594 275 @retval EFI_UNSUPPORTED Not supported.\r
276\r
277**/\r
28a00297 278EFI_STATUS\r
279EFIAPI\r
280FwVolBlockWriteBlock (\r
1436aea4
MK
281 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
282 IN EFI_LBA Lba,\r
283 IN UINTN Offset,\r
284 IN OUT UINTN *NumBytes,\r
285 IN UINT8 *Buffer\r
28a00297 286 )\r
28a00297 287{\r
288 return EFI_UNSUPPORTED;\r
289}\r
022c6d45 290\r
162ed594 291/**\r
292 Get Fvb's base address.\r
293\r
022c6d45 294 @param This Indicates the calling context.\r
295 @param Address Fvb device base address.\r
162ed594 296\r
022c6d45 297 @retval EFI_SUCCESS Successfully got Fvb's base address.\r
162ed594 298 @retval EFI_UNSUPPORTED Not supported.\r
299\r
300**/\r
28a00297 301EFI_STATUS\r
302EFIAPI\r
303FwVolBlockGetPhysicalAddress (\r
304 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
305 OUT EFI_PHYSICAL_ADDRESS *Address\r
306 )\r
28a00297 307{\r
1436aea4 308 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
022c6d45 309\r
28a00297 310 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
022c6d45 311\r
6e536468 312 if ((FvbDevice->FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {\r
28a00297 313 *Address = FvbDevice->BaseAddress;\r
314 return EFI_SUCCESS;\r
315 }\r
022c6d45 316\r
28a00297 317 return EFI_UNSUPPORTED;\r
318}\r
319\r
162ed594 320/**\r
321 Retrieves the size in bytes of a specific block within a firmware volume.\r
322\r
022c6d45 323 @param This Indicates the calling context.\r
324 @param Lba Indicates the block for which to return the\r
325 size.\r
326 @param BlockSize Pointer to a caller-allocated UINTN in which the\r
327 size of the block is returned.\r
328 @param NumberOfBlocks Pointer to a caller-allocated UINTN in which the\r
329 number of consecutive blocks starting with Lba\r
330 is returned. All blocks in this range have a\r
331 size of BlockSize.\r
332\r
333 @retval EFI_SUCCESS The firmware volume base address is returned.\r
162ed594 334 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.\r
335\r
336**/\r
28a00297 337EFI_STATUS\r
338EFIAPI\r
339FwVolBlockGetBlockSize (\r
340 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
341 IN CONST EFI_LBA Lba,\r
342 IN OUT UINTN *BlockSize,\r
343 IN OUT UINTN *NumberOfBlocks\r
344 )\r
28a00297 345{\r
1436aea4
MK
346 UINTN TotalBlocks;\r
347 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
348 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
349 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
022c6d45 350\r
28a00297 351 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
022c6d45 352\r
28a00297 353 //\r
354 // Do parameter checking\r
355 //\r
356 if (Lba >= FvbDevice->NumBlocks) {\r
357 return EFI_INVALID_PARAMETER;\r
358 }\r
022c6d45 359\r
28a00297 360 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINTN)FvbDevice->BaseAddress);\r
022c6d45 361\r
28a00297 362 PtrBlockMapEntry = FwVolHeader->BlockMap;\r
022c6d45 363\r
28a00297 364 //\r
365 // Search the block map for the given block\r
366 //\r
367 TotalBlocks = 0;\r
1436aea4 368 while ((PtrBlockMapEntry->NumBlocks != 0) || (PtrBlockMapEntry->Length != 0)) {\r
28a00297 369 TotalBlocks += PtrBlockMapEntry->NumBlocks;\r
370 if (Lba < TotalBlocks) {\r
371 //\r
372 // We find the range\r
373 //\r
374 break;\r
375 }\r
022c6d45 376\r
28a00297 377 PtrBlockMapEntry++;\r
378 }\r
022c6d45 379\r
1436aea4 380 *BlockSize = PtrBlockMapEntry->Length;\r
28a00297 381 *NumberOfBlocks = TotalBlocks - (UINTN)Lba;\r
022c6d45 382\r
28a00297 383 return EFI_SUCCESS;\r
384}\r
385\r
0c3a1db4
SZ
386/**\r
387\r
388 Get FVB authentication status\r
389\r
390 @param FvbProtocol FVB protocol.\r
28a00297 391\r
0c3a1db4
SZ
392 @return Authentication status.\r
393\r
394**/\r
395UINT32\r
396GetFvbAuthenticationStatus (\r
1436aea4 397 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
0c3a1db4
SZ
398 )\r
399{\r
1436aea4
MK
400 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
401 UINT32 AuthenticationStatus;\r
0c3a1db4
SZ
402\r
403 AuthenticationStatus = 0;\r
1436aea4 404 FvbDevice = BASE_CR (FvbProtocol, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance);\r
0c3a1db4
SZ
405 if (FvbDevice->Signature == FVB_DEVICE_SIGNATURE) {\r
406 AuthenticationStatus = FvbDevice->AuthenticationStatus;\r
407 }\r
408\r
409 return AuthenticationStatus;\r
410}\r
162ed594 411\r
412/**\r
413 This routine produces a firmware volume block protocol on a given\r
414 buffer.\r
415\r
022c6d45 416 @param BaseAddress base address of the firmware volume image\r
417 @param Length length of the firmware volume image\r
418 @param ParentHandle handle of parent firmware volume, if this image\r
0c3a1db4 419 came from an FV image file and section in another firmware\r
022c6d45 420 volume (ala capsules)\r
0c3a1db4
SZ
421 @param AuthenticationStatus Authentication status inherited, if this image\r
422 came from an FV image file and section in another firmware volume.\r
022c6d45 423 @param FvProtocol Firmware volume block protocol produced.\r
162ed594 424\r
022c6d45 425 @retval EFI_VOLUME_CORRUPTED Volume corrupted.\r
426 @retval EFI_OUT_OF_RESOURCES No enough buffer to be allocated.\r
427 @retval EFI_SUCCESS Successfully produced a FVB protocol on given\r
162ed594 428 buffer.\r
429\r
430**/\r
28a00297 431EFI_STATUS\r
432ProduceFVBProtocolOnBuffer (\r
1436aea4
MK
433 IN EFI_PHYSICAL_ADDRESS BaseAddress,\r
434 IN UINT64 Length,\r
435 IN EFI_HANDLE ParentHandle,\r
436 IN UINT32 AuthenticationStatus,\r
437 OUT EFI_HANDLE *FvProtocol OPTIONAL\r
28a00297 438 )\r
28a00297 439{\r
1436aea4
MK
440 EFI_STATUS Status;\r
441 EFI_FW_VOL_BLOCK_DEVICE *FvbDev;\r
442 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
443 UINTN BlockIndex;\r
444 UINTN BlockIndex2;\r
445 UINTN LinearOffset;\r
446 UINT32 FvAlignment;\r
447 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
022c6d45 448\r
38837959 449 FvAlignment = 0;\r
1436aea4 450 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
28a00297 451 //\r
452 // Validate FV Header, if not as expected, return\r
453 //\r
454 if (FwVolHeader->Signature != EFI_FVH_SIGNATURE) {\r
455 return EFI_VOLUME_CORRUPTED;\r
456 }\r
3837e91c 457\r
28a00297 458 //\r
3837e91c
SZ
459 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume\r
460 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from\r
461 // its initial linked location and maintain its alignment.\r
6d9a0f28 462 //\r
3837e91c 463 if ((FwVolHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {\r
38837959 464 //\r
3837e91c 465 // Get FvHeader alignment\r
38837959 466 //\r
3837e91c
SZ
467 FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);\r
468 //\r
469 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.\r
470 //\r
471 if (FvAlignment < 8) {\r
472 FvAlignment = 8;\r
473 }\r
1436aea4 474\r
3837e91c
SZ
475 if ((UINTN)BaseAddress % FvAlignment != 0) {\r
476 //\r
477 // FvImage buffer is not at its required alignment.\r
478 //\r
619c4889
SZ
479 DEBUG ((\r
480 DEBUG_ERROR,\r
481 "Unaligned FvImage found at 0x%lx:0x%lx, the required alignment is 0x%x\n",\r
482 BaseAddress,\r
483 Length,\r
484 FvAlignment\r
485 ));\r
3837e91c
SZ
486 return EFI_VOLUME_CORRUPTED;\r
487 }\r
38837959 488 }\r
3837e91c 489\r
38837959 490 //\r
022c6d45 491 // Allocate EFI_FW_VOL_BLOCK_DEVICE\r
28a00297 492 //\r
9c4ac31c 493 FvbDev = AllocateCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFwVolBlock);\r
28a00297 494 if (FvbDev == NULL) {\r
495 return EFI_OUT_OF_RESOURCES;\r
496 }\r
497\r
1436aea4
MK
498 FvbDev->BaseAddress = BaseAddress;\r
499 FvbDev->FvbAttributes = FwVolHeader->Attributes;\r
28a00297 500 FvbDev->FwVolBlockInstance.ParentHandle = ParentHandle;\r
1436aea4 501 FvbDev->AuthenticationStatus = AuthenticationStatus;\r
28a00297 502\r
503 //\r
504 // Init the block caching fields of the device\r
505 // First, count the number of blocks\r
506 //\r
507 FvbDev->NumBlocks = 0;\r
508 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
e94a9ff7 509 PtrBlockMapEntry->NumBlocks != 0;\r
1436aea4
MK
510 PtrBlockMapEntry++)\r
511 {\r
28a00297 512 FvbDev->NumBlocks += PtrBlockMapEntry->NumBlocks;\r
513 }\r
3a1966c4 514\r
28a00297 515 //\r
516 // Second, allocate the cache\r
517 //\r
3a1966c4
JY
518 if (FvbDev->NumBlocks >= (MAX_ADDRESS / sizeof (LBA_CACHE))) {\r
519 CoreFreePool (FvbDev);\r
520 return EFI_OUT_OF_RESOURCES;\r
521 }\r
1436aea4 522\r
9c4ac31c 523 FvbDev->LbaCache = AllocatePool (FvbDev->NumBlocks * sizeof (LBA_CACHE));\r
28a00297 524 if (FvbDev->LbaCache == NULL) {\r
525 CoreFreePool (FvbDev);\r
526 return EFI_OUT_OF_RESOURCES;\r
527 }\r
d1102dba 528\r
28a00297 529 //\r
530 // Last, fill in the cache with the linear address of the blocks\r
531 //\r
1436aea4 532 BlockIndex = 0;\r
28a00297 533 LinearOffset = 0;\r
534 for (PtrBlockMapEntry = FwVolHeader->BlockMap;\r
1436aea4
MK
535 PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++)\r
536 {\r
28a00297 537 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
1436aea4 538 FvbDev->LbaCache[BlockIndex].Base = LinearOffset;\r
28a00297 539 FvbDev->LbaCache[BlockIndex].Length = PtrBlockMapEntry->Length;\r
1436aea4 540 LinearOffset += PtrBlockMapEntry->Length;\r
28a00297 541 BlockIndex++;\r
542 }\r
543 }\r
544\r
545 //\r
84266565 546 // Judget whether FV name guid is produced in Fv extension header\r
28a00297 547 //\r
84266565 548 if (FwVolHeader->ExtHeaderOffset == 0) {\r
549 //\r
550 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH\r
551 //\r
1436aea4 552 FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);\r
18fcd6a7
LG
553 if (FvbDev->DevicePath == NULL) {\r
554 FreePool (FvbDev);\r
555 return EFI_OUT_OF_RESOURCES;\r
556 }\r
1436aea4
MK
557\r
558 ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;\r
559 ((FV_MEMMAP_DEVICE_PATH *)FvbDev->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;\r
84266565 560 } else {\r
561 //\r
562 // FV contains extension header, then produce MEDIA_FW_VOL_DEVICE_PATH\r
563 //\r
1436aea4 564 FvbDev->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);\r
18fcd6a7
LG
565 if (FvbDev->DevicePath == NULL) {\r
566 FreePool (FvbDev);\r
567 return EFI_OUT_OF_RESOURCES;\r
568 }\r
1436aea4 569\r
84266565 570 CopyGuid (\r
d1102dba 571 &((FV_PIWG_DEVICE_PATH *)FvbDev->DevicePath)->FvDevPath.FvName,\r
84266565 572 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)\r
573 );\r
574 }\r
d1102dba 575\r
28a00297 576 //\r
577 //\r
578 // Attach FvVolBlock Protocol to new handle\r
579 //\r
580 Status = CoreInstallMultipleProtocolInterfaces (\r
e94a9ff7 581 &FvbDev->Handle,\r
1436aea4
MK
582 &gEfiFirmwareVolumeBlockProtocolGuid,\r
583 &FvbDev->FwVolBlockInstance,\r
584 &gEfiDevicePathProtocolGuid,\r
585 FvbDev->DevicePath,\r
e94a9ff7 586 NULL\r
587 );\r
28a00297 588\r
589 //\r
590 // If they want the handle back, set it.\r
591 //\r
592 if (FvProtocol != NULL) {\r
593 *FvProtocol = FvbDev->Handle;\r
594 }\r
595\r
596 return Status;\r
597}\r
598\r
162ed594 599/**\r
ec90508b 600 This routine consumes FV hobs and produces instances of FW_VOL_BLOCK_PROTOCOL as appropriate.\r
162ed594 601\r
022c6d45 602 @param ImageHandle The image handle.\r
603 @param SystemTable The system table.\r
162ed594 604\r
022c6d45 605 @retval EFI_SUCCESS Successfully initialized firmware volume block\r
162ed594 606 driver.\r
607\r
608**/\r
28a00297 609EFI_STATUS\r
610EFIAPI\r
611FwVolBlockDriverInit (\r
1436aea4
MK
612 IN EFI_HANDLE ImageHandle,\r
613 IN EFI_SYSTEM_TABLE *SystemTable\r
28a00297 614 )\r
28a00297 615{\r
1436aea4
MK
616 EFI_PEI_HOB_POINTERS FvHob;\r
617 EFI_PEI_HOB_POINTERS Fv3Hob;\r
618 UINT32 AuthenticationStatus;\r
e94a9ff7 619\r
28a00297 620 //\r
621 // Core Needs Firmware Volumes to function\r
622 //\r
623 FvHob.Raw = GetHobList ();\r
624 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
c6037045
SZ
625 AuthenticationStatus = 0;\r
626 //\r
627 // Get the authentication status propagated from PEI-phase to DXE.\r
628 //\r
629 Fv3Hob.Raw = GetHobList ();\r
630 while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {\r
631 if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&\r
1436aea4
MK
632 (Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length))\r
633 {\r
c6037045
SZ
634 AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;\r
635 break;\r
636 }\r
1436aea4 637\r
c6037045
SZ
638 Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);\r
639 }\r
1436aea4 640\r
28a00297 641 //\r
642 // Produce an FVB protocol for it\r
643 //\r
c6037045 644 ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);\r
28a00297 645 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
646 }\r
e94a9ff7 647\r
28a00297 648 return EFI_SUCCESS;\r
649}\r
650\r
162ed594 651/**\r
652 This DXE service routine is used to process a firmware volume. In\r
653 particular, it can be called by BDS to process a single firmware\r
654 volume found in a capsule.\r
655\r
3a1966c4
JY
656 Caution: The caller need validate the input firmware volume to follow\r
657 PI specification.\r
658 DxeCore will trust the input data and process firmware volume directly.\r
659\r
022c6d45 660 @param FvHeader pointer to a firmware volume header\r
661 @param Size the size of the buffer pointed to by FvHeader\r
662 @param FVProtocolHandle the handle on which a firmware volume protocol\r
663 was produced for the firmware volume passed in.\r
162ed594 664\r
022c6d45 665 @retval EFI_OUT_OF_RESOURCES if an FVB could not be produced due to lack of\r
666 system resources\r
667 @retval EFI_VOLUME_CORRUPTED if the volume was corrupted\r
668 @retval EFI_SUCCESS a firmware volume protocol was produced for the\r
162ed594 669 firmware volume\r
670\r
671**/\r
28a00297 672EFI_STATUS\r
3b6ffb6a 673EFIAPI\r
28a00297 674CoreProcessFirmwareVolume (\r
1436aea4
MK
675 IN VOID *FvHeader,\r
676 IN UINTN Size,\r
677 OUT EFI_HANDLE *FVProtocolHandle\r
28a00297 678 )\r
28a00297 679{\r
680 VOID *Ptr;\r
681 EFI_STATUS Status;\r
682\r
683 *FVProtocolHandle = NULL;\r
1436aea4
MK
684 Status = ProduceFVBProtocolOnBuffer (\r
685 (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,\r
686 (UINT64)Size,\r
687 NULL,\r
688 0,\r
689 FVProtocolHandle\r
690 );\r
28a00297 691 //\r
692 // Since in our implementation we use register-protocol-notify to put a\r
693 // FV protocol on the FVB protocol handle, we can't directly verify that\r
694 // the FV protocol was produced. Therefore here we will check the handle\r
022c6d45 695 // and make sure an FV protocol is on it. This indicates that all went\r
696 // well. Otherwise we have to assume that the volume was corrupted\r
28a00297 697 // somehow.\r
698 //\r
1436aea4 699 if (!EFI_ERROR (Status)) {\r
328ce03e 700 ASSERT (*FVProtocolHandle != NULL);\r
1436aea4
MK
701 Ptr = NULL;\r
702 Status = CoreHandleProtocol (*FVProtocolHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Ptr);\r
703 if (EFI_ERROR (Status) || (Ptr == NULL)) {\r
28a00297 704 return EFI_VOLUME_CORRUPTED;\r
705 }\r
1436aea4 706\r
28a00297 707 return EFI_SUCCESS;\r
708 }\r
1436aea4 709\r
28a00297 710 return Status;\r
711}\r