]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvb.c
ArmPlatformPkg: Enable support for flash in 64-bit address space
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashFvb.c
CommitLineData
1e57a462 1/*++ @file NorFlashFvbDxe.c\r
2\r
8015f3f6 3 Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
1e57a462 4\r
f4dfad05 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 6\r
7 --*/\r
8\r
9#include <PiDxe.h>\r
10\r
11#include <Library/PcdLib.h>\r
12#include <Library/BaseLib.h>\r
1e57a462 13#include <Library/UefiLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
15#include <Library/MemoryAllocationLib.h>\r
1e57a462 16\r
17#include <Guid/VariableFormat.h>\r
18#include <Guid/SystemNvDataGuid.h>\r
6281a2ed 19#include <Guid/NvVarStoreFormatted.h>\r
1e57a462 20\r
c2d1cf1b 21#include "NorFlash.h"\r
1e57a462 22\r
c2d1cf1b 23extern UINTN mFlashNvStorageVariableBase;\r
1e57a462 24///\r
25/// The Firmware Volume Block Protocol is the low-level interface\r
26/// to a firmware volume. File-level access to a firmware volume\r
27/// should not be done using the Firmware Volume Block Protocol.\r
28/// Normal access to a firmware volume must use the Firmware\r
29/// Volume Protocol. Typically, only the file system driver that\r
30/// produces the Firmware Volume Protocol will bind to the\r
31/// Firmware Volume Block Protocol.\r
32///\r
33\r
34/**\r
35 Initialises the FV Header and Variable Store Header\r
36 to support variable operations.\r
37\r
38 @param[in] Ptr - Location to initialise the headers\r
39\r
40**/\r
41EFI_STATUS\r
42InitializeFvAndVariableStoreHeaders (\r
43 IN NOR_FLASH_INSTANCE *Instance\r
44 )\r
45{\r
46 EFI_STATUS Status;\r
47 VOID* Headers;\r
48 UINTN HeadersLength;\r
49 EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;\r
50 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
8015f3f6
VS
51 UINT32 NvStorageFtwSpareSize;\r
52 UINT32 NvStorageFtwWorkingSize;\r
53 UINT32 NvStorageVariableSize;\r
54 UINT64 NvStorageFtwSpareBase;\r
55 UINT64 NvStorageFtwWorkingBase;\r
56 UINT64 NvStorageVariableBase;\r
1e57a462 57\r
1e57a462 58 HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);\r
59 Headers = AllocateZeroPool(HeadersLength);\r
60\r
8015f3f6
VS
61 NvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
62 NvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
63 NvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
64\r
65 NvStorageFtwSpareBase = (PcdGet64 (PcdFlashNvStorageFtwSpareBase64) != 0) ?\r
66 PcdGet64 (PcdFlashNvStorageFtwSpareBase64) : PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
67 NvStorageFtwWorkingBase = (PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) != 0) ?\r
68 PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) : PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
69 NvStorageVariableBase = (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?\r
70 PcdGet64 (PcdFlashNvStorageVariableBase64) : PcdGet32 (PcdFlashNvStorageVariableBase);\r
71\r
1e57a462 72 // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.\r
8015f3f6
VS
73 if ((NvStorageVariableBase + NvStorageVariableSize) != NvStorageFtwWorkingBase) {\r
74 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwWorkingBase is not contiguous with NvStorageVariableBase region\n",\r
75 __FUNCTION__));\r
76 return EFI_INVALID_PARAMETER;\r
77 }\r
78\r
79 if ((NvStorageFtwWorkingBase + NvStorageFtwWorkingSize) != NvStorageFtwSpareBase) {\r
80 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwSpareBase is not contiguous with NvStorageFtwWorkingBase region\n",\r
81 __FUNCTION__));\r
82 return EFI_INVALID_PARAMETER;\r
83 }\r
1e57a462 84\r
85 // Check if the size of the area is at least one block size\r
8015f3f6
VS
86 if ((NvStorageVariableSize <= 0) || (NvStorageVariableSize / Instance->Media.BlockSize <= 0)) {\r
87 DEBUG ((DEBUG_ERROR, "%a: NvStorageVariableSize is 0x%x, should be atleast one block size\n", __FUNCTION__,\r
88 NvStorageVariableSize));\r
89 return EFI_INVALID_PARAMETER;\r
90 }\r
91\r
92 if ((NvStorageFtwWorkingSize <= 0) || (NvStorageFtwWorkingSize / Instance->Media.BlockSize <= 0)) {\r
93 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwWorkingSize is 0x%x, should be atleast one block size\n", __FUNCTION__,\r
94 NvStorageFtwWorkingSize));\r
95 return EFI_INVALID_PARAMETER;\r
96 }\r
97\r
98 if ((NvStorageFtwSpareSize <= 0) || (NvStorageFtwSpareSize / Instance->Media.BlockSize <= 0)) {\r
99 DEBUG ((DEBUG_ERROR, "%a: NvStorageFtwSpareSize is 0x%x, should be atleast one block size\n", __FUNCTION__,\r
100 NvStorageFtwSpareSize));\r
101 return EFI_INVALID_PARAMETER;\r
102 }\r
1e57a462 103\r
104 // Ensure the Variable area Base Addresses are aligned on a block size boundaries\r
8015f3f6
VS
105 if ((NvStorageVariableBase % Instance->Media.BlockSize != 0) ||\r
106 (NvStorageFtwWorkingBase % Instance->Media.BlockSize != 0) ||\r
107 (NvStorageFtwSpareBase % Instance->Media.BlockSize != 0)) {\r
108 DEBUG ((DEBUG_ERROR, "%a: NvStorage Base addresses must be aligned to block size boundaries", __FUNCTION__));\r
109 return EFI_INVALID_PARAMETER;\r
110 }\r
1e57a462 111\r
112 //\r
113 // EFI_FIRMWARE_VOLUME_HEADER\r
114 //\r
115 FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;\r
116 CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);\r
117 FirmwareVolumeHeader->FvLength =\r
118 PcdGet32(PcdFlashNvStorageVariableSize) +\r
119 PcdGet32(PcdFlashNvStorageFtwWorkingSize) +\r
120 PcdGet32(PcdFlashNvStorageFtwSpareSize);\r
121 FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;\r
122 FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (\r
123 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled\r
124 EFI_FVB2_READ_STATUS | // Reads are currently enabled\r
125 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY\r
126 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped\r
127 EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1')\r
128 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled\r
129 EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled\r
130 );\r
131 FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);\r
132 FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;\r
133 FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;\r
134 FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;\r
135 FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;\r
136 FirmwareVolumeHeader->BlockMap[1].Length = 0;\r
137 FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader,FirmwareVolumeHeader->HeaderLength);\r
138\r
139 //\r
140 // VARIABLE_STORE_HEADER\r
141 //\r
d5cd447b 142 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);\r
8753858f 143 CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);\r
1e57a462 144 VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;\r
145 VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;\r
146 VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;\r
147\r
148 // Install the combined super-header in the NorFlash\r
149 Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);\r
150\r
151 FreePool (Headers);\r
152 return Status;\r
153}\r
154\r
155/**\r
156 Check the integrity of firmware volume header.\r
157\r
158 @param[in] FwVolHeader - A pointer to a firmware volume header\r
159\r
160 @retval EFI_SUCCESS - The firmware volume is consistent\r
161 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.\r
162\r
163**/\r
164EFI_STATUS\r
165ValidateFvHeader (\r
166 IN NOR_FLASH_INSTANCE *Instance\r
167 )\r
168{\r
169 UINT16 Checksum;\r
170 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
171 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
172 UINTN VariableStoreLength;\r
91c38d4e 173 UINTN FvLength;\r
1e57a462 174\r
175 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress;\r
176\r
177 FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +\r
178 PcdGet32(PcdFlashNvStorageFtwSpareSize);\r
179\r
180 //\r
181 // Verify the header revision, header signature, length\r
182 // Length of FvBlock cannot be 2**64-1\r
183 // HeaderLength cannot be an odd number\r
184 //\r
185 if ( (FwVolHeader->Revision != EFI_FVH_REVISION)\r
186 || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)\r
187 || (FwVolHeader->FvLength != FvLength)\r
188 )\r
189 {\r
582085eb
LE
190 DEBUG ((EFI_D_INFO, "%a: No Firmware Volume header present\n",\r
191 __FUNCTION__));\r
1e57a462 192 return EFI_NOT_FOUND;\r
193 }\r
194\r
195 // Check the Firmware Volume Guid\r
196 if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) {\r
582085eb
LE
197 DEBUG ((EFI_D_INFO, "%a: Firmware Volume Guid non-compatible\n",\r
198 __FUNCTION__));\r
1e57a462 199 return EFI_NOT_FOUND;\r
200 }\r
201\r
202 // Verify the header checksum\r
203 Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);\r
204 if (Checksum != 0) {\r
582085eb
LE
205 DEBUG ((EFI_D_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n",\r
206 __FUNCTION__, Checksum));\r
1e57a462 207 return EFI_NOT_FOUND;\r
208 }\r
209\r
d5cd447b 210 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);\r
1e57a462 211\r
212 // Check the Variable Store Guid\r
8753858f
AB
213 if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&\r
214 !CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid)) {\r
582085eb
LE
215 DEBUG ((EFI_D_INFO, "%a: Variable Store Guid non-compatible\n",\r
216 __FUNCTION__));\r
1e57a462 217 return EFI_NOT_FOUND;\r
218 }\r
219\r
220 VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;\r
221 if (VariableStoreHeader->Size != VariableStoreLength) {\r
582085eb
LE
222 DEBUG ((EFI_D_INFO, "%a: Variable Store Length does not match\n",\r
223 __FUNCTION__));\r
1e57a462 224 return EFI_NOT_FOUND;\r
225 }\r
226\r
227 return EFI_SUCCESS;\r
228}\r
229\r
230/**\r
231 The GetAttributes() function retrieves the attributes and\r
232 current settings of the block.\r
233\r
234 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
235\r
236 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and\r
237 current settings are returned.\r
238 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.\r
239\r
240 @retval EFI_SUCCESS The firmware volume attributes were returned.\r
241\r
242 **/\r
243EFI_STATUS\r
244EFIAPI\r
245FvbGetAttributes(\r
246 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
247 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
248 )\r
249{\r
250 EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;\r
251 NOR_FLASH_INSTANCE *Instance;\r
252\r
253 Instance = INSTANCE_FROM_FVB_THIS(This);\r
254\r
255 FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) (\r
256\r
257 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled\r
258 EFI_FVB2_READ_STATUS | // Reads are currently enabled\r
259 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY\r
260 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped\r
261 EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1')\r
262\r
263 );\r
264\r
265 // Check if it is write protected\r
266 if (Instance->Media.ReadOnly != TRUE) {\r
267\r
268 FlashFvbAttributes = FlashFvbAttributes |\r
269 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled\r
270 EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled\r
271 }\r
272\r
273 *Attributes = FlashFvbAttributes;\r
274\r
275 DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes));\r
276\r
277 return EFI_SUCCESS;\r
278}\r
279\r
280/**\r
281 The SetAttributes() function sets configurable firmware volume attributes\r
282 and returns the new settings of the firmware volume.\r
283\r
284\r
285 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
286\r
287 @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2\r
288 that contains the desired firmware volume settings.\r
289 On successful return, it contains the new settings of\r
290 the firmware volume.\r
291 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.\r
292\r
293 @retval EFI_SUCCESS The firmware volume attributes were returned.\r
294\r
295 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities\r
296 as declared in the firmware volume header.\r
297\r
298 **/\r
299EFI_STATUS\r
300EFIAPI\r
301FvbSetAttributes(\r
302 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
303 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
304 )\r
305{\r
306 DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",*Attributes));\r
307 return EFI_UNSUPPORTED;\r
308}\r
309\r
310/**\r
311 The GetPhysicalAddress() function retrieves the base address of\r
312 a memory-mapped firmware volume. This function should be called\r
313 only for memory-mapped firmware volumes.\r
314\r
315 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
316\r
317 @param Address Pointer to a caller-allocated\r
318 EFI_PHYSICAL_ADDRESS that, on successful\r
319 return from GetPhysicalAddress(), contains the\r
320 base address of the firmware volume.\r
321\r
322 @retval EFI_SUCCESS The firmware volume base address was returned.\r
323\r
324 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.\r
325\r
326 **/\r
327EFI_STATUS\r
328EFIAPI\r
329FvbGetPhysicalAddress (\r
330 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
331 OUT EFI_PHYSICAL_ADDRESS *Address\r
332 )\r
333{\r
334 NOR_FLASH_INSTANCE *Instance;\r
335\r
336 Instance = INSTANCE_FROM_FVB_THIS(This);\r
337\r
338 DEBUG ((DEBUG_BLKIO, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n", Instance->RegionBaseAddress));\r
339\r
340 ASSERT(Address != NULL);\r
341\r
1dbbfc17 342 *Address = mFlashNvStorageVariableBase;\r
1e57a462 343 return EFI_SUCCESS;\r
344}\r
345\r
346/**\r
347 The GetBlockSize() function retrieves the size of the requested\r
348 block. It also returns the number of additional blocks with\r
349 the identical size. The GetBlockSize() function is used to\r
350 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).\r
351\r
352\r
353 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
354\r
355 @param Lba Indicates the block for which to return the size.\r
356\r
357 @param BlockSize Pointer to a caller-allocated UINTN in which\r
358 the size of the block is returned.\r
359\r
360 @param NumberOfBlocks Pointer to a caller-allocated UINTN in\r
361 which the number of consecutive blocks,\r
362 starting with Lba, is returned. All\r
363 blocks in this range have a size of\r
364 BlockSize.\r
365\r
366\r
367 @retval EFI_SUCCESS The firmware volume base address was returned.\r
368\r
369 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.\r
370\r
371 **/\r
372EFI_STATUS\r
373EFIAPI\r
374FvbGetBlockSize (\r
375 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
376 IN EFI_LBA Lba,\r
377 OUT UINTN *BlockSize,\r
378 OUT UINTN *NumberOfBlocks\r
379 )\r
380{\r
381 EFI_STATUS Status;\r
382 NOR_FLASH_INSTANCE *Instance;\r
383\r
384 Instance = INSTANCE_FROM_FVB_THIS(This);\r
385\r
386 DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba, Instance->Media.BlockSize, Instance->Media.LastBlock));\r
387\r
388 if (Lba > Instance->Media.LastBlock) {\r
389 DEBUG ((EFI_D_ERROR, "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n", Lba, Instance->Media.LastBlock));\r
390 Status = EFI_INVALID_PARAMETER;\r
391 } else {\r
392 // This is easy because in this platform each NorFlash device has equal sized blocks.\r
393 *BlockSize = (UINTN) Instance->Media.BlockSize;\r
394 *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1);\r
395\r
396 DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize, *NumberOfBlocks));\r
397\r
398 Status = EFI_SUCCESS;\r
399 }\r
400\r
401 return Status;\r
402}\r
403\r
404/**\r
405 Reads the specified number of bytes into a buffer from the specified block.\r
406\r
407 The Read() function reads the requested number of bytes from the\r
408 requested block and stores them in the provided buffer.\r
409 Implementations should be mindful that the firmware volume\r
410 might be in the ReadDisabled state. If it is in this state,\r
411 the Read() function must return the status code\r
412 EFI_ACCESS_DENIED without modifying the contents of the\r
413 buffer. The Read() function must also prevent spanning block\r
414 boundaries. If a read is requested that would span a block\r
415 boundary, the read must read up to the boundary but not\r
416 beyond. The output parameter NumBytes must be set to correctly\r
417 indicate the number of bytes actually read. The caller must be\r
418 aware that a read may be partially completed.\r
419\r
420 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
421\r
422 @param Lba The starting logical block index from which to read.\r
423\r
424 @param Offset Offset into the block at which to begin reading.\r
425\r
426 @param NumBytes Pointer to a UINTN.\r
427 At entry, *NumBytes contains the total size of the buffer.\r
428 At exit, *NumBytes contains the total number of bytes read.\r
429\r
430 @param Buffer Pointer to a caller-allocated buffer that will be used\r
431 to hold the data that is read.\r
432\r
433 @retval EFI_SUCCESS The firmware volume was read successfully, and contents are\r
434 in Buffer.\r
435\r
436 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.\r
437 On output, NumBytes contains the total number of bytes\r
438 returned in Buffer.\r
439\r
440 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.\r
441\r
442 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read.\r
443\r
444 **/\r
445EFI_STATUS\r
446EFIAPI\r
447FvbRead (\r
448 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
449 IN EFI_LBA Lba,\r
450 IN UINTN Offset,\r
451 IN OUT UINTN *NumBytes,\r
452 IN OUT UINT8 *Buffer\r
453 )\r
454{\r
1e57a462 455 EFI_STATUS TempStatus;\r
456 UINTN BlockSize;\r
1e57a462 457 NOR_FLASH_INSTANCE *Instance;\r
458\r
459 Instance = INSTANCE_FROM_FVB_THIS(This);\r
460\r
461 DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer));\r
462\r
518c243d 463 TempStatus = EFI_SUCCESS;\r
1e57a462 464\r
465 // Cache the block size to avoid de-referencing pointers all the time\r
466 BlockSize = Instance->Media.BlockSize;\r
467\r
468 DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));\r
469\r
470 // The read must not span block boundaries.\r
471 // We need to check each variable individually because adding two large values together overflows.\r
472 if ((Offset >= BlockSize) ||\r
473 (*NumBytes > BlockSize) ||\r
474 ((Offset + *NumBytes) > BlockSize)) {\r
475 DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));\r
476 return EFI_BAD_BUFFER_SIZE;\r
477 }\r
478\r
479 // We must have some bytes to read\r
480 if (*NumBytes == 0) {\r
481 return EFI_BAD_BUFFER_SIZE;\r
482 }\r
483\r
518c243d
HL
484 // Decide if we are doing full block reads or not.\r
485 if (*NumBytes % BlockSize != 0) {\r
486 TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, *NumBytes, Buffer);\r
487 if (EFI_ERROR (TempStatus)) {\r
488 return EFI_DEVICE_ERROR;\r
489 }\r
490 } else {\r
491 // Read NOR Flash data into shadow buffer\r
492 TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, Buffer);\r
493 if (EFI_ERROR (TempStatus)) {\r
494 // Return one of the pre-approved error statuses\r
495 return EFI_DEVICE_ERROR;\r
496 }\r
1e57a462 497 }\r
518c243d 498 return EFI_SUCCESS;\r
1e57a462 499}\r
500\r
501/**\r
502 Writes the specified number of bytes from the input buffer to the block.\r
503\r
504 The Write() function writes the specified number of bytes from\r
505 the provided buffer to the specified block and offset. If the\r
506 firmware volume is sticky write, the caller must ensure that\r
507 all the bits of the specified range to write are in the\r
508 EFI_FVB_ERASE_POLARITY state before calling the Write()\r
509 function, or else the result will be unpredictable. This\r
510 unpredictability arises because, for a sticky-write firmware\r
511 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY\r
512 state but cannot flip it back again. Before calling the\r
513 Write() function, it is recommended for the caller to first call\r
514 the EraseBlocks() function to erase the specified block to\r
515 write. A block erase cycle will transition bits from the\r
516 (NOT)EFI_FVB_ERASE_POLARITY state back to the\r
517 EFI_FVB_ERASE_POLARITY state. Implementations should be\r
518 mindful that the firmware volume might be in the WriteDisabled\r
519 state. If it is in this state, the Write() function must\r
520 return the status code EFI_ACCESS_DENIED without modifying the\r
521 contents of the firmware volume. The Write() function must\r
522 also prevent spanning block boundaries. If a write is\r
523 requested that spans a block boundary, the write must store up\r
524 to the boundary but not beyond. The output parameter NumBytes\r
525 must be set to correctly indicate the number of bytes actually\r
526 written. The caller must be aware that a write may be\r
527 partially completed. All writes, partial or otherwise, must be\r
528 fully flushed to the hardware before the Write() service\r
529 returns.\r
530\r
531 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.\r
532\r
533 @param Lba The starting logical block index to write to.\r
534\r
535 @param Offset Offset into the block at which to begin writing.\r
536\r
537 @param NumBytes The pointer to a UINTN.\r
538 At entry, *NumBytes contains the total size of the buffer.\r
539 At exit, *NumBytes contains the total number of bytes actually written.\r
540\r
541 @param Buffer The pointer to a caller-allocated buffer that contains the source for the write.\r
542\r
543 @retval EFI_SUCCESS The firmware volume was written successfully.\r
544\r
545 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.\r
546 On output, NumBytes contains the total number of bytes\r
547 actually written.\r
548\r
549 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
550\r
551 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written.\r
552\r
553\r
554 **/\r
555EFI_STATUS\r
556EFIAPI\r
557FvbWrite (\r
558 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
559 IN EFI_LBA Lba,\r
560 IN UINTN Offset,\r
561 IN OUT UINTN *NumBytes,\r
562 IN UINT8 *Buffer\r
563 )\r
564{\r
1e57a462 565 NOR_FLASH_INSTANCE *Instance;\r
518c243d 566\r
452a9ee1 567 Instance = INSTANCE_FROM_FVB_THIS (This);\r
1e57a462 568\r
36d66acf 569 return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset, NumBytes, Buffer);\r
1e57a462 570}\r
571\r
572/**\r
573 Erases and initialises a firmware volume block.\r
574\r
575 The EraseBlocks() function erases one or more blocks as denoted\r
576 by the variable argument list. The entire parameter list of\r
577 blocks must be verified before erasing any blocks. If a block is\r
578 requested that does not exist within the associated firmware\r
579 volume (it has a larger index than the last block of the\r
580 firmware volume), the EraseBlocks() function must return the\r
581 status code EFI_INVALID_PARAMETER without modifying the contents\r
582 of the firmware volume. Implementations should be mindful that\r
583 the firmware volume might be in the WriteDisabled state. If it\r
584 is in this state, the EraseBlocks() function must return the\r
585 status code EFI_ACCESS_DENIED without modifying the contents of\r
586 the firmware volume. All calls to EraseBlocks() must be fully\r
587 flushed to the hardware before the EraseBlocks() service\r
588 returns.\r
589\r
590 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL\r
591 instance.\r
592\r
593 @param ... The variable argument list is a list of tuples.\r
594 Each tuple describes a range of LBAs to erase\r
595 and consists of the following:\r
596 - An EFI_LBA that indicates the starting LBA\r
597 - A UINTN that indicates the number of blocks to erase.\r
598\r
599 The list is terminated with an EFI_LBA_LIST_TERMINATOR.\r
600 For example, the following indicates that two ranges of blocks\r
601 (5-7 and 10-11) are to be erased:\r
602 EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);\r
603\r
604 @retval EFI_SUCCESS The erase request successfully completed.\r
605\r
606 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.\r
607\r
608 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be written.\r
609 The firmware device may have been partially erased.\r
610\r
611 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable argument list do\r
612 not exist in the firmware volume.\r
613\r
614 **/\r
615EFI_STATUS\r
616EFIAPI\r
617FvbEraseBlocks (\r
618 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,\r
619 ...\r
620 )\r
621{\r
622 EFI_STATUS Status;\r
623 VA_LIST Args;\r
624 UINTN BlockAddress; // Physical address of Lba to erase\r
625 EFI_LBA StartingLba; // Lba from which we start erasing\r
626 UINTN NumOfLba; // Number of Lba blocks to erase\r
627 NOR_FLASH_INSTANCE *Instance;\r
628\r
629 Instance = INSTANCE_FROM_FVB_THIS(This);\r
630\r
631 DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n"));\r
632\r
633 Status = EFI_SUCCESS;\r
634\r
635 // Detect WriteDisabled state\r
636 if (Instance->Media.ReadOnly == TRUE) {\r
637 // Firmware volume is in WriteDisabled state\r
638 DEBUG ((EFI_D_ERROR, "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));\r
639 return EFI_ACCESS_DENIED;\r
640 }\r
641\r
642 // Before erasing, check the entire list of parameters to ensure all specified blocks are valid\r
643\r
644 VA_START (Args, This);\r
645 do {\r
646 // Get the Lba from which we start erasing\r
647 StartingLba = VA_ARG (Args, EFI_LBA);\r
648\r
649 // Have we reached the end of the list?\r
650 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
651 //Exit the while loop\r
652 break;\r
653 }\r
654\r
655 // How many Lba blocks are we requested to erase?\r
ce69cc77 656 NumOfLba = VA_ARG (Args, UINTN);\r
1e57a462 657\r
658 // All blocks must be within range\r
ce69cc77
LE
659 DEBUG ((\r
660 DEBUG_BLKIO,\r
661 "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%Lu - 1 ) > LastBlock=%ld.\n",\r
662 Instance->StartLba + StartingLba,\r
663 (UINT64)NumOfLba,\r
664 Instance->Media.LastBlock\r
665 ));\r
1e57a462 666 if ((NumOfLba == 0) || ((Instance->StartLba + StartingLba + NumOfLba - 1) > Instance->Media.LastBlock)) {\r
667 VA_END (Args);\r
668 DEBUG ((EFI_D_ERROR, "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));\r
669 Status = EFI_INVALID_PARAMETER;\r
670 goto EXIT;\r
671 }\r
672 } while (TRUE);\r
673 VA_END (Args);\r
674\r
675 //\r
676 // To get here, all must be ok, so start erasing\r
677 //\r
678 VA_START (Args, This);\r
679 do {\r
680 // Get the Lba from which we start erasing\r
681 StartingLba = VA_ARG (Args, EFI_LBA);\r
682\r
683 // Have we reached the end of the list?\r
684 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
685 // Exit the while loop\r
686 break;\r
687 }\r
688\r
689 // How many Lba blocks are we requested to erase?\r
ce69cc77 690 NumOfLba = VA_ARG (Args, UINTN);\r
1e57a462 691\r
692 // Go through each one and erase it\r
693 while (NumOfLba > 0) {\r
694\r
695 // Get the physical address of Lba to erase\r
696 BlockAddress = GET_NOR_BLOCK_ADDRESS (\r
697 Instance->RegionBaseAddress,\r
698 Instance->StartLba + StartingLba,\r
699 Instance->Media.BlockSize\r
700 );\r
701\r
702 // Erase it\r
703 DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", Instance->StartLba + StartingLba, BlockAddress));\r
704 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);\r
705 if (EFI_ERROR(Status)) {\r
706 VA_END (Args);\r
707 Status = EFI_DEVICE_ERROR;\r
708 goto EXIT;\r
709 }\r
710\r
711 // Move to the next Lba\r
712 StartingLba++;\r
713 NumOfLba--;\r
714 }\r
715 } while (TRUE);\r
716 VA_END (Args);\r
717\r
718EXIT:\r
719 return Status;\r
720}\r
721\r
1dbbfc17
OM
722/**\r
723 Fixup internal data so that EFI can be call in virtual mode.\r
724 Call the passed in Child Notify event and convert any pointers in\r
725 lib to virtual mode.\r
726\r
727 @param[in] Event The Event that is being processed\r
728 @param[in] Context Event Context\r
729**/\r
730VOID\r
731EFIAPI\r
732FvbVirtualNotifyEvent (\r
733 IN EFI_EVENT Event,\r
734 IN VOID *Context\r
735 )\r
736{\r
737 EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);\r
738 return;\r
739}\r
740\r