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