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