mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
661 lines
18 KiB
Diff
661 lines
18 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
Date: Tue, 15 Feb 2022 18:53:07 -0800
|
|
Subject: drivers: hv: dxgkrnl: Add VMBus message support, initialize VMBus
|
|
channels.
|
|
|
|
Implement support for sending/receiving VMBus messages between
|
|
the host and the guest.
|
|
|
|
Initialize the VMBus channels and notify the host about IO space
|
|
settings of the VMBus global channel.
|
|
|
|
Signed-off-by: Iouri Tarassov <iourit@linux.microsoft.com>
|
|
[kms: Forward port to v6.1]
|
|
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
|
|
---
|
|
drivers/hv/dxgkrnl/dxgkrnl.h | 14 +
|
|
drivers/hv/dxgkrnl/dxgmodule.c | 9 +-
|
|
drivers/hv/dxgkrnl/dxgvmbus.c | 318 ++++++++++
|
|
drivers/hv/dxgkrnl/dxgvmbus.h | 67 ++
|
|
drivers/hv/dxgkrnl/ioctl.c | 24 +
|
|
drivers/hv/dxgkrnl/misc.h | 72 +++
|
|
include/uapi/misc/d3dkmthk.h | 34 +
|
|
7 files changed, 536 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
|
|
@@ -28,6 +28,8 @@
|
|
#include <linux/hyperv.h>
|
|
#include <uapi/misc/d3dkmthk.h>
|
|
#include <linux/version.h>
|
|
+#include "misc.h"
|
|
+#include <uapi/misc/d3dkmthk.h>
|
|
|
|
struct dxgadapter;
|
|
|
|
@@ -100,6 +102,13 @@ static inline struct dxgglobal *dxggbl(void)
|
|
return dxgdrv.dxgglobal;
|
|
}
|
|
|
|
+int dxgglobal_init_global_channel(void);
|
|
+void dxgglobal_destroy_global_channel(void);
|
|
+struct vmbus_channel *dxgglobal_get_vmbus(void);
|
|
+struct dxgvmbuschannel *dxgglobal_get_dxgvmbuschannel(void);
|
|
+int dxgglobal_acquire_channel_lock(void);
|
|
+void dxgglobal_release_channel_lock(void);
|
|
+
|
|
struct dxgprocess {
|
|
/* Placeholder */
|
|
};
|
|
@@ -130,6 +139,11 @@ static inline void guid_to_luid(guid_t *guid, struct winluid *luid)
|
|
#define DXGK_VMBUS_INTERFACE_VERSION 40
|
|
#define DXGK_VMBUS_LAST_COMPATIBLE_INTERFACE_VERSION 16
|
|
|
|
+void dxgvmb_initialize(void);
|
|
+int dxgvmb_send_set_iospace_region(u64 start, u64 len);
|
|
+
|
|
+int ntstatus2int(struct ntstatus status);
|
|
+
|
|
#ifdef DEBUG
|
|
|
|
void dxgk_validate_ioctls(void);
|
|
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgmodule.c
|
|
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
|
|
@@ -260,6 +260,13 @@ int dxgglobal_init_global_channel(void)
|
|
goto error;
|
|
}
|
|
|
|
+ ret = dxgvmb_send_set_iospace_region(dxgglobal->mmiospace_base,
|
|
+ dxgglobal->mmiospace_size);
|
|
+ if (ret < 0) {
|
|
+ DXG_ERR("send_set_iospace_region failed");
|
|
+ goto error;
|
|
+ }
|
|
+
|
|
hv_set_drvdata(dxgglobal->hdev, dxgglobal);
|
|
|
|
error:
|
|
@@ -429,8 +436,6 @@ static void dxgglobal_destroy(struct dxgglobal *dxgglobal)
|
|
if (dxgglobal->vmbus_registered)
|
|
vmbus_driver_unregister(&dxgdrv.vmbus_drv);
|
|
|
|
- dxgglobal_destroy_global_channel();
|
|
-
|
|
if (dxgglobal->pci_registered)
|
|
pci_unregister_driver(&dxgdrv.pci_drv);
|
|
|
|
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
|
|
@@ -40,6 +40,121 @@ struct dxgvmbuspacket {
|
|
bool completed;
|
|
};
|
|
|
|
+struct dxgvmb_ext_header {
|
|
+ /* Offset from the start of the message to DXGKVMB_COMMAND_BASE */
|
|
+ u32 command_offset;
|
|
+ u32 reserved;
|
|
+ struct winluid vgpu_luid;
|
|
+};
|
|
+
|
|
+#define VMBUSMESSAGEONSTACK 64
|
|
+
|
|
+struct dxgvmbusmsg {
|
|
+/* Points to the allocated buffer */
|
|
+ struct dxgvmb_ext_header *hdr;
|
|
+/* Points to dxgkvmb_command_vm_to_host or dxgkvmb_command_vgpu_to_host */
|
|
+ void *msg;
|
|
+/* The vm bus channel, used to pass the message to the host */
|
|
+ struct dxgvmbuschannel *channel;
|
|
+/* Message size in bytes including the header and the payload */
|
|
+ u32 size;
|
|
+/* Buffer used for small messages */
|
|
+ char msg_on_stack[VMBUSMESSAGEONSTACK];
|
|
+};
|
|
+
|
|
+struct dxgvmbusmsgres {
|
|
+/* Points to the allocated buffer */
|
|
+ struct dxgvmb_ext_header *hdr;
|
|
+/* Points to dxgkvmb_command_vm_to_host or dxgkvmb_command_vgpu_to_host */
|
|
+ void *msg;
|
|
+/* The vm bus channel, used to pass the message to the host */
|
|
+ struct dxgvmbuschannel *channel;
|
|
+/* Message size in bytes including the header, the payload and the result */
|
|
+ u32 size;
|
|
+/* Result buffer size in bytes */
|
|
+ u32 res_size;
|
|
+/* Points to the result within the allocated buffer */
|
|
+ void *res;
|
|
+};
|
|
+
|
|
+static int init_message(struct dxgvmbusmsg *msg,
|
|
+ struct dxgprocess *process, u32 size)
|
|
+{
|
|
+ struct dxgglobal *dxgglobal = dxggbl();
|
|
+
|
|
+ bool use_ext_header = dxgglobal->vmbus_ver >=
|
|
+ DXGK_VMBUS_INTERFACE_VERSION;
|
|
+
|
|
+ if (use_ext_header)
|
|
+ size += sizeof(struct dxgvmb_ext_header);
|
|
+ msg->size = size;
|
|
+ if (size <= VMBUSMESSAGEONSTACK) {
|
|
+ msg->hdr = (void *)msg->msg_on_stack;
|
|
+ memset(msg->hdr, 0, size);
|
|
+ } else {
|
|
+ msg->hdr = vzalloc(size);
|
|
+ if (msg->hdr == NULL)
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ if (use_ext_header) {
|
|
+ msg->msg = (char *)&msg->hdr[1];
|
|
+ msg->hdr->command_offset = sizeof(msg->hdr[0]);
|
|
+ } else {
|
|
+ msg->msg = (char *)msg->hdr;
|
|
+ }
|
|
+ msg->channel = &dxgglobal->channel;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void free_message(struct dxgvmbusmsg *msg, struct dxgprocess *process)
|
|
+{
|
|
+ if (msg->hdr && (char *)msg->hdr != msg->msg_on_stack)
|
|
+ vfree(msg->hdr);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Helper functions
|
|
+ */
|
|
+
|
|
+int ntstatus2int(struct ntstatus status)
|
|
+{
|
|
+ if (NT_SUCCESS(status))
|
|
+ return (int)status.v;
|
|
+ switch (status.v) {
|
|
+ case STATUS_OBJECT_NAME_COLLISION:
|
|
+ return -EEXIST;
|
|
+ case STATUS_NO_MEMORY:
|
|
+ return -ENOMEM;
|
|
+ case STATUS_INVALID_PARAMETER:
|
|
+ return -EINVAL;
|
|
+ case STATUS_OBJECT_NAME_INVALID:
|
|
+ case STATUS_OBJECT_NAME_NOT_FOUND:
|
|
+ return -ENOENT;
|
|
+ case STATUS_TIMEOUT:
|
|
+ return -EAGAIN;
|
|
+ case STATUS_BUFFER_TOO_SMALL:
|
|
+ return -EOVERFLOW;
|
|
+ case STATUS_DEVICE_REMOVED:
|
|
+ return -ENODEV;
|
|
+ case STATUS_ACCESS_DENIED:
|
|
+ return -EACCES;
|
|
+ case STATUS_NOT_SUPPORTED:
|
|
+ return -EPERM;
|
|
+ case STATUS_ILLEGAL_INSTRUCTION:
|
|
+ return -EOPNOTSUPP;
|
|
+ case STATUS_INVALID_HANDLE:
|
|
+ return -EBADF;
|
|
+ case STATUS_GRAPHICS_ALLOCATION_BUSY:
|
|
+ return -EINPROGRESS;
|
|
+ case STATUS_OBJECT_TYPE_MISMATCH:
|
|
+ return -EPROTOTYPE;
|
|
+ case STATUS_NOT_IMPLEMENTED:
|
|
+ return -EPERM;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+}
|
|
+
|
|
int dxgvmbuschannel_init(struct dxgvmbuschannel *ch, struct hv_device *hdev)
|
|
{
|
|
int ret;
|
|
@@ -86,7 +201,210 @@ void dxgvmbuschannel_destroy(struct dxgvmbuschannel *ch)
|
|
}
|
|
}
|
|
|
|
+static void command_vm_to_host_init1(struct dxgkvmb_command_vm_to_host *command,
|
|
+ enum dxgkvmb_commandtype_global type)
|
|
+{
|
|
+ command->command_type = type;
|
|
+ command->process.v = 0;
|
|
+ command->command_id = 0;
|
|
+ command->channel_type = DXGKVMB_VM_TO_HOST;
|
|
+}
|
|
+
|
|
+static void process_inband_packet(struct dxgvmbuschannel *channel,
|
|
+ struct vmpacket_descriptor *desc)
|
|
+{
|
|
+ u32 packet_length = hv_pkt_datalen(desc);
|
|
+ struct dxgkvmb_command_host_to_vm *packet;
|
|
+
|
|
+ if (packet_length < sizeof(struct dxgkvmb_command_host_to_vm)) {
|
|
+ DXG_ERR("Invalid global packet");
|
|
+ } else {
|
|
+ packet = hv_pkt_data(desc);
|
|
+ DXG_TRACE("global packet %d",
|
|
+ packet->command_type);
|
|
+ switch (packet->command_type) {
|
|
+ case DXGK_VMBCOMMAND_SIGNALGUESTEVENT:
|
|
+ case DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE:
|
|
+ break;
|
|
+ case DXGK_VMBCOMMAND_SENDWNFNOTIFICATION:
|
|
+ break;
|
|
+ default:
|
|
+ DXG_ERR("unexpected host message %d",
|
|
+ packet->command_type);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void process_completion_packet(struct dxgvmbuschannel *channel,
|
|
+ struct vmpacket_descriptor *desc)
|
|
+{
|
|
+ struct dxgvmbuspacket *packet = NULL;
|
|
+ struct dxgvmbuspacket *entry;
|
|
+ u32 packet_length = hv_pkt_datalen(desc);
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&channel->packet_list_mutex, flags);
|
|
+ list_for_each_entry(entry, &channel->packet_list_head,
|
|
+ packet_list_entry) {
|
|
+ if (desc->trans_id == entry->request_id) {
|
|
+ packet = entry;
|
|
+ list_del(&packet->packet_list_entry);
|
|
+ packet->completed = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_irqrestore(&channel->packet_list_mutex, flags);
|
|
+ if (packet) {
|
|
+ if (packet->buffer_length) {
|
|
+ if (packet_length < packet->buffer_length) {
|
|
+ DXG_TRACE("invalid size %d Expected:%d",
|
|
+ packet_length,
|
|
+ packet->buffer_length);
|
|
+ packet->status = -EOVERFLOW;
|
|
+ } else {
|
|
+ memcpy(packet->buffer, hv_pkt_data(desc),
|
|
+ packet->buffer_length);
|
|
+ }
|
|
+ }
|
|
+ complete(&packet->wait);
|
|
+ } else {
|
|
+ DXG_ERR("did not find packet to complete");
|
|
+ }
|
|
+}
|
|
+
|
|
/* Receive callback for messages from the host */
|
|
void dxgvmbuschannel_receive(void *ctx)
|
|
{
|
|
+ struct dxgvmbuschannel *channel = ctx;
|
|
+ struct vmpacket_descriptor *desc;
|
|
+ u32 packet_length = 0;
|
|
+
|
|
+ foreach_vmbus_pkt(desc, channel->channel) {
|
|
+ packet_length = hv_pkt_datalen(desc);
|
|
+ DXG_TRACE("next packet (id, size, type): %llu %d %d",
|
|
+ desc->trans_id, packet_length, desc->type);
|
|
+ if (desc->type == VM_PKT_COMP) {
|
|
+ process_completion_packet(channel, desc);
|
|
+ } else {
|
|
+ if (desc->type != VM_PKT_DATA_INBAND)
|
|
+ DXG_ERR("unexpected packet type");
|
|
+ else
|
|
+ process_inband_packet(channel, desc);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+int dxgvmb_send_sync_msg(struct dxgvmbuschannel *channel,
|
|
+ void *command,
|
|
+ u32 cmd_size,
|
|
+ void *result,
|
|
+ u32 result_size)
|
|
+{
|
|
+ int ret;
|
|
+ struct dxgvmbuspacket *packet = NULL;
|
|
+
|
|
+ if (cmd_size > DXG_MAX_VM_BUS_PACKET_SIZE ||
|
|
+ result_size > DXG_MAX_VM_BUS_PACKET_SIZE) {
|
|
+ DXG_ERR("%s invalid data size", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ packet = kmem_cache_alloc(channel->packet_cache, 0);
|
|
+ if (packet == NULL) {
|
|
+ DXG_ERR("kmem_cache_alloc failed");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ packet->request_id = atomic64_inc_return(&channel->packet_request_id);
|
|
+ init_completion(&packet->wait);
|
|
+ packet->buffer = result;
|
|
+ packet->buffer_length = result_size;
|
|
+ packet->status = 0;
|
|
+ packet->completed = false;
|
|
+ spin_lock_irq(&channel->packet_list_mutex);
|
|
+ list_add_tail(&packet->packet_list_entry, &channel->packet_list_head);
|
|
+ spin_unlock_irq(&channel->packet_list_mutex);
|
|
+
|
|
+ ret = vmbus_sendpacket(channel->channel, command, cmd_size,
|
|
+ packet->request_id, VM_PKT_DATA_INBAND,
|
|
+ VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
|
+ if (ret) {
|
|
+ DXG_ERR("vmbus_sendpacket failed: %x", ret);
|
|
+ spin_lock_irq(&channel->packet_list_mutex);
|
|
+ list_del(&packet->packet_list_entry);
|
|
+ spin_unlock_irq(&channel->packet_list_mutex);
|
|
+ goto cleanup;
|
|
+ }
|
|
+
|
|
+ DXG_TRACE("waiting completion: %llu", packet->request_id);
|
|
+ ret = wait_for_completion_killable(&packet->wait);
|
|
+ if (ret) {
|
|
+ DXG_ERR("wait_for_completion failed: %x", ret);
|
|
+ spin_lock_irq(&channel->packet_list_mutex);
|
|
+ if (!packet->completed)
|
|
+ list_del(&packet->packet_list_entry);
|
|
+ spin_unlock_irq(&channel->packet_list_mutex);
|
|
+ goto cleanup;
|
|
+ }
|
|
+ DXG_TRACE("completion done: %llu %x",
|
|
+ packet->request_id, packet->status);
|
|
+ ret = packet->status;
|
|
+
|
|
+cleanup:
|
|
+
|
|
+ kmem_cache_free(channel->packet_cache, packet);
|
|
+ if (ret < 0)
|
|
+ DXG_TRACE("Error: %x", ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+dxgvmb_send_sync_msg_ntstatus(struct dxgvmbuschannel *channel,
|
|
+ void *command, u32 cmd_size)
|
|
+{
|
|
+ struct ntstatus status;
|
|
+ int ret;
|
|
+
|
|
+ ret = dxgvmb_send_sync_msg(channel, command, cmd_size,
|
|
+ &status, sizeof(status));
|
|
+ if (ret >= 0)
|
|
+ ret = ntstatus2int(status);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Global messages to the host
|
|
+ */
|
|
+
|
|
+int dxgvmb_send_set_iospace_region(u64 start, u64 len)
|
|
+{
|
|
+ int ret;
|
|
+ struct dxgkvmb_command_setiospaceregion *command;
|
|
+ struct dxgvmbusmsg msg;
|
|
+ struct dxgglobal *dxgglobal = dxggbl();
|
|
+
|
|
+ ret = init_message(&msg, NULL, sizeof(*command));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ command = (void *)msg.msg;
|
|
+
|
|
+ ret = dxgglobal_acquire_channel_lock();
|
|
+ if (ret < 0)
|
|
+ goto cleanup;
|
|
+
|
|
+ command_vm_to_host_init1(&command->hdr,
|
|
+ DXGK_VMBCOMMAND_SETIOSPACEREGION);
|
|
+ command->start = start;
|
|
+ command->length = len;
|
|
+ ret = dxgvmb_send_sync_msg_ntstatus(&dxgglobal->channel, msg.hdr,
|
|
+ msg.size);
|
|
+ if (ret < 0)
|
|
+ DXG_ERR("send_set_iospace_region failed %x", ret);
|
|
+
|
|
+ dxgglobal_release_channel_lock();
|
|
+cleanup:
|
|
+ free_message(&msg, NULL);
|
|
+ if (ret)
|
|
+ DXG_TRACE("Error: %d", ret);
|
|
+ return ret;
|
|
}
|
|
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
|
|
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
|
|
@@ -16,4 +16,71 @@
|
|
|
|
#define DXG_MAX_VM_BUS_PACKET_SIZE (1024 * 128)
|
|
|
|
+enum dxgkvmb_commandchanneltype {
|
|
+ DXGKVMB_VGPU_TO_HOST,
|
|
+ DXGKVMB_VM_TO_HOST,
|
|
+ DXGKVMB_HOST_TO_VM
|
|
+};
|
|
+
|
|
+/*
|
|
+ *
|
|
+ * Commands, sent to the host via the guest global VM bus channel
|
|
+ * DXG_GUEST_GLOBAL_VMBUS
|
|
+ *
|
|
+ */
|
|
+
|
|
+enum dxgkvmb_commandtype_global {
|
|
+ DXGK_VMBCOMMAND_VM_TO_HOST_FIRST = 1000,
|
|
+ DXGK_VMBCOMMAND_CREATEPROCESS = DXGK_VMBCOMMAND_VM_TO_HOST_FIRST,
|
|
+ DXGK_VMBCOMMAND_DESTROYPROCESS = 1001,
|
|
+ DXGK_VMBCOMMAND_OPENSYNCOBJECT = 1002,
|
|
+ DXGK_VMBCOMMAND_DESTROYSYNCOBJECT = 1003,
|
|
+ DXGK_VMBCOMMAND_CREATENTSHAREDOBJECT = 1004,
|
|
+ DXGK_VMBCOMMAND_DESTROYNTSHAREDOBJECT = 1005,
|
|
+ DXGK_VMBCOMMAND_SIGNALFENCE = 1006,
|
|
+ DXGK_VMBCOMMAND_NOTIFYPROCESSFREEZE = 1007,
|
|
+ DXGK_VMBCOMMAND_NOTIFYPROCESSTHAW = 1008,
|
|
+ DXGK_VMBCOMMAND_QUERYETWSESSION = 1009,
|
|
+ DXGK_VMBCOMMAND_SETIOSPACEREGION = 1010,
|
|
+ DXGK_VMBCOMMAND_COMPLETETRANSACTION = 1011,
|
|
+ DXGK_VMBCOMMAND_SHAREOBJECTWITHHOST = 1021,
|
|
+ DXGK_VMBCOMMAND_INVALID_VM_TO_HOST
|
|
+};
|
|
+
|
|
+/*
|
|
+ * Commands, sent by the host to the VM
|
|
+ */
|
|
+enum dxgkvmb_commandtype_host_to_vm {
|
|
+ DXGK_VMBCOMMAND_SIGNALGUESTEVENT,
|
|
+ DXGK_VMBCOMMAND_PROPAGATEPRESENTHISTORYTOKEN,
|
|
+ DXGK_VMBCOMMAND_SETGUESTDATA,
|
|
+ DXGK_VMBCOMMAND_SIGNALGUESTEVENTPASSIVE,
|
|
+ DXGK_VMBCOMMAND_SENDWNFNOTIFICATION,
|
|
+ DXGK_VMBCOMMAND_INVALID_HOST_TO_VM
|
|
+};
|
|
+
|
|
+struct dxgkvmb_command_vm_to_host {
|
|
+ u64 command_id;
|
|
+ struct d3dkmthandle process;
|
|
+ enum dxgkvmb_commandchanneltype channel_type;
|
|
+ enum dxgkvmb_commandtype_global command_type;
|
|
+};
|
|
+
|
|
+struct dxgkvmb_command_host_to_vm {
|
|
+ u64 command_id;
|
|
+ struct d3dkmthandle process;
|
|
+ u32 channel_type : 8;
|
|
+ u32 async_msg : 1;
|
|
+ u32 reserved : 23;
|
|
+ enum dxgkvmb_commandtype_host_to_vm command_type;
|
|
+};
|
|
+
|
|
+/* Returns ntstatus */
|
|
+struct dxgkvmb_command_setiospaceregion {
|
|
+ struct dxgkvmb_command_vm_to_host hdr;
|
|
+ u64 start;
|
|
+ u64 length;
|
|
+ u32 shared_page_gpadl;
|
|
+};
|
|
+
|
|
#endif /* _DXGVMBUS_H */
|
|
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/hv/dxgkrnl/ioctl.c
|
|
@@ -0,0 +1,24 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2022, Microsoft Corporation.
|
|
+ *
|
|
+ * Author:
|
|
+ * Iouri Tarassov <iourit@linux.microsoft.com>
|
|
+ *
|
|
+ * Dxgkrnl Graphics Driver
|
|
+ * Ioctl implementation
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/eventfd.h>
|
|
+#include <linux/file.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/anon_inodes.h>
|
|
+#include <linux/mman.h>
|
|
+
|
|
+#include "dxgkrnl.h"
|
|
+#include "dxgvmbus.h"
|
|
+
|
|
+#undef pr_fmt
|
|
+#define pr_fmt(fmt) "dxgk: " fmt
|
|
diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h
|
|
new file mode 100644
|
|
index 000000000000..111111111111
|
|
--- /dev/null
|
|
+++ b/drivers/hv/dxgkrnl/misc.h
|
|
@@ -0,0 +1,72 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+
|
|
+/*
|
|
+ * Copyright (c) 2022, Microsoft Corporation.
|
|
+ *
|
|
+ * Author:
|
|
+ * Iouri Tarassov <iourit@linux.microsoft.com>
|
|
+ *
|
|
+ * Dxgkrnl Graphics Driver
|
|
+ * Misc definitions
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _MISC_H_
|
|
+#define _MISC_H_
|
|
+
|
|
+extern const struct d3dkmthandle zerohandle;
|
|
+
|
|
+/*
|
|
+ * Synchronization lock hierarchy.
|
|
+ *
|
|
+ * The higher enum value, the higher is the lock order.
|
|
+ * When a lower lock ois held, the higher lock should not be acquired.
|
|
+ *
|
|
+ * channel_lock
|
|
+ * device_mutex
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Some of the Windows return codes, which needs to be translated to Linux
|
|
+ * IOCTL return codes. Positive values are success codes and need to be
|
|
+ * returned from the driver IOCTLs. libdxcore.so depends on returning
|
|
+ * specific return codes.
|
|
+ */
|
|
+#define STATUS_SUCCESS ((int)(0))
|
|
+#define STATUS_OBJECT_NAME_INVALID ((int)(0xC0000033L))
|
|
+#define STATUS_DEVICE_REMOVED ((int)(0xC00002B6L))
|
|
+#define STATUS_INVALID_HANDLE ((int)(0xC0000008L))
|
|
+#define STATUS_ILLEGAL_INSTRUCTION ((int)(0xC000001DL))
|
|
+#define STATUS_NOT_IMPLEMENTED ((int)(0xC0000002L))
|
|
+#define STATUS_PENDING ((int)(0x00000103L))
|
|
+#define STATUS_ACCESS_DENIED ((int)(0xC0000022L))
|
|
+#define STATUS_BUFFER_TOO_SMALL ((int)(0xC0000023L))
|
|
+#define STATUS_OBJECT_TYPE_MISMATCH ((int)(0xC0000024L))
|
|
+#define STATUS_GRAPHICS_ALLOCATION_BUSY ((int)(0xC01E0102L))
|
|
+#define STATUS_NOT_SUPPORTED ((int)(0xC00000BBL))
|
|
+#define STATUS_TIMEOUT ((int)(0x00000102L))
|
|
+#define STATUS_INVALID_PARAMETER ((int)(0xC000000DL))
|
|
+#define STATUS_NO_MEMORY ((int)(0xC0000017L))
|
|
+#define STATUS_OBJECT_NAME_COLLISION ((int)(0xC0000035L))
|
|
+#define STATUS_OBJECT_NAME_NOT_FOUND ((int)(0xC0000034L))
|
|
+
|
|
+
|
|
+#define NT_SUCCESS(status) (status.v >= 0)
|
|
+
|
|
+#ifndef DEBUG
|
|
+
|
|
+#define DXGKRNL_ASSERT(exp)
|
|
+
|
|
+#else
|
|
+
|
|
+#define DXGKRNL_ASSERT(exp) \
|
|
+do { \
|
|
+ if (!(exp)) { \
|
|
+ dump_stack(); \
|
|
+ BUG_ON(true); \
|
|
+ } \
|
|
+} while (0)
|
|
+
|
|
+#endif /* DEBUG */
|
|
+
|
|
+#endif /* _MISC_H_ */
|
|
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/include/uapi/misc/d3dkmthk.h
|
|
+++ b/include/uapi/misc/d3dkmthk.h
|
|
@@ -14,6 +14,40 @@
|
|
#ifndef _D3DKMTHK_H
|
|
#define _D3DKMTHK_H
|
|
|
|
+/*
|
|
+ * This structure matches the definition of D3DKMTHANDLE in Windows.
|
|
+ * The handle is opaque in user mode. It is used by user mode applications to
|
|
+ * represent kernel mode objects, created by dxgkrnl.
|
|
+ */
|
|
+struct d3dkmthandle {
|
|
+ union {
|
|
+ struct {
|
|
+ __u32 instance : 6;
|
|
+ __u32 index : 24;
|
|
+ __u32 unique : 2;
|
|
+ };
|
|
+ __u32 v;
|
|
+ };
|
|
+};
|
|
+
|
|
+/*
|
|
+ * VM bus messages return Windows' NTSTATUS, which is integer and only negative
|
|
+ * value indicates a failure. A positive number is a success and needs to be
|
|
+ * returned to user mode as the IOCTL return code. Negative status codes are
|
|
+ * converted to Linux error codes.
|
|
+ */
|
|
+struct ntstatus {
|
|
+ union {
|
|
+ struct {
|
|
+ int code : 16;
|
|
+ int facility : 13;
|
|
+ int customer : 1;
|
|
+ int severity : 2;
|
|
+ };
|
|
+ int v;
|
|
+ };
|
|
+};
|
|
+
|
|
/*
|
|
* Matches the Windows LUID definition.
|
|
* LUID is a locally unique identifier (similar to GUID, but not global),
|
|
--
|
|
Armbian
|
|
|