1 /** @file NorFlashDxe.c
3 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Library/UefiLib.h>
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/MemoryAllocationLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/PcdLib.h>
15 #include "NorFlashDxe.h"
17 STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent
;
20 // Global variable declarations
22 NOR_FLASH_INSTANCE
**mNorFlashInstances
;
23 UINT32 mNorFlashDeviceCount
;
25 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate
= {
26 NOR_FLASH_SIGNATURE
, // Signature
27 NULL
, // Handle ... NEED TO BE FILLED
29 0, // DeviceBaseAddress ... NEED TO BE FILLED
30 0, // RegionBaseAddress ... NEED TO BE FILLED
31 0, // Size ... NEED TO BE FILLED
35 EFI_BLOCK_IO_PROTOCOL_REVISION2
, // Revision
36 NULL
, // Media ... NEED TO BE FILLED
37 NorFlashBlockIoReset
, // Reset;
38 NorFlashBlockIoReadBlocks
, // ReadBlocks
39 NorFlashBlockIoWriteBlocks
, // WriteBlocks
40 NorFlashBlockIoFlushBlocks
// FlushBlocks
44 0, // MediaId ... NEED TO BE FILLED
45 FALSE
, // RemovableMedia
47 FALSE
, // LogicalPartition
49 FALSE
, // WriteCaching;
50 0, // BlockSize ... NEED TO BE FILLED
52 0, // LastBlock ... NEED TO BE FILLED
53 0, // LowestAlignedLba
54 1, // LogicalBlocksPerPhysicalBlock
58 EFI_DISK_IO_PROTOCOL_REVISION
, // Revision
59 NorFlashDiskIoReadDisk
, // ReadDisk
60 NorFlashDiskIoWriteDisk
// WriteDisk
64 FvbGetAttributes
, // GetAttributes
65 FvbSetAttributes
, // SetAttributes
66 FvbGetPhysicalAddress
, // GetPhysicalAddress
67 FvbGetBlockSize
, // GetBlockSize
70 FvbEraseBlocks
, // EraseBlocks
80 (UINT8
)(OFFSET_OF (NOR_FLASH_DEVICE_PATH
, End
)),
81 (UINT8
)(OFFSET_OF (NOR_FLASH_DEVICE_PATH
, End
) >> 8)
84 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED
89 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
90 { sizeof (EFI_DEVICE_PATH_PROTOCOL
), 0 }
96 NorFlashCreateInstance (
97 IN UINTN NorFlashDeviceBase
,
98 IN UINTN NorFlashRegionBase
,
99 IN UINTN NorFlashSize
,
102 IN BOOLEAN SupportFvb
,
103 OUT NOR_FLASH_INSTANCE
** NorFlashInstance
107 NOR_FLASH_INSTANCE
* Instance
;
109 ASSERT(NorFlashInstance
!= NULL
);
111 Instance
= AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE
),&mNorFlashInstanceTemplate
);
112 if (Instance
== NULL
) {
113 return EFI_OUT_OF_RESOURCES
;
116 Instance
->DeviceBaseAddress
= NorFlashDeviceBase
;
117 Instance
->RegionBaseAddress
= NorFlashRegionBase
;
118 Instance
->Size
= NorFlashSize
;
120 Instance
->BlockIoProtocol
.Media
= &Instance
->Media
;
121 Instance
->Media
.MediaId
= Index
;
122 Instance
->Media
.BlockSize
= BlockSize
;
123 Instance
->Media
.LastBlock
= (NorFlashSize
/ BlockSize
)-1;
125 CopyGuid (&Instance
->DevicePath
.Vendor
.Guid
, &gEfiCallerIdGuid
);
126 Instance
->DevicePath
.Index
= (UINT8
)Index
;
128 Instance
->ShadowBuffer
= AllocateRuntimePool (BlockSize
);;
129 if (Instance
->ShadowBuffer
== NULL
) {
130 return EFI_OUT_OF_RESOURCES
;
134 NorFlashFvbInitialize (Instance
);
136 Status
= gBS
->InstallMultipleProtocolInterfaces (
138 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
139 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
140 &gEfiFirmwareVolumeBlockProtocolGuid
, &Instance
->FvbProtocol
,
143 if (EFI_ERROR(Status
)) {
148 Status
= gBS
->InstallMultipleProtocolInterfaces (
150 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
151 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
152 &gEfiDiskIoProtocolGuid
, &Instance
->DiskIoProtocol
,
155 if (EFI_ERROR(Status
)) {
161 *NorFlashInstance
= Instance
;
166 NorFlashReadStatusRegister (
167 IN NOR_FLASH_INSTANCE
*Instance
,
171 // Prepare to read the status register
172 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_STATUS_REGISTER
);
173 return MmioRead32 (Instance
->DeviceBaseAddress
);
178 NorFlashBlockIsLocked (
179 IN NOR_FLASH_INSTANCE
*Instance
,
180 IN UINTN BlockAddress
185 // Send command for reading device id
186 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
188 // Read block lock status
189 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
191 // Decode block lock status
192 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
194 if ((LockStatus
& 0x2) != 0) {
195 DEBUG((EFI_D_ERROR
, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
198 return ((LockStatus
& 0x1) != 0);
203 NorFlashUnlockSingleBlock (
204 IN NOR_FLASH_INSTANCE
*Instance
,
205 IN UINTN BlockAddress
210 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
211 // and to protect shared data structures.
213 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked
) == TRUE
) {
215 // Request a lock setup
216 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
219 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
221 // Send command for reading device id
222 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
224 // Read block lock status
225 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
227 // Decode block lock status
228 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
229 } while ((LockStatus
& 0x1) == 1);
231 // Request a lock setup
232 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
235 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
237 // Wait until the status register gives us the all clear
239 LockStatus
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
240 } while ((LockStatus
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
243 // Put device back into Read Array mode
244 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_READ_ARRAY
);
246 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress
));
253 NorFlashUnlockSingleBlockIfNecessary (
254 IN NOR_FLASH_INSTANCE
*Instance
,
255 IN UINTN BlockAddress
260 Status
= EFI_SUCCESS
;
262 if (NorFlashBlockIsLocked (Instance
, BlockAddress
)) {
263 Status
= NorFlashUnlockSingleBlock (Instance
, BlockAddress
);
271 * The following function presumes that the block has already been unlocked.
275 NorFlashEraseSingleBlock (
276 IN NOR_FLASH_INSTANCE
*Instance
,
277 IN UINTN BlockAddress
281 UINT32 StatusRegister
;
283 Status
= EFI_SUCCESS
;
285 // Request a block erase and then confirm it
286 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
287 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
289 // Wait until the status register gives us the all clear
291 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
292 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
294 if (StatusRegister
& P30_SR_BIT_VPP
) {
295 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
296 Status
= EFI_DEVICE_ERROR
;
299 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
300 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
301 Status
= EFI_DEVICE_ERROR
;
304 if (StatusRegister
& P30_SR_BIT_ERASE
) {
305 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
306 Status
= EFI_DEVICE_ERROR
;
309 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
310 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
311 DEBUG((EFI_D_INFO
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
312 Status
= EFI_WRITE_PROTECTED
;
315 if (EFI_ERROR(Status
)) {
316 // Clear the Status Register
317 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
320 // Put device back into Read Array mode
321 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
327 * This function unlock and erase an entire NOR Flash block.
330 NorFlashUnlockAndEraseSingleBlock (
331 IN NOR_FLASH_INSTANCE
*Instance
,
332 IN UINTN BlockAddress
339 if (!EfiAtRuntime ()) {
340 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
341 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
343 // This initialization is only to prevent the compiler to complain about the
344 // use of uninitialized variables
345 OriginalTPL
= TPL_HIGH_LEVEL
;
349 // The block erase might fail a first time (SW bug ?). Retry it ...
351 // Unlock the block if we have to
352 Status
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
353 if (EFI_ERROR (Status
)) {
356 Status
= NorFlashEraseSingleBlock (Instance
, BlockAddress
);
358 } while ((Index
< NOR_FLASH_ERASE_RETRY
) && (Status
== EFI_WRITE_PROTECTED
));
360 if (Index
== NOR_FLASH_ERASE_RETRY
) {
361 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress
,Index
));
364 if (!EfiAtRuntime ()) {
365 // Interruptions can resume.
366 gBS
->RestoreTPL (OriginalTPL
);
375 NorFlashWriteSingleWord (
376 IN NOR_FLASH_INSTANCE
*Instance
,
377 IN UINTN WordAddress
,
382 UINT32 StatusRegister
;
384 Status
= EFI_SUCCESS
;
386 // Request a write single word command
387 SEND_NOR_COMMAND(WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
389 // Store the word into NOR Flash;
390 MmioWrite32 (WordAddress
, WriteData
);
392 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
394 // Prepare to read the status register
395 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
396 // The chip is busy while the WRITE bit is not asserted
397 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
400 // Perform a full status check:
401 // Mask the relevant bits of Status Register.
402 // Everything should be zero, if not, we have a problem
404 if (StatusRegister
& P30_SR_BIT_VPP
) {
405 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress
));
406 Status
= EFI_DEVICE_ERROR
;
409 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
410 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress
));
411 Status
= EFI_DEVICE_ERROR
;
414 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
415 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress
));
416 Status
= EFI_DEVICE_ERROR
;
419 if (!EFI_ERROR(Status
)) {
420 // Clear the Status Register
421 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
424 // Put device back into Read Array mode
425 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
431 * Writes data to the NOR Flash using the Buffered Programming method.
433 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
434 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
435 * To deal with larger buffers, call this function again.
437 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
438 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
440 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
441 * then programming time is doubled and power consumption is increased.
442 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
443 * i.e. the last 4 bits of the target start address must be zero: 0x......00
446 NorFlashWriteBuffer (
447 IN NOR_FLASH_INSTANCE
*Instance
,
448 IN UINTN TargetAddress
,
449 IN UINTN BufferSizeInBytes
,
454 UINTN BufferSizeInWords
;
456 volatile UINT32
*Data
;
458 BOOLEAN BufferAvailable
;
459 UINT32 StatusRegister
;
461 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
462 BufferAvailable
= FALSE
;
464 // Check that the target address does not cross a 32-word boundary.
465 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
466 return EFI_INVALID_PARAMETER
;
469 // Check there are some data to program
470 if (BufferSizeInBytes
== 0) {
471 return EFI_BUFFER_TOO_SMALL
;
474 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
475 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
476 return EFI_BAD_BUFFER_SIZE
;
479 // Check that the buffer size is a multiple of 32-bit words
480 if ((BufferSizeInBytes
% 4) != 0) {
481 return EFI_BAD_BUFFER_SIZE
;
484 // Pre-programming conditions checked, now start the algorithm.
486 // Prepare the data destination address
487 Data
= (UINT32
*)TargetAddress
;
489 // Check the availability of the buffer
491 // Issue the Buffered Program Setup command
492 SEND_NOR_COMMAND(TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
494 // Read back the status register bit#7 from the same address
495 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
496 BufferAvailable
= TRUE
;
499 // Update the loop counter
502 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
504 // The buffer was not available for writing
505 if (WaitForBuffer
== 0) {
506 Status
= EFI_DEVICE_ERROR
;
510 // From now on we work in 32-bit words
511 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
513 // Write the word count, which is (buffer_size_in_words - 1),
514 // because word count 0 means one word.
515 SEND_NOR_COMMAND(TargetAddress
, 0, (BufferSizeInWords
- 1));
517 // Write the data to the NOR Flash, advancing each address by 4 bytes
518 for(Count
=0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
519 MmioWrite32 ((UINTN
)Data
, *Buffer
);
522 // Issue the Buffered Program Confirm command, to start the programming operation
523 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
525 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
527 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
528 // The chip is busy while the WRITE bit is not asserted
529 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
532 // Perform a full status check:
533 // Mask the relevant bits of Status Register.
534 // Everything should be zero, if not, we have a problem
536 Status
= EFI_SUCCESS
;
538 if (StatusRegister
& P30_SR_BIT_VPP
) {
539 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
540 Status
= EFI_DEVICE_ERROR
;
543 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
544 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
545 Status
= EFI_DEVICE_ERROR
;
548 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
549 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress
));
550 Status
= EFI_DEVICE_ERROR
;
553 if (!EFI_ERROR(Status
)) {
554 // Clear the Status Register
555 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
559 // Put device back into Read Array mode
560 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
567 NorFlashWriteFullBlock (
568 IN NOR_FLASH_INSTANCE
*Instance
,
570 IN UINT32
*DataBuffer
,
571 IN UINT32 BlockSizeInWords
579 UINTN BuffersInBlock
;
580 UINTN RemainingWords
;
584 Status
= EFI_SUCCESS
;
586 // Get the physical address of the block
587 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSizeInWords
* 4);
589 // Start writing from the first address at the start of the block
590 WordAddress
= BlockAddress
;
592 if (!EfiAtRuntime ()) {
593 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
594 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
596 // This initialization is only to prevent the compiler to complain about the
597 // use of uninitialized variables
598 OriginalTPL
= TPL_HIGH_LEVEL
;
601 Status
= NorFlashUnlockAndEraseSingleBlock (Instance
, BlockAddress
);
602 if (EFI_ERROR(Status
)) {
603 DEBUG((EFI_D_ERROR
, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress
));
607 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
609 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
610 if ((WordAddress
& BOUNDARY_OF_32_WORDS
) == 0x00) {
612 // First, break the entire block into buffer-sized chunks.
613 BuffersInBlock
= (UINTN
)(BlockSizeInWords
* 4) / P30_MAX_BUFFER_SIZE_IN_BYTES
;
615 // Then feed each buffer chunk to the NOR Flash
616 // If a buffer does not contain any data, don't write it.
618 BufferIndex
< BuffersInBlock
;
619 BufferIndex
++, WordAddress
+= P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
+= P30_MAX_BUFFER_SIZE_IN_WORDS
621 // Check the buffer to see if it contains any data (not set all 1s).
622 for (Cnt
= 0; Cnt
< P30_MAX_BUFFER_SIZE_IN_WORDS
; Cnt
++) {
623 if (~DataBuffer
[Cnt
] != 0 ) {
624 // Some data found, write the buffer.
625 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, P30_MAX_BUFFER_SIZE_IN_BYTES
,
627 if (EFI_ERROR(Status
)) {
635 // Finally, finish off any remaining words that are less than the maximum size of the buffer
636 RemainingWords
= BlockSizeInWords
% P30_MAX_BUFFER_SIZE_IN_WORDS
;
638 if(RemainingWords
!= 0) {
639 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, (RemainingWords
* 4), DataBuffer
);
640 if (EFI_ERROR(Status
)) {
646 // For now, use the single word programming algorithm
647 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
648 // i.e. which ends in the range 0x......01 - 0x......7F.
649 for(WordIndex
=0; WordIndex
<BlockSizeInWords
; WordIndex
++, DataBuffer
++, WordAddress
= WordAddress
+ 4) {
650 Status
= NorFlashWriteSingleWord (Instance
, WordAddress
, *DataBuffer
);
651 if (EFI_ERROR(Status
)) {
658 if (!EfiAtRuntime ()) {
659 // Interruptions can resume.
660 gBS
->RestoreTPL (OriginalTPL
);
663 if (EFI_ERROR(Status
)) {
664 DEBUG((EFI_D_ERROR
, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress
, Status
));
671 NorFlashWriteBlocks (
672 IN NOR_FLASH_INSTANCE
*Instance
,
674 IN UINTN BufferSizeInBytes
,
678 UINT32
*pWriteBuffer
;
680 EFI_LBA CurrentBlock
;
681 UINT32 BlockSizeInWords
;
685 Status
= EFI_SUCCESS
;
687 // The buffer must be valid
688 if (Buffer
== NULL
) {
689 return EFI_INVALID_PARAMETER
;
692 if(Instance
->Media
.ReadOnly
== TRUE
) {
693 return EFI_WRITE_PROTECTED
;
696 // We must have some bytes to read
697 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
698 if(BufferSizeInBytes
== 0) {
699 return EFI_BAD_BUFFER_SIZE
;
702 // The size of the buffer must be a multiple of the block size
703 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
704 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
705 return EFI_BAD_BUFFER_SIZE
;
708 // All blocks must be within the device
709 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
711 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
713 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
714 DEBUG((EFI_D_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
715 return EFI_INVALID_PARAMETER
;
718 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
720 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
721 // to a proper data type, so use *ReadBuffer
722 pWriteBuffer
= (UINT32
*)Buffer
;
725 for (BlockCount
=0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
727 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
729 Status
= NorFlashWriteFullBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
731 if (EFI_ERROR(Status
)) {
736 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
740 #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
743 Copy Length bytes from Source to Destination, using aligned accesses only.
744 Note that this implementation uses memcpy() semantics rather then memmove()
745 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
747 @param DestinationBuffer The target of the copy request.
748 @param SourceBuffer The place to copy from.
749 @param Length The number of bytes to copy.
757 OUT VOID
*DestinationBuffer
,
758 IN CONST VOID
*SourceBuffer
,
763 CONST UINT8
*Source8
;
764 UINT32
*Destination32
;
765 CONST UINT32
*Source32
;
766 UINT64
*Destination64
;
767 CONST UINT64
*Source64
;
769 if (BOTH_ALIGNED(DestinationBuffer
, SourceBuffer
, 8) && Length
>= 8) {
770 Destination64
= DestinationBuffer
;
771 Source64
= SourceBuffer
;
772 while (Length
>= 8) {
773 *Destination64
++ = *Source64
++;
777 Destination8
= (UINT8
*)Destination64
;
778 Source8
= (CONST UINT8
*)Source64
;
779 } else if (BOTH_ALIGNED(DestinationBuffer
, SourceBuffer
, 4) && Length
>= 4) {
780 Destination32
= DestinationBuffer
;
781 Source32
= SourceBuffer
;
782 while (Length
>= 4) {
783 *Destination32
++ = *Source32
++;
787 Destination8
= (UINT8
*)Destination32
;
788 Source8
= (CONST UINT8
*)Source32
;
790 Destination8
= DestinationBuffer
;
791 Source8
= SourceBuffer
;
793 while (Length
-- != 0) {
794 *Destination8
++ = *Source8
++;
796 return DestinationBuffer
;
801 IN NOR_FLASH_INSTANCE
*Instance
,
803 IN UINTN BufferSizeInBytes
,
810 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
811 BufferSizeInBytes
, Instance
->Media
.BlockSize
, Instance
->Media
.LastBlock
, Lba
));
813 // The buffer must be valid
814 if (Buffer
== NULL
) {
815 return EFI_INVALID_PARAMETER
;
818 // Return if we have not any byte to read
819 if (BufferSizeInBytes
== 0) {
823 // The size of the buffer must be a multiple of the block size
824 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
825 return EFI_BAD_BUFFER_SIZE
;
828 // All blocks must be within the device
829 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
831 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
832 DEBUG((EFI_D_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
833 return EFI_INVALID_PARAMETER
;
836 // Get the address to start reading from
837 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
839 Instance
->Media
.BlockSize
842 // Put the device into Read Array mode
843 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
846 AlignedCopyMem (Buffer
, (VOID
*)StartAddress
, BufferSizeInBytes
);
853 IN NOR_FLASH_INSTANCE
*Instance
,
856 IN UINTN BufferSizeInBytes
,
862 // The buffer must be valid
863 if (Buffer
== NULL
) {
864 return EFI_INVALID_PARAMETER
;
867 // Return if we have not any byte to read
868 if (BufferSizeInBytes
== 0) {
872 if (((Lba
* Instance
->Media
.BlockSize
) + Offset
+ BufferSizeInBytes
) > Instance
->Size
) {
873 DEBUG ((EFI_D_ERROR
, "NorFlashRead: ERROR - Read will exceed device size.\n"));
874 return EFI_INVALID_PARAMETER
;
877 // Get the address to start reading from
878 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
880 Instance
->Media
.BlockSize
883 // Put the device into Read Array mode
884 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
887 AlignedCopyMem (Buffer
, (VOID
*)(StartAddress
+ Offset
), BufferSizeInBytes
);
893 Write a full or portion of a block. It must not span block boundaries; that is,
894 Offset + *NumBytes <= Instance->Media.BlockSize.
897 NorFlashWriteSingleBlock (
898 IN NOR_FLASH_INSTANCE
*Instance
,
901 IN OUT UINTN
*NumBytes
,
905 EFI_STATUS TempStatus
;
916 UINTN PrevBlockAddress
;
918 PrevBlockAddress
= 0;
920 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba
, Offset
, *NumBytes
, Buffer
));
922 // Detect WriteDisabled state
923 if (Instance
->Media
.ReadOnly
== TRUE
) {
924 DEBUG ((EFI_D_ERROR
, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
925 // It is in WriteDisabled state, return an error right away
926 return EFI_ACCESS_DENIED
;
929 // Cache the block size to avoid de-referencing pointers all the time
930 BlockSize
= Instance
->Media
.BlockSize
;
932 // The write must not span block boundaries.
933 // We need to check each variable individually because adding two large values together overflows.
934 if ( ( Offset
>= BlockSize
) ||
935 ( *NumBytes
> BlockSize
) ||
936 ( (Offset
+ *NumBytes
) > BlockSize
) ) {
937 DEBUG ((EFI_D_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
938 return EFI_BAD_BUFFER_SIZE
;
941 // We must have some bytes to write
942 if (*NumBytes
== 0) {
943 DEBUG ((EFI_D_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
944 return EFI_BAD_BUFFER_SIZE
;
947 // Pick 128bytes as a good start for word operations as opposed to erasing the
948 // block and writing the data regardless if an erase is really needed.
949 // It looks like most individual NV variable writes are smaller than 128bytes.
950 if (*NumBytes
<= 128) {
951 // Check to see if we need to erase before programming the data into NOR.
952 // If the destination bits are only changing from 1s to 0s we can just write.
953 // After a block is erased all bits in the block is set to 1.
954 // If any byte requires us to erase we just give up and rewrite all of it.
956 BytesToWrite
= *NumBytes
;
959 while (BytesToWrite
> 0) {
960 // Read full word from NOR, splice as required. A word is the smallest
961 // unit we can write.
962 TempStatus
= NorFlashRead (Instance
, Lba
, CurOffset
& ~(0x3), sizeof(Tmp
), &Tmp
);
963 if (EFI_ERROR (TempStatus
)) {
964 return EFI_DEVICE_ERROR
;
967 // Physical address of word in NOR to write.
968 WordAddr
= (CurOffset
& ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
970 // The word of data that is to be written.
971 TmpBuf
= *((UINT32
*)(Buffer
+ (*NumBytes
- BytesToWrite
)));
973 // First do word aligned chunks.
974 if ((CurOffset
& 0x3) == 0) {
975 if (BytesToWrite
>= 4) {
976 // Is the destination still in 'erased' state?
978 // Check to see if we are only changing bits to zero.
979 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
984 // Write this word to NOR
985 WordToWrite
= TmpBuf
;
986 CurOffset
+= sizeof(TmpBuf
);
987 BytesToWrite
-= sizeof(TmpBuf
);
989 // BytesToWrite < 4. Do small writes and left-overs
990 Mask
= ~((~0) << (BytesToWrite
* 8));
991 // Mask out the bytes we want.
993 // Is the destination still in 'erased' state?
994 if ((Tmp
& Mask
) != Mask
) {
995 // Check to see if we are only changing bits to zero.
996 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
1001 // Merge old and new data. Write merged word to NOR
1002 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
1003 CurOffset
+= BytesToWrite
;
1007 // Do multiple words, but starting unaligned.
1008 if (BytesToWrite
> (4 - (CurOffset
& 0x3))) {
1009 Mask
= ((~0) << ((CurOffset
& 0x3) * 8));
1010 // Mask out the bytes we want.
1012 // Is the destination still in 'erased' state?
1013 if ((Tmp
& Mask
) != Mask
) {
1014 // Check to see if we are only changing bits to zero.
1015 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
1020 // Merge old and new data. Write merged word to NOR
1021 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
1022 BytesToWrite
-= (4 - (CurOffset
& 0x3));
1023 CurOffset
+= (4 - (CurOffset
& 0x3));
1025 // Unaligned and fits in one word.
1026 Mask
= (~((~0) << (BytesToWrite
* 8))) << ((CurOffset
& 0x3) * 8);
1027 // Mask out the bytes we want.
1028 TmpBuf
= (TmpBuf
<< ((CurOffset
& 0x3) * 8)) & Mask
;
1029 // Is the destination still in 'erased' state?
1030 if ((Tmp
& Mask
) != Mask
) {
1031 // Check to see if we are only changing bits to zero.
1032 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
1037 // Merge old and new data. Write merged word to NOR
1038 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
1039 CurOffset
+= BytesToWrite
;
1045 // Write the word to NOR.
1048 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSize
);
1049 if (BlockAddress
!= PrevBlockAddress
) {
1050 TempStatus
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
1051 if (EFI_ERROR (TempStatus
)) {
1052 return EFI_DEVICE_ERROR
;
1054 PrevBlockAddress
= BlockAddress
;
1056 TempStatus
= NorFlashWriteSingleWord (Instance
, WordAddr
, WordToWrite
);
1057 if (EFI_ERROR (TempStatus
)) {
1058 return EFI_DEVICE_ERROR
;
1061 // Exit if we got here and could write all the data. Otherwise do the
1062 // Erase-Write cycle.
1068 // Check we did get some memory. Buffer is BlockSize.
1069 if (Instance
->ShadowBuffer
== NULL
) {
1070 DEBUG ((EFI_D_ERROR
, "FvbWrite: ERROR - Buffer not ready\n"));
1071 return EFI_DEVICE_ERROR
;
1074 // Read NOR Flash data into shadow buffer
1075 TempStatus
= NorFlashReadBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
1076 if (EFI_ERROR (TempStatus
)) {
1077 // Return one of the pre-approved error statuses
1078 return EFI_DEVICE_ERROR
;
1081 // Put the data at the appropriate location inside the buffer area
1082 CopyMem ((VOID
*)((UINTN
)Instance
->ShadowBuffer
+ Offset
), Buffer
, *NumBytes
);
1084 // Write the modified buffer back to the NorFlash
1085 TempStatus
= NorFlashWriteBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
1086 if (EFI_ERROR (TempStatus
)) {
1087 // Return one of the pre-approved error statuses
1088 return EFI_DEVICE_ERROR
;
1095 Although DiskIoDxe will automatically install the DiskIO protocol whenever
1096 we install the BlockIO protocol, its implementation is sub-optimal as it reads
1097 and writes entire blocks using the BlockIO protocol. In fact we can access
1098 NOR flash with a finer granularity than that, so we can improve performance
1099 by directly producing the DiskIO protocol.
1103 Read BufferSize bytes from Offset into Buffer.
1105 @param This Protocol instance pointer.
1106 @param MediaId Id of the media, changes every time the media is replaced.
1107 @param Offset The starting byte offset to read from
1108 @param BufferSize Size of Buffer
1109 @param Buffer Buffer containing read data
1111 @retval EFI_SUCCESS The data was read correctly from the device.
1112 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1113 @retval EFI_NO_MEDIA There is no media in the device.
1114 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1115 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1116 valid for the device.
1121 NorFlashDiskIoReadDisk (
1122 IN EFI_DISK_IO_PROTOCOL
*This
,
1124 IN UINT64 DiskOffset
,
1125 IN UINTN BufferSize
,
1129 NOR_FLASH_INSTANCE
*Instance
;
1134 Instance
= INSTANCE_FROM_DISKIO_THIS(This
);
1136 if (MediaId
!= Instance
->Media
.MediaId
) {
1137 return EFI_MEDIA_CHANGED
;
1140 BlockSize
= Instance
->Media
.BlockSize
;
1141 Lba
= (EFI_LBA
) DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
1143 return NorFlashRead (Instance
, Lba
, BlockOffset
, BufferSize
, Buffer
);
1147 Writes a specified number of bytes to a device.
1149 @param This Indicates a pointer to the calling context.
1150 @param MediaId ID of the medium to be written.
1151 @param Offset The starting byte offset on the logical block I/O device to write.
1152 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1153 @param Buffer A pointer to the buffer containing the data to be written.
1155 @retval EFI_SUCCESS The data was written correctly to the device.
1156 @retval EFI_WRITE_PROTECTED The device can not be written to.
1157 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1158 @retval EFI_NO_MEDIA There is no media in the device.
1159 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1160 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1161 valid for the device.
1166 NorFlashDiskIoWriteDisk (
1167 IN EFI_DISK_IO_PROTOCOL
*This
,
1169 IN UINT64 DiskOffset
,
1170 IN UINTN BufferSize
,
1174 NOR_FLASH_INSTANCE
*Instance
;
1178 UINTN RemainingBytes
;
1182 Instance
= INSTANCE_FROM_DISKIO_THIS(This
);
1184 if (MediaId
!= Instance
->Media
.MediaId
) {
1185 return EFI_MEDIA_CHANGED
;
1188 BlockSize
= Instance
->Media
.BlockSize
;
1189 Lba
= (EFI_LBA
) DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
1191 RemainingBytes
= BufferSize
;
1193 // Write either all the remaining bytes, or the number of bytes that bring
1194 // us up to a block boundary, whichever is less.
1195 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
1196 // block boundary (even if it is already on one).
1197 WriteSize
= MIN (RemainingBytes
, ((DiskOffset
| (BlockSize
- 1)) + 1) - DiskOffset
);
1200 if (WriteSize
== BlockSize
) {
1201 // Write a full block
1202 Status
= NorFlashWriteFullBlock (Instance
, Lba
, Buffer
, BlockSize
/ sizeof (UINT32
));
1204 // Write a partial block
1205 Status
= NorFlashWriteSingleBlock (Instance
, Lba
, BlockOffset
, &WriteSize
, Buffer
);
1207 if (EFI_ERROR (Status
)) {
1210 // Now continue writing either all the remaining bytes or single blocks.
1211 RemainingBytes
-= WriteSize
;
1212 Buffer
= (UINT8
*) Buffer
+ WriteSize
;
1215 WriteSize
= MIN (RemainingBytes
, BlockSize
);
1216 } while (RemainingBytes
);
1223 IN NOR_FLASH_INSTANCE
*Instance
1226 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
1227 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
1232 Fixup internal data so that EFI can be call in virtual mode.
1233 Call the passed in Child Notify event and convert any pointers in
1234 lib to virtual mode.
1236 @param[in] Event The Event that is being processed
1237 @param[in] Context Event Context
1241 NorFlashVirtualNotifyEvent (
1248 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
1249 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->DeviceBaseAddress
);
1250 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->RegionBaseAddress
);
1252 // Convert BlockIo protocol
1253 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.FlushBlocks
);
1254 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.ReadBlocks
);
1255 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.Reset
);
1256 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.WriteBlocks
);
1259 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.EraseBlocks
);
1260 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetAttributes
);
1261 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetBlockSize
);
1262 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetPhysicalAddress
);
1263 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Read
);
1264 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.SetAttributes
);
1265 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Write
);
1267 if (mNorFlashInstances
[Index
]->ShadowBuffer
!= NULL
) {
1268 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->ShadowBuffer
);
1277 NorFlashInitialise (
1278 IN EFI_HANDLE ImageHandle
,
1279 IN EFI_SYSTEM_TABLE
*SystemTable
1284 NOR_FLASH_DESCRIPTION
* NorFlashDevices
;
1285 BOOLEAN ContainVariableStorage
;
1287 Status
= NorFlashPlatformInitialization ();
1288 if (EFI_ERROR(Status
)) {
1289 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
1293 Status
= NorFlashPlatformGetDevices (&NorFlashDevices
, &mNorFlashDeviceCount
);
1294 if (EFI_ERROR(Status
)) {
1295 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
1299 mNorFlashInstances
= AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE
*) * mNorFlashDeviceCount
);
1301 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
1302 // Check if this NOR Flash device contain the variable storage region
1303 ContainVariableStorage
=
1304 (NorFlashDevices
[Index
].RegionBaseAddress
<= PcdGet32 (PcdFlashNvStorageVariableBase
)) &&
1305 (PcdGet32 (PcdFlashNvStorageVariableBase
) + PcdGet32 (PcdFlashNvStorageVariableSize
) <= NorFlashDevices
[Index
].RegionBaseAddress
+ NorFlashDevices
[Index
].Size
);
1307 Status
= NorFlashCreateInstance (
1308 NorFlashDevices
[Index
].DeviceBaseAddress
,
1309 NorFlashDevices
[Index
].RegionBaseAddress
,
1310 NorFlashDevices
[Index
].Size
,
1312 NorFlashDevices
[Index
].BlockSize
,
1313 ContainVariableStorage
,
1314 &mNorFlashInstances
[Index
]
1316 if (EFI_ERROR(Status
)) {
1317 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index
));
1322 // Register for the virtual address change event
1324 Status
= gBS
->CreateEventEx (
1327 NorFlashVirtualNotifyEvent
,
1329 &gEfiEventVirtualAddressChangeGuid
,
1330 &mNorFlashVirtualAddrChangeEvent
1332 ASSERT_EFI_ERROR (Status
);