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