As it was clarified at the analysis, it not simply spam. Probably it is a bug.
Function CUSBRequest:: InitDescriptor() (reactos\drivers\usb\usbehci\usb_request.cpp) prepares descriptors (use physical address). Function MmGetPhysicalAddress(), used for this purpose, failed when switch threads. One of decisions of this problem - to use physical addresses instead of the virtual. At once structure MDL is followed by the list of pages of physical memory. It can be used in the present state of affairs.
As experiment, I added one function (the incorporated copy functions BuildControlTransferQueueHead, BuildTransferDescriptorChain and InitDescriptor) in which refused from MmGetPhysicalAddress.
This function is caused only when Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL ! = 0 (InitializeWithIrp ()).
If Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL == 0 former function BuildBulkInterruptTransferQueueHead is caused.
Added function - BuildBulkInterruptTransferDataQueueHead ()
Code: Select all
NTSTATUS
CUSBRequest::BuildBulkInterruptTransferDataQueueHead(PQUEUE_HEAD * OutHead)
{
NTSTATUS Status;
PQUEUE_HEAD QueueHead;
PQUEUE_TRANSFER_DESCRIPTOR FirstDescriptor = NULL;
PQUEUE_TRANSFER_DESCRIPTOR LastDescriptor = NULL;
PQUEUE_TRANSFER_DESCRIPTOR CurrentDescriptor;
ULONG TransferSize;
ULONG TransferBufferOffset = 0;
ULONG MaxPacketSize = 0;
ULONG MaxTransferLength;
UCHAR DataToggle;
PHYSICAL_ADDRESS Address;
ULONG_PTR PfnArray;
ULONG PageNumber;
ULONG MAX_TRANSFER; // const?
DPRINT("BuildBulkInterruptTransferDataQueueHead\n");
MAX_TRANSFER = 1 * PAGE_SIZE; // FIXME. Use 4 * PAGE_SIZE at max for each new request
Status = CreateQueueHead(&QueueHead); // Allocate the queue head
DPRINT1("QueueHead - %p, Addr - %x, CurrentThread - %p, CurrentIrql - %x\n", QueueHead, QueueHead->PhysicalAddr, PsGetCurrentThread(), KeGetCurrentIrql());
if ( !NT_SUCCESS(Status) ) return STATUS_INSUFFICIENT_RESOURCES; // failed to allocate queue heads
// sanity checks
PC_ASSERT(QueueHead);
PC_ASSERT(m_TransferBufferLength);
PC_ASSERT(m_EndpointDescriptor);
MaxTransferLength = min(MAX_TRANSFER, m_TransferBufferLength - m_TransferBufferLengthCompleted);
if ( m_EndpointDescriptor ) // is there an endpoint descriptor
MaxPacketSize = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize; // use endpoint packet size
if ( MaxPacketSize )
TransferSize = min(MaxTransferLength - TransferBufferOffset, MaxPacketSize); // transfer size is minimum available buffer or endpoint size
else
TransferSize = MaxTransferLength - TransferBufferOffset; // use available buffer
ASSERT(TransferSize); // sanity check
// build bulk transfer descriptor chain
do
{
Status = CreateDescriptor(&CurrentDescriptor); // allocate transfer descriptor
if ( !NT_SUCCESS(Status) ) return STATUS_INSUFFICIENT_RESOURCES; // failed to allocate transfer descriptor
PfnArray = (ULONG_PTR)MmGetMdlPfnArray(m_TransferBufferMDL);
if ( m_TransferBufferLength >= PAGE_SIZE ) // if transfer size >= 4096 (1 and more pages)
{
PageNumber = (m_TransferBufferLengthCompleted >> PAGE_SHIFT) & 0x0000001F; // 0x3F for 0x40000 (0x1F for 0x10000)
DPRINT("PageNumber - %x\n", PageNumber);
if ( *(PULONG)((PULONG)PfnArray + PageNumber) > 1 )
{
if ( (PageNumber == 0) && (m_TransferBufferMDL->ByteOffset > 0) )
Address.LowPart = ((*(PULONG)PfnArray) << PAGE_SHIFT) + m_TransferBufferMDL->ByteOffset;
else
Address.LowPart = ((*(PULONG)((PULONG)PfnArray + PageNumber)) << PAGE_SHIFT);
}
else
{
DPRINT1("PhysAdr < 0x1000\n"); //??
}
}
else // if transfer size < 4096 (< 1 page)
{
if ( m_TransferBufferMDL->ByteOffset > 0 )
Address.LowPart = ((*(PULONG)PfnArray) << PAGE_SHIFT) + m_TransferBufferMDL->ByteOffset;
else
Address.LowPart = ((*(PULONG)PfnArray) << PAGE_SHIFT);
}
if ( Address.LowPart == 0 )
{
DumpQueueHead(QueueHead);
return STATUS_UNSUCCESSFUL; // Status = STATUS_UNSUCCESSFUL;
}
// init transfer descriptor
CurrentDescriptor->Token.Bits.PIDCode = InternalGetPidDirection();
CurrentDescriptor->Token.Bits.TotalBytesToTransfer = 0;
CurrentDescriptor->Token.Bits.DataToggle = DataToggle = m_EndpointDescriptor->DataToggle;
// use physical address
CurrentDescriptor->BufferPointer[0] = Address.LowPart + TransferBufferOffset;
CurrentDescriptor->ExtendedBufferPointer[0] = 0; // Address.HighPart;
DPRINT1("CurrentDescriptor->BufferPointer[0] - %p\n", CurrentDescriptor->BufferPointer[0]);
// increment transfer bytes
CurrentDescriptor->Token.Bits.TotalBytesToTransfer += TransferSize;
CurrentDescriptor->TotalBytesToTransfer += TransferSize;
TransferBufferOffset += TransferSize; // adjust offset
InsertTailList(&QueueHead->TransferDescriptorListHead, &CurrentDescriptor->DescriptorEntry); // insert into queue head
if ( LastDescriptor )
{
// link to current descriptor
LastDescriptor->NextPointer = CurrentDescriptor->PhysicalAddr;
LastDescriptor = CurrentDescriptor;
}
else
{
LastDescriptor = FirstDescriptor = CurrentDescriptor; // first descriptor in chain
}
DataToggle = !DataToggle; // flip data toggle
if ( MaxTransferLength == TransferBufferOffset ) break; // end reached
} while ( TRUE );
LastDescriptor = CurrentDescriptor; // store last descriptor
m_EndpointDescriptor->DataToggle = DataToggle; // save data toggle
m_TransferBufferLengthCompleted += TransferBufferOffset; // move to next offset
// init queue head
QueueHead->EndPointCharacteristics.DeviceAddress = GetDeviceAddress();
QueueHead->EndPointCharacteristics.EndPointNumber = m_EndpointDescriptor->EndPointDescriptor.bEndpointAddress & 0x0F;
QueueHead->EndPointCharacteristics.MaximumPacketLength = m_EndpointDescriptor->EndPointDescriptor.wMaxPacketSize;
QueueHead->NextPointer = FirstDescriptor->PhysicalAddr;
QueueHead->CurrentLinkPointer = FirstDescriptor->PhysicalAddr;
QueueHead->AlternateNextPointer = TERMINATE_POINTER;
ASSERT(QueueHead->EndPointCharacteristics.DeviceAddress);
ASSERT(QueueHead->EndPointCharacteristics.EndPointNumber);
ASSERT(QueueHead->EndPointCharacteristics.MaximumPacketLength);
ASSERT(QueueHead->NextPointer);
LastDescriptor->Token.Bits.InterruptOnComplete = TRUE; // interrupt on last descriptor
*OutHead = QueueHead; // store result
//DumpQueueHead(QueueHead); // dump status
return STATUS_SUCCESS; // done
}
I seem now is relieved of "spam"