diff options
author | Feng Tian <feng.tian@intel.com> | 2015-06-03 03:08:59 +0000 |
---|---|---|
committer | erictian <erictian@Edk2> | 2015-06-03 03:08:59 +0000 |
commit | 51492422806c7d9cc932e8d27f1e32bab7ac7cf0 (patch) | |
tree | 65b8756eb3a6e75dcc6beb517c7a3527da8a4001 /MdeModulePkg/Bus/Ata | |
parent | 5930f541b7e8540d259cbf4febc41d3e636bbbea (diff) | |
download | edk2-51492422806c7d9cc932e8d27f1e32bab7ac7cf0.zip edk2-51492422806c7d9cc932e8d27f1e32bab7ac7cf0.tar.gz edk2-51492422806c7d9cc932e8d27f1e32bab7ac7cf0.tar.bz2 |
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
Diffstat (limited to 'MdeModulePkg/Bus/Ata')
-rw-r--r-- | MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c index e5beea6..420ad27 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);
}
|