Files
yttrium-virtio-gpu/viogpu/common/viogpu_queue.cpp
T
Ake Rehnman 95fd452dfd CtrlQueue: Add fences to
CreateResource
CreateResource3D
ResFlush
TransferToHost2D
TransferToHost3D
AttachBacking
DetachBacking
2025-11-09 07:27:50 +01:00

1433 lines
38 KiB
C++

/*
* Copyright (C) 2019-2020 Red Hat, Inc.
*
* Written By: Vadim Rozenfeld <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of their contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "viogpu_queue.h"
#include "baseobj.h"
#if !DBG
#include "viogpu_queue.tmh"
#endif
static BOOLEAN BuildSGElement(VirtIOBufferDescriptor *sg, PVOID buf, ULONG size)
{
if (size != 0 && MmIsAddressValid(buf))
{
sg->length = min(size, PAGE_SIZE);
sg->physAddr = MmGetPhysicalAddress(buf);
return TRUE;
}
return FALSE;
}
static void NotifyEventCompleteCB(void *ctx)
{
KeSetEvent((PKEVENT)ctx, IO_NO_INCREMENT, FALSE);
}
VioGpuQueue::VioGpuQueue()
{
m_pBuf = NULL;
m_Index = (UINT)-1;
m_pVIODevice = NULL;
m_pVirtQueue = NULL;
KeInitializeSpinLock(&m_SpinLock);
}
VioGpuQueue::~VioGpuQueue()
{
Close();
}
void VioGpuQueue::Close(void)
{
KIRQL SavedIrql;
Lock(&SavedIrql);
m_pVirtQueue = NULL;
Unlock(SavedIrql);
}
BOOLEAN VioGpuQueue::Init(_In_ VirtIODevice *pVIODevice, _In_ struct virtqueue *pVirtQueue, _In_ UINT index)
{
if ((pVIODevice == NULL) || (pVirtQueue == NULL))
{
return FALSE;
}
m_pVIODevice = pVIODevice;
m_pVirtQueue = pVirtQueue;
m_Index = index;
EnableInterrupt();
return TRUE;
}
_IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_saves_global_(OldIrql, Irql) _IRQL_raises_(DISPATCH_LEVEL) void VioGpuQueue::
Lock(KIRQL *Irql)
{
KIRQL SavedIrql = KeGetCurrentIrql();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s at IRQL %d\n", __FUNCTION__, SavedIrql));
if (SavedIrql < DISPATCH_LEVEL)
{
KeAcquireSpinLock(&m_SpinLock, &SavedIrql);
}
else if (SavedIrql == DISPATCH_LEVEL)
{
KeAcquireSpinLockAtDpcLevel(&m_SpinLock);
}
else
{
VioGpuDbgBreak();
}
*Irql = SavedIrql;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
_IRQL_requires_(DISPATCH_LEVEL) _IRQL_restores_global_(OldIrql, Irql) void VioGpuQueue::Unlock(KIRQL Irql)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s at IRQL %d\n", __FUNCTION__, Irql));
if (Irql < DISPATCH_LEVEL)
{
KeReleaseSpinLock(&m_SpinLock, Irql);
}
else
{
KeReleaseSpinLockFromDpcLevel(&m_SpinLock);
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
PAGED_CODE_SEG_BEGIN
UINT VioGpuQueue::QueryAllocation()
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
USHORT NumEntries;
ULONG RingSize, HeapSize;
NTSTATUS status = virtio_query_queue_allocation(m_pVIODevice, m_Index, &NumEntries, &RingSize, &HeapSize);
if (!NT_SUCCESS(status))
{
DbgPrint(TRACE_LEVEL_FATAL,
("[%s] virtio_query_queue_allocation(%d) failed with error %x\n", __FUNCTION__, m_Index, status));
return 0;
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return NumEntries;
}
PAGED_CODE_SEG_END
PAGED_CODE_SEG_BEGIN
BOOLEAN CtrlQueue::GetDisplayInfo(PGPU_VBUFFER buf, UINT id, PULONG xres, PULONG yres)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RESP_DISP_INFO resp = (PGPU_RESP_DISP_INFO)buf->resp_buf;
if (resp->hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO)
{
DbgPrint(TRACE_LEVEL_VERBOSE, (" %s type = %x: disabled\n", __FUNCTION__, resp->hdr.type));
return FALSE;
}
if (resp->pmodes[id].enabled)
{
DbgPrint(TRACE_LEVEL_VERBOSE,
("output %d: %dx%d+%d+%d\n",
id,
resp->pmodes[id].r.width,
resp->pmodes[id].r.height,
resp->pmodes[id].r.x,
resp->pmodes[id].r.y));
*xres = resp->pmodes[id].r.width;
*yres = resp->pmodes[id].r.height;
}
else
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("output %d: disabled\n", id));
return FALSE;
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
BOOLEAN CtrlQueue::AskDisplayInfo(PGPU_VBUFFER *buf)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CTRL_HDR cmd;
PGPU_VBUFFER vbuf;
PGPU_RESP_DISP_INFO resp_buf;
KEVENT event;
NTSTATUS status;
resp_buf = reinterpret_cast<PGPU_RESP_DISP_INFO>(new (NonPagedPoolNx) BYTE[sizeof(GPU_RESP_DISP_INFO)]);
if (!resp_buf)
{
DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_DISP_INFO)));
return FALSE;
}
cmd = (PGPU_CTRL_HDR)AllocCmdResp(&vbuf, sizeof(GPU_CTRL_HDR), resp_buf, sizeof(GPU_RESP_DISP_INFO));
RtlZeroMemory(cmd, sizeof(GPU_CTRL_HDR));
cmd->type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
KeInitializeEvent(&event, NotificationEvent, FALSE);
vbuf->complete_cb = NotifyEventCompleteCB;
vbuf->complete_ctx = &event;
vbuf->auto_release = false;
LARGE_INTEGER timeout = {0};
timeout.QuadPart = Int32x32To64(1000, -10000);
QueueBuffer(vbuf);
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
if (status == STATUS_TIMEOUT)
{
DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to ask display info\n"));
VioGpuDbgBreak();
}
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
BOOLEAN CtrlQueue::AskEdidInfo(PGPU_VBUFFER *buf, UINT id)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_GET_EDID cmd;
PGPU_VBUFFER vbuf;
PGPU_RESP_EDID resp_buf;
KEVENT event;
NTSTATUS status;
resp_buf = reinterpret_cast<PGPU_RESP_EDID>(new (NonPagedPoolNx) BYTE[sizeof(GPU_RESP_EDID)]);
if (!resp_buf)
{
DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_EDID)));
return FALSE;
}
cmd = (PGPU_CMD_GET_EDID)AllocCmdResp(&vbuf, sizeof(GPU_CMD_GET_EDID), resp_buf, sizeof(GPU_RESP_EDID));
RtlZeroMemory(cmd, sizeof(GPU_CMD_GET_EDID));
cmd->hdr.type = VIRTIO_GPU_CMD_GET_EDID;
cmd->scanout = id;
KeInitializeEvent(&event, NotificationEvent, FALSE);
vbuf->complete_cb = NotifyEventCompleteCB;
vbuf->complete_ctx = &event;
vbuf->auto_release = false;
LARGE_INTEGER timeout = {0};
timeout.QuadPart = Int32x32To64(1000, -10000);
QueueBuffer(vbuf);
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
if (status == STATUS_TIMEOUT)
{
DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to get edid info\n"));
VioGpuDbgBreak();
}
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
BOOLEAN CtrlQueue::GetEdidInfo(PGPU_VBUFFER buf, UINT id, PBYTE edid)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_GET_EDID cmd = (PGPU_CMD_GET_EDID)buf->buf;
PGPU_RESP_EDID resp = (PGPU_RESP_EDID)buf->resp_buf;
PUCHAR resp_edit = (PUCHAR)(resp->edid + (ULONGLONG)id * EDID_V1_BLOCK_SIZE);
if (resp->hdr.type != VIRTIO_GPU_RESP_OK_EDID)
{
DbgPrint(TRACE_LEVEL_VERBOSE, (" %s type = %x: disabled\n", __FUNCTION__, resp->hdr.type));
return FALSE;
}
if (cmd->scanout != id)
{
DbgPrint(TRACE_LEVEL_VERBOSE, (" %s invalid scaout = %x\n", __FUNCTION__, cmd->scanout));
return FALSE;
}
RtlCopyMemory(edid, resp_edit, EDID_RAW_BLOCK_SIZE);
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
return TRUE;
}
BOOLEAN CtrlQueue::AskCapsetInfo(PGPU_VBUFFER *buf, ULONG idx)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_GET_CASPSET_INFO cmd;
PGPU_VBUFFER vbuf;
PGPU_RESP_CAPSET_INFO resp_buf;
KEVENT event;
NTSTATUS status;
resp_buf = reinterpret_cast<PGPU_RESP_CAPSET_INFO>(new (NonPagedPoolNx) BYTE[sizeof(GPU_RESP_CAPSET_INFO)]);
if (!resp_buf)
{
DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_CAPSET_INFO)));
return FALSE;
}
cmd = (PGPU_CMD_GET_CASPSET_INFO)AllocCmdResp(&vbuf,
sizeof(GPU_CMD_GET_CAPSET_INFO),
resp_buf,
sizeof(GPU_RESP_CAPSET_INFO));
RtlZeroMemory(cmd, sizeof(GPU_CMD_GET_CAPSET_INFO));
cmd->hdr.type = VIRTIO_GPU_CMD_GET_CAPSET_INFO;
cmd->capset_index = idx;
cmd->padding = 0;
KeInitializeEvent(&event, NotificationEvent, FALSE);
vbuf->complete_cb = NotifyEventCompleteCB;
vbuf->complete_ctx = &event;
vbuf->auto_release = false;
LARGE_INTEGER timeout = {0};
timeout.QuadPart = Int32x32To64(1000, -10000);
QueueBuffer(vbuf);
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
if (status == STATUS_TIMEOUT)
{
DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to get capset info\n"));
VioGpuDbgBreak();
return FALSE;
}
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
BOOLEAN CtrlQueue::AskCapset(PGPU_VBUFFER *buf, ULONG capset_id, ULONG capset_size, ULONG capset_version)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_GET_CASPSET cmd;
PGPU_VBUFFER vbuf;
PGPU_RESP_CAPSET resp_buf;
KEVENT event;
NTSTATUS status;
int resp_size = sizeof(GPU_RESP_CAPSET) + capset_size;
resp_buf = reinterpret_cast<PGPU_RESP_CAPSET>(new (NonPagedPoolNx) BYTE[resp_size]);
if (!resp_buf)
{
DbgPrint(TRACE_LEVEL_ERROR, ("---> %s Failed allocate %d bytes\n", __FUNCTION__, sizeof(GPU_RESP_CAPSET_INFO)));
return FALSE;
}
cmd = (PGPU_CMD_GET_CASPSET)AllocCmdResp(&vbuf, sizeof(GPU_CMD_GET_CAPSET), resp_buf, resp_size);
RtlZeroMemory(cmd, sizeof(GPU_CMD_GET_CAPSET));
cmd->hdr.type = VIRTIO_GPU_CMD_GET_CAPSET;
cmd->capset_id = capset_id;
cmd->capset_version = capset_version;
KeInitializeEvent(&event, NotificationEvent, FALSE);
vbuf->complete_cb = NotifyEventCompleteCB;
vbuf->complete_ctx = &event;
vbuf->auto_release = false;
LARGE_INTEGER timeout = {0};
timeout.QuadPart = Int32x32To64(1000, -10000);
QueueBuffer(vbuf);
status = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &timeout);
if (status == STATUS_TIMEOUT)
{
DbgPrint(TRACE_LEVEL_FATAL, ("---> Failed to get capset\n"));
VioGpuDbgBreak();
return FALSE;
}
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
void CtrlQueue::CreateResource(UINT res_id, UINT format, UINT width, UINT height)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_CREATE_2D cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_CREATE_2D)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
cmd->resource_id = res_id;
cmd->format = format;
cmd->width = width;
cmd->height = height;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
// FIXME!!! if
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::CreateResource3D(UINT res_id, VIOGPU_RESOURCE_OPTIONS *options)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_RES_CREATE_3D cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_RES_CREATE_3D)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_3D;
cmd->res_id = res_id;
cmd->target = options->target;
cmd->format = options->format;
cmd->bind = options->bind;
cmd->width = options->width;
cmd->height = options->height;
cmd->depth = options->depth;
cmd->array_size = options->array_size;
cmd->last_level = options->last_level;
cmd->nr_samples = options->nr_samples;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
// FIXME!!! if
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::CreateCtx(UINT ctx_id, UINT context_init)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_CTX_CREATE cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_CTX_CREATE)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_CTX_CREATE;
cmd->hdr.ctx_id = ctx_id;
cmd->nlen = 0;
cmd->context_init = context_init;
// FIXME!!! if
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::DestroyCtx(UINT ctx_id)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_CTX_DESTROY cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_CTX_DESTROY)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_CTX_DESTROY;
cmd->hdr.ctx_id = ctx_id;
// FIXME!!! if
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::ResFlush(UINT res_id, UINT width, UINT height, UINT x, UINT y)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_FLUSH cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_FLUSH)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
cmd->resource_id = res_id;
cmd->r.width = width;
cmd->r.height = height;
cmd->r.x = x;
cmd->r.y = y;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::TransferToHost2D(UINT res_id, ULONG offset, UINT width, UINT height, UINT x, UINT y)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_TRANSF_TO_HOST_2D cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_TRANSF_TO_HOST_2D)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
cmd->resource_id = res_id;
cmd->offset = offset;
cmd->r.width = width;
cmd->r.height = height;
cmd->r.x = x;
cmd->r.y = y;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::TransferToHost3D(UINT res_id, GPU_BOX *box)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_TRANSFER_HOST_3D cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_TRANSFER_HOST_3D)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D;
cmd->resource_id = res_id;
cmd->offset = 0;
cmd->level = 0;
cmd->stride = 0;
cmd->layer_stride = 0;
memcpy(&cmd->box, box, sizeof(GPU_BOX));
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::AttachBacking(UINT res_id, PGPU_MEM_ENTRY ents, UINT nents)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_ATTACH_BACKING cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_ATTACH_BACKING)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
cmd->resource_id = res_id;
cmd->nr_entries = nents;
vbuf->data_buf = ents;
vbuf->data_size = sizeof(*ents) * nents;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::CtxResource(bool attach, UINT ctx_id, UINT res_id)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_CTX_RESOURCE cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_CTX_RESOURCE)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = attach ? VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE : VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE;
cmd->hdr.ctx_id = ctx_id;
cmd->resource_id = res_id;
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
PAGED_CODE_SEG_END
void CtrlQueue::SubmitCommand(void *cmdbuf, ULONG size, ULONG ctx_id, void (*complete_cb)(void *), void *complete_ctx)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_SUBMIT cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_SUBMIT)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_SUBMIT_3D;
cmd->size = size;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
cmd->hdr.ctx_id = ctx_id;
vbuf->data_buf = cmdbuf;
vbuf->data_size = size;
vbuf->complete_cb = complete_cb;
vbuf->complete_ctx = complete_ctx;
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::TransferHostCmd(bool to_host,
ULONG ctx_id,
VIOGPU_TRANSFER_CMD *options,
void (*complete_cb)(void *),
void *complete_ctx)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_CMD_TRANSFER_HOST_3D cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_CMD_TRANSFER_HOST_3D)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = to_host ? VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D : VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D;
cmd->resource_id = options->res_id;
cmd->box.x = options->box.x;
cmd->box.y = options->box.y;
cmd->box.z = options->box.z;
cmd->box.width = options->box.width;
cmd->box.height = options->box.height;
cmd->box.depth = options->box.depth;
cmd->offset = options->offset;
cmd->level = options->level;
cmd->stride = options->stride;
cmd->layer_stride = options->layer_stride;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
cmd->hdr.ctx_id = ctx_id;
vbuf->complete_cb = complete_cb;
vbuf->complete_ctx = complete_ctx;
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::DestroyResource(UINT res_id)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_UNREF cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_UNREF)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF;
cmd->resource_id = res_id;
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
void CtrlQueue::DetachBacking(UINT res_id)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_RES_DETACH_BACKING cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_RES_DETACH_BACKING)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING;
cmd->resource_id = res_id;
cmd->hdr.flags |= VIRTIO_GPU_FLAG_FENCE;
cmd->hdr.fence_id = InterlockedIncrement(&m_FenceIdr);
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
PVOID CtrlQueue::AllocCmdResp(PGPU_VBUFFER *buf, int cmd_sz, PVOID resp_buf, int resp_sz)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_VBUFFER vbuf;
vbuf = m_pBuf->GetBuf(cmd_sz, resp_sz, resp_buf);
ASSERT(vbuf);
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return vbuf ? vbuf->buf : NULL;
}
PVOID CtrlQueue::AllocCmd(PGPU_VBUFFER *buf, int sz)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
if (buf == NULL || sz == 0)
{
return NULL;
}
PGPU_VBUFFER vbuf = m_pBuf->GetBuf(sz, sizeof(GPU_CTRL_HDR), NULL);
ASSERT(vbuf);
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s vbuf = %p\n", __FUNCTION__, vbuf));
return vbuf ? vbuf->buf : NULL;
}
void CtrlQueue::SetScanout(UINT scan_id, UINT res_id, UINT width, UINT height, UINT x, UINT y)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_SET_SCANOUT cmd;
PGPU_VBUFFER vbuf;
cmd = (PGPU_SET_SCANOUT)AllocCmd(&vbuf, sizeof(*cmd));
RtlZeroMemory(cmd, sizeof(*cmd));
cmd->hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
cmd->resource_id = res_id;
cmd->scanout_id = scan_id;
cmd->r.width = width;
cmd->r.height = height;
cmd->r.x = x;
cmd->r.y = y;
// FIXME if
QueueBuffer(vbuf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
#define SGLIST_SIZE 256
UINT CtrlQueue::QueueBuffer(PGPU_VBUFFER buf)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
VirtIOBufferDescriptor sg[SGLIST_SIZE];
UINT sgleft = SGLIST_SIZE;
UINT outcnt = 0, incnt = 0;
UINT ret = 0;
KIRQL SavedIrql;
if (buf->size > PAGE_SIZE)
{
DbgPrint(TRACE_LEVEL_ERROR, ("<--> %s size is too big %d\n", __FUNCTION__, buf->size));
return 0;
}
if (BuildSGElement(&sg[outcnt + incnt], (PVOID)buf->buf, buf->size))
{
outcnt++;
sgleft--;
}
if (buf->data_size)
{
ULONG data_size = buf->data_size;
PVOID data_buf = (PVOID)buf->data_buf;
while (data_size)
{
if (BuildSGElement(&sg[outcnt + incnt], data_buf, data_size))
{
data_buf = (PVOID)((LONG_PTR)(data_buf) + PAGE_SIZE);
data_size -= min(data_size, PAGE_SIZE);
outcnt++;
sgleft--;
if (sgleft == 0)
{
DbgPrint(TRACE_LEVEL_ERROR, ("<--> %s no more sgelenamt spots left %d\n", __FUNCTION__, outcnt));
return 0;
}
}
}
}
if (buf->resp_size > PAGE_SIZE)
{
DbgPrint(TRACE_LEVEL_ERROR, ("<--> %s resp_size is too big %d\n", __FUNCTION__, buf->resp_size));
return 0;
}
if (buf->resp_size && (sgleft > 0))
{
if (BuildSGElement(&sg[outcnt + incnt], (PVOID)buf->resp_buf, buf->resp_size))
{
incnt++;
sgleft--;
}
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--> %s sgleft %d\n", __FUNCTION__, sgleft));
do
{
Lock(&SavedIrql);
ret = AddBuf(&sg[0], outcnt, incnt, buf, NULL, 0);
Kick();
Unlock(SavedIrql);
if (ret == 0)
{
break;
}
KeWaitForSingleObject(&m_CtrlQueueEvent, Executive, KernelMode, FALSE, NULL);
} while (ret);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s ret = %d\n", __FUNCTION__, ret));
return ret;
}
PGPU_VBUFFER CtrlQueue::DequeueBuffer(_Out_ UINT *len)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_VBUFFER buf = NULL;
KIRQL SavedIrql;
Lock(&SavedIrql);
buf = (PGPU_VBUFFER)GetBuf(len);
Unlock(SavedIrql);
if (buf == NULL)
{
*len = 0;
}
KeSetEvent(&m_CtrlQueueEvent, IO_NO_INCREMENT, FALSE);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return buf;
}
void VioGpuQueue::ReleaseBuffer(PGPU_VBUFFER buf)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
m_pBuf->FreeBuf(buf);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
BOOLEAN VioGpuBuf::Init(_In_ UINT cnt)
{
KIRQL OldIrql;
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
m_uCountMin = cnt;
for (UINT i = 0; i < cnt; ++i)
{
PGPU_VBUFFER pvbuf = reinterpret_cast<PGPU_VBUFFER>(new (NonPagedPoolNx) BYTE[VBUFFER_SIZE]);
// FIXME
RtlZeroMemory(pvbuf, VBUFFER_SIZE);
if (pvbuf)
{
KeAcquireSpinLock(&m_SpinLock, &OldIrql);
InsertTailList(&m_FreeBufs, &pvbuf->list_entry);
++m_uCount;
KeReleaseSpinLock(&m_SpinLock, OldIrql);
}
}
ASSERT(m_uCount == cnt);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return (m_uCount > 0);
}
void VioGpuBuf::Close(void)
{
KIRQL OldIrql;
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
KeAcquireSpinLock(&m_SpinLock, &OldIrql);
while (!IsListEmpty(&m_InUseBufs))
{
LIST_ENTRY *pListItem = RemoveHeadList(&m_InUseBufs);
if (pListItem)
{
PGPU_VBUFFER pvbuf = CONTAINING_RECORD(pListItem, GPU_VBUFFER, list_entry);
ASSERT(pvbuf);
if (pvbuf->resp_size > MAX_INLINE_RESP_SIZE)
{
delete[] reinterpret_cast<PBYTE>(pvbuf->resp_buf);
pvbuf->resp_buf = NULL;
pvbuf->resp_size = 0;
}
ASSERT(pvbuf->data_buf == NULL && pvbuf->data_size == 0);
delete[] reinterpret_cast<PBYTE>(pvbuf);
--m_uCount;
}
}
while (!IsListEmpty(&m_FreeBufs))
{
LIST_ENTRY *pListItem = RemoveHeadList(&m_FreeBufs);
if (pListItem)
{
PGPU_VBUFFER pbuf = CONTAINING_RECORD(pListItem, GPU_VBUFFER, list_entry);
ASSERT(pbuf);
if (pbuf->resp_buf && pbuf->resp_size > MAX_INLINE_RESP_SIZE)
{
delete[] reinterpret_cast<PBYTE>(pbuf->resp_buf);
pbuf->resp_buf = NULL;
pbuf->resp_size = 0;
}
if (pbuf->data_buf && pbuf->data_size)
{
delete[] reinterpret_cast<PBYTE>(pbuf->data_buf);
pbuf->data_buf = NULL;
pbuf->data_size = 0;
}
delete[] reinterpret_cast<PBYTE>(pbuf);
--m_uCount;
}
}
KeReleaseSpinLock(&m_SpinLock, OldIrql);
ASSERT(m_uCount == 0);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
PGPU_VBUFFER VioGpuBuf::GetBuf(_In_ int size, _In_ int resp_size, _In_opt_ void *resp_buf)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_VBUFFER pbuf = NULL;
PLIST_ENTRY pListItem = NULL;
KIRQL SavedIrql = KeGetCurrentIrql();
if (SavedIrql < DISPATCH_LEVEL)
{
KeAcquireSpinLock(&m_SpinLock, &SavedIrql);
}
else if (SavedIrql == DISPATCH_LEVEL)
{
KeAcquireSpinLockAtDpcLevel(&m_SpinLock);
}
else
{
VioGpuDbgBreak();
}
if (IsListEmpty(&m_FreeBufs))
{
pbuf = reinterpret_cast<PGPU_VBUFFER>(new (NonPagedPoolNx) BYTE[VBUFFER_SIZE]);
++m_uCount;
}
else
{
pListItem = RemoveHeadList(&m_FreeBufs);
pbuf = CONTAINING_RECORD(pListItem, GPU_VBUFFER, list_entry);
}
ASSERT(pbuf);
memset(pbuf, 0, VBUFFER_SIZE);
ASSERT(size <= MAX_INLINE_CMD_SIZE);
pbuf->buf = (char *)((ULONG_PTR)pbuf + sizeof(*pbuf));
pbuf->size = size;
pbuf->auto_release = true;
pbuf->resp_size = resp_size;
if (resp_size <= MAX_INLINE_RESP_SIZE)
{
ASSERT(resp_buf == NULL);
pbuf->resp_buf = (char *)((ULONG_PTR)pbuf->buf + size);
}
else
{
pbuf->resp_buf = (char *)resp_buf;
}
ASSERT(pbuf->resp_buf);
InsertTailList(&m_InUseBufs, &pbuf->list_entry);
if (SavedIrql < DISPATCH_LEVEL)
{
KeReleaseSpinLock(&m_SpinLock, SavedIrql);
}
else if (SavedIrql == DISPATCH_LEVEL)
{
KeReleaseSpinLockFromDpcLevel(&m_SpinLock);
}
else
{
VioGpuDbgBreak();
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s buf = %p\n", __FUNCTION__, pbuf));
return pbuf;
}
void VioGpuBuf::FreeBuf(_In_ PGPU_VBUFFER pbuf)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s buf = %p\n", __FUNCTION__, pbuf));
KIRQL SavedIrql = KeGetCurrentIrql();
if (SavedIrql < DISPATCH_LEVEL)
{
KeAcquireSpinLock(&m_SpinLock, &SavedIrql);
}
else if (SavedIrql == DISPATCH_LEVEL)
{
KeAcquireSpinLockAtDpcLevel(&m_SpinLock);
}
else
{
VioGpuDbgBreak();
}
RemoveEntryList(&pbuf->list_entry);
if (pbuf->resp_buf && pbuf->resp_size > MAX_INLINE_RESP_SIZE)
{
delete[] reinterpret_cast<PBYTE>(pbuf->resp_buf);
pbuf->resp_buf = NULL;
pbuf->resp_size = 0;
}
if (pbuf->data_buf && pbuf->data_size)
{
delete[] reinterpret_cast<PBYTE>(pbuf->data_buf);
pbuf->data_buf = NULL;
pbuf->data_size = 0;
}
if (m_uCount > m_uCountMin)
{
delete[] reinterpret_cast<PBYTE>(pbuf);
--m_uCount;
}
else
{
InsertTailList(&m_FreeBufs, &pbuf->list_entry);
}
if (SavedIrql < DISPATCH_LEVEL)
{
KeReleaseSpinLock(&m_SpinLock, SavedIrql);
}
else if (SavedIrql == DISPATCH_LEVEL)
{
KeReleaseSpinLockFromDpcLevel(&m_SpinLock);
}
else
{
VioGpuDbgBreak();
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
PAGED_CODE_SEG_BEGIN
VioGpuBuf::VioGpuBuf()
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
InitializeListHead(&m_FreeBufs);
InitializeListHead(&m_InUseBufs);
KeInitializeSpinLock(&m_SpinLock);
m_uCount = 0;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
VioGpuBuf::~VioGpuBuf()
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_FATAL, ("---> %s 0x%p\n", __FUNCTION__, this));
Close();
DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s\n", __FUNCTION__));
}
VioGpuMemSegment::VioGpuMemSegment(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
m_pSGList = NULL;
m_pVAddr = NULL;
m_pMdl = NULL;
m_bSystemMemory = FALSE;
m_bMapped = FALSE;
m_Size = 0;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
VioGpuMemSegment::~VioGpuMemSegment(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
Close();
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
BOOLEAN VioGpuMemSegment::Init(_In_ UINT size, _In_opt_ PPHYSICAL_ADDRESS pPAddr)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
ASSERT(size);
PVOID buf = NULL;
UINT pages = BYTES_TO_PAGES(size);
UINT sglsize = sizeof(SCATTER_GATHER_LIST) + (sizeof(SCATTER_GATHER_ELEMENT) * pages);
size = pages * PAGE_SIZE;
if ((pPAddr == NULL) || pPAddr->QuadPart == 0LL)
{
m_pVAddr = new (NonPagedPoolNx) BYTE[size];
if (!m_pVAddr)
{
DbgPrint(TRACE_LEVEL_FATAL, ("%s insufficient resources to allocate %x bytes\n", __FUNCTION__, size));
return FALSE;
}
RtlZeroMemory(m_pVAddr, size);
m_bSystemMemory = TRUE;
}
else
{
NTSTATUS Status = MapFrameBuffer(*pPAddr, size, &m_pVAddr);
if (!NT_SUCCESS(Status))
{
DbgPrint(TRACE_LEVEL_FATAL, ("<--- %s MapFrameBuffer failed with Status: 0x%X\n", __FUNCTION__, Status));
return FALSE;
}
m_bMapped = TRUE;
}
m_pMdl = IoAllocateMdl(m_pVAddr, size, FALSE, FALSE, NULL);
if (!m_pMdl)
{
DbgPrint(TRACE_LEVEL_FATAL, ("%s insufficient resources to allocate MDLs\n", __FUNCTION__));
return FALSE;
}
if (m_bSystemMemory == TRUE)
{
__try
{
MmProbeAndLockPages(m_pMdl, KernelMode, IoWriteAccess);
}
#pragma prefast(suppress : __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint(TRACE_LEVEL_FATAL, ("%s Failed to lock pages with error %x\n", __FUNCTION__, GetExceptionCode()));
IoFreeMdl(m_pMdl);
return FALSE;
}
}
m_pSGList = reinterpret_cast<PSCATTER_GATHER_LIST>(new (NonPagedPoolNx) BYTE[sglsize]);
m_pSGList->NumberOfElements = 0;
m_pSGList->Reserved = 0;
// m_pSAddr = reinterpret_cast<BYTE*>
// (MmGetSystemAddressForMdlSafe(m_pMdl, NormalPagePriority | MdlMappingNoExecute));
RtlZeroMemory(m_pSGList, sglsize);
buf = PAGE_ALIGN(m_pVAddr);
for (UINT i = 0; i < pages; ++i)
{
PHYSICAL_ADDRESS pa = {0};
ASSERT(MmIsAddressValid(buf));
pa = MmGetPhysicalAddress(buf);
if (pa.QuadPart == 0LL)
{
DbgPrint(TRACE_LEVEL_FATAL, ("%s Invalid PA buf = %p element %d\n", __FUNCTION__, buf, i));
break;
}
m_pSGList->Elements[i].Address = pa;
m_pSGList->Elements[i].Length = PAGE_SIZE;
buf = (PVOID)((LONG_PTR)(buf) + PAGE_SIZE);
m_pSGList->NumberOfElements++;
}
m_Size = size;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE;
}
PHYSICAL_ADDRESS VioGpuMemSegment::GetPhysicalAddress(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PHYSICAL_ADDRESS pa = {0};
if (m_pVAddr && MmIsAddressValid(m_pVAddr))
{
pa = MmGetPhysicalAddress(m_pVAddr);
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return pa;
}
void VioGpuMemSegment::Close(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
if (m_pMdl)
{
if (m_bSystemMemory)
{
MmUnlockPages(m_pMdl);
}
IoFreeMdl(m_pMdl);
m_pMdl = NULL;
}
if (m_bSystemMemory)
{
delete[] m_pVAddr;
}
else
{
UnmapFrameBuffer(m_pVAddr, (ULONG)m_Size);
m_bMapped = FALSE;
}
m_pVAddr = NULL;
delete[] reinterpret_cast<PBYTE>(m_pSGList);
m_pSGList = NULL;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
VioGpuObj::VioGpuObj(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
m_uiHwRes = 0;
m_pSegment = NULL;
m_Size = 0;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
VioGpuObj::~VioGpuObj(void)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
}
BOOLEAN VioGpuObj::Init(_In_ UINT size, VioGpuMemSegment *pSegment)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s requested size = %d\n", __FUNCTION__, size));
ASSERT(size);
ASSERT(pSegment);
UINT pages = BYTES_TO_PAGES(size);
size = pages * PAGE_SIZE;
if (size > pSegment->GetSize())
{
DbgPrint(TRACE_LEVEL_FATAL,
("<--- %s segment size too small = %Iu (%u)\n", __FUNCTION__, m_pSegment->GetSize(), size));
return FALSE;
}
m_pSegment = pSegment;
m_Size = size;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s size = %Iu\n", __FUNCTION__, m_Size));
return TRUE;
}
PVOID CrsrQueue::AllocCursor(PGPU_VBUFFER *buf)
{
PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_VBUFFER vbuf;
vbuf = m_pBuf->GetBuf(sizeof(GPU_UPDATE_CURSOR), 0, NULL);
ASSERT(vbuf);
*buf = vbuf;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s vbuf = %p\n", __FUNCTION__, vbuf));
return vbuf ? vbuf->buf : NULL;
}
PAGED_CODE_SEG_END
UINT CrsrQueue::QueueCursor(PGPU_VBUFFER buf)
{
// PAGED_CODE();
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
UINT res = 0;
KIRQL SavedIrql;
VirtIOBufferDescriptor sg[1];
int outcnt = 0;
UINT ret = 0;
ASSERT(buf->size <= PAGE_SIZE);
if (BuildSGElement(&sg[outcnt], (PVOID)buf->buf, buf->size))
{
outcnt++;
}
ASSERT(outcnt);
Lock(&SavedIrql);
ret = AddBuf(&sg[0], outcnt, 0, buf, NULL, 0);
Kick();
Unlock(SavedIrql);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s vbuf = %p outcnt = %d, ret = %d\n", __FUNCTION__, buf, outcnt, ret));
return res;
}
PGPU_VBUFFER CrsrQueue::DequeueCursor(_Out_ UINT *len)
{
DbgPrint(TRACE_LEVEL_VERBOSE, ("---> %s\n", __FUNCTION__));
PGPU_VBUFFER buf = NULL;
KIRQL SavedIrql;
Lock(&SavedIrql);
buf = (PGPU_VBUFFER)GetBuf(len);
Unlock(SavedIrql);
if (buf == NULL)
{
*len = 0;
}
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s buf %p len = %u\n", __FUNCTION__, buf, *len));
return buf;
}