Users of this device might pass data pointers which are above 4G, in which case
we can't pass the pointers directly to the controller because the descriptors
contain 32-bit pointers.

Instead of failing the request, use below-4G memory to support the request.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Nikita Leshenko <nikita.leshche...@oracle.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.w...@oracle.com>
Reviewed-by: Aaron Young <aaron.yo...@oracle.com>
Reviewed-by: Liran Alon <liran.a...@oracle.com>
---
 OvmfPkg/MptScsiDxe/MptScsi.c | 50 +++++++++++++++++++++++++++++++-----
 1 file changed, 44 insertions(+), 6 deletions(-)

diff --git a/OvmfPkg/MptScsiDxe/MptScsi.c b/OvmfPkg/MptScsiDxe/MptScsi.c
index 0b888a1c56..9e803735d2 100644
--- a/OvmfPkg/MptScsiDxe/MptScsi.c
+++ b/OvmfPkg/MptScsiDxe/MptScsi.c
@@ -160,6 +160,9 @@ typedef struct {
   UINT8                           MaxTarget;
   MPT_SCSI_IO_ERROR_REPLY         IoErrorReply;
   MPT_SCSI_REQUEST_WITH_SG        IoRequest;
+
+  UINT8                           SenseBuffer[MAX_UINT8];
+  UINT8                           DataBuffer[0x2000];
 } MPT_SCSI_DEV;
 
 #define MPT_SCSI_FROM_PASS_THRU(PassThruPtr) \
@@ -323,6 +326,18 @@ MptScsiPopulateRequest (
     return EFI_INVALID_PARAMETER;
   }
 
+  // If the buffers are above 4G, make sure that we can buffer that data
+  if ((UINTN) Packet->InDataBuffer > MAX_UINT32 &&
+      Packet->InTransferLength > sizeof (Dev->DataBuffer)) {
+    Packet->InTransferLength = sizeof (Dev->DataBuffer);
+    return EFI_BAD_BUFFER_SIZE;
+  }
+  if ((UINTN) Packet->OutDataBuffer > MAX_UINT32 &&
+      Packet->OutTransferLength > sizeof (Dev->DataBuffer)) {
+    Packet->OutTransferLength = sizeof (Dev->DataBuffer);
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
   if (Packet->InTransferLength > MPT_SG_ENTRY_SIMPLE_MAX_LENGTH) {
     Packet->InTransferLength = MPT_SG_ENTRY_SIMPLE_MAX_LENGTH;
     return EFI_BAD_BUFFER_SIZE;
@@ -343,8 +358,14 @@ MptScsiPopulateRequest (
   CopyMem (Request->Header.CDB, Packet->Cdb, Packet->CdbLength);
 
   Request->Header.SenseBufferLength = Packet->SenseDataLength;
-  ASSERT ((UINTN) Packet->SenseData <= MAX_UINT32);
-  Request->Header.SenseBufferLowAddress = (UINT32)(UINTN) Packet->SenseData;
+  // If sense is above 4G, we can't pass it directly to controller
+  if ((UINTN) Packet->SenseData > MAX_UINT32) {
+    // Zero because the controller doesn't report the resulting sense data size
+    ZeroMem (&Dev->SenseBuffer, Packet->SenseDataLength);
+    Request->Header.SenseBufferLowAddress = (UINT32)(UINTN) &Dev->SenseBuffer;
+  } else {
+    Request->Header.SenseBufferLowAddress = (UINT32)(UINTN) Packet->SenseData;
+  }
 
   Request->Sg.EndOfList = 1;
   Request->Sg.EndOfBuffer = 1;
@@ -356,15 +377,24 @@ MptScsiPopulateRequest (
   case EFI_EXT_SCSI_DATA_DIRECTION_READ:
     Request->Header.DataLength = Packet->InTransferLength;
     Request->Sg.Length = Packet->InTransferLength;
-    ASSERT ((UINTN) Packet->InDataBuffer <= MAX_UINT32);
-    Request->Sg.DataBufferAddress = (UINT32)(UINTN) Packet->InDataBuffer;
+    // If buffer is above 4G, we can't pass it directly to controller
+    if ((UINTN) Packet->InDataBuffer > MAX_UINT32) {
+      Request->Sg.DataBufferAddress = (UINT32)(UINTN) &Dev->DataBuffer;
+    } else {
+      Request->Sg.DataBufferAddress = (UINT32)(UINTN) Packet->InDataBuffer;
+    }
     Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_READ;
     break;
   case EFI_EXT_SCSI_DATA_DIRECTION_WRITE:
     Request->Header.DataLength = Packet->OutTransferLength;
     Request->Sg.Length = Packet->OutTransferLength;
-    ASSERT ((UINTN) Packet->OutDataBuffer <= MAX_UINT32);
-    Request->Sg.DataBufferAddress = (UINT32)(UINTN) Packet->OutDataBuffer;
+    // If buffer is above 4G, we can't pass it directly to controller
+    if ((UINTN) Packet->OutDataBuffer > MAX_UINT32) {
+      CopyMem (&Dev->DataBuffer, Packet->OutDataBuffer, 
Packet->OutTransferLength);
+      Request->Sg.DataBufferAddress = (UINT32)(UINTN) &Dev->DataBuffer;
+    } else {
+      Request->Sg.DataBufferAddress = (UINT32)(UINTN) Packet->OutDataBuffer;
+    }
     Request->Header.Control = MPT_SCSIIO_REQUEST_CONTROL_TXDIR_WRITE;
     Request->Sg.BufferContainsData = 1;
     break;
@@ -451,6 +481,14 @@ MptScsiHandleReply (
   OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
   )
 {
+  if ((UINTN) Packet->SenseData > MAX_UINT32) {
+    CopyMem (Packet->SenseData, &Dev->SenseBuffer, Packet->SenseDataLength);
+  }
+  if ((UINTN) Packet->InDataBuffer > MAX_UINT32 &&
+      Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) {
+    CopyMem (Packet->InDataBuffer, &Dev->DataBuffer, Packet->InTransferLength);
+  }
+
   if (Reply == Request->Header.MessageContext) {
     // Everything is good
     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK;
-- 
2.20.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to