summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2016-01-25 18:38:42 -0200
committerPaulo Alcantara <pcacjr@zytor.com>2016-01-25 18:38:42 -0200
commit44933b3ed28cbba95a38700ac625ceba71e60eeb (patch)
treeec8241c6750bc59cc46f296d28da79743ab9113f
parent0179180d6dbacc1bed53c3b6a886693790f75365 (diff)
downloadedk2-blockio-cache.tar.gz
edk2-blockio-cache.tar.xz
edk2-blockio-cache.zip
Add BlockIoCacheLib (WIP)blockio-cache
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c108
-rw-r--r--MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h3
-rw-r--r--MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf1
-rw-r--r--MdePkg/Include/Library/BlockIoCacheLib.h126
-rw-r--r--MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.c564
-rw-r--r--MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf28
-rw-r--r--MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.uni14
-rw-r--r--MdePkg/MdePkg.dec2
-rw-r--r--MdePkg/MdePkg.dsc2
-rw-r--r--OvmfPkg/OvmfPkgX64.dsc2
10 files changed, 846 insertions, 4 deletions
diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
index e7449f9714..95d6975630 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.c
@@ -377,6 +377,17 @@ RegisterAtaDevice (
DEBUG ((EFI_D_INFO, "Successfully Install Storage Security Protocol on the ATA device\n"));
}
+ ZeroMem (&AtaDevice->BlockIoCache, sizeof (BLOCK_IO_CACHE));
+
+ //
+ // Initialize internal cache
+ //
+ Status = BlockIoCacheInitialize (&AtaDevice->BlockIoCache, &AtaDevice->BlockMedia);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "AtaBus: failed to initialize internal cache: %r\n", Status));
+ goto Done;
+ }
+
gBS->OpenProtocol (
AtaBusDriverData->Controller,
&gEfiAtaPassThruProtocolGuid,
@@ -1038,6 +1049,13 @@ BlockIoReadWrite (
UINTN BlockSize;
UINTN NumberOfBlocks;
UINTN IoAlign;
+ UINTN Index;
+ UINTN CurrentLba;
+ UINTN BufferOffset;
+ EFI_LBA CacheLba;
+ UINTN CacheNumberOfBlocks;
+ UINTN CacheBlockSize;
+ VOID *CacheEntryBuffer;
if (IsBlockIo2) {
Media = ((EFI_BLOCK_IO2_PROTOCOL *) This)->Media;
@@ -1083,11 +1101,93 @@ BlockIoReadWrite (
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
- //
- // Invoke low level AtaDevice Access Routine.
- //
- Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite, Token);
+ Status = BlockIoCacheGetCacheParameters (
+ &AtaDevice->BlockIoCache,
+ Lba,
+ &CacheLba,
+ NumberOfBlocks,
+ &CacheNumberOfBlocks
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "AtaBus: failed to get number of blocks for disk cache: %r\n", Status));
+ goto Done;
+ }
+ Status = BlockIoCacheGetBlockSize (&AtaDevice->BlockIoCache, &CacheBlockSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (!IsWrite) {
+ CurrentLba = Lba;
+ BufferOffset = 0;
+ for (Index = 0; Index < CacheNumberOfBlocks; Index++) {
+ DEBUG ((DEBUG_ERROR, "AtaBus: request disk block from cache\n"));
+ Status = BlockIoCacheRead2 (
+ &AtaDevice->BlockIoCache,
+ CacheLba,
+ 1,
+ &CurrentLba,
+ NumberOfBlocks,
+ Buffer,
+ &BufferOffset
+ );
+ if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_ERROR, "AtaBus: failed to read from Block Io cache: %r\n", Status));
+ goto Done;
+ }
+ if (Status == EFI_NOT_FOUND) {
+ CacheEntryBuffer = AllocatePool (CacheBlockSize);
+ if (CacheEntryBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Invoke low level AtaDevice Access Routine.
+ //
+ DEBUG ((DEBUG_ERROR, "AtaBus: invoke low level AtaDevice access routine\n"));
+ Status = AccessAtaDevice (
+ AtaDevice,
+ CacheEntryBuffer,
+ CacheLba,
+ CacheBlockSize / Media->BlockSize,
+ IsWrite,
+ Token
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((DEBUG_ERROR, "AtaBus: BufferOffset: %d\n", BufferOffset));
+
+ CopyMem (
+ (VOID *)((UINTN)Buffer + BufferOffset),
+ CacheEntryBuffer,
+ (CurrentLba - Lba) * Media->BlockSize
+ );
+ BufferOffset += (CurrentLba - Lba) * Media->BlockSize;
+
+ DEBUG ((DEBUG_ERROR, "AtaBus: copied %d blocks into Buffer\n", CurrentLba - Lba));
+
+ DEBUG ((DEBUG_ERROR, "AtaBus: add read block to cache\n"));
+ Status = BlockIoCacheAdd2 (
+ &AtaDevice->BlockIoCache,
+ CacheLba,
+ CacheEntryBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CacheLba += (CacheBlockSize / Media->BlockSize);
+ }
+ } else {
+ //
+ // Invoke low level AtaDevice Access Routine.
+ //
+ Status = AccessAtaDevice (AtaDevice, Buffer, Lba, NumberOfBlocks, IsWrite, Token);
+ }
+
+Done:
gBS->RestoreTPL (OldTpl);
return Status;
diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
index 26ec70d30a..c61dafb5fd 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBus.h
@@ -38,6 +38,7 @@
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/TimerLib.h>
#include <Library/ReportStatusCodeLib.h>
+#include <Library/BlockIoCacheLib.h>
#include <IndustryStandard/Atapi.h>
@@ -133,6 +134,8 @@ typedef struct {
LIST_ENTRY AtaTaskList;
LIST_ENTRY AtaSubTaskList;
BOOLEAN Abort;
+
+ BLOCK_IO_CACHE BlockIoCache;
} ATA_DEVICE;
//
diff --git a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
index 4aab75bab7..86c925672b 100644
--- a/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
+++ b/MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf
@@ -58,6 +58,7 @@
DebugLib
TimerLib
ReportStatusCodeLib
+ BlockIoCacheLib
[Guids]
gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED
diff --git a/MdePkg/Include/Library/BlockIoCacheLib.h b/MdePkg/Include/Library/BlockIoCacheLib.h
new file mode 100644
index 0000000000..96840cf833
--- /dev/null
+++ b/MdePkg/Include/Library/BlockIoCacheLib.h
@@ -0,0 +1,126 @@
+/** @file
+ Library used Block I/O cache.
+
+ <Copyright notice>
+
+**/
+#ifndef __BLOCK_IO_CACHE_LIB_H__
+#define __BLOCK_IO_CACHE_LIB_H__
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+
+typedef struct _BLOCK_IO_CACHE_ENTRY BLOCK_IO_CACHE_ENTRY;
+typedef struct _BLOCK_IO_CACHE_DATA BLOCK_IO_CACHE_DATA;
+typedef struct _BLOCK_IO_CACHE BLOCK_IO_CACHE;
+
+#define BLOCK_IO_CACHE_ENTRY_SIGNATURE SIGNATURE_32 ('B', 'I', 'O', 'C')
+
+#define BIO_CACHE_DATA_SIZE_SHIFT 12
+#define BIO_CACHE_DATA_SIZE (1 << CACHE_DATA_SIZE_SHIFT)
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheInitialize (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_BLOCK_IO_MEDIA *Media
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheGetCacheParameters (
+ IN BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ OUT EFI_LBA *AlignedLba,
+ IN UINTN NumberOfBlocks,
+ OUT UINTN *AlignedNumberOfBlocks
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheGetBlockSize (
+ IN BLOCK_IO_CACHE *BlockIoCache,
+ OUT UINTN *BlockSize
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheRead2 (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN OUT EFI_LBA *Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer,
+ IN OUT UINTN *BufferOffset
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheRead (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheAdd2 (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheAdd (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheInvalidate (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheCleanup (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache
+ );
+
+struct _BLOCK_IO_CACHE_DATA {
+ EFI_LBA Lba;
+ VOID *Data;
+};
+
+struct _BLOCK_IO_CACHE_ENTRY {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+};
+
+struct _BLOCK_IO_CACHE {
+ UINT32 BlockSize;
+ UINT32 IoAlign;
+ EFI_LBA LastLba;
+ BLOCK_IO_CACHE_DATA *CacheData;
+ UINT16 CacheSize;
+ UINT16 CacheCount;
+ LIST_ENTRY CacheList;
+ BOOLEAN CacheInitialized;
+};
+
+#endif // __BLOCK_IO_CACHE_LIB_H__
diff --git a/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.c b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.c
new file mode 100644
index 0000000000..82e3a870fc
--- /dev/null
+++ b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.c
@@ -0,0 +1,564 @@
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/BlockIo.h>
+
+#include <Library/BlockIoCacheLib.h>
+
+#define BIO_CACHE_DEBUG
+
+#define NR_CACHE_BLOCKS(_BlockIoCache) (UINTN)(EFI_PAGE_SIZE / _BlockIoCache->BlockSize)
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheInitialize (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_BLOCK_IO_MEDIA *Media
+ )
+{
+ UINT16 CacheSize;
+
+ if (Media == NULL || BlockIoCache == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BlockIoCache->CacheInitialized) {
+ return EFI_SUCCESS;
+ }
+
+ CacheSize = PcdGet16 (PcdBlockIoCacheSize);
+ if ((CacheSize & (CacheSize - 1)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BlockIoCache->CacheData = AllocateZeroPool (CacheSize * sizeof (BLOCK_IO_CACHE_DATA));
+ if (BlockIoCache->CacheData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlockIoCache->BlockSize = Media->BlockSize;
+ BlockIoCache->IoAlign = Media->IoAlign;
+ BlockIoCache->LastLba = Media->LastBlock;
+ BlockIoCache->CacheSize = CacheSize;
+ BlockIoCache->CacheCount = 0;
+ InitializeListHead (&BlockIoCache->CacheList);
+ BlockIoCache->CacheInitialized = TRUE;
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: cache initialized - BlockSize: %ld\n", Media->BlockSize));
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheGetCacheParameters (
+ IN BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ OUT EFI_LBA *AlignedLba,
+ IN UINTN NumberOfBlocks,
+ OUT UINTN *AlignedNumberOfBlocks
+ )
+{
+ UINTN CacheBlocksNo;
+
+ if (BlockIoCache == NULL || AlignedLba == NULL || AlignedNumberOfBlocks == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!BlockIoCache->CacheInitialized) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+
+ if ((Lba % CacheBlocksNo) != 0) {
+ *AlignedLba = Lba & ~(CacheBlocksNo - 1);
+ } else {
+ *AlignedLba = Lba;
+ }
+
+ *AlignedNumberOfBlocks = (NumberOfBlocks + CacheBlocksNo - 1) / CacheBlocksNo;
+ if ((Lba - *AlignedLba) + NumberOfBlocks > CacheBlocksNo) {
+ (*AlignedNumberOfBlocks)++;
+ }
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: cache parameters:\n"
+ " Lba: %lld\n"
+ " AlignedLba: %lld\n"
+ " NumberOfBlocks: %d\n"
+ " AlignedNumberOfBlocks: %d\n",
+ Lba, *AlignedLba, NumberOfBlocks, *AlignedNumberOfBlocks));
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheGetBlockSize (
+ IN BLOCK_IO_CACHE *BlockIoCache,
+ OUT UINTN *BlockSize
+ )
+{
+ if (BlockIoCache == NULL || !BlockIoCache->CacheInitialized || BlockSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *BlockSize = EFI_PAGE_SIZE;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetNewBlockInfo (
+ IN BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ IN VOID *Data,
+ IN OUT BLOCK_IO_CACHE_DATA *BlockInfo
+ )
+{
+ BlockInfo->Data = Data;
+ BlockInfo->Lba = Lba;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+GetNewCacheEntry (
+ IN BLOCK_IO_CACHE_DATA *BlockInfo,
+ IN BLOCK_IO_CACHE_ENTRY **CacheEntry
+ )
+{
+ BLOCK_IO_CACHE_ENTRY *NewCacheEntry;
+
+ NewCacheEntry = AllocatePool (sizeof (BLOCK_IO_CACHE_ENTRY));
+ if (NewCacheEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewCacheEntry->Signature = BLOCK_IO_CACHE_ENTRY_SIGNATURE;
+ NewCacheEntry->BlockInfo = BlockInfo;
+ *CacheEntry = NewCacheEntry;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheRead2 (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN OUT EFI_LBA *Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer,
+ IN OUT UINTN *BufferOffset
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *CacheList;
+ LIST_ENTRY *Link;
+ BLOCK_IO_CACHE_ENTRY *CacheEntry;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+ UINTN DataOffset;
+ UINTN CacheBlocksNo;
+ UINTN BlocksToCopy;
+
+ if (BlockIoCache == NULL || Lba == NULL || Buffer == NULL || BufferOffset == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!BlockIoCache->CacheInitialized) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_ERROR,
+ "BlockIoCache: CacheLba %lld CacheNumberOfBlocks %d Lba %lld NumberOfBlocks %d\n",
+ CacheLba, CacheNumberOfBlocks, *Lba, NumberOfBlocks));
+
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+
+ if ((*Lba - CacheLba) + NumberOfBlocks > CacheBlocksNo) {
+ BlocksToCopy = CacheBlocksNo - (*Lba - CacheLba);
+ } else {
+ BlocksToCopy = NumberOfBlocks;
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ if (BlockIoCache->CacheCount == 0) {
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache miss\n", CacheLba));
+ goto Done;
+ }
+
+ CacheList = &BlockIoCache->CacheList;
+ CacheEntry = NULL;
+ BlockInfo = NULL;
+ for (Link = GetFirstNode (CacheList); !IsNull (CacheList, Link);
+ Link = GetNextNode (CacheList, Link)) {
+ CacheEntry = CR (Link, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ BlockInfo = CacheEntry->BlockInfo;
+ if (BlockInfo->Lba == CacheLba) {
+ break;
+ }
+ }
+
+ if (IsNull (CacheList, Link)) {
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache miss\n", CacheLba));
+ goto Done;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache hit\n", CacheLba));
+
+ Status = EFI_SUCCESS;
+
+ if ((*Lba & (CacheBlocksNo - 1)) != 0) {
+ DataOffset = (*Lba - CacheLba) * BlockIoCache->BlockSize;
+ } else {
+ DataOffset = 0;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: DataOffset %d BufferOffset %d\n", DataOffset, *BufferOffset));
+
+ CopyMem (
+ (VOID *)((UINTN)Buffer + *BufferOffset),
+ (VOID *)((UINTN)BlockInfo->Data + DataOffset),
+ BlocksToCopy * BlockIoCache->BlockSize
+ );
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: copied %d blocks from cache\n", BlocksToCopy));
+
+ RemoveEntryList (Link);
+ InsertHeadList (CacheList, &CacheEntry->Link);
+
+ *BufferOffset += BlocksToCopy * BlockIoCache->BlockSize;
+
+Done:
+ *Lba += BlocksToCopy;
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: new values: BlocksToCopy %d Lba %lld\n", BlocksToCopy, *Lba));
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheRead (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *CacheList;
+ LIST_ENTRY *Link;
+ BLOCK_IO_CACHE_ENTRY *CacheEntry;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+ UINTN DataOffset;
+ UINTN BufferOffset;
+ UINTN CacheBlocksNo;
+ UINTN BlocksToCopy;
+
+ if (BlockIoCache == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!BlockIoCache->CacheInitialized) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BlockIoCache->CacheCount == 0) {
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache miss\n", Lba));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_ERROR,
+ "BlockIoCache: CacheLba %lld CacheNumberOfBlocks %d Lba %lld NumberOfBlocks %d\n",
+ CacheLba, CacheNumberOfBlocks, Lba, NumberOfBlocks));
+
+ CacheList = &BlockIoCache->CacheList;
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+ BufferOffset = 0;
+ while (NumberOfBlocks > 0) {
+ CacheEntry = NULL;
+ BlockInfo = NULL;
+ for (Link = GetFirstNode (CacheList); !IsNull (CacheList, Link);
+ Link = GetNextNode (CacheList, Link)) {
+ CacheEntry = CR (Link, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ BlockInfo = CacheEntry->BlockInfo;
+ if (BlockInfo->Lba == CacheLba) {
+ break;
+ }
+ }
+
+ if (IsNull (CacheList, Link)) {
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache miss\n", CacheLba));
+ return EFI_NOT_FOUND;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld - cache hit\n", CacheLba));
+
+ if ((Lba - CacheLba) + NumberOfBlocks > CacheBlocksNo) {
+ BlocksToCopy = CacheBlocksNo - (Lba - CacheLba);
+ } else {
+ BlocksToCopy = NumberOfBlocks;
+ }
+
+ if ((Lba & (CacheBlocksNo - 1)) != 0) {
+ DataOffset = (Lba - CacheLba) * BlockIoCache->BlockSize;
+ } else {
+ DataOffset = 0;
+ }
+
+ CopyMem (
+ (VOID *)((UINTN)Buffer + BufferOffset),
+ (VOID *)((UINTN)BlockInfo->Data + DataOffset),
+ BlocksToCopy * BlockIoCache->BlockSize
+ );
+ RemoveEntryList (Link);
+ InsertHeadList (CacheList, &CacheEntry->Link);
+
+ BufferOffset += BlocksToCopy * BlockIoCache->BlockSize;
+ NumberOfBlocks -= BlocksToCopy;
+ Lba += BlocksToCopy;
+ CacheLba += CacheBlocksNo;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheAdd2 (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *CacheList;
+ UINTN CacheBlocksNo;
+ EFI_STATUS Status;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+ BLOCK_IO_CACHE_ENTRY *CacheEntry;
+ BLOCK_IO_CACHE_ENTRY *NewCacheEntry;
+
+ if (BlockIoCache == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!BlockIoCache->CacheInitialized) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: Lba %lld\n", Lba));
+
+ CacheList = &BlockIoCache->CacheList;
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+ if (BlockIoCache->CacheCount < BlockIoCache->CacheSize) {
+ BlockInfo = &BlockIoCache->CacheData[BlockIoCache->CacheCount];
+ BlockInfo->Data = Buffer;
+ BlockInfo->Lba = Lba;
+
+ BlockIoCache->CacheCount++;
+
+ Status = GetNewCacheEntry (BlockInfo, &NewCacheEntry);
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+ } else {
+ CacheEntry = CR (CacheList->BackLink, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ RemoveEntryList (CacheList->BackLink);
+
+ BlockInfo = CacheEntry->BlockInfo;
+
+ BlockInfo->Lba = Lba;
+ FreePool (BlockInfo->Data);
+ BlockInfo->Data = Buffer;
+
+ NewCacheEntry = CacheEntry;
+ }
+#ifdef BIO_CACHE_DEBUG
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: insert new cache entry (LBA %lld)\n", BlockInfo->Lba));
+#endif
+ InsertHeadList (CacheList, &NewCacheEntry->Link);
+
+ return EFI_SUCCESS;
+
+ERROR:
+ if (NewCacheEntry != NULL) {
+ FreePool (NewCacheEntry);
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheAdd (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *CacheList;
+ UINTN CacheBlocksNo;
+ LIST_ENTRY *Link;
+ EFI_STATUS Status;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+ BLOCK_IO_CACHE_ENTRY *CacheEntry;
+ BLOCK_IO_CACHE_ENTRY *NewCacheEntry;
+
+ if (BlockIoCache == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!BlockIoCache->CacheInitialized) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: Lba %lld NumberOfBlocks %d\n", Lba, NumberOfBlocks));
+
+ CacheList = &BlockIoCache->CacheList;
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+ for (;;) {
+ for (Link = GetFirstNode (CacheList); !IsNull (CacheList, Link);
+ Link = GetNextNode (CacheList, Link)) {
+ CacheEntry = CR (Link, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ if (CacheEntry->BlockInfo->Lba == Lba) {
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: LBA %lld is already cached\n", CacheEntry->BlockInfo->Lba));
+ RemoveEntryList (Link);
+ InsertHeadList (CacheList, &CacheEntry->Link);
+ goto NEXT_LBA;
+ }
+ }
+
+ NewCacheEntry = NULL;
+ if (BlockIoCache->CacheCount < BlockIoCache->CacheSize) {
+ BlockInfo = &BlockIoCache->CacheData[BlockIoCache->CacheCount];
+ BlockInfo->Data = Buffer;
+ BlockInfo->Lba = Lba;
+
+ BlockIoCache->CacheCount++;
+
+ Status = GetNewCacheEntry (BlockInfo, &NewCacheEntry);
+ if (EFI_ERROR (Status)) {
+ goto ERROR;
+ }
+ } else {
+ CacheEntry = CR (CacheList->BackLink, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ RemoveEntryList (CacheList->BackLink);
+
+ BlockInfo = CacheEntry->BlockInfo;
+ BlockInfo->Lba = Lba;
+ CopyMem (BlockInfo->Data, Buffer, EFI_PAGE_SIZE);
+
+ NewCacheEntry = CacheEntry;
+ }
+#ifdef BIO_CACHE_DEBUG
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: insert new cache entry (LBA %lld)\n", BlockInfo->Lba));
+#endif
+ InsertHeadList (CacheList, &NewCacheEntry->Link);
+
+ NEXT_LBA:
+ if (--NumberOfBlocks == 0) {
+ break;
+ }
+ Buffer = (VOID *)((UINTN)Buffer + EFI_PAGE_SIZE);
+ Lba += CacheBlocksNo;
+ }
+
+ return EFI_SUCCESS;
+
+ERROR:
+ if (NewCacheEntry != NULL) {
+ FreePool (NewCacheEntry);
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheInvalidate (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache,
+ IN EFI_LBA CacheLba,
+ IN UINTN CacheNumberOfBlocks,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN VOID *Buffer
+ )
+{
+ LIST_ENTRY *CacheList;
+ LIST_ENTRY *Link;
+ BLOCK_IO_CACHE_ENTRY *CacheEntry;
+ BLOCK_IO_CACHE_DATA *BlockInfo;
+ UINTN DataOffset;
+ UINTN BufferOffset;
+ UINTN CacheBlocksNo;
+ UINTN BlocksToCopy;
+
+ if (BlockIoCache == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!BlockIoCache->CacheInitialized || BlockIoCache->CacheCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_ERROR,
+ "BlockIoCache: CacheLba %lld CacheNumberOfBlocks %d Lba %lld NumberOfBlocks %d\n",
+ CacheLba, CacheNumberOfBlocks, Lba, NumberOfBlocks));
+
+ CacheList = &BlockIoCache->CacheList;
+ CacheBlocksNo = NR_CACHE_BLOCKS (BlockIoCache);
+ BufferOffset = 0;
+ while (NumberOfBlocks > 0) {
+ CacheEntry = NULL;
+ BlockInfo = NULL;
+ for (Link = GetFirstNode (CacheList); !IsNull (CacheList, Link);
+ Link = GetNextNode (CacheList, Link)) {
+ CacheEntry = CR (Link, BLOCK_IO_CACHE_ENTRY, Link, BLOCK_IO_CACHE_ENTRY_SIGNATURE);
+ BlockInfo = CacheEntry->BlockInfo;
+ if (BlockInfo->Lba == CacheLba) {
+ break;
+ }
+ }
+
+ if ((Lba - CacheLba) + NumberOfBlocks > CacheBlocksNo) {
+ BlocksToCopy = CacheBlocksNo - (Lba - CacheLba);
+ } else {
+ BlocksToCopy = NumberOfBlocks;
+ }
+
+ if (IsNull (CacheList, Link)) {
+ goto NEXT_LBA;
+ }
+
+ DEBUG ((DEBUG_ERROR, "BlockIoCache: invalidate LBA %lld\n", Lba));
+
+ if ((Lba & (CacheBlocksNo - 1)) != 0) {
+ DataOffset = (Lba - CacheLba) * BlockIoCache->BlockSize;
+ } else {
+ DataOffset = 0;
+ }
+
+ CopyMem (
+ (VOID *)((UINTN)BlockInfo->Data + DataOffset),
+ (VOID *)((UINTN)Buffer + BufferOffset),
+ BlocksToCopy * BlockIoCache->BlockSize
+ );
+ RemoveEntryList (Link);
+ InsertHeadList (CacheList, &CacheEntry->Link);
+
+ NEXT_LBA:
+ BufferOffset += BlocksToCopy * BlockIoCache->BlockSize;
+ NumberOfBlocks -= BlocksToCopy;
+ Lba += BlocksToCopy;
+ CacheLba += CacheBlocksNo;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+BlockIoCacheCleanup (
+ IN OUT BLOCK_IO_CACHE *BlockIoCache
+ )
+{
+ //
+ // TODO: implement me
+ //
+ return EFI_SUCCESS;
+}
diff --git a/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf
new file mode 100644
index 0000000000..0129ffea24
--- /dev/null
+++ b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf
@@ -0,0 +1,28 @@
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BlockIoCacheLib
+ MODULE_UNI_FILE = BlockIoCacheLib.uni
+ FILE_GUID = 710AE701-2C25-4202-A647-979963A76DA4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = BlockIoCacheLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BlockIoCacheLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ MemoryAllocationLib
+ BaseLib
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdBlockIoCacheSize ## CONSUMES
diff --git a/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.uni b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.uni
new file mode 100644
index 0000000000..d042becfae
--- /dev/null
+++ b/MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.uni
@@ -0,0 +1,14 @@
+// /** @file
+// <Module brief description>
+//
+// <Module full description>
+//
+// <Copyright notice>
+//
+// <license>
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Block I/O Cache"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides cache for block devices."
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index 7ab0cbbcfb..00548cdff0 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -1844,6 +1844,8 @@
# @Prompt Fixed Debug Message Print Level.
gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel|0xFFFFFFFF|UINT32|0x30001016
+ gEfiMdePkgTokenSpaceGuid.PcdBlockIoCacheSize|0x0100|UINT16|0x30001020
+
[PcdsFixedAtBuild,PcdsPatchableInModule]
## Indicates the maximum length of unicode string used in the following
# BaseLib functions: StrLen(), StrSize(), StrCmp(), StrnCmp(), StrCpy(), StrnCpy()<BR><BR>
diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc
index 7fe9e6bb4a..994df02ab5 100644
--- a/MdePkg/MdePkg.dsc
+++ b/MdePkg/MdePkg.dsc
@@ -132,6 +132,8 @@
MdePkg/Library/SmmLibNull/SmmLibNull.inf
MdePkg/Library/BaseExtractGuidedSectionLib/BaseExtractGuidedSectionLib.inf
+ MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf
+
[Components.IA32, Components.X64]
MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
MdePkg/Library/BaseMemoryLibMmx/BaseMemoryLibMmx.inf
diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
index fa37b1e4da..cf01eb7286 100644
--- a/OvmfPkg/OvmfPkgX64.dsc
+++ b/OvmfPkg/OvmfPkgX64.dsc
@@ -151,6 +151,8 @@
OrderedCollectionLib|MdePkg/Library/BaseOrderedCollectionRedBlackTreeLib/BaseOrderedCollectionRedBlackTreeLib.inf
XenHypercallLib|OvmfPkg/Library/XenHypercallLib/XenHypercallLib.inf
+ BlockIoCacheLib|MdePkg/Library/BlockIoCacheLib/BlockIoCacheLib.inf
+
[LibraryClasses.common]
!if $(SECURE_BOOT_ENABLE) == TRUE
BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf