1 /** @file
2 *
3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
4 * Copyright (c) 2015, Hisilicon Limited. All rights reserved.
5 * Copyright (c) 2015, Linaro Limited. All rights reserved.
6 *
7 * This program and the accompanying materials
8 * are licensed and made available under the terms and conditions of the BSD License
9 * which accompanies this distribution. The full text of the license may be found at
10 * http://opensource.org/licenses/bsd-license.php
11 *
12 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 *
15 * Based on files under ArmPlatformPkg/Drivers/NorFlashDxe/
16 **/
17
18 #include "FlashFvbDxe.h"
19 STATIC EFI_EVENT mFlashFvbVirtualAddrChangeEvent;
20 STATIC UINTN mFlashNvStorageVariableBase;
21
22
23 //
24 // Global variable declarations
25 //
26
27 FLASH_DESCRIPTION mFlashDevices[FLASH_DEVICE_COUNT] =
28 {
29 {
30 // UEFI Variable Services non-volatile storage
31 0xa4000000,
32 FixedPcdGet32(PcdFlashNvStorageVariableBase),
33 0x20000,
34 SIZE_64KB,
35 {0xCC2CBF29, 0x1498, 0x4CDD, {0x81, 0x71, 0xF8, 0xB6, 0xB4, 0x1D, 0x09, 0x09}}
36 }
37
38 };
39
40 FLASH_INSTANCE** mFlashInstances;
41
42 FLASH_INSTANCE mFlashInstanceTemplate =
43 {
44 FLASH_SIGNATURE, // Signature
45 NULL, // Handle ... NEED TO BE FILLED
46
47 FALSE, // Initialized
48 NULL, // Initialize
49
50 0, // DeviceBaseAddress ... NEED TO BE FILLED
51 0, // RegionBaseAddress ... NEED TO BE FILLED
52 0, // Size ... NEED TO BE FILLED
53 0, // StartLba
54
55 {
56 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
57 NULL, // Media ... NEED TO BE FILLED
58 NULL, //NorFlashBlockIoReset
59 FlashBlockIoReadBlocks,
60 FlashBlockIoWriteBlocks,
61 FlashBlockIoFlushBlocks
62 }, // BlockIoProtocol
63
64 {
65 0, // MediaId ... NEED TO BE FILLED
66 FALSE, // RemovableMedia
67 TRUE, // MediaPresent
68 FALSE, // LogicalPartition
69 FALSE, // ReadOnly
70 FALSE, // WriteCaching;
71 SIZE_64KB, // BlockSize ... NEED TO BE FILLED
72 4, // IoAlign
73 0, // LastBlock ... NEED TO BE FILLED
74 0, // LowestAlignedLba
75 1, // LogicalBlocksPerPhysicalBlock
76 }, //Media;
77
78 FALSE, // SupportFvb ... NEED TO BE FILLED
79 {
80 FvbGetAttributes,
81 FvbSetAttributes,
82 FvbGetPhysicalAddress,
83 FvbGetBlockSize,
84 FvbRead,
85 FvbWrite,
86 FvbEraseBlocks,
87 NULL, //ParentHandle
88 }, // FvbProtoccol;
89
90 {
91 {
92 {
93 HARDWARE_DEVICE_PATH,
94 HW_VENDOR_DP,
95 {(UINT8)(sizeof(VENDOR_DEVICE_PATH)),
96 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)},
97 },
98 { 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }}, // GUID ... NEED TO BE FILLED
99 },
100 {
101 END_DEVICE_PATH_TYPE,
102 END_ENTIRE_DEVICE_PATH_SUBTYPE,
103 {sizeof (EFI_DEVICE_PATH_PROTOCOL),
104 0}
105 }
106 } // DevicePath
107 };
108
109 HISI_SPI_FLASH_PROTOCOL* mFlash;
110
111 ///
112 /// The Firmware Volume Block Protocol is the low-level interface
113 /// to a firmware volume. File-level access to a firmware volume
114 /// should not be done using the Firmware Volume Block Protocol.
115 /// Normal access to a firmware volume must use the Firmware
116 /// Volume Protocol. Typically, only the file system driver that
117 /// produces the Firmware Volume Protocol will bind to the
118 /// Firmware Volume Block Protocol.
119 ///
120
121 /**
122 Initialises the FV Header and Variable Store Header
123 to support variable operations.
124
125 @param[in] Ptr - Location to initialise the headers
126
127 **/
128 EFI_STATUS
InitializeFvAndVariableStoreHeaders(IN FLASH_INSTANCE * Instance)129 InitializeFvAndVariableStoreHeaders (
130 IN FLASH_INSTANCE* Instance
131 )
132 {
133 EFI_STATUS Status;
134 VOID* Headers;
135 UINTN HeadersLength;
136 EFI_FIRMWARE_VOLUME_HEADER* FirmwareVolumeHeader;
137 VARIABLE_STORE_HEADER* VariableStoreHeader;
138
139 if (!Instance->Initialized && Instance->Initialize)
140 {
141 Instance->Initialize (Instance);
142 }
143
144 HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
145 Headers = AllocateZeroPool(HeadersLength);
146
147 // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.
148 ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + PcdGet32(PcdFlashNvStorageVariableSize) == PcdGet32(PcdFlashNvStorageFtwWorkingBase));
149 ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) == PcdGet32(PcdFlashNvStorageFtwSpareBase));
150
151 // Check if the size of the area is at least one block size
152 ASSERT((PcdGet32(PcdFlashNvStorageVariableSize) > 0) && ((UINT32)PcdGet32(PcdFlashNvStorageVariableSize) / Instance->Media.BlockSize > 0));
153 ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize) > 0) && ((UINT32)PcdGet32(PcdFlashNvStorageFtwWorkingSize) / Instance->Media.BlockSize > 0));
154 ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize) > 0) && ((UINT32)PcdGet32(PcdFlashNvStorageFtwSpareSize) / Instance->Media.BlockSize > 0));
155
156 // Ensure the Variable area Base Addresses are aligned on a block size boundaries
157 ASSERT((UINT32)PcdGet32(PcdFlashNvStorageVariableBase) % Instance->Media.BlockSize == 0);
158 ASSERT((UINT32)PcdGet32(PcdFlashNvStorageFtwWorkingBase) % Instance->Media.BlockSize == 0);
159 ASSERT((UINT32)PcdGet32(PcdFlashNvStorageFtwSpareBase) % Instance->Media.BlockSize == 0);
160
161 //
162 // EFI_FIRMWARE_VOLUME_HEADER
163 //
164 FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
165 CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
166 FirmwareVolumeHeader->FvLength =
167 PcdGet32(PcdFlashNvStorageVariableSize) +
168 PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
169 PcdGet32(PcdFlashNvStorageFtwSpareSize);
170 FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
171 FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (
172 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
173 EFI_FVB2_READ_STATUS | // Reads are currently enabled
174 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
175 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
176 EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1')
177 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
178 EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled
179 );
180 FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
181 FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
182 FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;
183 FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;
184 FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
185 FirmwareVolumeHeader->BlockMap[1].Length = 0;
186 FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
187
188 //
189 // VARIABLE_STORE_HEADER
190 //
191 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + (UINTN)FirmwareVolumeHeader->HeaderLength);
192 CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);
193 VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
194 VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
195 VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
196
197 // Install the combined super-header in the NorFlash
198 Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
199
200 FreePool (Headers);
201 return Status;
202 }
203
204 /**
205 Check the integrity of firmware volume header.
206
207 @param[in] FwVolHeader - A pointer to a firmware volume header
208
209 @retval EFI_SUCCESS - The firmware volume is consistent
210 @retval EFI_NOT_FOUND - The firmware volume has been corrupted.
211
212 **/
213 EFI_STATUS
ValidateFvHeader(IN FLASH_INSTANCE * Instance)214 ValidateFvHeader (
215 IN FLASH_INSTANCE* Instance
216 )
217 {
218 UINT16 Checksum;
219 EFI_FIRMWARE_VOLUME_HEADER* FwVolHeader;
220 VARIABLE_STORE_HEADER* VariableStoreHeader;
221 UINTN VariableStoreLength;
222 UINTN FvLength;
223
224 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress;
225
226 FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
227 PcdGet32(PcdFlashNvStorageFtwSpareSize);
228
229 //
230 // Verify the header revision, header signature, length
231 // Length of FvBlock cannot be 2**64-1
232 // HeaderLength cannot be an odd number
233 //
234 if ( (FwVolHeader->Revision != EFI_FVH_REVISION)
235 || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
236 || (FwVolHeader->FvLength != FvLength)
237 )
238 {
239 DEBUG ((EFI_D_ERROR, "ValidateFvHeader: No Firmware Volume header present\n"));
240 return EFI_NOT_FOUND;
241 }
242
243 // Check the Firmware Volume Guid
244 if ( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE )
245 {
246 DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Firmware Volume Guid non-compatible\n"));
247 return EFI_NOT_FOUND;
248 }
249
250 // Verify the header checksum
251 Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
252 if (Checksum != 0)
253 {
254 DEBUG ((EFI_D_ERROR, "ValidateFvHeader: FV checksum is invalid (Checksum:0x%X)\n", Checksum));
255 return EFI_NOT_FOUND;
256 }
257
258 VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + (UINTN)FwVolHeader->HeaderLength);
259
260 // Check the Variable Store Guid
261 if ( CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) == FALSE )
262 {
263 DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Variable Store Guid non-compatible\n"));
264 return EFI_NOT_FOUND;
265 }
266
267 VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;
268 if (VariableStoreHeader->Size != VariableStoreLength)
269 {
270 DEBUG ((EFI_D_ERROR, "ValidateFvHeader: Variable Store Length does not match\n"));
271 return EFI_NOT_FOUND;
272 }
273
274 return EFI_SUCCESS;
275 }
276
277 /**
278 The FvbGetAttributes() function retrieves the attributes and
279 current settings of the block.
280
281 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
282
283 @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
284 current settings are returned.
285 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
286
287 @retval EFI_SUCCESS The firmware volume attributes were returned.
288
289 **/
290 EFI_STATUS
291 EFIAPI
FvbGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)292 FvbGetAttributes(
293 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
294 OUT EFI_FVB_ATTRIBUTES_2* Attributes
295 )
296 {
297 EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
298 FLASH_INSTANCE* Instance;
299
300 Instance = INSTANCE_FROM_FVB_THIS(This);
301
302 FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) (
303
304 EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
305 EFI_FVB2_READ_STATUS | // Reads are currently enabled
306 EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
307 EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
308 EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1')
309
310 );
311
312 // Check if it is write protected
313 if (Instance->Media.ReadOnly != TRUE)
314 {
315
316 FlashFvbAttributes = FlashFvbAttributes |
317 EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
318 EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled
319 }
320
321 *Attributes = FlashFvbAttributes;
322
323 return EFI_SUCCESS;
324 }
325
326 /**
327 The FvbSetAttributes() function sets configurable firmware volume attributes
328 and returns the new settings of the firmware volume.
329
330
331 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
332
333 @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2
334 that contains the desired firmware volume settings.
335 On successful return, it contains the new settings of
336 the firmware volume.
337 Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER.
338
339 @retval EFI_SUCCESS The firmware volume attributes were returned.
340
341 @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities
342 as declared in the firmware volume header.
343
344 **/
345 EFI_STATUS
346 EFIAPI
FvbSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)347 FvbSetAttributes(
348 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
349 IN OUT EFI_FVB_ATTRIBUTES_2* Attributes
350 )
351 {
352 DEBUG ((EFI_D_ERROR, "FvbSetAttributes(0x%X) is not supported\n", *Attributes));
353 return EFI_UNSUPPORTED;
354 }
355
356 /**
357 The GetPhysicalAddress() function retrieves the base address of
358 a memory-mapped firmware volume. This function should be called
359 only for memory-mapped firmware volumes.
360
361 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
362
363 @param Address Pointer to a caller-allocated
364 EFI_PHYSICAL_ADDRESS that, on successful
365 return from GetPhysicalAddress(), contains the
366 base address of the firmware volume.
367
368 @retval EFI_SUCCESS The firmware volume base address was returned.
369
370 @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
371
372 **/
373 EFI_STATUS
374 EFIAPI
FvbGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)375 FvbGetPhysicalAddress (
376 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
377 OUT EFI_PHYSICAL_ADDRESS* Address
378 )
379 {
380
381 if(NULL == Address)
382 {
383 return EFI_UNSUPPORTED;
384 };
385
386 *Address = mFlashNvStorageVariableBase;
387 return EFI_SUCCESS;
388 }
389
390 /**
391 The GetBlockSize() function retrieves the size of the requested
392 block. It also returns the number of additional blocks with
393 the identical size. The GetBlockSize() function is used to
394 retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
395
396
397 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
398
399 @param Lba Indicates the block for which to return the size.
400
401 @param BlockSize Pointer to a caller-allocated UINTN in which
402 the size of the block is returned.
403
404 @param NumberOfBlocks Pointer to a caller-allocated UINTN in
405 which the number of consecutive blocks,
406 starting with Lba, is returned. All
407 blocks in this range have a size of
408 BlockSize.
409
410
411 @retval EFI_SUCCESS The firmware volume base address was returned.
412
413 @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
414
415 **/
416 EFI_STATUS
417 EFIAPI
FvbGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumberOfBlocks)418 FvbGetBlockSize (
419 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
420 IN EFI_LBA Lba,
421 OUT UINTN* BlockSize,
422 OUT UINTN* NumberOfBlocks
423 )
424 {
425 EFI_STATUS Status;
426 FLASH_INSTANCE* Instance;
427
428 Instance = INSTANCE_FROM_FVB_THIS(This);
429
430 if (Lba > Instance->Media.LastBlock)
431 {
432 Status = EFI_INVALID_PARAMETER;
433 }
434 else
435 {
436 // This is easy because in this platform each NorFlash device has equal sized blocks.
437 *BlockSize = (UINTN) Instance->Media.BlockSize;
438 *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1);
439
440
441 Status = EFI_SUCCESS;
442 }
443
444 return Status;
445 }
446
447 /**
448 Reads the specified number of bytes into a buffer from the specified block.
449
450 The Read() function reads the requested number of bytes from the
451 requested block and stores them in the provided buffer.
452 Implementations should be mindful that the firmware volume
453 might be in the ReadDisabled state. If it is in this state,
454 the Read() function must return the status code
455 EFI_ACCESS_DENIED without modifying the contents of the
456 buffer. The Read() function must also prevent spanning block
457 boundaries. If a read is requested that would span a block
458 boundary, the read must read up to the boundary but not
459 beyond. The output parameter NumBytes must be set to correctly
460 indicate the number of bytes actually read. The caller must be
461 aware that a read may be partially completed.
462
463 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
464
465 @param Lba The starting logical block index from which to read.
466
467 @param Offset Offset into the block at which to begin reading.
468
469 @param NumBytes Pointer to a UINTN.
470 At entry, *NumBytes contains the total size of the buffer.
471 At exit, *NumBytes contains the total number of bytes read.
472
473 @param Buffer Pointer to a caller-allocated buffer that will be used
474 to hold the data that is read.
475
476 @retval EFI_SUCCESS The firmware volume was read successfully, and contents are
477 in Buffer.
478
479 @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
480 On output, NumBytes contains the total number of bytes
481 returned in Buffer.
482
483 @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state.
484
485 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be read.
486
487 **/
488 EFI_STATUS
489 EFIAPI
FvbRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN OUT UINT8 * Buffer)490 FvbRead (
491 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
492 IN EFI_LBA Lba,
493 IN UINTN Offset,
494 IN OUT UINTN* NumBytes,
495 IN OUT UINT8* Buffer
496 )
497 {
498 EFI_STATUS Status;
499 UINTN BlockSize;
500 FLASH_INSTANCE* Instance;
501
502 UINTN StartAddress;
503 UINTN ReadAddress;
504
505 Instance = INSTANCE_FROM_FVB_THIS(This);
506
507 if (!Instance->Initialized && Instance->Initialize)
508 {
509 if (EfiAtRuntime ()) {
510 DEBUG ((EFI_D_ERROR, "[%a]:[%dL] Initialize at runtime is not supported!\n", __FUNCTION__, __LINE__));
511 return EFI_UNSUPPORTED;
512 }
513
514 Instance->Initialize(Instance);
515 }
516
517 Status = EFI_SUCCESS;
518
519 // Cache the block size to avoid de-referencing pointers all the time
520 BlockSize = Instance->Media.BlockSize;
521
522 // The read must not span block boundaries.
523 // We need to check each variable individually because adding two large values together overflows.
524 if ((Offset >= BlockSize) ||
525 (*NumBytes > BlockSize) ||
526 ((Offset + *NumBytes) > BlockSize))
527 {
528 DEBUG ((EFI_D_ERROR, "[%a]:[%dL] ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", __FUNCTION__, __LINE__, Offset, *NumBytes, BlockSize ));
529 return EFI_BAD_BUFFER_SIZE;
530 }
531
532 // We must have some bytes to read
533 if (*NumBytes == 0)
534 {
535 return EFI_BAD_BUFFER_SIZE;
536 }
537
538 // Get the address to start reading from
539 StartAddress = GET_BLOCK_ADDRESS (Instance->RegionBaseAddress,
540 Lba,
541 BlockSize
542 );
543 ReadAddress = StartAddress - Instance->DeviceBaseAddress + Offset;
544
545 Status = mFlash->Read(mFlash, (UINT32)ReadAddress, Buffer, *NumBytes);
546 if (EFI_SUCCESS != Status)
547 {
548 // Return one of the pre-approved error statuses
549 Status = EFI_DEVICE_ERROR;
550 return Status;
551 }
552
553
554 return Status;
555 }
556
557 /**
558 Writes the specified number of bytes from the input buffer to the block.
559
560 The Write() function writes the specified number of bytes from
561 the provided buffer to the specified block and offset. If the
562 firmware volume is sticky write, the caller must ensure that
563 all the bits of the specified range to write are in the
564 EFI_FVB_ERASE_POLARITY state before calling the Write()
565 function, or else the result will be unpredictable. This
566 unpredictability arises because, for a sticky-write firmware
567 volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
568 state but cannot flip it back again. Before calling the
569 Write() function, it is recommended for the caller to first call
570 the EraseBlocks() function to erase the specified block to
571 write. A block erase cycle will transition bits from the
572 (NOT)EFI_FVB_ERASE_POLARITY state back to the
573 EFI_FVB_ERASE_POLARITY state. Implementations should be
574 mindful that the firmware volume might be in the WriteDisabled
575 state. If it is in this state, the Write() function must
576 return the status code EFI_ACCESS_DENIED without modifying the
577 contents of the firmware volume. The Write() function must
578 also prevent spanning block boundaries. If a write is
579 requested that spans a block boundary, the write must store up
580 to the boundary but not beyond. The output parameter NumBytes
581 must be set to correctly indicate the number of bytes actually
582 written. The caller must be aware that a write may be
583 partially completed. All writes, partial or otherwise, must be
584 fully flushed to the hardware before the Write() service
585 returns.
586
587 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
588
589 @param Lba The starting logical block index to write to.
590
591 @param Offset Offset into the block at which to begin writing.
592
593 @param NumBytes The pointer to a UINTN.
594 At entry, *NumBytes contains the total size of the buffer.
595 At exit, *NumBytes contains the total number of bytes actually written.
596
597 @param Buffer The pointer to a caller-allocated buffer that contains the source for the write.
598
599 @retval EFI_SUCCESS The firmware volume was written successfully.
600
601 @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary.
602 On output, NumBytes contains the total number of bytes
603 actually written.
604
605 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
606
607 @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written.
608
609
610 **/
611 EFI_STATUS
612 EFIAPI
FvbWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)613 FvbWrite (
614 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
615 IN EFI_LBA Lba,
616 IN UINTN Offset,
617 IN OUT UINTN* NumBytes,
618 IN UINT8* Buffer
619 )
620 {
621 EFI_STATUS Status;
622 UINTN BlockSize;
623 FLASH_INSTANCE* Instance;
624 UINTN BlockAddress;
625 UINTN WriteAddress;
626
627 Instance = INSTANCE_FROM_FVB_THIS(This);
628 if (NULL == Instance)
629 {
630 return EFI_INVALID_PARAMETER;
631
632 }
633
634 if (!Instance->Initialized && Instance->Initialize)
635 {
636 if (EfiAtRuntime ()) {
637 DEBUG ((EFI_D_ERROR, "[%a]:[%dL] Initialize at runtime is not supported!\n", __FUNCTION__, __LINE__));
638 return EFI_UNSUPPORTED;
639 }
640
641 Instance->Initialize(Instance);
642 }
643
644 Status = EFI_SUCCESS;
645
646 // Detect WriteDisabled state
647 if (Instance->Media.ReadOnly == TRUE)
648 {
649 DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Can not write: Device is in WriteDisabled state.\n"));
650 // It is in WriteDisabled state, return an error right away
651 return EFI_ACCESS_DENIED;
652 }
653
654 // Cache the block size to avoid de-referencing pointers all the time
655 BlockSize = Instance->Media.BlockSize;
656
657 // The write must not span block boundaries.
658 // We need to check each variable individually because adding two large values together overflows.
659 if ( ( Offset >= BlockSize ) ||
660 ( *NumBytes > BlockSize ) ||
661 ( (Offset + *NumBytes) > BlockSize ) )
662 {
663 DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
664 return EFI_BAD_BUFFER_SIZE;
665 }
666
667 // We must have some bytes to write
668 if (*NumBytes == 0)
669 {
670 DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
671 return EFI_BAD_BUFFER_SIZE;
672 }
673
674 BlockAddress = GET_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
675 WriteAddress = BlockAddress - Instance->DeviceBaseAddress + Offset;
676
677 Status = mFlash->Write(mFlash, (UINT32)WriteAddress, (UINT8*)Buffer, *NumBytes);
678 if (EFI_SUCCESS != Status)
679 {
680 DEBUG((EFI_D_ERROR, "%s - %d Status=%r\n", __FILE__, __LINE__, Status));
681 return Status;
682 }
683
684 return Status;
685
686 }
687
688 /**
689 Erases and initialises a firmware volume block.
690
691 The EraseBlocks() function erases one or more blocks as denoted
692 by the variable argument list. The entire parameter list of
693 blocks must be verified before erasing any blocks. If a block is
694 requested that does not exist within the associated firmware
695 volume (it has a larger index than the last block of the
696 firmware volume), the EraseBlocks() function must return the
697 status code EFI_INVALID_PARAMETER without modifying the contents
698 of the firmware volume. Implementations should be mindful that
699 the firmware volume might be in the WriteDisabled state. If it
700 is in this state, the EraseBlocks() function must return the
701 status code EFI_ACCESS_DENIED without modifying the contents of
702 the firmware volume. All calls to EraseBlocks() must be fully
703 flushed to the hardware before the EraseBlocks() service
704 returns.
705
706 @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
707 instance.
708
709 @param ... The variable argument list is a list of tuples.
710 Each tuple describes a range of LBAs to erase
711 and consists of the following:
712 - An EFI_LBA that indicates the starting LBA
713 - A UINTN that indicates the number of blocks to erase.
714
715 The list is terminated with an EFI_LBA_LIST_TERMINATOR.
716 For example, the following indicates that two ranges of blocks
717 (5-7 and 10-11) are to be erased:
718 EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
719
720 @retval EFI_SUCCESS The erase request successfully completed.
721
722 @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state.
723
724 @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be written.
725 The firmware device may have been partially erased.
726
727 @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable argument list do
728 not exist in the firmware volume.
729
730 **/
731 EFI_STATUS
732 EFIAPI
FvbEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL * This,...)733 FvbEraseBlocks (
734 IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
735 ...
736 )
737 {
738 EFI_STATUS Status;
739 VA_LIST Args;
740 UINTN BlockAddress; // Physical address of Lba to erase
741 EFI_LBA StartingLba; // Lba from which we start erasing
742 UINTN NumOfLba; // Number of Lba blocks to erase
743 FLASH_INSTANCE* Instance;
744
745 Instance = INSTANCE_FROM_FVB_THIS(This);
746
747 Status = EFI_SUCCESS;
748
749 // Detect WriteDisabled state
750 if (Instance->Media.ReadOnly == TRUE)
751 {
752 // Firmware volume is in WriteDisabled state
753 return EFI_ACCESS_DENIED;
754 }
755
756 // Before erasing, check the entire list of parameters to ensure all specified blocks are valid
757 VA_START (Args, This);
758 do
759 {
760 // Get the Lba from which we start erasing
761 StartingLba = VA_ARG (Args, EFI_LBA);
762
763 // Have we reached the end of the list?
764 if (StartingLba == EFI_LBA_LIST_TERMINATOR)
765 {
766 //Exit the while loop
767 break;
768 }
769
770 // How many Lba blocks are we requested to erase?
771 NumOfLba = VA_ARG (Args, UINT32);
772
773 // All blocks must be within range
774 if ((NumOfLba == 0) || ((Instance->StartLba + StartingLba + NumOfLba - 1) > Instance->Media.LastBlock))
775 {
776 VA_END (Args);
777 Status = EFI_INVALID_PARAMETER;
778 goto EXIT;
779 }
780 }
781 while (TRUE);
782 VA_END (Args);
783
784 //
785 // To get here, all must be ok, so start erasing
786 //
787 VA_START (Args, This);
788 do
789 {
790 // Get the Lba from which we start erasing
791 StartingLba = VA_ARG (Args, EFI_LBA);
792
793 // Have we reached the end of the list?
794 if (StartingLba == EFI_LBA_LIST_TERMINATOR)
795 {
796 // Exit the while loop
797 break;
798 }
799
800 // How many Lba blocks are we requested to erase?
801 NumOfLba = VA_ARG (Args, UINT32);
802
803 // Go through each one and erase it
804 while (NumOfLba > 0)
805 {
806
807 // Get the physical address of Lba to erase
808 BlockAddress = GET_BLOCK_ADDRESS (
809 Instance->RegionBaseAddress,
810 Instance->StartLba + StartingLba,
811 Instance->Media.BlockSize
812 );
813
814 // Erase it
815
816 Status = FlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
817 if (EFI_ERROR(Status))
818 {
819 VA_END (Args);
820 Status = EFI_DEVICE_ERROR;
821 goto EXIT;
822 }
823
824 // Move to the next Lba
825 StartingLba++;
826 NumOfLba--;
827 }
828 }
829 while (TRUE);
830 VA_END (Args);
831
832 EXIT:
833 return Status;
834 }
835
836 EFI_STATUS
837 EFIAPI
FvbInitialize(IN FLASH_INSTANCE * Instance)838 FvbInitialize (
839 IN FLASH_INSTANCE* Instance
840 )
841 {
842 EFI_STATUS Status;
843 UINT32 FvbNumLba;
844
845 Instance->Initialized = TRUE;
846 mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
847
848 // Set the index of the first LBA for the FVB
849 Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;
850
851 // Determine if there is a valid header at the beginning of the Flash
852 Status = ValidateFvHeader (Instance);
853 if (EFI_ERROR(Status))
854 {
855 // There is no valid header, so time to install one.
856 // Erase all the Flash that is reserved for variable storage
857 FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + (UINT32)PcdGet32(PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize;
858 Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);
859 if (EFI_ERROR(Status))
860 {
861 return Status;
862 }
863
864 // Install all appropriate headers
865 Status = InitializeFvAndVariableStoreHeaders (Instance);
866 if (EFI_ERROR(Status))
867 {
868 return Status;
869 }
870 }
871 return Status;
872 }
873
874
875 EFI_STATUS
FlashPlatformGetDevices(OUT FLASH_DESCRIPTION ** FlashDevices,OUT UINT32 * Count)876 FlashPlatformGetDevices (
877 OUT FLASH_DESCRIPTION** FlashDevices,
878 OUT UINT32* Count
879 )
880 {
881 if ((FlashDevices == NULL) || (Count == NULL))
882 {
883 return EFI_INVALID_PARAMETER;
884 }
885
886 *FlashDevices = mFlashDevices;
887 *Count = FLASH_DEVICE_COUNT;
888
889 return EFI_SUCCESS;
890 }
891
892
893 EFI_STATUS
FlashCreateInstance(IN UINTN FlashDeviceBase,IN UINTN FlashRegionBase,IN UINTN FlashSize,IN UINT32 MediaId,IN UINT32 BlockSize,IN BOOLEAN SupportFvb,IN CONST GUID * FlashGuid,OUT FLASH_INSTANCE ** FlashInstance)894 FlashCreateInstance (
895 IN UINTN FlashDeviceBase,
896 IN UINTN FlashRegionBase,
897 IN UINTN FlashSize,
898 IN UINT32 MediaId,
899 IN UINT32 BlockSize,
900 IN BOOLEAN SupportFvb,
901 IN CONST GUID* FlashGuid,
902 OUT FLASH_INSTANCE** FlashInstance
903 )
904 {
905 EFI_STATUS Status;
906 FLASH_INSTANCE* Instance;
907
908 if (FlashInstance == NULL)
909 {
910 return EFI_INVALID_PARAMETER;
911 }
912
913 Instance = AllocateRuntimeCopyPool (sizeof(FLASH_INSTANCE), &mFlashInstanceTemplate);
914 if (Instance == NULL)
915 {
916 return EFI_INVALID_PARAMETER;
917 }
918
919 Instance->DeviceBaseAddress = FlashDeviceBase;
920 Instance->RegionBaseAddress = FlashRegionBase;
921 Instance->Size = FlashSize;
922
923 Instance->BlockIoProtocol.Media = &Instance->Media;
924 Instance->Media.MediaId = MediaId;
925 Instance->Media.BlockSize = BlockSize;
926 Instance->Media.LastBlock = (FlashSize / BlockSize) - 1;
927
928 CopyGuid (&Instance->DevicePath.Vendor.Guid, FlashGuid);
929
930 if (SupportFvb)
931 {
932 Instance->SupportFvb = TRUE;
933 Instance->Initialize = FvbInitialize;
934
935 Status = gBS->InstallMultipleProtocolInterfaces (
936 &Instance->Handle,
937 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
938 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
939 &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
940 NULL
941 );
942
943 if (EFI_ERROR(Status))
944 {
945 FreePool(Instance);
946 return Status;
947 }
948 }
949 else
950 {
951 Instance->Initialized = TRUE;
952
953 Status = gBS->InstallMultipleProtocolInterfaces (
954 &Instance->Handle,
955 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
956 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
957 NULL
958 );
959 if (EFI_ERROR(Status))
960 {
961 FreePool(Instance);
962 return Status;
963 }
964 }
965
966 *FlashInstance = Instance;
967 return Status;
968 }
969
970 EFI_STATUS
FlashUnlockSingleBlockIfNecessary(IN FLASH_INSTANCE * Instance,IN UINTN BlockAddress)971 FlashUnlockSingleBlockIfNecessary (
972 IN FLASH_INSTANCE* Instance,
973 IN UINTN BlockAddress
974 )
975 {
976 return EFI_SUCCESS;
977 }
978
979
980 EFI_STATUS
FlashEraseSingleBlock(IN FLASH_INSTANCE * Instance,IN UINTN BlockAddress)981 FlashEraseSingleBlock (
982 IN FLASH_INSTANCE* Instance,
983 IN UINTN BlockAddress
984 )
985 {
986 EFI_STATUS Status;
987 UINTN EraseAddress;
988
989 Status = EFI_SUCCESS;
990 EraseAddress = BlockAddress - Instance->DeviceBaseAddress;
991
992 Status = mFlash->Erase(mFlash, (UINT32)EraseAddress, Instance->Media.BlockSize);
993 if (EFI_SUCCESS != Status)
994 {
995 DEBUG((EFI_D_ERROR, "%s - %d Status=%r\n", __FILE__, __LINE__, Status));
996 return Status;
997 }
998
999 return EFI_SUCCESS;
1000 }
1001
1002 /**
1003 * The following function presumes that the block has already been unlocked.
1004 **/
1005 EFI_STATUS
FlashUnlockAndEraseSingleBlock(IN FLASH_INSTANCE * Instance,IN UINTN BlockAddress)1006 FlashUnlockAndEraseSingleBlock (
1007 IN FLASH_INSTANCE* Instance,
1008 IN UINTN BlockAddress
1009 )
1010 {
1011 EFI_STATUS Status;
1012 UINTN Index;
1013
1014 Index = 0;
1015 // The block erase might fail a first time (SW bug ?). Retry it ...
1016 do
1017 {
1018 // Unlock the block if we have to
1019 Status = FlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
1020 if (!EFI_ERROR(Status))
1021 {
1022 Status = FlashEraseSingleBlock (Instance, BlockAddress);
1023 }
1024 Index++;
1025 }
1026 while ((Index < FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
1027
1028 if (Index == FLASH_ERASE_RETRY)
1029 {
1030 DEBUG((EFI_D_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));
1031 }
1032
1033 return Status;
1034 }
1035
1036 EFI_STATUS
FlashWriteBlocks(IN FLASH_INSTANCE * Instance,IN EFI_LBA Lba,IN UINTN BufferSizeInBytes,IN VOID * Buffer)1037 FlashWriteBlocks (
1038 IN FLASH_INSTANCE* Instance,
1039 IN EFI_LBA Lba,
1040 IN UINTN BufferSizeInBytes,
1041 IN VOID* Buffer
1042 )
1043 {
1044 EFI_STATUS Status = EFI_SUCCESS;
1045 UINTN BlockAddress;
1046 UINT32 NumBlocks;
1047 UINTN WriteAddress;
1048
1049 // The buffer must be valid
1050 if (Buffer == NULL)
1051 {
1052 return EFI_INVALID_PARAMETER;
1053 }
1054
1055 if (Instance->Media.ReadOnly == TRUE)
1056 {
1057 return EFI_WRITE_PROTECTED;
1058 }
1059
1060 // We must have some bytes to read
1061 if (BufferSizeInBytes == 0)
1062 {
1063 return EFI_BAD_BUFFER_SIZE;
1064 }
1065
1066 // The size of the buffer must be a multiple of the block size
1067 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0)
1068 {
1069 return EFI_BAD_BUFFER_SIZE;
1070 }
1071
1072 // All blocks must be within the device
1073 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
1074 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1))
1075 {
1076 DEBUG((EFI_D_ERROR, "[%a]:[%dL]ERROR - Write will exceed last block.\n", __FUNCTION__, __LINE__ ));
1077 return EFI_INVALID_PARAMETER;
1078 }
1079
1080 BlockAddress = GET_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, Instance->Media.BlockSize);
1081
1082 WriteAddress = BlockAddress - Instance->DeviceBaseAddress;
1083
1084 Status = mFlash->Write(mFlash, (UINT32)WriteAddress, (UINT8*)Buffer, BufferSizeInBytes);
1085 if (EFI_SUCCESS != Status)
1086 {
1087 DEBUG((EFI_D_ERROR, "%s - %d Status=%r\n", __FILE__, __LINE__, Status));
1088 return Status;
1089 }
1090
1091 return Status;
1092 }
1093
1094 EFI_STATUS
FlashReadBlocks(IN FLASH_INSTANCE * Instance,IN EFI_LBA Lba,IN UINTN BufferSizeInBytes,OUT VOID * Buffer)1095 FlashReadBlocks (
1096 IN FLASH_INSTANCE* Instance,
1097 IN EFI_LBA Lba,
1098 IN UINTN BufferSizeInBytes,
1099 OUT VOID* Buffer
1100 )
1101 {
1102 UINT32 NumBlocks;
1103 UINTN StartAddress;
1104 UINTN ReadAddress;
1105 EFI_STATUS Status;
1106
1107 // The buffer must be valid
1108 if (Buffer == NULL)
1109 {
1110 return EFI_INVALID_PARAMETER;
1111 }
1112
1113 // We must have some bytes to read
1114 if (BufferSizeInBytes == 0)
1115 {
1116 return EFI_BAD_BUFFER_SIZE;
1117 }
1118
1119 // The size of the buffer must be a multiple of the block size
1120 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0)
1121 {
1122 return EFI_BAD_BUFFER_SIZE;
1123 }
1124
1125 // All blocks must be within the device
1126 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
1127 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1))
1128 {
1129 DEBUG((EFI_D_ERROR, "FlashReadBlocks: ERROR - Read will exceed last block\n"));
1130 return EFI_INVALID_PARAMETER;
1131 }
1132
1133 // Get the address to start reading from
1134 StartAddress = GET_BLOCK_ADDRESS (Instance->RegionBaseAddress,
1135 Lba,
1136 Instance->Media.BlockSize
1137 );
1138
1139
1140 ReadAddress = StartAddress - Instance->DeviceBaseAddress;
1141
1142 Status = mFlash->Read(mFlash, (UINT32)ReadAddress, Buffer, BufferSizeInBytes);
1143 if (EFI_SUCCESS != Status)
1144 {
1145 DEBUG((EFI_D_ERROR, "%s - %d Status=%r\n", __FILE__, __LINE__, Status));
1146 return Status;
1147 }
1148
1149 return EFI_SUCCESS;
1150 }
1151
1152 VOID
1153 EFIAPI
FlashFvbVirtualNotifyEvent(IN EFI_EVENT Event,IN VOID * Context)1154 FlashFvbVirtualNotifyEvent (
1155 IN EFI_EVENT Event,
1156 IN VOID *Context
1157 )
1158 {
1159 EfiConvertPointer (0x0, (VOID**)&mFlash);
1160 EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
1161 return;
1162 }
1163
1164 EFI_STATUS
1165 EFIAPI
FlashFvbInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1166 FlashFvbInitialize (
1167 IN EFI_HANDLE ImageHandle,
1168 IN EFI_SYSTEM_TABLE* SystemTable
1169 )
1170 {
1171 EFI_STATUS Status;
1172 UINT32 Index;
1173 FLASH_DESCRIPTION* FlashDevices;
1174 UINT32 FlashDeviceCount;
1175 BOOLEAN ContainVariableStorage;
1176
1177
1178 Status = FlashPlatformGetDevices (&FlashDevices, &FlashDeviceCount);
1179 if (EFI_ERROR(Status))
1180 {
1181 DEBUG((EFI_D_ERROR, "[%a]:[%dL] Fail to get Flash devices\n", __FUNCTION__, __LINE__));
1182 return Status;
1183 }
1184
1185 mFlashInstances = AllocatePool ((UINT32)(sizeof(FLASH_INSTANCE*) * FlashDeviceCount));
1186
1187 Status = gBS->LocateProtocol (&gHisiSpiFlashProtocolGuid, NULL, (VOID*) &mFlash);
1188 if (EFI_ERROR(Status))
1189 {
1190 DEBUG((EFI_D_ERROR, "[%a]:[%dL] Status=%r\n", __FUNCTION__, __LINE__, Status));
1191 return Status;
1192 }
1193
1194 for (Index = 0; Index < FlashDeviceCount; Index++)
1195 {
1196 // Check if this Flash device contain the variable storage region
1197 ContainVariableStorage =
1198 (FlashDevices[Index].RegionBaseAddress <= (UINT32)PcdGet32 (PcdFlashNvStorageVariableBase)) &&
1199 ((UINT32)(PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize)) <= FlashDevices[Index].RegionBaseAddress + FlashDevices[Index].Size);
1200
1201 Status = FlashCreateInstance (
1202 FlashDevices[Index].DeviceBaseAddress,
1203 FlashDevices[Index].RegionBaseAddress,
1204 FlashDevices[Index].Size,
1205 Index,
1206 FlashDevices[Index].BlockSize,
1207 ContainVariableStorage,
1208 &FlashDevices[Index].Guid,
1209 &mFlashInstances[Index]
1210 );
1211 if (EFI_ERROR(Status))
1212 {
1213 DEBUG((EFI_D_ERROR, "[%a]:[%dL] Fail to create instance for Flash[%d]\n", __FUNCTION__, __LINE__, Index));
1214 }
1215 }
1216 //
1217 // Register for the virtual address change event
1218 //
1219 Status = gBS->CreateEventEx (
1220 EVT_NOTIFY_SIGNAL,
1221 TPL_NOTIFY,
1222 FlashFvbVirtualNotifyEvent,
1223 NULL,
1224 &gEfiEventVirtualAddressChangeGuid,
1225 &mFlashFvbVirtualAddrChangeEvent
1226 );
1227 ASSERT_EFI_ERROR (Status);
1228
1229 return Status;
1230 }
1231