1 /** @file
2   This file implement the Variable Protocol for the block device.
3 
4   Copyright (c) 2015-2016, Linaro Limited. All rights reserved.
5   Copyright (c) 2015-2016, Hisilicon Limited. All rights reserved.
6 
7   This program and the accompanying materials
8   are licensed and made available under the terms and conditions of the BSD License
9   which accompanies this distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include <Guid/VariableFormat.h>
18 #include <Guid/SystemNvDataGuid.h>
19 
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/CacheMaintenanceLib.h>
22 #include <Library/DebugLib.h>
23 #include <Library/DevicePathLib.h>
24 #include <Library/IoLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/PcdLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiLib.h>
29 
30 #include "BlockVariableDxe.h"
31 
32 
33 STATIC EFI_PHYSICAL_ADDRESS      mMapNvStorageVariableBase;
34 
35 EFI_STATUS
36 EFIAPI
FvbGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)37 FvbGetAttributes (
38   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    *This,
39   OUT       EFI_FVB_ATTRIBUTES_2                   *Attributes
40   )
41 {
42   EFI_FVB_ATTRIBUTES_2 FvbAttributes;
43   FvbAttributes = (EFI_FVB_ATTRIBUTES_2) (
44 
45       EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
46       EFI_FVB2_READ_STATUS      | // Reads are currently enabled
47       EFI_FVB2_STICKY_WRITE     | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
48       EFI_FVB2_MEMORY_MAPPED    | // It is memory mapped
49       EFI_FVB2_ERASE_POLARITY     // After erasure all bits take this value (i.e. '1')
50 
51       );
52   FvbAttributes |= EFI_FVB2_WRITE_STATUS      | // Writes are currently enabled
53                    EFI_FVB2_WRITE_ENABLED_CAP;  // Writes may be enabled
54 
55   *Attributes = FvbAttributes;
56 
57   DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes));
58   return EFI_SUCCESS;
59 }
60 
61 EFI_STATUS
62 EFIAPI
FvbSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)63 FvbSetAttributes(
64   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
65   IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
66   )
67 {
68   DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",*Attributes));
69   return EFI_UNSUPPORTED;
70 }
71 
72 EFI_STATUS
73 EFIAPI
FvbGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)74 FvbGetPhysicalAddress (
75   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
76   OUT       EFI_PHYSICAL_ADDRESS                 *Address
77   )
78 {
79   *Address = mMapNvStorageVariableBase;
80   return EFI_SUCCESS;
81 }
82 
83 EFI_STATUS
84 EFIAPI
FvbGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumberOfBlocks)85 FvbGetBlockSize (
86   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
87   IN        EFI_LBA                              Lba,
88   OUT       UINTN                                *BlockSize,
89   OUT       UINTN                                *NumberOfBlocks
90   )
91 {
92   BLOCK_VARIABLE_INSTANCE       *Instance;
93 
94   Instance = CR (This, BLOCK_VARIABLE_INSTANCE, FvbProtocol, BLOCK_VARIABLE_SIGNATURE);
95   *BlockSize = (UINTN) Instance->Media.BlockSize;
96   *NumberOfBlocks = PcdGet32 (PcdNvStorageVariableBlockCount);
97   return EFI_SUCCESS;
98 }
99 
100 EFI_STATUS
101 EFIAPI
FvbRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN OUT UINT8 * Buffer)102 FvbRead (
103   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *This,
104   IN        EFI_LBA                               Lba,
105   IN        UINTN                                 Offset,
106   IN OUT    UINTN                                 *NumBytes,
107   IN OUT    UINT8                                 *Buffer
108   )
109 {
110   BLOCK_VARIABLE_INSTANCE       *Instance;
111   EFI_BLOCK_IO_PROTOCOL         *BlockIo;
112   EFI_STATUS                    Status;
113   UINTN                         Bytes;
114   VOID                          *DataPtr;
115 
116   Instance = CR (This, BLOCK_VARIABLE_INSTANCE, FvbProtocol, BLOCK_VARIABLE_SIGNATURE);
117   BlockIo = Instance->BlockIoProtocol;
118   Bytes = (Offset + *NumBytes + Instance->Media.BlockSize - 1) / Instance->Media.BlockSize * Instance->Media.BlockSize;
119   DataPtr = AllocateZeroPool (Bytes);
120   if (DataPtr == NULL) {
121     DEBUG ((EFI_D_ERROR, "FvbWrite: failed to allocate buffer.\n"));
122     return EFI_BUFFER_TOO_SMALL;
123   }
124   WriteBackDataCacheRange (DataPtr, Bytes);
125   InvalidateDataCacheRange (Buffer, *NumBytes);
126   Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Instance->StartLba + Lba,
127 		                Bytes, DataPtr);
128   if (EFI_ERROR (Status)) {
129     DEBUG ((EFI_D_ERROR, "FvbRead StartLba:%x, Lba:%x, Offset:%x, Status:%x\n",
130 	    Instance->StartLba, Lba, Offset, Status));
131     goto exit;
132   }
133   CopyMem (Buffer, DataPtr + Offset, *NumBytes);
134   WriteBackDataCacheRange (Buffer, *NumBytes);
135 exit:
136   FreePool (DataPtr);
137   return Status;
138 }
139 
140 EFI_STATUS
141 EFIAPI
FvbWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)142 FvbWrite (
143   IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *This,
144   IN        EFI_LBA                               Lba,
145   IN        UINTN                                 Offset,
146   IN OUT    UINTN                                 *NumBytes,
147   IN        UINT8                                 *Buffer
148   )
149 {
150   BLOCK_VARIABLE_INSTANCE       *Instance;
151   EFI_BLOCK_IO_PROTOCOL         *BlockIo;
152   EFI_STATUS                    Status;
153   UINTN                         Bytes;
154   VOID                          *DataPtr;
155 
156   Instance = CR (This, BLOCK_VARIABLE_INSTANCE, FvbProtocol, BLOCK_VARIABLE_SIGNATURE);
157   BlockIo = Instance->BlockIoProtocol;
158   Bytes = (Offset + *NumBytes + Instance->Media.BlockSize - 1) / Instance->Media.BlockSize * Instance->Media.BlockSize;
159   DataPtr = AllocateZeroPool (Bytes);
160   if (DataPtr == NULL) {
161     DEBUG ((EFI_D_ERROR, "FvbWrite: failed to allocate buffer.\n"));
162     return EFI_BUFFER_TOO_SMALL;
163   }
164   WriteBackDataCacheRange (DataPtr, Bytes);
165   Status = BlockIo->ReadBlocks (BlockIo, BlockIo->Media->MediaId, Instance->StartLba + Lba,
166                                 Bytes, DataPtr);
167   if (EFI_ERROR (Status)) {
168     DEBUG ((EFI_D_ERROR, "FvbWrite: failed on reading blocks.\n"));
169     goto exit;
170   }
171   CopyMem (DataPtr + Offset, Buffer, *NumBytes);
172   WriteBackDataCacheRange (DataPtr, Bytes);
173   Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Instance->StartLba + Lba,
174                                  Bytes, DataPtr);
175   if (EFI_ERROR (Status)) {
176     DEBUG ((EFI_D_ERROR, "FvbWrite StartLba:%x, Lba:%x, Offset:%x, Status:%x\n",
177             Instance->StartLba, Lba, Offset, Status));
178   }
179   // Sometimes the variable isn't flushed into block device if it's the last flush operation.
180   // So flush it again.
181   Status = BlockIo->WriteBlocks (BlockIo, BlockIo->Media->MediaId, Instance->StartLba + Lba,
182                                  Bytes, DataPtr);
183   if (EFI_ERROR (Status)) {
184     DEBUG ((EFI_D_ERROR, "FvbWrite StartLba:%x, Lba:%x, Offset:%x, Status:%x\n",
185             Instance->StartLba, Lba, Offset, Status));
186   }
187 exit:
188   FreePool (DataPtr);
189   return Status;
190 }
191 
192 EFI_STATUS
193 EFIAPI
FvbEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,...)194 FvbEraseBlocks (
195   IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
196   ...
197   )
198 {
199   return EFI_SUCCESS;
200 }
201 
202 STATIC BLOCK_VARIABLE_INSTANCE   mBlockVariableInstance = {
203   .Signature      = BLOCK_VARIABLE_SIGNATURE,
204   .Media          = {
205     .MediaId                       = 0,
206     .RemovableMedia                = FALSE,
207     .MediaPresent                  = TRUE,
208     .LogicalPartition              = TRUE,
209     .ReadOnly                      = FALSE,
210     .WriteCaching                  = FALSE,
211     .BlockSize                     = 0,
212     .IoAlign                       = 4,
213     .LastBlock                     = 0,
214     .LowestAlignedLba              = 0,
215     .LogicalBlocksPerPhysicalBlock = 0,
216   },
217   .FvbProtocol    = {
218     .GetAttributes        = FvbGetAttributes,
219     .SetAttributes        = FvbSetAttributes,
220     .GetPhysicalAddress   = FvbGetPhysicalAddress,
221     .GetBlockSize         = FvbGetBlockSize,
222     .Read                 = FvbRead,
223     .Write                = FvbWrite,
224     .EraseBlocks          = FvbEraseBlocks,
225   }
226 };
227 
228 EFI_STATUS
ValidateFvHeader(IN EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)229 ValidateFvHeader (
230   IN EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader
231   )
232 {
233   UINT16                      Checksum, TempChecksum;
234   VARIABLE_STORE_HEADER       *VariableStoreHeader;
235   UINTN                       VariableStoreLength;
236   UINTN                       FvLength;
237 
238   FvLength = (UINTN) (PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
239       PcdGet32(PcdFlashNvStorageFtwSpareSize));
240 
241   //
242   // Verify the header revision, header signature, length
243   // Length of FvBlock cannot be 2**64-1
244   // HeaderLength cannot be an odd number
245   //
246   if (   (FwVolHeader->Revision  != EFI_FVH_REVISION)
247       || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
248       || (FwVolHeader->FvLength  != FvLength)
249       )
250   {
251     DEBUG ((EFI_D_ERROR, "ValidateFvHeader: No Firmware Volume header present\n"));
252     return EFI_NOT_FOUND;
253   }
254 
255   // Check the Firmware Volume Guid
256   if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) {
257     DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Firmware Volume Guid non-compatible\n"));
258     return EFI_NOT_FOUND;
259   }
260 
261   // Verify the header checksum
262   TempChecksum = FwVolHeader->Checksum;
263   FwVolHeader->Checksum = 0;
264   Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
265   if (Checksum != TempChecksum) {
266     DEBUG ((EFI_D_ERROR, "ValidateFvHeader: FV checksum is invalid (Checksum:0x%X)\n",Checksum));
267     return EFI_NOT_FOUND;
268   }
269   FwVolHeader->Checksum = Checksum;
270 
271   VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);
272 
273   // Check the Variable Store Guid
274   if( CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) == FALSE ) {
275     DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Variable Store Guid non-compatible\n"));
276     return EFI_NOT_FOUND;
277   }
278 
279   VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;
280   if (VariableStoreHeader->Size != VariableStoreLength) {
281     DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Variable Store Length does not match\n"));
282     return EFI_NOT_FOUND;
283   }
284 
285   return EFI_SUCCESS;
286 }
287 
288 EFI_STATUS
InitNonVolatileVariableStore(IN BLOCK_VARIABLE_INSTANCE * Instance,IN VOID * Headers,IN UINTN HeadersLength)289 InitNonVolatileVariableStore (
290   IN BLOCK_VARIABLE_INSTANCE      *Instance,
291   IN VOID                         *Headers,
292   IN UINTN                        HeadersLength
293   )
294 {
295   EFI_FIRMWARE_VOLUME_HEADER            *FirmwareVolumeHeader;
296   EFI_STATUS                            Status;
297   VARIABLE_STORE_HEADER                 *VariableStoreHeader;
298 
299   // Check if the size of the area is at least one block size
300   ASSERT((PcdGet32(PcdFlashNvStorageVariableSize) > 0) && (PcdGet32(PcdFlashNvStorageVariableSize) / Instance->BlockIoProtocol->Media->BlockSize > 0));
301   ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwWorkingSize) / Instance->BlockIoProtocol->Media->BlockSize > 0));
302   ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32(PcdFlashNvStorageFtwSpareSize) / Instance->BlockIoProtocol->Media->BlockSize > 0));
303 
304   //
305   // EFI_FIRMWARE_VOLUME_HEADER
306   //
307   FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
308   CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
309   FirmwareVolumeHeader->FvLength =
310       PcdGet32(PcdFlashNvStorageVariableSize) +
311       PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
312       PcdGet32(PcdFlashNvStorageFtwSpareSize);
313   FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
314   FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (
315                                             EFI_FVB2_READ_ENABLED_CAP   | // Reads may be enabled
316                                             EFI_FVB2_READ_STATUS        | // Reads are currently enabled
317                                             EFI_FVB2_STICKY_WRITE       | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
318                                             EFI_FVB2_MEMORY_MAPPED      | // It is memory mapped
319                                             EFI_FVB2_ERASE_POLARITY     | // After erasure all bits take this value (i.e. '1')
320                                             EFI_FVB2_WRITE_STATUS       | // Writes are currently enabled
321                                             EFI_FVB2_WRITE_ENABLED_CAP    // Writes may be enabled
322                                         );
323   FirmwareVolumeHeader->HeaderLength          = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
324   FirmwareVolumeHeader->Revision              = EFI_FVH_REVISION;
325   FirmwareVolumeHeader->BlockMap[0].NumBlocks = PcdGet32 (PcdNvStorageVariableBlockCount);
326   FirmwareVolumeHeader->BlockMap[0].Length    = Instance->BlockIoProtocol->Media->BlockSize;
327   // BlockMap Terminator
328   FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
329   FirmwareVolumeHeader->BlockMap[1].Length    = 0;
330   FirmwareVolumeHeader->Checksum = 0;
331   FirmwareVolumeHeader->Checksum = CalculateSum16 ((UINT16*)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
332 
333   //
334   // VARIABLE_STORE_HEADER
335   //
336   VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FirmwareVolumeHeader + FirmwareVolumeHeader->HeaderLength);
337   CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);
338   VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
339   VariableStoreHeader->Format            = VARIABLE_STORE_FORMATTED;
340   VariableStoreHeader->State             = VARIABLE_STORE_HEALTHY;
341 
342   Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
343   return Status;
344 }
345 
346 EFI_STATUS
BlockVariableDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)347 BlockVariableDxeInitialize (
348   IN EFI_HANDLE                   ImageHandle,
349   IN EFI_SYSTEM_TABLE             *SystemTable
350   )
351 {
352   EFI_HANDLE                      Handle;
353   EFI_STATUS                      Status;
354   BLOCK_VARIABLE_INSTANCE         *Instance = &mBlockVariableInstance;
355   UINT32                          Count;
356   EFI_LBA                         Lba;
357   UINTN                           NvStorageSize;
358   EFI_DEVICE_PATH_PROTOCOL        *NvBlockDevicePath;
359   UINT8                           *NvStorageData;
360   VOID                            *Headers;
361   UINTN                           HeadersLength;
362 
363   Instance->Signature = BLOCK_VARIABLE_SIGNATURE;
364 
365   HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
366   Headers = AllocateZeroPool(HeadersLength);
367   if (Headers == NULL) {
368     DEBUG ((EFI_D_ERROR, "%a: failed to allocate memory of Headers\n", __func__));
369     return EFI_OUT_OF_RESOURCES;
370   }
371 
372   Lba = (EFI_LBA) PcdGet32 (PcdNvStorageVariableBlockLba);
373   Count = PcdGet32 (PcdNvStorageVariableBlockCount);
374   Instance->Media.BlockSize = PcdGet32 (PcdNvStorageVariableBlockSize);
375   NvStorageSize = Count * Instance->Media.BlockSize;
376   Instance->StartLba = Lba;
377   HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
378   if (NvStorageSize < HeadersLength) {
379     return EFI_BAD_BUFFER_SIZE;
380   }
381   NvStorageData = (UINT8 *) (UINTN) PcdGet32(PcdFlashNvStorageVariableBase);
382   mMapNvStorageVariableBase = PcdGet32(PcdFlashNvStorageVariableBase);
383   NvBlockDevicePath = &Instance->DevicePath;
384   NvBlockDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdNvStorageVariableBlockDevicePath));
385   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &NvBlockDevicePath,
386                                   &Instance->Handle);
387   if (EFI_ERROR (Status)) {
388     DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate NVM device (status: %r)\n", Status));
389     return EFI_INVALID_PARAMETER;
390   }
391   Status = gBS->OpenProtocol (
392 		      Instance->Handle,
393                       &gEfiBlockIoProtocolGuid,
394 		      (VOID **) &Instance->BlockIoProtocol,
395                       gImageHandle,
396                       NULL,
397                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
398                       );
399   if (EFI_ERROR (Status)) {
400     DEBUG ((EFI_D_ERROR, "Warning: Couldn't open NVM device (status: %r)\n", Status));
401     return EFI_DEVICE_ERROR;
402   }
403   WriteBackDataCacheRange (Instance, sizeof(BLOCK_VARIABLE_INSTANCE));
404 
405   Handle = NULL;
406   Status = gBS->InstallMultipleProtocolInterfaces (
407 		  &Handle,
408 		  &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
409 		  NULL
410 		  );
411   if (EFI_ERROR (Status)) {
412     goto exit;
413   }
414 
415   Status = FvbRead (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
416   if (EFI_ERROR (Status)) {
417     return Status;
418   }
419 
420   Status = ValidateFvHeader (Headers);
421   if (EFI_ERROR (Status)) {
422     DEBUG ((EFI_D_ERROR, "%a, Found invalid Fv Header\n", __func__));
423 
424     // Erase all the block device that is reserved for variable storage
425     Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, Count, EFI_LBA_LIST_TERMINATOR);
426     if (EFI_ERROR (Status)) {
427       goto exit;
428     }
429 
430     Status = InitNonVolatileVariableStore (Instance, Headers, HeadersLength);
431     if (EFI_ERROR (Status)) {
432       goto exit;
433     }
434   }
435 
436   if (NvStorageSize > ((EFI_FIRMWARE_VOLUME_HEADER*)Headers)->FvLength) {
437     NvStorageSize = ((EFI_FIRMWARE_VOLUME_HEADER*)Headers)->FvLength;
438     NvStorageSize = ((NvStorageSize + Instance->Media.BlockSize - 1) / Instance->Media.BlockSize) * Instance->Media.BlockSize;
439   }
440   Status = FvbRead (&Instance->FvbProtocol, 0, 0, &NvStorageSize, NvStorageData);
441 
442 exit:
443   return Status;
444 }
445