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
This commit is contained in:
parent
5930f541b7
commit
5149242280
|
@ -1,7 +1,7 @@
|
||||||
/** @file
|
/** @file
|
||||||
Header file for AHCI mode of ATA host controller.
|
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
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -1525,7 +1525,7 @@ AtaUdmaInOut (
|
||||||
UINTN PrdTableSize;
|
UINTN PrdTableSize;
|
||||||
EFI_PHYSICAL_ADDRESS PrdTableMapAddr;
|
EFI_PHYSICAL_ADDRESS PrdTableMapAddr;
|
||||||
VOID *PrdTableMap;
|
VOID *PrdTableMap;
|
||||||
EFI_ATA_DMA_PRD *PrdBaseAddr;
|
EFI_PHYSICAL_ADDRESS PrdTableBaseAddr;
|
||||||
EFI_ATA_DMA_PRD *TempPrdBaseAddr;
|
EFI_ATA_DMA_PRD *TempPrdBaseAddr;
|
||||||
UINTN PrdTableNum;
|
UINTN PrdTableNum;
|
||||||
|
|
||||||
|
@ -1543,12 +1543,17 @@ AtaUdmaInOut (
|
||||||
EFI_PCI_IO_PROTOCOL *PciIo;
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
||||||
EFI_TPL OldTpl;
|
EFI_TPL OldTpl;
|
||||||
|
|
||||||
|
UINTN AlignmentMask;
|
||||||
|
UINTN RealPageCount;
|
||||||
|
EFI_PHYSICAL_ADDRESS BaseAddr;
|
||||||
|
EFI_PHYSICAL_ADDRESS BaseMapAddr;
|
||||||
|
|
||||||
Status = EFI_SUCCESS;
|
Status = EFI_SUCCESS;
|
||||||
PrdBaseAddr = NULL;
|
|
||||||
PrdTableMap = NULL;
|
PrdTableMap = NULL;
|
||||||
BufferMap = NULL;
|
BufferMap = NULL;
|
||||||
PageCount = 0;
|
PageCount = 0;
|
||||||
|
RealPageCount = 0;
|
||||||
|
BaseAddr = 0;
|
||||||
PciIo = Instance->PciIo;
|
PciIo = Instance->PciIo;
|
||||||
|
|
||||||
if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {
|
if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {
|
||||||
|
@ -1606,40 +1611,56 @@ AtaUdmaInOut (
|
||||||
|
|
||||||
//
|
//
|
||||||
// Allocate buffer for PRD table initialization.
|
// 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 (
|
Status = PciIo->AllocateBuffer (
|
||||||
PciIo,
|
PciIo,
|
||||||
AllocateAnyPages,
|
AllocateAnyPages,
|
||||||
EfiBootServicesData,
|
EfiBootServicesData,
|
||||||
PageCount,
|
RealPageCount,
|
||||||
(VOID **)&PrdBaseAddr,
|
(VOID **)&BaseAddr,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
return EFI_OUT_OF_RESOURCES;
|
return EFI_OUT_OF_RESOURCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteCount = EFI_PAGES_TO_SIZE (PageCount);
|
ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);
|
||||||
Status = PciIo->Map (
|
Status = PciIo->Map (
|
||||||
PciIo,
|
PciIo,
|
||||||
EfiPciIoOperationBusMasterCommonBuffer,
|
EfiPciIoOperationBusMasterCommonBuffer,
|
||||||
PrdBaseAddr,
|
(VOID*)(UINTN)BaseAddr,
|
||||||
&ByteCount,
|
&ByteCount,
|
||||||
&PrdTableMapAddr,
|
&BaseMapAddr,
|
||||||
&PrdTableMap
|
&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,
|
// 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.
|
// it means the DMA operation may be broken into several discontinuous smaller chunks.
|
||||||
// Can't handle this case.
|
// Can't handle this case.
|
||||||
//
|
//
|
||||||
PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
|
PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
|
||||||
return EFI_OUT_OF_RESOURCES;
|
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.
|
// Map the host address of DataBuffer to DMA master address.
|
||||||
|
@ -1661,7 +1682,7 @@ AtaUdmaInOut (
|
||||||
);
|
);
|
||||||
if (EFI_ERROR (Status) || (ByteCount != DataLength)) {
|
if (EFI_ERROR (Status) || (ByteCount != DataLength)) {
|
||||||
PciIo->Unmap (PciIo, PrdTableMap);
|
PciIo->Unmap (PciIo, PrdTableMap);
|
||||||
PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
|
PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
|
||||||
return EFI_OUT_OF_RESOURCES;
|
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.
|
// Fill the PRD table with appropriate bus master address of data buffer and data length.
|
||||||
//
|
//
|
||||||
ByteRemaining = ByteCount;
|
ByteRemaining = ByteCount;
|
||||||
TempPrdBaseAddr = PrdBaseAddr;
|
TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;
|
||||||
while (ByteRemaining != 0) {
|
while (ByteRemaining != 0) {
|
||||||
if (ByteRemaining <= 0x10000) {
|
if (ByteRemaining <= 0x10000) {
|
||||||
TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
|
TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);
|
||||||
|
@ -1731,8 +1752,8 @@ AtaUdmaInOut (
|
||||||
if (Task != NULL) {
|
if (Task != NULL) {
|
||||||
Task->Map = BufferMap;
|
Task->Map = BufferMap;
|
||||||
Task->TableMap = PrdTableMap;
|
Task->TableMap = PrdTableMap;
|
||||||
Task->MapBaseAddress = PrdBaseAddr;
|
Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;
|
||||||
Task->PageCount = PageCount;
|
Task->PageCount = RealPageCount;
|
||||||
Task->IsStart = TRUE;
|
Task->IsStart = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1819,7 +1840,7 @@ Exit:
|
||||||
PciIo->Unmap (PciIo, Task->Map);
|
PciIo->Unmap (PciIo, Task->Map);
|
||||||
} else {
|
} else {
|
||||||
PciIo->Unmap (PciIo, PrdTableMap);
|
PciIo->Unmap (PciIo, PrdTableMap);
|
||||||
PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);
|
PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);
|
||||||
PciIo->Unmap (PciIo, BufferMap);
|
PciIo->Unmap (PciIo, BufferMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue