drivers: hv: dxgkrnl: Implement known escapes

Implement an escape to build test command buffer.
Implement other known escapes.

Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
This commit is contained in:
Iouri Tarassov 2023-04-11 16:44:36 -07:00
Родитель 7b9f0bba61
Коммит 2fc7de22b3
4 изменённых файлов: 205 добавлений и 39 удалений

Просмотреть файл

@ -957,7 +957,8 @@ int dxgvmb_send_query_alloc_residency(struct dxgprocess *process,
*args);
int dxgvmb_send_escape(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_escape *args);
struct d3dkmt_escape *args,
bool user_mode);
int dxgvmb_send_query_vidmem_info(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_queryvideomemoryinfo *args,

Просмотреть файл

@ -2182,7 +2182,8 @@ cleanup:
int dxgvmb_send_escape(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_escape *args)
struct d3dkmt_escape *args,
bool user_mode)
{
int ret;
struct dxgkvmb_command_escape *command = NULL;
@ -2211,13 +2212,18 @@ int dxgvmb_send_escape(struct dxgprocess *process,
command->priv_drv_data_size = args->priv_drv_data_size;
command->context = args->context;
if (args->priv_drv_data_size) {
ret = copy_from_user(command->priv_drv_data,
args->priv_drv_data,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy priv data");
ret = -EFAULT;
goto cleanup;
if (user_mode) {
ret = copy_from_user(command->priv_drv_data,
args->priv_drv_data,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy priv data");
ret = -EFAULT;
goto cleanup;
}
} else {
memcpy(command->priv_drv_data, args->priv_drv_data,
args->priv_drv_data_size);
}
}
@ -2228,12 +2234,18 @@ int dxgvmb_send_escape(struct dxgprocess *process,
goto cleanup;
if (args->priv_drv_data_size) {
ret = copy_to_user(args->priv_drv_data,
command->priv_drv_data,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy priv data");
ret = -EINVAL;
if (user_mode) {
ret = copy_to_user(args->priv_drv_data,
command->priv_drv_data,
args->priv_drv_data_size);
if (ret) {
DXG_ERR("failed to copy priv data");
ret = -EINVAL;
}
} else {
memcpy(args->priv_drv_data,
command->priv_drv_data,
args->priv_drv_data_size);
}
}

Просмотреть файл

@ -4257,10 +4257,8 @@ dxgkio_change_vidmem_reservation(struct dxgprocess *process, void *__user inargs
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
adapter = NULL;
if (ret < 0)
goto cleanup;
}
adapter_locked = true;
args.adapter.v = 0;
ret = dxgvmb_send_change_vidmem_reservation(process, adapter,
@ -4299,10 +4297,8 @@ dxgkio_query_clock_calibration(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
adapter = NULL;
if (ret < 0)
goto cleanup;
}
adapter_locked = true;
args.adapter = adapter->host_handle;
@ -4349,10 +4345,8 @@ dxgkio_flush_heap_transitions(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
adapter = NULL;
if (ret < 0)
goto cleanup;
}
adapter_locked = true;
args.adapter = adapter->host_handle;
@ -4417,6 +4411,134 @@ cleanup:
return ret;
}
static int
build_test_command_buffer(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_escape *args)
{
int ret;
struct d3dddi_buildtestcommandbuffer cmd;
struct d3dkmt_escape newargs = *args;
u32 buf_size;
struct d3dddi_buildtestcommandbuffer *buf = NULL;
struct d3dddi_buildtestcommandbuffer *__user ucmd;
ucmd = args->priv_drv_data;
if (args->priv_drv_data_size <
sizeof(struct d3dddi_buildtestcommandbuffer)) {
DXG_ERR("Invalid private data size");
return -EINVAL;
}
ret = copy_from_user(&cmd, ucmd, sizeof(cmd));
if (ret) {
DXG_ERR("Failed to copy private data");
return -EFAULT;
}
if (cmd.dma_buffer_size < sizeof(u32) ||
cmd.dma_buffer_size > D3DDDI_MAXTESTBUFFERSIZE ||
cmd.dma_buffer_priv_data_size >
D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE) {
DXG_ERR("Invalid DMA buffer or private data size");
return -EINVAL;
}
/* Allocate a new buffer for the escape call */
buf_size = sizeof(struct d3dddi_buildtestcommandbuffer) +
cmd.dma_buffer_size +
cmd.dma_buffer_priv_data_size;
buf = vzalloc(buf_size);
if (buf == NULL) {
ret = -ENOMEM;
goto cleanup;
}
*buf = cmd;
buf->dma_buffer = NULL;
buf->dma_buffer_priv_data = NULL;
/* Replace private data in the escape arguments and call the host */
newargs.priv_drv_data = buf;
newargs.priv_drv_data_size = buf_size;
ret = dxgvmb_send_escape(process, adapter, &newargs, false);
if (ret) {
DXG_ERR("Host failed escape");
goto cleanup;
}
ret = copy_to_user(&ucmd->dma_buffer_size, &buf->dma_buffer_size,
sizeof(u32));
if (ret) {
DXG_ERR("Failed to dma size to user");
ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(&ucmd->dma_buffer_priv_data_size,
&buf->dma_buffer_priv_data_size,
sizeof(u32));
if (ret) {
DXG_ERR("Failed to dma private data size to user");
ret = -EFAULT;
goto cleanup;
}
ret = copy_to_user(cmd.dma_buffer, (char *)buf + sizeof(*buf),
buf->dma_buffer_size);
if (ret) {
DXG_ERR("Failed to copy dma buffer to user");
ret = -EFAULT;
goto cleanup;
}
if (buf->dma_buffer_priv_data_size) {
ret = copy_to_user(cmd.dma_buffer_priv_data,
(char *)buf + sizeof(*buf) + cmd.dma_buffer_size,
buf->dma_buffer_priv_data_size);
if (ret) {
DXG_ERR("Failed to copy private data to user");
ret = -EFAULT;
goto cleanup;
}
}
cleanup:
if (buf)
vfree(buf);
return ret;
}
static int
driver_known_escape(struct dxgprocess *process,
struct dxgadapter *adapter,
struct d3dkmt_escape *args)
{
enum d3dkmt_escapetype escape_type;
int ret = 0;
if (args->priv_drv_data_size < sizeof(enum d3dddi_knownescapetype))
{
DXG_ERR("Invalid private data size");
return -EINVAL;
}
ret = copy_from_user(&escape_type, args->priv_drv_data,
sizeof(escape_type));
if (ret) {
DXG_ERR("Failed to read escape type");
return -EFAULT;
}
switch (escape_type) {
case _D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE:
case _D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE:
/*
* The host and VM handles are the same
*/
break;
case _D3DDDI_DRIVERESCAPETYPE_BUILDTESTCOMMANDBUFFER:
ret = build_test_command_buffer(process, adapter, args);
break;
default:
ret = dxgvmb_send_escape(process, adapter, args, true);
break;
}
return ret;
}
static int
dxgkio_escape(struct dxgprocess *process, void *__user inargs)
{
@ -4438,14 +4560,17 @@ dxgkio_escape(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
adapter = NULL;
if (ret < 0)
goto cleanup;
}
adapter_locked = true;
args.adapter = adapter->host_handle;
ret = dxgvmb_send_escape(process, adapter, &args);
if (args.type == _D3DKMT_ESCAPE_DRIVERPRIVATE &&
args.flags.driver_known_escape)
ret = driver_known_escape(process, adapter, &args);
else
ret = dxgvmb_send_escape(process, adapter, &args, true);
cleanup:
@ -4485,10 +4610,8 @@ dxgkio_query_vidmem_info(struct dxgprocess *process, void *__user inargs)
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0) {
adapter = NULL;
if (ret < 0)
goto cleanup;
}
adapter_locked = true;
args.adapter = adapter->host_handle;
@ -5323,9 +5446,9 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
{
struct d3dkmt_isfeatureenabled args;
struct dxgadapter *adapter = NULL;
struct dxgglobal *dxgglobal = dxggbl();
struct d3dkmt_isfeatureenabled *__user uargs = inargs;
int ret;
bool adapter_locked = false;
ret = copy_from_user(&args, inargs, sizeof(args));
if (ret) {
@ -5340,11 +5463,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
goto cleanup;
}
if (adapter) {
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0)
goto cleanup;
}
ret = dxgadapter_acquire_lock_shared(adapter);
if (ret < 0)
goto cleanup;
adapter_locked = true;
ret = dxgvmb_send_is_feature_enabled(adapter, &args);
if (ret)
@ -5354,10 +5476,10 @@ dxgkio_is_feature_enabled(struct dxgprocess *process, void *__user inargs)
cleanup:
if (adapter) {
if (adapter_locked)
dxgadapter_release_lock_shared(adapter);
if (adapter)
kref_put(&adapter->adapter_kref, dxgadapter_release);
}
DXG_TRACE_IOCTL_END(ret);
return ret;

Просмотреть файл

@ -237,6 +237,37 @@ struct d3dddi_destroypagingqueue {
struct d3dkmthandle paging_queue;
};
enum d3dddi_knownescapetype {
_D3DDDI_DRIVERESCAPETYPE_TRANSLATEALLOCATIONHANDLE = 0,
_D3DDDI_DRIVERESCAPETYPE_TRANSLATERESOURCEHANDLE = 1,
_D3DDDI_DRIVERESCAPETYPE_CPUEVENTUSAGE = 2,
_D3DDDI_DRIVERESCAPETYPE_BUILDTESTCOMMANDBUFFER = 3,
};
struct d3dddi_translate_allocation_handle {
enum d3dddi_knownescapetype escape_type;
struct d3dkmthandle allocation;
};
struct d3dddi_testcommand {
char buffer[72];
};
#define D3DDDI_MAXTESTBUFFERSIZE 4096
#define D3DDDI_MAXTESTBUFFERPRIVATEDRIVERDATASIZE 1024
struct d3dddi_buildtestcommandbuffer {
enum d3dddi_knownescapetype escape_type;
struct d3dkmthandle device;
struct d3dkmthandle context;
__u32 flags;
struct d3dddi_testcommand command;
void *dma_buffer;
void *dma_buffer_priv_data;
__u32 dma_buffer_size;
__u32 dma_buffer_priv_data_size;
};
enum d3dkmt_escapetype {
_D3DKMT_ESCAPE_DRIVERPRIVATE = 0,
_D3DKMT_ESCAPE_VIDMM = 1,