* Re: [edk2-devel] [PATCH] MdeModulePkg/UfsPassThruDxe: Fix unaligned data transfer handling
2019-06-24 11:38 ` [edk2-devel] [PATCH] MdeModulePkg/UfsPassThruDxe: Fix unaligned data transfer handling Albecki, Mateusz
@ 2019-06-25 1:44 ` Wu, Hao A
0 siblings, 0 replies; 2+ messages in thread
From: Wu, Hao A @ 2019-06-25 1:44 UTC (permalink / raw)
To: Albecki, Mateusz, devel@edk2.groups.io
> -----Original Message-----
> From: Albecki, Mateusz
> Sent: Monday, June 24, 2019 7:39 PM
> To: devel@edk2.groups.io; Albecki, Mateusz
> Cc: Wu, Hao A
> Subject: RE: [edk2-devel] [PATCH] MdeModulePkg/UfsPassThruDxe: Fix
> unaligned data transfer handling
>
> Test info:
>
> Tested UFS enumeration in EFI shell and it is passing on real HW with
> Samsung device.
> Tested read/write to UFS device in EFI shell.
Thanks for the information.
Two comments below with regard to the cleanup of the auxiliary buffer.
With these handled,
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
>
> > -----Original Message-----
> > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> > Albecki, Mateusz
> > Sent: Friday, June 21, 2019 5:20 PM
> > To: devel@edk2.groups.io
> > Cc: Albecki, Mateusz <mateusz.albecki@intel.com>; Wu, Hao A
> > <hao.a.wu@intel.com>
> > Subject: [edk2-devel] [PATCH] 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.wu@intel.com>
> > Signed-off-by: Mateusz Albecki <mateusz.albecki@intel.com>
> > ---
> > MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThru.h | 2 +
> > .../Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c | 194
> +++++++++++++++-
> > -----
> > 2 files changed, 142 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..6eb50f09ac 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,135 @@ 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);
> > + }
Please help to wipe out the content in the 'TransReq->AlignedDataBuf'
before freeing. It may contain information that is not intended to remain
in memory.
> > + 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) {
> > + FreePages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES
> > (TransReq->AlignedDataBufSize));
I think FreeAlignedPages() should be used here.
Also, please help to wipe out the content in 'TransReq->AlignedDataBuf'.
Best Regards,
Hao Wu
> > + 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 +1478,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 +1519,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 +1607,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 +1622,6 @@ Exit1:
> > return Status;
> > }
> >
> > -
> > /**
> > Sent UIC DME_LINKSTARTUP command to start the link startup procedure.
> >
> > @@ -2100,7 +2189,6 @@ UfsControllerStop (
> > return EFI_SUCCESS;
> > }
> >
> > -
> > /**
> > Internal helper function which will signal the caller event and clean up
> > resources.
> > @@ -2132,9 +2220,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
> >
> > --------------------------------------------------------------------
> >
> > Intel Technology Poland sp. z o.o.
> > ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII
> > Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP
> 957-
> > 07-52-316 | Kapital zakladowy 200.000 PLN.
> >
> > Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego
> > adresata i moze zawierac informacje poufne. W razie przypadkowego
> > otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale
> > jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest
> > zabronione.
> > This e-mail and any attachments may contain confidential material for the
> > sole use of the intended recipient(s). If you are not the intended recipient,
> > please contact the sender and delete all copies; any review or distribution
> by
> > others is strictly prohibited.
> >
> >
> >
^ permalink raw reply [flat|nested] 2+ messages in thread