]> git.proxmox.com Git - mirror_edk2.git/blame - UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
OvmfPkg/PlatformPei: set the Hypervisor Features PCD
[mirror_edk2.git] / UefiPayloadPkg / FvbRuntimeDxe / FvbService.c
CommitLineData
ae8acce8
GD
1/** @file\r
2Firmware Volume Block Driver to provide FVB service.\r
3\r
4 Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "FvbService.h"\r
10\r
11//\r
12// Global variable for this FVB driver which contains\r
13// the private data of all firmware volume block instances\r
14//\r
e5efcf8b 15FWB_GLOBAL mFvbModuleGlobal;\r
ae8acce8 16\r
e5efcf8b 17FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {\r
ae8acce8
GD
18 {\r
19 {\r
20 HARDWARE_DEVICE_PATH,\r
21 HW_MEMMAP_DP,\r
22 {\r
23 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
24 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)\r
25 }\r
26 },\r
27 EfiMemoryMappedIO,\r
e5efcf8b
MK
28 (EFI_PHYSICAL_ADDRESS)0,\r
29 (EFI_PHYSICAL_ADDRESS)0,\r
ae8acce8
GD
30 },\r
31 {\r
32 END_DEVICE_PATH_TYPE,\r
33 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
34 {\r
35 END_DEVICE_PATH_LENGTH,\r
36 0\r
37 }\r
38 }\r
39};\r
40\r
e5efcf8b 41FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {\r
ae8acce8
GD
42 {\r
43 {\r
44 MEDIA_DEVICE_PATH,\r
45 MEDIA_PIWG_FW_VOL_DP,\r
46 {\r
47 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),\r
48 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)\r
49 }\r
50 },\r
51 { 0 }\r
52 },\r
53 {\r
54 END_DEVICE_PATH_TYPE,\r
55 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
56 {\r
57 END_DEVICE_PATH_LENGTH,\r
58 0\r
59 }\r
60 }\r
61};\r
62\r
e5efcf8b 63EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
ae8acce8
GD
64 FVB_DEVICE_SIGNATURE,\r
65 NULL,\r
66 0, // Instance\r
67 {\r
68 FvbProtocolGetAttributes,\r
69 FvbProtocolSetAttributes,\r
70 FvbProtocolGetPhysicalAddress,\r
71 FvbProtocolGetBlockSize,\r
72 FvbProtocolRead,\r
73 FvbProtocolWrite,\r
74 FvbProtocolEraseBlocks,\r
75 NULL\r
76 } // FwVolBlockInstance\r
77};\r
78\r
ae8acce8
GD
79/**\r
80 Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed\r
81 by mFvbModuleGlobal.FvInstance based on a index.\r
82 Each EFI_FW_VOL_INSTANCE is with variable length as\r
83 we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.\r
84\r
85 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.\r
86\r
87 @return A pointer to EFI_FW_VOL_INSTANCE.\r
88\r
89**/\r
90EFI_FW_VOL_INSTANCE *\r
91GetFvbInstance (\r
e5efcf8b 92 IN UINTN Instance\r
ae8acce8
GD
93 )\r
94{\r
e5efcf8b 95 EFI_FW_VOL_INSTANCE *FwhRecord;\r
ae8acce8
GD
96\r
97 if ( Instance >= mFvbModuleGlobal.NumFv ) {\r
98 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
99 return NULL;\r
100 }\r
101\r
102 //\r
103 // Find the right instance of the FVB private data\r
104 //\r
105 FwhRecord = mFvbModuleGlobal.FvInstance;\r
106 while ( Instance > 0 ) {\r
e5efcf8b
MK
107 FwhRecord = (EFI_FW_VOL_INSTANCE *)((UINTN)((UINT8 *)FwhRecord) +\r
108 FwhRecord->VolumeHeader.HeaderLength +\r
109 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
ae8acce8
GD
110 Instance--;\r
111 }\r
112\r
113 return FwhRecord;\r
ae8acce8
GD
114}\r
115\r
ae8acce8
GD
116/**\r
117 Get the EFI_FVB_ATTRIBUTES_2 of a FV.\r
118\r
119 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.\r
120\r
121 @retval EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.\r
122\r
123**/\r
124STATIC\r
125EFI_FVB_ATTRIBUTES_2\r
126FvbGetVolumeAttributes (\r
e5efcf8b 127 IN UINTN Instance\r
ae8acce8
GD
128 )\r
129{\r
e5efcf8b
MK
130 EFI_FW_VOL_INSTANCE *FwInstance;\r
131\r
132 FwInstance = GetFvbInstance (Instance);\r
ae8acce8
GD
133 ASSERT (FwInstance != NULL);\r
134\r
135 if (FwInstance == NULL) {\r
136 return 0;\r
137 }\r
138\r
139 return FwInstance->VolumeHeader.Attributes;\r
140}\r
141\r
ae8acce8
GD
142/**\r
143 Retrieves the starting address of an LBA in an FV. It also\r
144 return a few other attribut of the FV.\r
145\r
146 @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.\r
147 @param[in] Lba The logical block address\r
148 @param[out] LbaAddress On output, contains the physical starting address\r
149 of the Lba\r
150 @param[out] LbaLength On output, contains the length of the block\r
151 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the\r
152 number of consecutive blocks starting with Lba is\r
153 returned. All blocks in this range have a size of\r
154 BlockSize\r
155\r
156 @retval EFI_SUCCESS Successfully returns\r
157 @retval EFI_INVALID_PARAMETER Instance not found\r
158\r
159**/\r
160STATIC\r
161EFI_STATUS\r
162FvbGetLbaAddress (\r
e5efcf8b
MK
163 IN UINTN Instance,\r
164 IN EFI_LBA Lba,\r
165 OUT UINTN *LbaAddress,\r
166 OUT UINTN *LbaLength,\r
167 OUT UINTN *NumOfBlocks\r
ae8acce8
GD
168 )\r
169{\r
e5efcf8b
MK
170 UINT32 NumBlocks;\r
171 UINT32 BlockLength;\r
172 UINTN Offset;\r
173 EFI_LBA StartLba;\r
174 EFI_LBA NextLba;\r
175 EFI_FW_VOL_INSTANCE *FwhInstance;\r
176 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
ae8acce8
GD
177\r
178 //\r
179 // Find the right instance of the FVB private data\r
180 //\r
181 FwhInstance = GetFvbInstance (Instance);\r
182 if (FwhInstance == NULL) {\r
183 return EFI_INVALID_PARAMETER;\r
184 }\r
185\r
e5efcf8b
MK
186 StartLba = 0;\r
187 Offset = 0;\r
188 BlockMap = &FwhInstance->VolumeHeader.BlockMap[0];\r
ae8acce8
GD
189 ASSERT (BlockMap != NULL);\r
190\r
191 //\r
192 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
193 //\r
194 while (TRUE) {\r
195 if ( BlockMap != NULL) {\r
196 NumBlocks = BlockMap->NumBlocks;\r
197 BlockLength = BlockMap->Length;\r
198 }\r
199\r
e5efcf8b 200 if ((NumBlocks == 0) || (BlockLength == 0)) {\r
ae8acce8
GD
201 return EFI_INVALID_PARAMETER;\r
202 }\r
203\r
204 NextLba = StartLba + NumBlocks;\r
205\r
206 //\r
207 // The map entry found\r
208 //\r
e5efcf8b
MK
209 if ((Lba >= StartLba) && (Lba < NextLba)) {\r
210 Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);\r
ae8acce8
GD
211 if (LbaAddress != NULL) {\r
212 *LbaAddress = FwhInstance->FvBase + Offset;\r
213 }\r
214\r
215 if (LbaLength != NULL) {\r
216 *LbaLength = BlockLength;\r
217 }\r
218\r
219 if (NumOfBlocks != NULL) {\r
220 *NumOfBlocks = (UINTN)(NextLba - Lba);\r
221 }\r
e5efcf8b 222\r
ae8acce8
GD
223 return EFI_SUCCESS;\r
224 }\r
225\r
e5efcf8b
MK
226 StartLba = NextLba;\r
227 Offset = Offset + NumBlocks * BlockLength;\r
ae8acce8
GD
228 BlockMap++;\r
229 }\r
230}\r
231\r
ae8acce8
GD
232/**\r
233 Reads specified number of bytes into a buffer from the specified block\r
234\r
235 @param[in] Instance The FV instance to be read from\r
236 @param[in] Lba The logical block address to be read from\r
237 @param[in] BlockOffset Offset into the block at which to begin reading\r
238 @param[in, out] NumBytes Pointer that on input contains the total size of\r
239 the buffer. On output, it contains the total number\r
240 of bytes read\r
241 @param[in] Buffer Pointer to a caller allocated buffer that will be\r
242 used to hold the data read\r
243\r
244\r
245 @retval EFI_SUCCESS The firmware volume was read successfully and\r
246 contents are in Buffer\r
247 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,\r
248 NumBytes contains the total number of bytes returned\r
249 in Buffer\r
250 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state\r
251 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
252 could not be read\r
253 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL\r
254\r
255**/\r
256STATIC\r
257EFI_STATUS\r
258FvbReadBlock (\r
e5efcf8b
MK
259 IN UINTN Instance,\r
260 IN EFI_LBA Lba,\r
261 IN UINTN BlockOffset,\r
262 IN OUT UINTN *NumBytes,\r
263 IN UINT8 *Buffer\r
ae8acce8
GD
264 )\r
265{\r
e5efcf8b
MK
266 EFI_FVB_ATTRIBUTES_2 Attributes;\r
267 UINTN LbaAddress;\r
268 UINTN LbaLength;\r
269 EFI_STATUS Status;\r
270 EFI_STATUS ReadStatus;\r
ae8acce8 271\r
e5efcf8b 272 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
ae8acce8
GD
273 return (EFI_INVALID_PARAMETER);\r
274 }\r
e5efcf8b 275\r
ae8acce8
GD
276 if (*NumBytes == 0) {\r
277 return (EFI_INVALID_PARAMETER);\r
278 }\r
279\r
280 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
e5efcf8b 281 if (EFI_ERROR (Status)) {\r
ae8acce8
GD
282 return Status;\r
283 }\r
284\r
285 Attributes = FvbGetVolumeAttributes (Instance);\r
286\r
e5efcf8b 287 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
ae8acce8
GD
288 return (EFI_ACCESS_DENIED);\r
289 }\r
290\r
291 if (BlockOffset > LbaLength) {\r
e5efcf8b 292 return (EFI_INVALID_PARAMETER);\r
ae8acce8
GD
293 }\r
294\r
e5efcf8b
MK
295 if (LbaLength < (*NumBytes + BlockOffset)) {\r
296 *NumBytes = (UINT32)(LbaLength - BlockOffset);\r
297 Status = EFI_BAD_BUFFER_SIZE;\r
ae8acce8
GD
298 }\r
299\r
300 ReadStatus = LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);\r
e5efcf8b 301 if (EFI_ERROR (ReadStatus)) {\r
ae8acce8
GD
302 return ReadStatus;\r
303 }\r
304\r
305 return Status;\r
306}\r
307\r
ae8acce8
GD
308/**\r
309 Writes specified number of bytes from the input buffer to the block\r
310\r
311 @param[in] Instance The FV instance to be written to\r
312 @param[in] Lba The starting logical block index to write to\r
313 @param[in] BlockOffset Offset into the block at which to begin writing\r
314 @param[in, out] NumBytes Pointer that on input contains the total size of\r
315 the buffer. On output, it contains the total number\r
316 of bytes actually written\r
317 @param[in] Buffer Pointer to a caller allocated buffer that contains\r
318 the source for the write\r
319 @retval EFI_SUCCESS The firmware volume was written successfully\r
320 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,\r
321 NumBytes contains the total number of bytes\r
322 actually written\r
323 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
324 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
325 could not be written\r
326 @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL\r
327\r
328**/\r
329EFI_STATUS\r
330FvbWriteBlock (\r
e5efcf8b
MK
331 IN UINTN Instance,\r
332 IN EFI_LBA Lba,\r
333 IN UINTN BlockOffset,\r
334 IN OUT UINTN *NumBytes,\r
335 IN UINT8 *Buffer\r
ae8acce8
GD
336 )\r
337{\r
e5efcf8b
MK
338 EFI_FVB_ATTRIBUTES_2 Attributes;\r
339 UINTN LbaAddress;\r
340 UINTN LbaLength;\r
341 EFI_STATUS Status;\r
ae8acce8 342\r
e5efcf8b 343 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
ae8acce8
GD
344 return (EFI_INVALID_PARAMETER);\r
345 }\r
e5efcf8b 346\r
ae8acce8
GD
347 if (*NumBytes == 0) {\r
348 return (EFI_INVALID_PARAMETER);\r
349 }\r
350\r
351 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
e5efcf8b 352 if (EFI_ERROR (Status)) {\r
ae8acce8
GD
353 return Status;\r
354 }\r
355\r
356 //\r
357 // Check if the FV is write enabled\r
358 //\r
359 Attributes = FvbGetVolumeAttributes (Instance);\r
e5efcf8b 360 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
ae8acce8
GD
361 return EFI_ACCESS_DENIED;\r
362 }\r
363\r
364 //\r
365 // Perform boundary checks and adjust NumBytes\r
366 //\r
367 if (BlockOffset > LbaLength) {\r
368 return EFI_INVALID_PARAMETER;\r
369 }\r
370\r
e5efcf8b
MK
371 if ( LbaLength < (*NumBytes + BlockOffset)) {\r
372 DEBUG ((\r
373 DEBUG_ERROR,\r
ae8acce8 374 "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",\r
e5efcf8b
MK
375 *NumBytes,\r
376 (UINT32)(LbaLength - BlockOffset)\r
377 ));\r
378 *NumBytes = (UINT32)(LbaLength - BlockOffset);\r
ae8acce8
GD
379 return EFI_BAD_BUFFER_SIZE;\r
380 }\r
381\r
382 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
383 Status = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);\r
384\r
385 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
e5efcf8b 386 WriteBackInvalidateDataCacheRange ((VOID *)(LbaAddress + BlockOffset), *NumBytes);\r
ae8acce8
GD
387 return Status;\r
388}\r
389\r
ae8acce8
GD
390/**\r
391 Erases and initializes a firmware volume block\r
392\r
393 @param[in] Instance The FV instance to be erased\r
394 @param[in] Lba The logical block index to be erased\r
395\r
396 @retval EFI_SUCCESS The erase request was successfully completed\r
397 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
398 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
399 could not be written. Firmware device may have been\r
400 partially erased\r
401 @retval EFI_INVALID_PARAMETER Instance not found\r
402\r
403**/\r
404EFI_STATUS\r
405FvbEraseBlock (\r
e5efcf8b
MK
406 IN UINTN Instance,\r
407 IN EFI_LBA Lba\r
ae8acce8
GD
408 )\r
409{\r
e5efcf8b
MK
410 EFI_FVB_ATTRIBUTES_2 Attributes;\r
411 UINTN LbaAddress;\r
412 UINTN LbaLength;\r
413 EFI_STATUS Status;\r
ae8acce8
GD
414\r
415 //\r
416 // Check if the FV is write enabled\r
417 //\r
418 Attributes = FvbGetVolumeAttributes (Instance);\r
419\r
e5efcf8b 420 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
ae8acce8
GD
421 return (EFI_ACCESS_DENIED);\r
422 }\r
423\r
424 //\r
425 // Get the starting address of the block for erase.\r
426 //\r
427 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
e5efcf8b 428 if (EFI_ERROR (Status)) {\r
ae8acce8
GD
429 return Status;\r
430 }\r
431\r
432 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
433\r
434 Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);\r
435\r
436 LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
437\r
e5efcf8b 438 WriteBackInvalidateDataCacheRange ((VOID *)LbaAddress, LbaLength);\r
ae8acce8
GD
439\r
440 return Status;\r
441}\r
442\r
443/**\r
444 Modifies the current settings of the firmware volume according to the\r
445 input parameter, and returns the new setting of the volume\r
446\r
447 @param[in] Instance The FV instance whose attributes is going to be\r
448 modified\r
449 @param[in, out] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2\r
450 containing the desired firmware volume settings.\r
451 On successful return, it contains the new settings\r
452 of the firmware volume\r
453\r
454 @retval EFI_SUCCESS Successfully returns\r
455 @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified\r
456 @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are\r
457 in conflict with the capabilities as declared in the\r
458 firmware volume header\r
459\r
460**/\r
461STATIC\r
462EFI_STATUS\r
463FvbSetVolumeAttributes (\r
e5efcf8b
MK
464 IN UINTN Instance,\r
465 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
ae8acce8
GD
466 )\r
467{\r
e5efcf8b
MK
468 EFI_FW_VOL_INSTANCE *FwhInstance;\r
469 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
470 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
471 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;\r
472 UINT32 Capabilities;\r
473 UINT32 OldStatus;\r
474 UINT32 NewStatus;\r
ae8acce8
GD
475\r
476 //\r
477 // Find the right instance of the FVB private data\r
478 //\r
479 FwhInstance = GetFvbInstance (Instance);\r
480 if (FwhInstance == NULL) {\r
481 return EFI_INVALID_PARAMETER;\r
482 }\r
483\r
e5efcf8b 484 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);\r
ae8acce8
GD
485 ASSERT (AttribPtr != NULL);\r
486 if ( AttribPtr == NULL) {\r
487 return EFI_INVALID_PARAMETER;\r
488 }\r
489\r
490 OldAttributes = *AttribPtr;\r
491 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;\r
492 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
493 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
494\r
495 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \\r
496 EFI_FVB2_READ_ENABLED_CAP | \\r
497 EFI_FVB2_WRITE_DISABLED_CAP | \\r
498 EFI_FVB2_WRITE_ENABLED_CAP | \\r
499 EFI_FVB2_LOCK_CAP | \\r
500 EFI_FVB2_STICKY_WRITE | \\r
501 EFI_FVB2_MEMORY_MAPPED | \\r
502 EFI_FVB2_ERASE_POLARITY | \\r
503 EFI_FVB2_READ_LOCK_CAP | \\r
504 EFI_FVB2_WRITE_LOCK_CAP | \\r
505 EFI_FVB2_ALIGNMENT;\r
506\r
507 //\r
508 // Some attributes of FV is read only can *not* be set\r
509 //\r
510 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
511 return EFI_INVALID_PARAMETER;\r
512 }\r
513\r
514 //\r
515 // If firmware volume is locked, no status bit can be updated\r
516 //\r
517 if ((OldAttributes & EFI_FVB2_LOCK_STATUS) != 0) {\r
518 if ((OldStatus ^ NewStatus) != 0) {\r
519 return EFI_ACCESS_DENIED;\r
520 }\r
521 }\r
522\r
523 //\r
524 // Test read disable\r
525 //\r
526 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
527 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
528 return EFI_INVALID_PARAMETER;\r
529 }\r
530 }\r
531\r
532 //\r
533 // Test read enable\r
534 //\r
535 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
536 if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {\r
537 return EFI_INVALID_PARAMETER;\r
538 }\r
539 }\r
540\r
541 //\r
542 // Test write disable\r
543 //\r
544 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
545 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
546 return EFI_INVALID_PARAMETER;\r
547 }\r
548 }\r
549\r
550 //\r
551 // Test write enable\r
552 //\r
553 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
554 if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {\r
555 return EFI_INVALID_PARAMETER;\r
556 }\r
557 }\r
558\r
559 //\r
560 // Test lock\r
561 //\r
562 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
563 if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {\r
564 return EFI_INVALID_PARAMETER;\r
565 }\r
566 }\r
567\r
568 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
569 *AttribPtr = (*AttribPtr) | NewStatus;\r
570 *Attributes = *AttribPtr;\r
571\r
572 return EFI_SUCCESS;\r
573}\r
574\r
ae8acce8
GD
575/**\r
576 Retrieves the physical address of the device.\r
577\r
578 @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.\r
579 @param[out] Address Output buffer containing the address.\r
580\r
581 @retval EFI_SUCCESS The function always return successfully.\r
582 @retval EFI_INVALID_PARAMETER Instance not found.\r
583\r
584**/\r
585EFI_STATUS\r
586EFIAPI\r
587FvbProtocolGetPhysicalAddress (\r
e5efcf8b
MK
588 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
589 OUT EFI_PHYSICAL_ADDRESS *Address\r
ae8acce8
GD
590 )\r
591{\r
e5efcf8b
MK
592 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
593 EFI_FW_VOL_INSTANCE *FwhInstance;\r
ae8acce8
GD
594\r
595 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
e5efcf8b 596 FwhInstance = GetFvbInstance (FvbDevice->Instance);\r
ae8acce8
GD
597 if (FwhInstance == NULL) {\r
598 return EFI_INVALID_PARAMETER;\r
599 }\r
600\r
601 *Address = FwhInstance->FvBase;\r
602 return EFI_SUCCESS;\r
603}\r
604\r
ae8acce8
GD
605/**\r
606 Retrieve the size of a logical block\r
607\r
608 @param[in] This Calling context\r
609 @param[in] Lba Indicates which block to return the size for.\r
610 @param[out] BlockSize A pointer to a caller allocated UINTN in which\r
611 the size of the block is returned\r
612 @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the\r
613 number of consecutive blocks starting with Lba is\r
614 returned. All blocks in this range have a size of\r
615 BlockSize\r
616\r
617 @retval EFI_SUCCESS The function always return successfully.\r
618\r
619**/\r
620EFI_STATUS\r
621EFIAPI\r
622FvbProtocolGetBlockSize (\r
e5efcf8b
MK
623 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
624 IN EFI_LBA Lba,\r
625 OUT UINTN *BlockSize,\r
626 OUT UINTN *NumOfBlocks\r
ae8acce8
GD
627 )\r
628{\r
e5efcf8b 629 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
ae8acce8
GD
630\r
631 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
632 return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumOfBlocks);\r
633}\r
634\r
ae8acce8
GD
635/**\r
636 Retrieves Volume attributes. No polarity translations are done.\r
637\r
638 @param[in] This Calling context\r
639 @param[out] Attributes Output buffer which contains attributes\r
640\r
641 @retval EFI_SUCCESS The function always return successfully.\r
642\r
643**/\r
644EFI_STATUS\r
645EFIAPI\r
646FvbProtocolGetAttributes (\r
e5efcf8b
MK
647 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
648 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
ae8acce8
GD
649 )\r
650{\r
e5efcf8b 651 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
ae8acce8 652\r
e5efcf8b 653 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
ae8acce8
GD
654 *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);\r
655\r
656 return EFI_SUCCESS;\r
657}\r
658\r
ae8acce8
GD
659/**\r
660 Sets Volume attributes. No polarity translations are done.\r
661\r
662 @param[in] This Calling context\r
663 @param[in, out] Attributes Output buffer which contains attributes\r
664\r
665 @retval EFI_SUCCESS The function always return successfully.\r
666\r
667**/\r
668EFI_STATUS\r
669EFIAPI\r
670FvbProtocolSetAttributes (\r
e5efcf8b
MK
671 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
672 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
ae8acce8
GD
673 )\r
674{\r
e5efcf8b
MK
675 EFI_STATUS Status;\r
676 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
ae8acce8
GD
677\r
678 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
679 Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);\r
680 return Status;\r
681}\r
682\r
ae8acce8
GD
683/**\r
684 This function erases one or more blocks as denoted by the\r
685 variable argument list. The entire parameter list of blocks must be verified\r
686 prior to erasing any blocks. If a block is requested that does not exist\r
687 within the associated firmware volume (it has a larger index than the last\r
688 block of the firmware volume), the EraseBlock() function must return\r
689 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
690\r
691 @param[in] This Calling context\r
692 @param[in] ... Starting LBA followed by Number of Lba to erase.\r
693 a -1 to terminate the list.\r
694\r
695 @retval EFI_SUCCESS The erase request was successfully completed\r
696 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
697 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
698 could not be written. Firmware device may have been\r
699 partially erased\r
700\r
701**/\r
702EFI_STATUS\r
703EFIAPI\r
704FvbProtocolEraseBlocks (\r
e5efcf8b 705 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
ae8acce8
GD
706 ...\r
707 )\r
708{\r
e5efcf8b
MK
709 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
710 EFI_FW_VOL_INSTANCE *FwhInstance;\r
711 UINTN NumOfBlocks;\r
712 VA_LIST args;\r
713 EFI_LBA StartingLba;\r
714 UINTN NumOfLba;\r
715 EFI_STATUS Status;\r
716\r
717 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
718 FwhInstance = GetFvbInstance (FvbDevice->Instance);\r
ae8acce8
GD
719 if (FwhInstance == NULL) {\r
720 return EFI_OUT_OF_RESOURCES;\r
721 }\r
722\r
723 NumOfBlocks = FwhInstance->NumOfBlocks;\r
724 VA_START (args, This);\r
725\r
726 do {\r
727 StartingLba = VA_ARG (args, EFI_LBA);\r
728 if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {\r
729 break;\r
730 }\r
731\r
732 NumOfLba = VA_ARG (args, UINT32);\r
733\r
734 //\r
735 // Check input parameters\r
736 //\r
737 if (NumOfLba == 0) {\r
738 VA_END (args);\r
739 return EFI_INVALID_PARAMETER;\r
740 }\r
741\r
e5efcf8b 742 if ((StartingLba + NumOfLba) > NumOfBlocks ) {\r
ae8acce8
GD
743 return EFI_INVALID_PARAMETER;\r
744 }\r
e5efcf8b 745 } while (1);\r
ae8acce8
GD
746\r
747 VA_END (args);\r
748\r
749 VA_START (args, This);\r
750 do {\r
751 StartingLba = VA_ARG (args, EFI_LBA);\r
752 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
753 break;\r
754 }\r
755\r
756 NumOfLba = VA_ARG (args, UINT32);\r
757\r
758 while ( NumOfLba > 0 ) {\r
759 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);\r
e5efcf8b 760 if ( EFI_ERROR (Status)) {\r
ae8acce8
GD
761 VA_END (args);\r
762 return Status;\r
763 }\r
e5efcf8b 764\r
ae8acce8
GD
765 StartingLba++;\r
766 NumOfLba--;\r
767 }\r
e5efcf8b 768 } while (1);\r
ae8acce8
GD
769\r
770 VA_END (args);\r
771\r
772 return EFI_SUCCESS;\r
773}\r
774\r
ae8acce8
GD
775/**\r
776 Writes data beginning at Lba:Offset from FV. The write terminates either\r
777 when *NumBytes of data have been written, or when a block boundary is\r
778 reached. *NumBytes is updated to reflect the actual number of bytes\r
779 written. The write opertion does not include erase. This routine will\r
780 attempt to write only the specified bytes. If the writes do not stick,\r
781 it will return an error.\r
782\r
783 @param[in] This Calling context\r
784 @param[in] Lba Block in which to begin write\r
785 @param[in] Offset Offset in the block at which to begin write\r
786 @param[in,out] NumBytes On input, indicates the requested write size. On\r
787 output, indicates the actual number of bytes written\r
788 @param[in] Buffer Buffer containing source data for the write.\r
789\r
790 @retval EFI_SUCCESS The firmware volume was written successfully\r
791 @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,\r
792 NumBytes contains the total number of bytes\r
793 actually written\r
794 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
795 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
796 could not be written\r
797 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL\r
798\r
799**/\r
800EFI_STATUS\r
801EFIAPI\r
802FvbProtocolWrite (\r
e5efcf8b
MK
803 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
804 IN EFI_LBA Lba,\r
805 IN UINTN Offset,\r
806 IN OUT UINTN *NumBytes,\r
807 IN UINT8 *Buffer\r
ae8acce8
GD
808 )\r
809{\r
e5efcf8b
MK
810 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
811 EFI_STATUS Status;\r
ae8acce8
GD
812\r
813 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
814 Status = FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
e5efcf8b
MK
815 DEBUG ((\r
816 DEBUG_VERBOSE,\r
ae8acce8 817 "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",\r
e5efcf8b
MK
818 Lba,\r
819 Offset,\r
820 *NumBytes,\r
821 Buffer,\r
822 Status\r
823 ));\r
ae8acce8
GD
824\r
825 return Status;\r
826}\r
827\r
ae8acce8
GD
828/**\r
829 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
830 when *NumBytes of data have been read, or when a block boundary is\r
831 reached. *NumBytes is updated to reflect the actual number of bytes\r
832 written. The write opertion does not include erase. This routine will\r
833 attempt to write only the specified bytes. If the writes do not stick,\r
834 it will return an error.\r
835\r
836 @param[in] This Calling context\r
837 @param[in] Lba Block in which to begin write\r
838 @param[in] Offset Offset in the block at which to begin write\r
839 @param[in,out] NumBytes On input, indicates the requested write size. On\r
840 output, indicates the actual number of bytes written\r
841 @param[out] Buffer Buffer containing source data for the write.\r
842\r
843\r
844Returns:\r
845 @retval EFI_SUCCESS The firmware volume was read successfully and\r
846 contents are in Buffer\r
847 @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,\r
848 NumBytes contains the total number of bytes returned\r
849 in Buffer\r
850 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state\r
851 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and\r
852 could not be read\r
853 @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL\r
854\r
855**/\r
856EFI_STATUS\r
857EFIAPI\r
858FvbProtocolRead (\r
e5efcf8b
MK
859 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
860 IN EFI_LBA Lba,\r
861 IN UINTN Offset,\r
862 IN OUT UINTN *NumBytes,\r
863 OUT UINT8 *Buffer\r
ae8acce8
GD
864 )\r
865{\r
e5efcf8b
MK
866 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
867 EFI_STATUS Status;\r
ae8acce8
GD
868\r
869 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
870 Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
e5efcf8b
MK
871 DEBUG ((\r
872 DEBUG_VERBOSE,\r
ae8acce8 873 "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",\r
e5efcf8b
MK
874 Lba,\r
875 Offset,\r
876 *NumBytes,\r
877 Buffer,\r
878 Status\r
879 ));\r
ae8acce8
GD
880\r
881 return Status;\r
882}\r
883\r
884/**\r
885 Check the integrity of firmware volume header in FvBase\r
886\r
887 @param[in] FvBase A pointer to firmware volume base address.\r
888\r
889 @retval TRUE The firmware volume is consistent\r
890 @retval FALSE The firmware volume has corrupted.\r
891\r
892**/\r
893BOOLEAN\r
894IsFvHeaderValid (\r
e5efcf8b 895 IN EFI_PHYSICAL_ADDRESS FvBase\r
ae8acce8
GD
896 )\r
897{\r
e5efcf8b
MK
898 UINT16 Sum;\r
899 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
ae8acce8 900\r
e5efcf8b
MK
901 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;\r
902 if (FvBase == PcdGet32 (PcdFlashNvStorageVariableBase)) {\r
903 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof (EFI_GUID)) != 0 ) {\r
904 DEBUG ((DEBUG_INFO, " --FileSystemGuid not match: %g\n", &FwVolHeader->FileSystemGuid));\r
ae8acce8
GD
905 return FALSE;\r
906 }\r
907 } else {\r
e5efcf8b
MK
908 if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof (EFI_GUID)) != 0 ) {\r
909 DEBUG ((DEBUG_INFO, " --not expected guid.\n"));\r
ae8acce8
GD
910 return FALSE;\r
911 }\r
912 }\r
913\r
e5efcf8b
MK
914 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
915 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
916 (FwVolHeader->FvLength == ((UINTN)-1)) ||\r
917 ((FwVolHeader->HeaderLength & 0x01) != 0))\r
918 {\r
919 DEBUG ((DEBUG_INFO, " -- >Revision = 0x%x, Signature = 0x%x\n", FwVolHeader->Revision, FwVolHeader->Signature));\r
920 DEBUG ((DEBUG_INFO, " -- >FvLength = 0x%lx, HeaderLength = 0x%x\n", FwVolHeader->FvLength, FwVolHeader->HeaderLength));\r
ae8acce8
GD
921 return FALSE;\r
922 }\r
923\r
e5efcf8b 924 Sum = CalculateSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength);\r
ae8acce8 925 if (Sum != 0) {\r
e5efcf8b 926 DEBUG ((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum));\r
ae8acce8
GD
927 return FALSE;\r
928 }\r
929\r
930 return TRUE;\r
931}\r
932\r
ae8acce8
GD
933/**\r
934 Get intial variable data.\r
935\r
936 @param[out] VarData Valid variable data.\r
937 @param[out] VarSize Valid variable size.\r
938\r
939 @retval RETURN_SUCCESS Successfully found initial variable data.\r
940 @retval RETURN_NOT_FOUND Failed to find the variable data file from FV.\r
941 @retval EFI_INVALID_PARAMETER VarData or VarSize is null.\r
942\r
943**/\r
944EFI_STATUS\r
945GetInitialVariableData (\r
e5efcf8b
MK
946 OUT VOID **VarData,\r
947 OUT UINTN *VarSize\r
ae8acce8
GD
948 )\r
949{\r
950 EFI_STATUS Status;\r
951 VOID *ImageData;\r
952 UINTN ImageSize;\r
953 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
954 VARIABLE_STORE_HEADER *VariableStore;\r
955 AUTHENTICATED_VARIABLE_HEADER *Variable;\r
956 UINTN VariableSize;\r
957 UINTN VarEndAddr;\r
958\r
959 if ((VarData == NULL) || (VarSize == NULL)) {\r
960 return EFI_INVALID_PARAMETER;\r
961 }\r
962\r
e5efcf8b 963 Status = GetSectionFromAnyFv (PcdGetPtr (PcdNvsDataFile), EFI_SECTION_RAW, 0, &ImageData, &ImageSize);\r
ae8acce8
GD
964 if (EFI_ERROR (Status)) {\r
965 return Status;\r
966 }\r
967\r
e5efcf8b
MK
968 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)ImageData;\r
969 VariableStore = (VARIABLE_STORE_HEADER *)((UINT8 *)ImageData + FvHeader->HeaderLength);\r
ae8acce8 970 VarEndAddr = (UINTN)VariableStore + VariableStore->Size;\r
e5efcf8b 971 Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (VariableStore + 1);\r
ae8acce8
GD
972 *VarData = (VOID *)Variable;\r
973 while (((UINTN)Variable < VarEndAddr)) {\r
974 if (Variable->StartId != VARIABLE_DATA) {\r
975 break;\r
976 }\r
e5efcf8b 977\r
ae8acce8 978 VariableSize = sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize;\r
e5efcf8b 979 Variable = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)Variable + VariableSize);\r
ae8acce8
GD
980 }\r
981\r
982 *VarSize = (UINTN)Variable - HEADER_ALIGN (VariableStore + 1);\r
983\r
984 return EFI_SUCCESS;\r
985}\r
986\r
987/**\r
988 The function does the necessary initialization work for\r
989 Firmware Volume Block Driver.\r
990\r
991 @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.\r
992 It will ASSERT on errors.\r
993\r
994**/\r
995EFI_STATUS\r
996FvbInitialize (\r
997 VOID\r
998 )\r
999{\r
e5efcf8b
MK
1000 EFI_FW_VOL_INSTANCE *FwVolInstance;\r
1001 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1002 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
1003 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1004 UINTN WriteAddr;\r
1005 EFI_STATUS Status;\r
1006 UINTN BufferSize;\r
1007 UINTN Length;\r
1008 VARIABLE_STORE_HEADER VariableStore;\r
1009 VOID *VarData;\r
ae8acce8
GD
1010\r
1011 InitVariableStore ();\r
e5efcf8b
MK
1012 BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);\r
1013 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
ae8acce8
GD
1014\r
1015 //\r
1016 // Check FV header and variable store header\r
1017 //\r
1018 if (!IsFvHeaderValid (BaseAddress)) {\r
1019 //\r
1020 // Write back a healthy FV header\r
1021 //\r
1022 DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n", BaseAddress));\r
1023 FvHeader = GetFvHeaderTemplate ();\r
1024 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, FALSE);\r
1025\r
1026 Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->BlockMap->Length);\r
e5efcf8b 1027 ASSERT_EFI_ERROR (Status);\r
ae8acce8 1028\r
e5efcf8b
MK
1029 Length = FvHeader->HeaderLength;\r
1030 WriteAddr = (UINTN)BaseAddress;\r
1031 Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)FvHeader);\r
ae8acce8 1032 WriteAddr += Length;\r
e5efcf8b 1033 ASSERT_EFI_ERROR (Status);\r
ae8acce8
GD
1034\r
1035 //\r
1036 // Write back variable store header\r
1037 //\r
e5efcf8b 1038 VariableStore.Size = PcdGet32 (PcdFlashNvStorageVariableSize) - FvHeader->HeaderLength;\r
ae8acce8
GD
1039 VariableStore.Format = VARIABLE_STORE_FORMATTED;\r
1040 VariableStore.State = VARIABLE_STORE_HEALTHY;\r
1041 CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid);\r
1042 BufferSize = sizeof (VARIABLE_STORE_HEADER);\r
e5efcf8b 1043 Status = LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *)&VariableStore);\r
ae8acce8 1044 WriteAddr += BufferSize;\r
e5efcf8b 1045 ASSERT_EFI_ERROR (Status);\r
ae8acce8
GD
1046\r
1047 //\r
1048 // Write initial variable data if found\r
1049 //\r
1050 Status = GetInitialVariableData (&VarData, &Length);\r
1051 if (!EFI_ERROR (Status)) {\r
e5efcf8b
MK
1052 Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *)VarData);\r
1053 ASSERT_EFI_ERROR (Status);\r
ae8acce8
GD
1054 }\r
1055\r
1056 LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, TRUE);\r
e5efcf8b 1057 WriteBackInvalidateDataCacheRange ((VOID *)(UINTN)BaseAddress, FvHeader->BlockMap->Length);\r
ae8acce8
GD
1058 }\r
1059\r
1060 //\r
1061 // Create a new FW volume instance for NVS variable\r
1062 //\r
1063 BufferSize = FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
e5efcf8b 1064 FwVolInstance = (EFI_FW_VOL_INSTANCE *)AllocateRuntimeZeroPool (BufferSize);\r
ae8acce8
GD
1065 if (FwVolInstance == NULL) {\r
1066 return EFI_OUT_OF_RESOURCES;\r
1067 }\r
e5efcf8b 1068\r
ae8acce8
GD
1069 FwVolInstance->FvBase = (UINTN)BaseAddress;\r
1070 CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength);\r
1071\r
1072 //\r
1073 // Process the block map for each FV. Assume it has same block size.\r
1074 //\r
1075 FwVolInstance->NumOfBlocks = 0;\r
e5efcf8b 1076 FvHeader = &FwVolInstance->VolumeHeader;\r
ae8acce8
GD
1077 for (BlockMap = FvHeader->BlockMap; BlockMap->NumBlocks != 0; BlockMap++) {\r
1078 FwVolInstance->NumOfBlocks += BlockMap->NumBlocks;\r
1079 }\r
1080\r
1081 //\r
1082 // Add a FVB Protocol Instance\r
1083 //\r
1084 Status = InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv);\r
1085 mFvbModuleGlobal.NumFv++;\r
1086 mFvbModuleGlobal.FvInstance = FwVolInstance;\r
1087\r
1088 return Status;\r
1089}\r