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