]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/AtaAtapiPassThru: ensure PRDT of IDE is in 64K boundary
authorFeng Tian <feng.tian@intel.com>
Wed, 3 Jun 2015 03:08:59 +0000 (03:08 +0000)
committererictian <erictian@Edk2>
Wed, 3 Jun 2015 03:08:59 +0000 (03:08 +0000)
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

MdeModulePkg/Bus/Ata/AtaAtapiPassThru/IdeMode.c

index e5beea65a22d1489613eb4987db133b71d3a3998..420ad273dc3cea2a0ffdee58102799cbff524ca6 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Header file for AHCI mode of ATA host controller.\r
 \r
-  Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -1525,7 +1525,7 @@ AtaUdmaInOut (
   UINTN                         PrdTableSize;\r
   EFI_PHYSICAL_ADDRESS          PrdTableMapAddr;\r
   VOID                          *PrdTableMap;\r
-  EFI_ATA_DMA_PRD               *PrdBaseAddr;\r
+  EFI_PHYSICAL_ADDRESS          PrdTableBaseAddr;\r
   EFI_ATA_DMA_PRD               *TempPrdBaseAddr;\r
   UINTN                         PrdTableNum;\r
 \r
@@ -1543,12 +1543,17 @@ AtaUdmaInOut (
   EFI_PCI_IO_PROTOCOL           *PciIo;\r
   EFI_TPL                       OldTpl;\r
 \r
+  UINTN                         AlignmentMask;\r
+  UINTN                         RealPageCount;\r
+  EFI_PHYSICAL_ADDRESS          BaseAddr;\r
+  EFI_PHYSICAL_ADDRESS          BaseMapAddr;\r
 \r
   Status        = EFI_SUCCESS;\r
-  PrdBaseAddr   = NULL;\r
   PrdTableMap   = NULL;\r
   BufferMap     = NULL;\r
   PageCount     = 0;\r
+  RealPageCount = 0;\r
+  BaseAddr      = 0;\r
   PciIo         = Instance->PciIo;\r
 \r
   if ((PciIo == NULL) || (IdeRegisters == NULL) || (DataBuffer == NULL) || (AtaCommandBlock == NULL)) {\r
@@ -1606,40 +1611,56 @@ AtaUdmaInOut (
 \r
     //\r
     // Allocate buffer for PRD table initialization.\r
+    // Note Ide Bus Master spec said the descriptor table must be aligned on a 4 byte\r
+    // boundary and the table cannot cross a 64K boundary in memory.\r
     //\r
-    PageCount = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    PageCount     = EFI_SIZE_TO_PAGES (PrdTableSize);\r
+    RealPageCount = PageCount + EFI_SIZE_TO_PAGES (SIZE_64KB);\r
+\r
+    //\r
+    // Make sure that PageCount plus EFI_SIZE_TO_PAGES (SIZE_64KB) does not overflow.\r
+    //\r
+    ASSERT (RealPageCount > PageCount);\r
+\r
     Status    = PciIo->AllocateBuffer (\r
                          PciIo,\r
                          AllocateAnyPages,\r
                          EfiBootServicesData,\r
-                         PageCount,\r
-                         (VOID **)&PrdBaseAddr,\r
+                         RealPageCount,\r
+                         (VOID **)&BaseAddr,\r
                          0\r
                          );\r
     if (EFI_ERROR (Status)) {\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    ByteCount = EFI_PAGES_TO_SIZE (PageCount);\r
+    ByteCount = EFI_PAGES_TO_SIZE (RealPageCount);\r
     Status    = PciIo->Map (\r
                          PciIo,\r
                          EfiPciIoOperationBusMasterCommonBuffer,\r
-                         PrdBaseAddr,\r
+                         (VOID*)(UINTN)BaseAddr,\r
                          &ByteCount,\r
-                         &PrdTableMapAddr,\r
+                         &BaseMapAddr,\r
                          &PrdTableMap\r
                          );\r
-    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (PageCount))) {\r
+    if (EFI_ERROR (Status) || (ByteCount != EFI_PAGES_TO_SIZE (RealPageCount))) {\r
       //\r
       // If the data length actually mapped is not equal to the requested amount,\r
       // it means the DMA operation may be broken into several discontinuous smaller chunks.\r
       // Can't handle this case.\r
       //\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    ZeroMem ((VOID *) ((UINTN) PrdBaseAddr), ByteCount);\r
+    ZeroMem ((VOID *) ((UINTN) BaseAddr), ByteCount);\r
+\r
+    //\r
+    // Calculate the 64K align address as PRD Table base address.\r
+    //\r
+    AlignmentMask    = SIZE_64KB - 1;\r
+    PrdTableBaseAddr = ((UINTN) BaseAddr + AlignmentMask) & ~AlignmentMask;\r
+    PrdTableMapAddr  = ((UINTN) BaseMapAddr + AlignmentMask) & ~AlignmentMask;\r
 \r
     //\r
     // Map the host address of DataBuffer to DMA master address.\r
@@ -1661,7 +1682,7 @@ AtaUdmaInOut (
                          );\r
     if (EFI_ERROR (Status) || (ByteCount != DataLength)) {\r
       PciIo->Unmap (PciIo, PrdTableMap);\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
@@ -1675,7 +1696,7 @@ AtaUdmaInOut (
     // Fill the PRD table with appropriate bus master address of data buffer and data length.\r
     //\r
     ByteRemaining   = ByteCount;\r
-    TempPrdBaseAddr = PrdBaseAddr;\r
+    TempPrdBaseAddr = (EFI_ATA_DMA_PRD*)(UINTN)PrdTableBaseAddr;\r
     while (ByteRemaining != 0) {\r
       if (ByteRemaining <= 0x10000) {\r
         TempPrdBaseAddr->RegionBaseAddr = (UINT32) ((UINTN) BufferMapAddress);\r
@@ -1731,8 +1752,8 @@ AtaUdmaInOut (
     if (Task != NULL) {\r
       Task->Map            = BufferMap;\r
       Task->TableMap       = PrdTableMap;\r
-      Task->MapBaseAddress = PrdBaseAddr;\r
-      Task->PageCount      = PageCount;\r
+      Task->MapBaseAddress = (EFI_ATA_DMA_PRD*)(UINTN)BaseAddr;\r
+      Task->PageCount      = RealPageCount;\r
       Task->IsStart        = TRUE;\r
     }\r
 \r
@@ -1819,7 +1840,7 @@ Exit:
       PciIo->Unmap (PciIo, Task->Map);\r
     } else {\r
       PciIo->Unmap (PciIo, PrdTableMap);\r
-      PciIo->FreeBuffer (PciIo, PageCount, PrdBaseAddr);\r
+      PciIo->FreeBuffer (PciIo, RealPageCount, (VOID*)(UINTN)BaseAddr);\r
       PciIo->Unmap (PciIo, BufferMap);\r
     }\r
 \r