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