mirror of
https://github.com/arehnman/yttrium-virtio-gpu.git
synced 2026-10-31 02:05:04 +00:00
https://bugzilla.redhat.com/show_bug.cgi?id=1872384 At least one dump when IOCTL sent from work item in tcpip protocol stack when the control queue is deleted (actually all the queues are deleted). Signed-off-by: Yuri Benditovich <[email protected]>
160 lines
4.6 KiB
C++
160 lines
4.6 KiB
C++
#include "ndis56common.h"
|
|
#include "virtio_net.h"
|
|
#include "kdebugprint.h"
|
|
#include "Trace.h"
|
|
#ifdef NETKVM_WPP_ENABLED
|
|
#include "ParaNdis_CX.tmh"
|
|
#endif
|
|
|
|
CParaNdisCX::CParaNdisCX(PPARANDIS_ADAPTER Context)
|
|
{
|
|
m_Context = Context;
|
|
m_ControlData.Virtual = nullptr;
|
|
KeInitializeDpc(&m_DPC, MiniportMSIInterruptCXDpc, m_Context);
|
|
}
|
|
|
|
CParaNdisCX::~CParaNdisCX()
|
|
{
|
|
if (m_ControlData.Virtual != nullptr)
|
|
{
|
|
ParaNdis_FreePhysicalMemory(m_Context, &m_ControlData);
|
|
}
|
|
}
|
|
|
|
bool CParaNdisCX::Create(UINT DeviceQueueIndex)
|
|
{
|
|
m_queueIndex = (u16)DeviceQueueIndex;
|
|
|
|
if (!ParaNdis_InitialAllocatePhysicalMemory(m_Context, 512, &m_ControlData))
|
|
{
|
|
DPrintf(0, "CParaNdisCX::Create - ParaNdis_InitialAllocatePhysicalMemory failed for %u\n",
|
|
DeviceQueueIndex);
|
|
m_ControlData.Virtual = nullptr;
|
|
return false;
|
|
}
|
|
|
|
m_Context->m_CxStateMachine.Start();
|
|
|
|
CreatePath();
|
|
|
|
return m_VirtQueue.Create(DeviceQueueIndex,
|
|
&m_Context->IODevice,
|
|
m_Context->MiniportHandle);
|
|
}
|
|
|
|
BOOLEAN CParaNdisCX::SendControlMessage(
|
|
UCHAR cls,
|
|
UCHAR cmd,
|
|
PVOID buffer1,
|
|
ULONG size1,
|
|
PVOID buffer2,
|
|
ULONG size2,
|
|
int levelIfOK
|
|
)
|
|
{
|
|
BOOLEAN bOK = FALSE;
|
|
CLockedContext<CNdisSpinLock> autoLock(m_Lock);
|
|
|
|
if (m_ControlData.Virtual && m_ControlData.size > (size1 + size2 + 16) &&
|
|
m_VirtQueue.IsValid() && m_VirtQueue.CanTouchHardware())
|
|
{
|
|
struct VirtIOBufferDescriptor sg[4];
|
|
PUCHAR pBase = (PUCHAR)m_ControlData.Virtual;
|
|
PHYSICAL_ADDRESS phBase = m_ControlData.Physical;
|
|
ULONG offset = 0;
|
|
UINT nOut = 1;
|
|
|
|
((virtio_net_ctrl_hdr *)pBase)->class_of_command = cls;
|
|
((virtio_net_ctrl_hdr *)pBase)->cmd = cmd;
|
|
sg[0].physAddr = phBase;
|
|
sg[0].length = sizeof(virtio_net_ctrl_hdr);
|
|
offset += sg[0].length;
|
|
offset = (offset + 3) & ~3;
|
|
if (size1)
|
|
{
|
|
NdisMoveMemory(pBase + offset, buffer1, size1);
|
|
sg[nOut].physAddr = phBase;
|
|
sg[nOut].physAddr.QuadPart += offset;
|
|
sg[nOut].length = size1;
|
|
offset += size1;
|
|
offset = (offset + 3) & ~3;
|
|
nOut++;
|
|
}
|
|
if (size2)
|
|
{
|
|
NdisMoveMemory(pBase + offset, buffer2, size2);
|
|
sg[nOut].physAddr = phBase;
|
|
sg[nOut].physAddr.QuadPart += offset;
|
|
sg[nOut].length = size2;
|
|
offset += size2;
|
|
offset = (offset + 3) & ~3;
|
|
nOut++;
|
|
}
|
|
sg[nOut].physAddr = phBase;
|
|
sg[nOut].physAddr.QuadPart += offset;
|
|
sg[nOut].length = sizeof(virtio_net_ctrl_ack);
|
|
*(virtio_net_ctrl_ack *)(pBase + offset) = VIRTIO_NET_ERR;
|
|
|
|
if (0 <= m_VirtQueue.AddBuf(sg, nOut, 1, (PVOID)1, NULL, 0))
|
|
{
|
|
UINT len;
|
|
void *p;
|
|
m_Context->m_CxStateMachine.RegisterOutstandingItem();
|
|
|
|
m_VirtQueue.Kick();
|
|
p = m_VirtQueue.GetBuf(&len);
|
|
for (int i = 0; i < 500000 && !p; ++i)
|
|
{
|
|
UINT interval = 1;
|
|
NdisStallExecution(interval);
|
|
p = m_VirtQueue.GetBuf(&len);
|
|
}
|
|
m_Context->m_CxStateMachine.UnregisterOutstandingItem();
|
|
|
|
if (!p)
|
|
{
|
|
DPrintf(0, "%s - ERROR: get_buf failed\n", __FUNCTION__);
|
|
}
|
|
else if (len != sizeof(virtio_net_ctrl_ack))
|
|
{
|
|
DPrintf(0, "%s - ERROR: wrong len %d\n", __FUNCTION__, len);
|
|
}
|
|
else if (*(virtio_net_ctrl_ack *)(pBase + offset) != VIRTIO_NET_OK)
|
|
{
|
|
DPrintf(0, "%s - ERROR: error %d returned for class %d\n", __FUNCTION__, *(virtio_net_ctrl_ack *)(pBase + offset), cls);
|
|
}
|
|
else
|
|
{
|
|
// everything is OK
|
|
DPrintf(levelIfOK, "%s OK(%d.%d,buffers of %d and %d) \n", __FUNCTION__, cls, cmd, size1, size2);
|
|
bOK = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPrintf(0, "%s - ERROR: add_buf failed\n", __FUNCTION__);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPrintf(0, "%s (buffer %d,%d) - ERROR: message too LARGE\n", __FUNCTION__, size1, size2);
|
|
}
|
|
return bOK;
|
|
}
|
|
|
|
NDIS_STATUS CParaNdisCX::SetupMessageIndex(u16 vector)
|
|
{
|
|
DPrintf(0, "[%s] Using message %u for controls\n", __FUNCTION__, vector);
|
|
|
|
virtio_set_config_vector(&m_Context->IODevice, vector);
|
|
|
|
return CParaNdisAbstractPath::SetupMessageIndex(vector);
|
|
}
|
|
|
|
bool CParaNdisCX::FireDPC(ULONG messageId)
|
|
{
|
|
DPrintf(0, "[%s] message %u\n", __FUNCTION__, messageId);
|
|
KeInsertQueueDpc(&m_DPC, NULL, NULL);
|
|
return TRUE;
|
|
}
|