当前位置:网站首页>UEFI source code learning 3.7 - norflashdxe
UEFI source code learning 3.7 - norflashdxe
2022-06-23 09:21:00 【MyeDy】
List of articles
AARCH64 QEMU Upper NOR FLASH Drive in ArmPlatFromPkg/Drivers/NorFlashDxe Under the table of contents .
1. QEMU CFI NOR FLASH
Based on the analysis of QEMU On CFI NOR FLASH Before , Need to know something QEMU CFI NOR FLASH Parameters of .
FLASH ARRAY Address : 0x04000000 - 0x08000000
Register address :0x04000000. Registers and FLASH ARRAY With the same address , When writing 0xFF Command to register , The operation is FLASH ARRAY. Otherwise, the register of the operation .
Command table
| command | function |
|---|---|
| 0x00 | Reset |
| 0x10 | Single byte write |
| 0x20 | Block erase |
| 0x28 | Block erase |
| 0x40 | Single byte write |
| 0x50 | eliminate Status register |
| 0x60 | Block Lock / Unlock |
| 0x70 | Read Status register |
| 0xe8 | Write a Block |
| 0x90 | Read Device ID register |
| 0x90 | Query CFI |
| 0xff | Enter read FLASH ARRAY Pattern |
Command definition
ArmPlatFromPkg/Drivers/NorFlashDxe/NorFlash.h
#define P30_MAX_BUFFER_SIZE_IN_BYTES ((UINTN)128)
#define P30_MAX_BUFFER_SIZE_IN_WORDS (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINTN)4))
#define MAX_BUFFERED_PROG_ITERATIONS 10000000
#define BOUNDARY_OF_32_WORDS 0x7F
// CFI Addresses
#define P30_CFI_ADDR_QUERY_UNIQUE_QRY 0x10
#define P30_CFI_ADDR_VENDOR_ID 0x13
// CFI Data
#define CFI_QRY 0x00595251
// READ Commands
#define P30_CMD_READ_DEVICE_ID 0x0090
#define P30_CMD_READ_STATUS_REGISTER 0x0070
#define P30_CMD_CLEAR_STATUS_REGISTER 0x0050
#define P30_CMD_READ_ARRAY 0x00FF
#define P30_CMD_READ_CFI_QUERY 0x0098
// WRITE Commands
#define P30_CMD_WORD_PROGRAM_SETUP 0x0040
#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP 0x0010
#define P30_CMD_BUFFERED_PROGRAM_SETUP 0x00E8
#define P30_CMD_BUFFERED_PROGRAM_CONFIRM 0x00D0
#define P30_CMD_BEFP_SETUP 0x0080
#define P30_CMD_BEFP_CONFIRM 0x00D0
// ERASE Commands
#define P30_CMD_BLOCK_ERASE_SETUP 0x0020
#define P30_CMD_BLOCK_ERASE_CONFIRM 0x00D0
// SUSPEND Commands
#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND 0x00B0
#define P30_CMD_SUSPEND_RESUME 0x00D0
// BLOCK LOCKING / UNLOCKING Commands
#define P30_CMD_LOCK_BLOCK_SETUP 0x0060
#define P30_CMD_LOCK_BLOCK 0x0001
#define P30_CMD_UNLOCK_BLOCK 0x00D0
#define P30_CMD_LOCK_DOWN_BLOCK 0x002F
// PROTECTION Commands
#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP 0x00C0
// CONFIGURATION Commands
#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP 0x0060
#define P30_CMD_READ_CONFIGURATION_REGISTER 0x0003
2. data structure
Used to describe NOR FLASH The structure of is called NOR_FLASH_INSTACE, The structure layout is as follows 
struct _NOR_FLASH_INSTANCE {
UINT32 Signature; --> One 4 The signature of the byte is "norx", x On behalf of the digital 0,1,2
EFI_HANDLE Handle; --> Corresponding image handle
UINTN DeviceBaseAddress; --> Nor Flash The address of the register
UINTN RegionBaseAddress; --> Nor Flash Address of the storage area
UINTN Size; --> Nor Flash Size
EFI_LBA StartLba; --> start Logic Block Address
EFI_BLOCK_IO_PROTOCOL BlockIoProtocol; --> One EFI_BLOCK_IO_PROTOCOL For providing Block IO service
EFI_BLOCK_IO_MEDIA Media; --> Describe the structure of the block device
EFI_DISK_IO_PROTOCOL DiskIoProtocol; --> One EFI_DISK_IO_PROTOCOL For providing Disk IO service
EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; --> One EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL For providing Fv2 service
VOID *ShadowBuffer; --> cache buffer
NOR_FLASH_DEVICE_PATH DevicePath; --> Device path object
};
3. initialization
NorFlashInitialise yes NorFlashDxe The entry function of , It's initialized NorFlashDxe.
- the reason being that QEMU,NorFlashPlatformInitialization Nothing is done here . The actual hardware should be initialized clock,power, iomux wait .
- NorFlashPlatformGetDevices from FDT( Get from the device tree file NOR FLASH Instances and number of ). There is only one example here NOR FLASH, therefore mNorFlashDeviceCount = 1.
- call AllocateRuntimePool Assign to each NOR_FLASH_INSTANCE Memory required by the instance .
- according to PCD obtain ContainVariableStorage Information .
- call NorFlashCreateInstance For every one NOR FLASH Object member initialization of .
- establish Event, Used to call back when the virtual address changes NorFlashVirtualNotifyEvent function .
EFI_STATUS
EFIAPI
NorFlashInitialise (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
UINT32 Index;
NOR_FLASH_DESCRIPTION *NorFlashDevices;
BOOLEAN ContainVariableStorage;
//1. the reason being that QEMU,NorFlashPlatformInitialization Nothing is done here . The actual hardware should be initialized clock,power, iomux wait .
Status = NorFlashPlatformInitialization ();
//2. NorFlashPlatformGetDevices from FDT( Get from the device tree file NOR FLASH Instances and number of ). There is only one example here NOR FLASH, therefore mNorFlashDeviceCount = 1.
Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
//3. call AllocateRuntimePool Assign to each NOR_FLASH_INSTANCE example .
mNorFlashInstances = AllocateRuntimePool (sizeof (NOR_FLASH_INSTANCE *) * mNorFlashDeviceCount);
for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
// Check if this NOR Flash device contain the variable storage region
//4. according to PCD obtain ContainVariableStorage Information .
if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {
ContainVariableStorage =
(NorFlashDevices[Index].RegionBaseAddress <= PcdGet64 (PcdFlashNvStorageVariableBase64)) &&
(PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize) <=
NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
} else {
ContainVariableStorage =
(NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&
(PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <=
NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
}
//5. call NorFlashCreateInstance For every one NOR FLASH Object member initialization of .
Status = NorFlashCreateInstance (
NorFlashDevices[Index].DeviceBaseAddress,
NorFlashDevices[Index].RegionBaseAddress,
NorFlashDevices[Index].Size,
Index,
NorFlashDevices[Index].BlockSize,
ContainVariableStorage,
&mNorFlashInstances[Index]
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", Index));
}
}
//6. establish Event, Used to call back when the virtual address changes NorFlashVirtualNotifyEvent function .
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
NorFlashVirtualNotifyEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mNorFlashVirtualAddrChangeEvent
);
ASSERT_EFI_ERROR (Status);
return Status;
}
NOR FLASH The members of the object are mainly in NorFlashCreateInstance In the initialization .
- First call AllocateRuntimeCopyPool hold mNorFlashInstanceTemplate Copy the contents of to NOR_FLASH_INSTANCE On . You can see mNorFlashInstanceTemplate Mainly some function pointers .
- Initialization according to parameters NOR_FLASH_INSTANCE Members .
| Member name | value |
|---|---|
| DeviceBaseAddress | 0x04000000 |
| RegionBaseAddress | 0x04000000 |
| Size | 0x04000000 |
| Media.MediaId | 0 |
| Media.BlockSize | 0x40000 |
| DevicePath.Vendor.Guid | 93E34C7E-B50E-11DF-9223-2443DFD72085 |
- call AllocateRuntimePool Allocate cache buffer.
- NorFlashFvbInitialize initialization NOR FLASH Upper FV.
- call InstallMultipleProtocolInterfaces Install the following Protocol:gEfiDevicePathProtocolGuid,gEfiBlockIoProtocolGuid, gEfiFirmwareVolumeBlockProtocolGuid,gEfiDiskIoProtocolGuid
EFI_STATUS
NorFlashCreateInstance (
IN UINTN NorFlashDeviceBase,
IN UINTN NorFlashRegionBase,
IN UINTN NorFlashSize,
IN UINT32 Index,
IN UINT32 BlockSize,
IN BOOLEAN SupportFvb,
OUT NOR_FLASH_INSTANCE **NorFlashInstance
)
{
EFI_STATUS Status;
NOR_FLASH_INSTANCE *Instance;
ASSERT (NorFlashInstance != NULL);
//1. First call AllocateRuntimeCopyPool hold mNorFlashInstanceTemplate Copy the contents of to NOR_FLASH_INSTANCE On . You can see mNorFlashInstanceTemplate Mainly some function pointers .
Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), &mNorFlashInstanceTemplate);
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//2. Initialization according to parameters NOR_FLASH_INSTANCE Members .
Instance->DeviceBaseAddress = NorFlashDeviceBase;
Instance->RegionBaseAddress = NorFlashRegionBase;
Instance->Size = NorFlashSize;
Instance->BlockIoProtocol.Media = &Instance->Media;
Instance->Media.MediaId = Index;
Instance->Media.BlockSize = BlockSize;
Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
Instance->DevicePath.Index = (UINT8)Index;
//3. call AllocateRuntimePool Allocate cache buffer.
Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
if (Instance->ShadowBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//4. NorFlashFvbInitialize initialization NOR FLASH Upper FV.
NorFlashFvbInitialize (Instance);
//5. Install the following Protoco
Status = gBS->InstallMultipleProtocolInterfaces (
&Instance->Handle,
&gEfiDevicePathProtocolGuid,
&Instance->DevicePath,
&gEfiBlockIoProtocolGuid,
&Instance->BlockIoProtocol,
&gEfiFirmwareVolumeBlockProtocolGuid,
&Instance->FvbProtocol,
&gEfiDiskIoProtocolGuid,
&Instance->DiskIoProtocol,
NULL
);
...
*NorFlashInstance = Instance;
return Status;
}
mNorFlashInstanceTemplate Is defined as follows , Achieved some Protocol Function of .
NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
NOR_FLASH_SIGNATURE, // Signature
NULL, // Handle ... NEED TO BE FILLED
0, // DeviceBaseAddress ... NEED TO BE FILLED
0, // RegionBaseAddress ... NEED TO BE FILLED
0, // Size ... NEED TO BE FILLED
0, // StartLba
{
EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
NULL, // Media ... NEED TO BE FILLED
NorFlashBlockIoReset, // Reset;
NorFlashBlockIoReadBlocks, // ReadBlocks
NorFlashBlockIoWriteBlocks, // WriteBlocks
NorFlashBlockIoFlushBlocks // FlushBlocks
}, // BlockIoProtocol
{
0, // MediaId ... NEED TO BE FILLED
FALSE, // RemovableMedia
TRUE, // MediaPresent
FALSE, // LogicalPartition
FALSE, // ReadOnly
FALSE, // WriteCaching;
0, // BlockSize ... NEED TO BE FILLED
4, // IoAlign
0, // LastBlock ... NEED TO BE FILLED
0, // LowestAlignedLba
1, // LogicalBlocksPerPhysicalBlock
}, // Media;
{
EFI_DISK_IO_PROTOCOL_REVISION, // Revision
NorFlashDiskIoReadDisk, // ReadDisk
NorFlashDiskIoWriteDisk // WriteDisk
},
{
FvbGetAttributes, // GetAttributes
FvbSetAttributes, // SetAttributes
FvbGetPhysicalAddress, // GetPhysicalAddress
FvbGetBlockSize, // GetBlockSize
FvbRead, // Read
FvbWrite, // Write
FvbEraseBlocks, // EraseBlocks
NULL, // ParentHandle
}, // FvbProtoccol;
NULL, // ShadowBuffer
{
{
{
HARDWARE_DEVICE_PATH,
HW_VENDOR_DP,
{
(UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
(UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
}
},
{
0x0, 0x0, 0x0, {
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
}, // GUID ... NEED TO BE FILLED
},
0, // Index
{
END_DEVICE_PATH_TYPE,
END_ENTIRE_DEVICE_PATH_SUBTYPE,
{
sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
}
} // DevicePath
};
NorFlashFvbInitialize initialization NOR FLASH Upper FV head .
- call AddMemorySpace and SetMemorySpaceAttributes towards DxeCore Report NOR FLASH Of memory space .
- call ValidateFvHeader see NOR FLASH Is there a FV.
- If it doesn't exist FV Words , It's just NOR FLASH Initialization on FV, This FV It's for saving Non Volatile Variable Of .
- install Protocol:gEdkiiNvVarStoreFormattedGuid.
- establish Event, Callback when the virtual address changes FvbVirtualNotifyEvent.
EFI_STATUS
EFIAPI
NorFlashFvbInitialize (
IN NOR_FLASH_INSTANCE *Instance
)
{
EFI_STATUS Status;
UINT32 FvbNumLba;
EFI_BOOT_MODE BootMode;
UINTN RuntimeMmioRegionSize;
...
//1. call AddMemorySpace and SetMemorySpaceAttributes towards DxeCore Report NOR FLASH Of memory space .
RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size;
Status = gDS->AddMemorySpace (
EfiGcdMemoryTypeMemoryMappedIo,
Instance->DeviceBaseAddress,
RuntimeMmioRegionSize,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
);
Status = gDS->SetMemorySpaceAttributes (
Instance->DeviceBaseAddress,
RuntimeMmioRegionSize,
EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
);
// according to PCD obtain NvStorageVariable Base address for storage
mFlashNvStorageVariableBase = (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?
PcdGet64 (PcdFlashNvStorageVariableBase64) : PcdGet32 (PcdFlashNvStorageVariableBase);
//2. call ValidateFvHeader see NOR FLASH Is there a FV.
Status = ValidateFvHeader (Instance);
// Install the Default FVB header if required
if (EFI_ERROR (Status)) {
// There is no valid header, so time to install one.
//3. If it doesn't exist FV Words , It's just NOR FLASH Initialization on FV, This FV It's for saving Non Volatile Variable Of .
// erase Flash
FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize;
Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);
// install NvStorageVariable FV head
Status = InitializeFvAndVariableStoreHeaders (Instance);
}
//4. install Protocol:gEdkiiNvVarStoreFormattedGuid.
Status = gBS->InstallProtocolInterface (
&gImageHandle,
&gEdkiiNvVarStoreFormattedGuid,
EFI_NATIVE_INTERFACE,
NULL
);
//5. establish Event, Callback when the virtual address changes FvbVirtualNotifyEvent.
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
FvbVirtualNotifyEvent,
NULL,
&gEfiEventVirtualAddressChangeGuid,
&mFvbVirtualAddrChangeEvent
);
ASSERT_EFI_ERROR (Status);
return Status;
}
InitializeFvAndVariableStoreHeaders It's simple , It is based on PCD Read in NvStrorageVariable FV The parameters of , Then generate FV head , The final call FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers); hold FV Write header to NOR FLASH On .
EFI_STATUS
InitializeFvAndVariableStoreHeaders (
IN NOR_FLASH_INSTANCE *Instance
)
{
...
FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
FirmwareVolumeHeader->FvLength =
PcdGet32 (PcdFlashNvStorageVariableSize) +
PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
PcdGet32 (PcdFlashNvStorageFtwSpareSize);
FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2)(
EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
EFI_FVB2_READ_STATUS | // Reads are currently enabled
EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1')
EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled
);
FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY);
FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1;
FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize;
FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
FirmwareVolumeHeader->BlockMap[1].Length = 0;
FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16 *)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
//
// VARIABLE_STORE_HEADER
//
VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);
CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
// Install the combined super-header in the NorFlash
Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
FreePool (Headers);
return Status;
}
4. Read and write
4.1 NOR FLASH Reading and writing
ArmPlatFromPkg/Drivers/NorFlashDxe/NorFlash.c
Single byte write NorFlashWriteSingleWord
- towards NOR FLASH send out P30_CMD_WORD_PROGRAM_SETUP command .
- The data WriteData write in NOR FLASH Address WordAddress.
- Read Status register , Wait for the write to complete .
- send out P30_CMD_READ_ARRAY The order will NOR FLASH Set to READ ARRAY Pattern
EFI_STATUS
NorFlashWriteSingleWord (
IN NOR_FLASH_INSTANCE *Instance,
IN UINTN WordAddress,
IN UINT32 WriteData
)
{
EFI_STATUS Status;
UINT32 StatusRegister;
Status = EFI_SUCCESS;
//1. towards NOR FLASH send out P30_CMD_WORD_PROGRAM_SETUP command
SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
//2. The data WriteData write in NOR FLASH Address WordAddress.
MmioWrite32 (WordAddress, WriteData);
//3. Read Status register , Wait for the write to complete .
do {
// Prepare to read the status register
StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
// The chip is busy while the WRITE bit is not asserted
} while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
// Perform a full status check:
// Mask the relevant bits of Status Register.
// Everything should be zero, if not, we have a problem
if (StatusRegister & P30_SR_BIT_VPP) {
DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));
Status = EFI_DEVICE_ERROR;
}
if (StatusRegister & P30_SR_BIT_PROGRAM) {
DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
Status = EFI_DEVICE_ERROR;
}
if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));
Status = EFI_DEVICE_ERROR;
}
if (!EFI_ERROR (Status)) {
// Clear the Status Register
SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
}
//4. take NOR FLASH Set to READ ARRAY Pattern
SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
return Status;
}
Other NorFlashWriteBlocks、NorFlashWriteSingleBlock and NorFlashWriteBuffer The process is similar : Give orders -> Writing data -> read Status register -> Set to READ ARRAY Pattern .
Just send different commands .
The implementation of reading is simple .NOR FLASH yes memory map The equipment , Directly from 0x04000000 You can read it on the address NOR FLASH The data of .
- Do a bunch of parameter checks , obtain NOR FLASH ARRAY From .
- send out P30_CMD_READ_ARRAY The command NOR FLASH Set to READY ARRAY Pattern .
- Transfer the data from the corresponding FLASH The address space is copied to the destination address .
EFI_STATUS
NorFlashRead (
IN NOR_FLASH_INSTANCE *Instance,
IN EFI_LBA Lba,
IN UINTN Offset,
IN UINTN BufferSizeInBytes,
OUT VOID *Buffer
)
{
UINTN StartAddress;
...
// 1. Do a bunch of parameter checks , obtain NOR FLASH ARRAY From .
StartAddress = GET_NOR_BLOCK_ADDRESS (
Instance->RegionBaseAddress,
Lba,
Instance->Media.BlockSize
);
// 2. send out P30_CMD_READ_ARRAY The command NOR FLASH Set to READY ARRAY Pattern .
SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
// 3. Transfer the data from the corresponding FLASH The address space is copied to the destination address .
AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
return EFI_SUCCESS;
}
4.2 Block IO Protocol Realization
ArmPlatFromPkg/Drivers/NorFlashDxe/NorFlashBlockIo.c, This is the realization BlockIO Protocol The correlation function of , The underlying call is still NorFlash.c The function on .
- NorFlashBlockIoReadBlocks After checking a bunch of parameters, I called NorFlashReadBlocks Read the data .
- NorFlashBlockIoWriteBlocks After doing a bunch of checks, call NorFlashWriteBlocks Write data .
EFI_STATUS
EFIAPI
NorFlashBlockIoReadBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSizeInBytes,
OUT VOID *Buffer
)
{
NOR_FLASH_INSTANCE *Instance;
EFI_STATUS Status;
EFI_BLOCK_IO_MEDIA *Media;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Instance = INSTANCE_FROM_BLKIO_THIS (This);
Media = This->Media;
DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReadBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));
if (!Media) {
Status = EFI_INVALID_PARAMETER;
} else if (!Media->MediaPresent) {
Status = EFI_NO_MEDIA;
} else if (Media->MediaId != MediaId) {
Status = EFI_MEDIA_CHANGED;
} else if ((Media->IoAlign > 2) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {
Status = EFI_INVALID_PARAMETER;
} else {
Status = NorFlashReadBlocks (Instance, Lba, BufferSizeInBytes, Buffer);
}
return Status;
}
EFI_STATUS
EFIAPI
NorFlashBlockIoWriteBlocks (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA Lba,
IN UINTN BufferSizeInBytes,
IN VOID *Buffer
)
{
NOR_FLASH_INSTANCE *Instance;
EFI_STATUS Status;
Instance = INSTANCE_FROM_BLKIO_THIS (This);
DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoWriteBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes (%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer));
if ( !This->Media->MediaPresent ) {
Status = EFI_NO_MEDIA;
} else if ( This->Media->MediaId != MediaId ) {
Status = EFI_MEDIA_CHANGED;
} else if ( This->Media->ReadOnly ) {
Status = EFI_WRITE_PROTECTED;
} else {
Status = NorFlashWriteBlocks (Instance, Lba, BufferSizeInBytes, Buffer);
}
return Status;
}
4.3 Disk IO Protocol Realization
Disk IO And Block IO It's the same thing , The final call NorFlash.c The underlying functions in the . But it wraps a little bit of outer logic in the outer layer to achieve the writing function of arbitrary byte size .
EFI_STATUS
EFIAPI
NorFlashDiskIoReadDisk (
IN EFI_DISK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 DiskOffset,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
NOR_FLASH_INSTANCE *Instance;
UINT32 BlockSize;
UINT32 BlockOffset;
EFI_LBA Lba;
Instance = INSTANCE_FROM_DISKIO_THIS (This);
if (MediaId != Instance->Media.MediaId) {
return EFI_MEDIA_CHANGED;
}
BlockSize = Instance->Media.BlockSize;
Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
}
EFI_STATUS
EFIAPI
NorFlashDiskIoWriteDisk (
IN EFI_DISK_IO_PROTOCOL *This,
IN UINT32 MediaId,
IN UINT64 DiskOffset,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
NOR_FLASH_INSTANCE *Instance;
UINT32 BlockSize;
UINT32 BlockOffset;
EFI_LBA Lba;
UINTN RemainingBytes;
UINTN WriteSize;
EFI_STATUS Status;
Instance = INSTANCE_FROM_DISKIO_THIS (This);
if (MediaId != Instance->Media.MediaId) {
return EFI_MEDIA_CHANGED;
}
BlockSize = Instance->Media.BlockSize;
Lba = (EFI_LBA)DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
RemainingBytes = BufferSize;
WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);
do {
if (WriteSize == BlockSize) {
// Write a full block
Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));
} else {
// Write a partial block
Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);
}
if (EFI_ERROR (Status)) {
return Status;
}
// Now continue writing either all the remaining bytes or single blocks.
RemainingBytes -= WriteSize;
Buffer = (UINT8 *)Buffer + WriteSize;
Lba++;
BlockOffset = 0;
WriteSize = MIN (RemainingBytes, BlockSize);
} while (RemainingBytes);
return Status;
}
5. Test code
The test function is as follows , call NOR FLASH Of DiskIO Protocol.
- Due to the current FD There is only one NorFlash This DiskIO equipment , So just use LocateProtocol To find the only DiskIO In order to get NOR FLASH Read and write .
- Use them separately DiskIO And direct reading FLASH Address 0x4000010 Read by FLASH The data on the .
- Go to FLASH Write... On the header 16 Bytes of data .
- Use them separately DiskIO And direct reading FLASH Address 0x4000000 Read by FLASH The data on the .
VOID
TestDxeTestNorFlashProtocol()
{
EFI_STATUS Status;
UINT32 Buffer[128];
UINT32 *Addr = (UINT32 *)0x4000000;
DEBUG((DEBUG_INFO, "TestDxeTestNorFlashProtocol\n"));
EFI_DISK_IO_PROTOCOL *DiskIo;
Status = gBS->LocateProtocol(&gEfiDiskIoProtocolGuid, NULL, (VOID **)&DiskIo);
if (Status != EFI_SUCCESS) {
DEBUG((DEBUG_INFO, "Locate block io failed\n"));
return;
}
DiskIo->ReadDisk(DiskIo, 0, 0, 512, Buffer);
DEBUG((DEBUG_INFO, "#######Read by Bufffer:0x%08x 0x%08x 0x%08x 0x%08x\n", Buffer[4], Buffer[5], Buffer[6], Buffer[7]));
DEBUG((DEBUG_INFO, "#######Read by Address: 0x4000010: 0x%08x 0x%08x 0x%08x 0x%08x\n", *(Addr + 4), *(Addr+5), *(Addr+6), *(Addr + 7)));
for (UINT32 i = 0; i < 4; i++) {
Buffer[i] = i;
}
DiskIo->WriteDisk(DiskIo, 0, 0, 16, Buffer);
DiskIo->ReadDisk(DiskIo, 0, 0, 512, Buffer);
DEBUG((DEBUG_INFO, "#######Read by Bufffer: 0x%08x 0x%08x 0x%08x 0x%08x\n", Buffer[0], Buffer[1], Buffer[2], Buffer[3]));
DEBUG((DEBUG_INFO, "#######Read by Address: 0x4000000: 0x%08x 0x%08x 0x%08x 0x%08x\n", *Addr, *(Addr+1), *(Addr+2), *(Addr + 3)));
}
Printed log
TestDxeTestNorFlashProtocol
#######Read by Bufffer: 0xFFF12B8D 0x4C8B7696 0x472785A9 0x504F5B07
#######Read by Address: 0x4000010: 0xFFF12B8D 0x4C8B7696 0x472785A9 0x504F5B07
#######Read by Bufffer: 0x00000000 0x00000001 0x00000002 0x00000003
#######Read by Address: 0x4000000: 0x00000000 0x00000001 0x00000002 0x00000003
边栏推荐
猜你喜欢
![[网鼎杯 2020 青龙组]AreUSerialz](/img/38/b67f7a42abec1cdaad02f2b7df6546.png)
[网鼎杯 2020 青龙组]AreUSerialz
![[GXYCTF2019]BabyUpload](/img/82/7941edd523d86f7634f5532ab97717.png)
[GXYCTF2019]BabyUpload

Typora设置图片上传服务
Redis学习笔记—发布订阅
![[极客大挑战 2019]HardSQL](/img/73/ebfb410296b8e950c9ac0cf00adc17.png)
[极客大挑战 2019]HardSQL

Precautions for map interface

Implementation of s5p4418 bare metal programming (replace 2ndboot)

学习SCI论文绘制技巧(E)

Jog运动模式

"Coach, I want to play basketball" -- AI Learning Series booklet for students who are making systems
随机推荐
[SUCTF 2019]CheckIn
Use of type dependent names must be prefixed with 'typename'
Best time to buy and sell stock
[極客大挑戰 2019]HardSQL
2022.6.22-----leetcode. five hundred and thirteen
Redis学习笔记—客户端通讯协议RESP
位绑定
ARM中常见的英文解释
[MRCTF2020]Ez_bypass
node request模塊cookie使用
Redis learning notes - single key management
Correspondence between three-tier architecture and SSM
UCOSII (learning notes)
Pizza ordering design - simple factory model
栈(Stack)的链式实现详解----线性结构
多线程初学
Set the CPU to have 16 address lines and 8 data lines, and use mreq as the access control line number Connection between memory and CPU
@Response
Opening, creating and storing files
Precautions for map interface