> -----Original Message----- > From: Albecki, Mateusz > Sent: Tuesday, June 25, 2019 5:44 PM > To: devel@edk2.groups.io > Cc: Albecki, Mateusz; Wu, Hao A > Subject: [PATCH v2] MdeModulePkg/UfsPassThruDxe: Fix unaligned data > transfer handling > > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1341 > > Since UFS specification requirs the data buffer specified > in PRDT to be DWORD aligned in size we had a code in > UfsInitUtpPrdt that aligned the data buffer by rounding down > the buffer size to DWORD boundary. This meant that for SCSI > commands that wanted to perform unaligned data transfer(such as > SENSE command) we specified to small buffer for the data to fit > and transfer was aborted. This change introduces code that allocates > auxiliary DWORD aligned data buffer for unaligned transfer. Device > transfers data to aligned buffer and when data transfer is over driver > copies data from aligned buffer to data buffer passed by user. > > Cc: Hao A Wu <hao.a...@intel.com> > Signed-off-by: Mateusz Albecki <mateusz.albe...@intel.com> > --- > MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h | 2 + > .../Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c | 198 +++++++++++++++- > ----- > 2 files changed, 146 insertions(+), 54 deletions(-) > > diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h > b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h > index 6c98b3a76a..9b68db5ffe 100644 > --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h > +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h > @@ -92,6 +92,8 @@ typedef struct { > UINT32 CmdDescSize; > VOID *CmdDescHost; > VOID *CmdDescMapping; > + VOID *AlignedDataBuf; > + UINTN AlignedDataBufSize; > VOID *DataBufMapping; > > EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet; > diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c > b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c > index 4b93821f38..4f41183504 100644 > --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c > +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c > @@ -394,17 +394,13 @@ UfsInitUtpPrdt ( > UINT8 *Remaining; > UINTN PrdtNumber; > > - if ((BufferSize & (BIT0 | BIT1)) != 0) { > - BufferSize &= ~(BIT0 | BIT1); > - DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not > dword-aligned!\n", BufferSize)); > - } > + ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0); > + ASSERT ((BufferSize & (BIT1 | BIT0)) == 0); > > if (BufferSize == 0) { > return EFI_SUCCESS; > } > > - ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0); > - > RemainingLen = BufferSize; > Remaining = Buffer; > PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + > UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD); > @@ -1317,6 +1313,139 @@ Exit: > return Status; > } > > +/** > + Cleanup data buffers after data transfer. This function > + also takes care to copy all data to user memory pool for > + unaligned data transfers. > + > + @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA > + @param[in] TransReq Pointer to the transfer request > +**/ > +VOID > +UfsReconcileDataTransferBuffer ( > + IN UFS_PASS_THRU_PRIVATE_DATA *Private, > + IN UFS_PASS_THRU_TRANS_REQ *TransReq > + ) > +{ > + if (TransReq->DataBufMapping != NULL) { > + Private->UfsHostController->Unmap ( > + Private->UfsHostController, > + TransReq->DataBufMapping > + ); > + } > + > + // > + // Check if unaligned transfer was performed. If it was and we read > + // data from device copy memory to user data buffers before cleanup. > + // The assumption is if auxiliary aligned data buffer is not NULL then > + // unaligned transfer has been performed. > + // > + if (TransReq->AlignedDataBuf != NULL) { > + if (TransReq->Packet->DataDirection == > EFI_EXT_SCSI_DATA_DIRECTION_READ) { > + CopyMem (TransReq->Packet->InDataBuffer, TransReq- > >AlignedDataBuf, TransReq->Packet->InTransferLength); > + } > + // > + // Wipe out the transfer buffer in case it contains sensitive data. > + // > + ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize); > + FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES > (TransReq->AlignedDataBufSize)); > + TransReq->AlignedDataBuf = NULL; > + } > +} > + > +/** > + Prepare data buffer for transfer > + > + @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA > + @param[in, out] TransReq Pointer to the transfer request > + > + @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer > + @retval EFI_SUCCESS Buffer ready for transfer > +**/ > +EFI_STATUS > +UfsPrepareDataTransferBuffer ( > + IN UFS_PASS_THRU_PRIVATE_DATA *Private, > + IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq > + ) > +{ > + EFI_STATUS Status; > + VOID *DataBuf; > + UINT32 DataLen; > + UINTN MapLength; > + EFI_PHYSICAL_ADDRESS DataBufPhyAddr; > + EDKII_UFS_HOST_CONTROLLER_OPERATION Flag; > + UTP_TR_PRD *PrdtBase; > + > + DataBufPhyAddr = (EFI_PHYSICAL_ADDRESS) NULL; > + DataBuf = NULL; > + > + // > + // For unaligned data transfers we allocate auxiliary DWORD aligned > memory pool. > + // When command is finished auxiliary memory pool is copied into actual > user memory. > + // This is requiered to assure data transfer safety(DWORD alignment > required by UFS spec.) > + // > + if (TransReq->Packet->DataDirection == > EFI_EXT_SCSI_DATA_DIRECTION_READ) { > + if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq- > >Packet->InTransferLength % 4 != 0)) { > + DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq- > >Packet->InTransferLength % 4)); > + DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4); > + if (DataBuf == NULL) { > + return EFI_DEVICE_ERROR; > + } > + ZeroMem (DataBuf, DataLen); > + TransReq->AlignedDataBuf = DataBuf; > + TransReq->AlignedDataBufSize = DataLen; > + } else { > + DataLen = TransReq->Packet->InTransferLength; > + DataBuf = TransReq->Packet->InDataBuffer; > + } > + Flag = EdkiiUfsHcOperationBusMasterWrite; > + } else { > + if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq- > >Packet->OutTransferLength % 4 != 0)) { > + DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq- > >Packet->OutTransferLength % 4)); > + DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4); > + if (DataBuf == NULL) { > + return EFI_DEVICE_ERROR; > + } > + CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq- > >Packet->OutTransferLength); > + TransReq->AlignedDataBuf = DataBuf; > + TransReq->AlignedDataBufSize = DataLen; > + } else { > + DataLen = TransReq->Packet->OutTransferLength; > + DataBuf = TransReq->Packet->OutDataBuffer; > + } > + Flag = EdkiiUfsHcOperationBusMasterRead; > + } > + > + if (DataLen != 0) { > + MapLength = DataLen; > + Status = Private->UfsHostController->Map ( > + Private->UfsHostController, > + Flag, > + DataBuf, > + &MapLength, > + &DataBufPhyAddr, > + &TransReq->DataBufMapping > + ); > + > + if (EFI_ERROR (Status) || (DataLen != MapLength)) { > + if (TransReq->AlignedDataBuf != NULL) {
Hello, I will also add ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize); here before freeing the auxiliary buffer when pushing the patch. Please help to raise if there is any concern. With that, Reviewed-by: Hao A Wu <hao.a...@intel.com> Best Regards, Hao Wu > + FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES > (TransReq->AlignedDataBufSize)); > + TransReq->AlignedDataBuf = NULL; > + } > + return EFI_DEVICE_ERROR; > + } > + } > + > + // > + // Fill PRDT table of Command UPIU for executed SCSI cmd. > + // > + PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + > ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof > (UTP_RESPONSE_UPIU))); > + ASSERT (PrdtBase != NULL); > + UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen); > + > + return EFI_SUCCESS; > +} > + > /** > Sends a UFS-supported SCSI Request Packet to a UFS device that is > attached to the UFS host controller. > > @@ -1353,24 +1482,19 @@ UfsExecScsiCmds ( > UTP_RESPONSE_UPIU *Response; > UINT16 SenseDataLen; > UINT32 ResTranCount; > - VOID *DataBuf; > - EFI_PHYSICAL_ADDRESS DataBufPhyAddr; > - UINT32 DataLen; > - UINTN MapLength; > - EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; > - EDKII_UFS_HOST_CONTROLLER_OPERATION Flag; > - UTP_TR_PRD *PrdtBase; > EFI_TPL OldTpl; > UFS_PASS_THRU_TRANS_REQ *TransReq; > + EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; > > - TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ)); > + TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ)); > if (TransReq == NULL) { > return EFI_OUT_OF_RESOURCES; > } > > TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG; > TransReq->TimeoutRemain = Packet->Timeout; > - DataBufPhyAddr = 0; > + TransReq->Packet = Packet; > + > UfsHc = Private->UfsHostController; > // > // Find out which slot of transfer request list is available. > @@ -1399,44 +1523,16 @@ UfsExecScsiCmds ( > > TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + > TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD); > > - if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { > - DataBuf = Packet->InDataBuffer; > - DataLen = Packet->InTransferLength; > - Flag = EdkiiUfsHcOperationBusMasterWrite; > - } else { > - DataBuf = Packet->OutDataBuffer; > - DataLen = Packet->OutTransferLength; > - Flag = EdkiiUfsHcOperationBusMasterRead; > - } > - > - if (DataLen != 0) { > - MapLength = DataLen; > - Status = UfsHc->Map ( > - UfsHc, > - Flag, > - DataBuf, > - &MapLength, > - &DataBufPhyAddr, > - &TransReq->DataBufMapping > - ); > - > - if (EFI_ERROR (Status) || (DataLen != MapLength)) { > - goto Exit1; > - } > + Status = UfsPrepareDataTransferBuffer (Private, TransReq); > + if (EFI_ERROR (Status)) { > + goto Exit1; > } > - // > - // Fill PRDT table of Command UPIU for executed SCSI cmd. > - // > - PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + > ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof > (UTP_RESPONSE_UPIU))); > - ASSERT (PrdtBase != NULL); > - UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen); > > // > // Insert the async SCSI cmd to the Async I/O list > // > if (Event != NULL) { > OldTpl = gBS->RaiseTPL (TPL_NOTIFY); > - TransReq->Packet = Packet; > TransReq->CallerEvent = Event; > InsertTailList (&Private->Queue, &TransReq->TransferList); > gBS->RestoreTPL (OldTpl); > @@ -1515,9 +1611,7 @@ Exit: > > UfsStopExecCmd (Private, TransReq->Slot); > > - if (TransReq->DataBufMapping != NULL) { > - UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); > - } > + UfsReconcileDataTransferBuffer (Private, TransReq); > > Exit1: > if (TransReq->CmdDescMapping != NULL) { > @@ -1532,7 +1626,6 @@ Exit1: > return Status; > } > > - > /** > Sent UIC DME_LINKSTARTUP command to start the link startup procedure. > > @@ -2100,7 +2193,6 @@ UfsControllerStop ( > return EFI_SUCCESS; > } > > - > /** > Internal helper function which will signal the caller event and clean up > resources. > @@ -2132,9 +2224,7 @@ SignalCallerEvent ( > > UfsStopExecCmd (Private, TransReq->Slot); > > - if (TransReq->DataBufMapping != NULL) { > - UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); > - } > + UfsReconcileDataTransferBuffer (Private, TransReq); > > if (TransReq->CmdDescMapping != NULL) { > UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping); > -- > 2.14.1.windows.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#42840): https://edk2.groups.io/g/devel/message/42840 Mute This Topic: https://groups.io/mt/32201696/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-