summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFeng Tian <feng.tian@intel.com>2015-06-03 03:08:59 +0000
committererictian <erictian@Edk2>2015-06-03 03:08:59 +0000
commit51492422806c7d9cc932e8d27f1e32bab7ac7cf0 (patch)
tree65b8756eb3a6e75dcc6beb517c7a3527da8a4001
parent5930f541b7e8540d259cbf4febc41d3e636bbbea (diff)
downloadedk2-platforms-51492422806c7d9cc932e8d27f1e32bab7ac7cf0.tar.xz
MdeModulePkg/AtaAtapiPassThru: ensure PRDT of IDE is in 64K boundary
Follow IDE BUS Master spec to ensure the PRDT table not cross 64k boundary in memory. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17552 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r--MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
index e5beea65a2..420ad273dc 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c
@@ -1,7 +1,7 @@
/** @file
Header file for AHCI mode of ATA host controller.
- Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -1525,7 +1525,7 @@ AtaUdmaInOut (
UINTN PrdTableSize;
EFI_PHYSICAL_ADDRESS PrdTableMapAddr;
VOID *PrdTableMap;
- EFI_ATA_DMA_PRD *PrdBaseAddr;
+ EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;
EFI_ATA_DMA_PRD *TempPrdBaseAddr;
UINTN PrdTableNum;
@@ -1543,12 +1543,17 @@ AtaUdmaInOut (
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_TPL OldTpl;
+ UINTN AlignmentMask;
+ UINTN RealPageCount;
+ EFI_PHYSICAL_ADDRESS BaseAddr;
+ EFI_PHYSICAL_ADDRESS BaseMapAddr;
Status = EFI_SUCCESS;
- PrdBaseAddr = NULL;
PrdTableMap = NULL;
BufferMap = NULL;
PageCount = 0;
+ RealPageCount = 0;
+ BaseAddr = 0;
PciIo = Instance->PciIo;
if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {
@@ -1606,40 +1611,56 @@ AtaUdmaInOut (
//
// Allocate buffer for PRD table initialization.
+ // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte
+ // boundary and the table cannot cross a 64K boundary in memory.
//
- PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);
+ PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);
+ RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);
+
+ //
+ // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.
+ //
+ ASSERT (RealPageCount > PageCount);
+
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
- PageCount,
- (VOID **)&PrdBaseAddr,
+ RealPageCount,
+ (VOID **)&BaseAddr,
0
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
- ByteCount = EFI_PAGES_TO_SIZE (PageCount);
+ ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);
Status = PciIo->Map (
PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
- PrdBaseAddr,
+ (VOID*)(UINTN)BaseAddr,
&ByteCount,
- &PrdTableMapAddr,
+ &BaseMapAddr,
&PrdTableMap
);
- if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {
+ if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {
//
// If the data length actually mapped is not equal to the requested amount,
// it means the DMA operation may be broken into several discontinuous smaller chunks.
// Can't handle this case.
//
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
return EFI_OUT_OF_RESOURCES;
}
- ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);
+ ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);
+
+ //
+ // Calculate the 64K align address as PRD Table base address.
+ //
+ AlignmentMask = SIZE_64KB - 1;
+ PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;
+ PrdTableMapAddr = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;
//
// Map the host address of DataBuffer to DMA master address.
@@ -1661,7 +1682,7 @@ AtaUdmaInOut (
);
if (EFI_ERROR (Status) || (ByteCount != DataLength)) {
PciIo->Unmap (PciIo, PrdTableMap);
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
return EFI_OUT_OF_RESOURCES;
}
@@ -1675,7 +1696,7 @@ AtaUdmaInOut (
// Fill the PRD table with appropriate bus master address of data buffer and data length.
//
ByteRemaining = ByteCount;
- TempPrdBaseAddr = PrdBaseAddr;
+ TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;
while (ByteRemaining != 0) {
if (ByteRemaining <= 0x10000) {
TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
@@ -1731,8 +1752,8 @@ AtaUdmaInOut (
if (Task != NULL) {
Task->Map = BufferMap;
Task->TableMap = PrdTableMap;
- Task->MapBaseAddress = PrdBaseAddr;
- Task->PageCount = PageCount;
+ Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;
+ Task->PageCount = RealPageCount;
Task->IsStart = TRUE;
}
@@ -1819,7 +1840,7 @@ Exit:
PciIo->Unmap (PciIo, Task->Map);
} else {
PciIo->Unmap (PciIo, PrdTableMap);
- PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
+ PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
PciIo->Unmap (PciIo, BufferMap);
}