From: Iouri Tarassov <[email protected]>

- Implement opening of the device (/dev/dxg) file object and creation of
dxgprocess objects.

- Add VM bus messages to create and destroy the host side of a dxgprocess
object.

- Implement the handle manager, which manages d3dkmthandle handles
for the internal process objects. The handles are used by a user mode
client to reference dxgkrnl objects.

dxgprocess is created for each process, which opens /dev/dxg.
dxgprocess is ref counted, so the existing dxgprocess objects is used
for a process, which opens the device object multiple time.
dxgprocess is destroyed when the file object is released.

A corresponding dxgprocess object is created on the host for every
dxgprocess object in the guest.

When a dxgkrnl object is created, in most cases the corresponding
object is created in the host. The VM references the host objects by
handles (d3dkmthandle). d3dkmthandle values for a host object and
the corresponding VM object are the same. A host handle is allocated
first and its value is assigned to the guest object.

Signed-off-by: Iouri Tarassov <[email protected]>
[kms: forward port to 6.6 from 6.1. No code changes made.]
Signed-off-by: Kelsey Steele <[email protected]>
---
 drivers/hv/dxgkrnl/Makefile     |   2 +-
 drivers/hv/dxgkrnl/dxgadapter.c |  72 ++++
 drivers/hv/dxgkrnl/dxgkrnl.h    |  95 +++++-
 drivers/hv/dxgkrnl/dxgmodule.c  |  97 ++++++
 drivers/hv/dxgkrnl/dxgprocess.c | 262 +++++++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.c   | 164 ++++++++++
 drivers/hv/dxgkrnl/dxgvmbus.h   |  36 ++
 drivers/hv/dxgkrnl/hmgr.c       | 563 ++++++++++++++++++++++++++++++++
 drivers/hv/dxgkrnl/hmgr.h       | 112 +++++++
 drivers/hv/dxgkrnl/ioctl.c      |  60 ++++
 drivers/hv/dxgkrnl/misc.h       |   9 +-
 include/uapi/misc/d3dkmthk.h    | 103 ++++++
 12 files changed, 1569 insertions(+), 6 deletions(-)
 create mode 100644 drivers/hv/dxgkrnl/dxgprocess.c
 create mode 100644 drivers/hv/dxgkrnl/hmgr.c
 create mode 100644 drivers/hv/dxgkrnl/hmgr.h

diff --git a/drivers/hv/dxgkrnl/Makefile b/drivers/hv/dxgkrnl/Makefile
index 2ed07d877c91..9d821e83448a 100644
--- a/drivers/hv/dxgkrnl/Makefile
+++ b/drivers/hv/dxgkrnl/Makefile
@@ -2,4 +2,4 @@
 # Makefile for the hyper-v compute device driver (dxgkrnl).
 
 obj-$(CONFIG_DXGKRNL)  += dxgkrnl.o
-dxgkrnl-y              := dxgmodule.o misc.o dxgadapter.o ioctl.o dxgvmbus.o
+dxgkrnl-y              := dxgmodule.o hmgr.o misc.o dxgadapter.o ioctl.o 
dxgvmbus.o dxgprocess.o
diff --git a/drivers/hv/dxgkrnl/dxgadapter.c b/drivers/hv/dxgkrnl/dxgadapter.c
index 07d47699d255..fa0d6beca157 100644
--- a/drivers/hv/dxgkrnl/dxgadapter.c
+++ b/drivers/hv/dxgkrnl/dxgadapter.c
@@ -100,6 +100,7 @@ void dxgadapter_start(struct dxgadapter *adapter)
 
 void dxgadapter_stop(struct dxgadapter *adapter)
 {
+       struct dxgprocess_adapter *entry;
        bool adapter_stopped = false;
 
        down_write(&adapter->core_lock);
@@ -112,6 +113,15 @@ void dxgadapter_stop(struct dxgadapter *adapter)
        if (adapter_stopped)
                return;
 
+       dxgglobal_acquire_process_adapter_lock();
+
+       list_for_each_entry(entry, &adapter->adapter_process_list_head,
+                           adapter_process_list_entry) {
+               dxgprocess_adapter_stop(entry);
+       }
+
+       dxgglobal_release_process_adapter_lock();
+
        if (dxgadapter_acquire_lock_exclusive(adapter) == 0) {
                dxgvmb_send_close_adapter(adapter);
                dxgadapter_release_lock_exclusive(adapter);
@@ -135,6 +145,21 @@ bool dxgadapter_is_active(struct dxgadapter *adapter)
        return adapter->adapter_state == DXGADAPTER_STATE_ACTIVE;
 }
 
+/* Protected by dxgglobal_acquire_process_adapter_lock */
+void dxgadapter_add_process(struct dxgadapter *adapter,
+                           struct dxgprocess_adapter *process_info)
+{
+       DXG_TRACE("%p %p", adapter, process_info);
+       list_add_tail(&process_info->adapter_process_list_entry,
+                     &adapter->adapter_process_list_head);
+}
+
+void dxgadapter_remove_process(struct dxgprocess_adapter *process_info)
+{
+       DXG_TRACE("%p %p", process_info->adapter, process_info);
+       list_del(&process_info->adapter_process_list_entry);
+}
+
 int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter)
 {
        down_write(&adapter->core_lock);
@@ -168,3 +193,50 @@ void dxgadapter_release_lock_shared(struct dxgadapter 
*adapter)
 {
        up_read(&adapter->core_lock);
 }
+
+struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess 
*process,
+                                                    struct dxgadapter *adapter)
+{
+       struct dxgprocess_adapter *adapter_info;
+
+       adapter_info = kzalloc(sizeof(*adapter_info), GFP_KERNEL);
+       if (adapter_info) {
+               if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
+                       DXG_ERR("failed to acquire adapter reference");
+                       goto cleanup;
+               }
+               adapter_info->adapter = adapter;
+               adapter_info->process = process;
+               adapter_info->refcount = 1;
+               list_add_tail(&adapter_info->process_adapter_list_entry,
+                             &process->process_adapter_list_head);
+               dxgadapter_add_process(adapter, adapter_info);
+       }
+       return adapter_info;
+cleanup:
+       if (adapter_info)
+               kfree(adapter_info);
+       return NULL;
+}
+
+void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info)
+{
+}
+
+void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info)
+{
+       dxgadapter_remove_process(adapter_info);
+       kref_put(&adapter_info->adapter->adapter_kref, dxgadapter_release);
+       list_del(&adapter_info->process_adapter_list_entry);
+       kfree(adapter_info);
+}
+
+/*
+ * Must be called when dxgglobal::process_adapter_mutex is held
+ */
+void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter_info)
+{
+       adapter_info->refcount--;
+       if (adapter_info->refcount == 0)
+               dxgprocess_adapter_destroy(adapter_info);
+}
diff --git a/drivers/hv/dxgkrnl/dxgkrnl.h b/drivers/hv/dxgkrnl/dxgkrnl.h
index ba2a7c6001aa..b089d126f801 100644
--- a/drivers/hv/dxgkrnl/dxgkrnl.h
+++ b/drivers/hv/dxgkrnl/dxgkrnl.h
@@ -29,8 +29,10 @@
 #include <uapi/misc/d3dkmthk.h>
 #include <linux/version.h>
 #include "misc.h"
+#include "hmgr.h"
 #include <uapi/misc/d3dkmthk.h>
 
+struct dxgprocess;
 struct dxgadapter;
 
 /*
@@ -111,6 +113,10 @@ struct dxgglobal {
        struct miscdevice       dxgdevice;
        struct mutex            device_mutex;
 
+       /*  list of created  processes */
+       struct list_head        plisthead;
+       struct mutex            plistmutex;
+
        /* list of created adapters */
        struct list_head        adapter_list_head;
        struct rw_semaphore     adapter_list_lock;
@@ -124,6 +130,9 @@ struct dxgglobal {
        /* protects acces to the global VM bus channel */
        struct rw_semaphore     channel_lock;
 
+       /* protects the dxgprocess_adapter lists */
+       struct mutex            process_adapter_mutex;
+
        bool                    global_channel_initialized;
        bool                    async_msg_enabled;
        bool                    misc_registered;
@@ -144,13 +153,84 @@ 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);
+void dxgglobal_acquire_process_adapter_lock(void);
+void dxgglobal_release_process_adapter_lock(void);
 int dxgglobal_acquire_channel_lock(void);
 void dxgglobal_release_channel_lock(void);
 
+/*
+ * Describes adapter information for each process
+ */
+struct dxgprocess_adapter {
+       /* Entry in dxgadapter::adapter_process_list_head */
+       struct list_head        adapter_process_list_entry;
+       /* Entry in dxgprocess::process_adapter_list_head */
+       struct list_head        process_adapter_list_entry;
+       struct dxgadapter       *adapter;
+       struct dxgprocess       *process;
+       int                     refcount;
+};
+
+struct dxgprocess_adapter *dxgprocess_adapter_create(struct dxgprocess 
*process,
+                                                    struct dxgadapter
+                                                    *adapter);
+void dxgprocess_adapter_release(struct dxgprocess_adapter *adapter);
+void dxgprocess_adapter_stop(struct dxgprocess_adapter *adapter_info);
+void dxgprocess_adapter_destroy(struct dxgprocess_adapter *adapter_info);
+
+/*
+ * The structure represents a process, which opened the /dev/dxg device.
+ * A corresponding object is created on the host.
+ */
 struct dxgprocess {
-       /* Placeholder */
+       /*
+        * Process list entry in dxgglobal.
+        * Protected by the dxgglobal->plistmutex.
+        */
+       struct list_head        plistentry;
+       pid_t                   pid;
+       pid_t                   tgid;
+       /* how many time the process was opened */
+       struct kref             process_kref;
+       /*
+        * This handle table is used for all objects except dxgadapter
+        * The handle table lock order is higher than the local_handle_table
+        * lock
+        */
+       struct hmgrtable        handle_table;
+       /*
+        * This handle table is used for dxgadapter objects.
+        * The handle table lock order is lowest.
+        */
+       struct hmgrtable        local_handle_table;
+       /* Handle of the corresponding objec on the host */
+       struct d3dkmthandle     host_handle;
+
+       /* List of opened adapters (dxgprocess_adapter) */
+       struct list_head        process_adapter_list_head;
 };
 
+struct dxgprocess *dxgprocess_create(void);
+void dxgprocess_destroy(struct dxgprocess *process);
+void dxgprocess_release(struct kref *refcount);
+int dxgprocess_open_adapter(struct dxgprocess *process,
+                                       struct dxgadapter *adapter,
+                                       struct d3dkmthandle *handle);
+int dxgprocess_close_adapter(struct dxgprocess *process,
+                                        struct d3dkmthandle handle);
+struct dxgadapter *dxgprocess_get_adapter(struct dxgprocess *process,
+                                         struct d3dkmthandle handle);
+struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process,
+                                               struct d3dkmthandle handle);
+void dxgprocess_ht_lock_shared_down(struct dxgprocess *process);
+void dxgprocess_ht_lock_shared_up(struct dxgprocess *process);
+void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process);
+void dxgprocess_ht_lock_exclusive_up(struct dxgprocess *process);
+struct dxgprocess_adapter *dxgprocess_get_adapter_info(struct dxgprocess
+                                                      *process,
+                                                      struct dxgadapter
+                                                      *adapter);
+
 enum dxgadapter_state {
        DXGADAPTER_STATE_ACTIVE         = 0,
        DXGADAPTER_STATE_STOPPED        = 1,
@@ -168,6 +248,8 @@ struct dxgadapter {
        struct kref             adapter_kref;
        /* Entry in the list of adapters in dxgglobal */
        struct list_head        adapter_list_entry;
+       /* The list of dxgprocess_adapter entries */
+       struct list_head        adapter_process_list_head;
        struct pci_dev          *pci_dev;
        struct hv_device        *hv_dev;
        struct dxgvmbuschannel  channel;
@@ -191,6 +273,12 @@ void dxgadapter_release_lock_shared(struct dxgadapter 
*adapter);
 int dxgadapter_acquire_lock_exclusive(struct dxgadapter *adapter);
 void dxgadapter_acquire_lock_forced(struct dxgadapter *adapter);
 void dxgadapter_release_lock_exclusive(struct dxgadapter *adapter);
+void dxgadapter_add_process(struct dxgadapter *adapter,
+                           struct dxgprocess_adapter *process_info);
+void dxgadapter_remove_process(struct dxgprocess_adapter *process_info);
+
+long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2);
+long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2);
 
 /*
  * The convention is that VNBus instance id is a GUID, but the host sets
@@ -220,9 +308,14 @@ static inline void guid_to_luid(guid_t *guid, struct 
winluid *luid)
 
 void dxgvmb_initialize(void);
 int dxgvmb_send_set_iospace_region(u64 start, u64 len);
+int dxgvmb_send_create_process(struct dxgprocess *process);
+int dxgvmb_send_destroy_process(struct d3dkmthandle process);
 int dxgvmb_send_open_adapter(struct dxgadapter *adapter);
 int dxgvmb_send_close_adapter(struct dxgadapter *adapter);
 int dxgvmb_send_get_internal_adapter_info(struct dxgadapter *adapter);
+int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
+                                  struct dxgadapter *adapter,
+                                  struct d3dkmt_queryadapterinfo *args);
 int dxgvmb_send_async_msg(struct dxgvmbuschannel *channel,
                          void *command,
                          u32 cmd_size);
diff --git a/drivers/hv/dxgkrnl/dxgmodule.c b/drivers/hv/dxgkrnl/dxgmodule.c
index ef80b920f010..17c22001ca6c 100644
--- a/drivers/hv/dxgkrnl/dxgmodule.c
+++ b/drivers/hv/dxgkrnl/dxgmodule.c
@@ -123,6 +123,20 @@ static struct dxgadapter *find_adapter(struct winluid 
*luid)
        return adapter;
 }
 
+void dxgglobal_acquire_process_adapter_lock(void)
+{
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       mutex_lock(&dxgglobal->process_adapter_mutex);
+}
+
+void dxgglobal_release_process_adapter_lock(void)
+{
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       mutex_unlock(&dxgglobal->process_adapter_mutex);
+}
+
 /*
  * Creates a new dxgadapter object, which represents a virtual GPU, projected
  * by the host.
@@ -147,6 +161,7 @@ int dxgglobal_create_adapter(struct pci_dev *dev, guid_t 
*guid,
        kref_init(&adapter->adapter_kref);
        init_rwsem(&adapter->core_lock);
 
+       INIT_LIST_HEAD(&adapter->adapter_process_list_head);
        adapter->pci_dev = dev;
        guid_to_luid(guid, &adapter->luid);
 
@@ -205,8 +220,87 @@ static void dxgglobal_stop_adapters(void)
        dxgglobal_release_adapter_list_lock(DXGLOCK_EXCL);
 }
 
+/*
+ * Returns dxgprocess for the current executing process.
+ * Creates dxgprocess if it doesn't exist.
+ */
+static struct dxgprocess *dxgglobal_get_current_process(void)
+{
+       /*
+        * Find the DXG process for the current process.
+        * A new process is created if necessary.
+        */
+       struct dxgprocess *process = NULL;
+       struct dxgprocess *entry = NULL;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       mutex_lock(&dxgglobal->plistmutex);
+       list_for_each_entry(entry, &dxgglobal->plisthead, plistentry) {
+               /* All threads of a process have the same thread group ID */
+               if (entry->tgid == current->tgid) {
+                       if (kref_get_unless_zero(&entry->process_kref)) {
+                               process = entry;
+                               DXG_TRACE("found dxgprocess");
+                       } else {
+                               DXG_TRACE("process is destroyed");
+                       }
+                       break;
+               }
+       }
+       mutex_unlock(&dxgglobal->plistmutex);
+
+       if (process == NULL)
+               process = dxgprocess_create();
+
+       return process;
+}
+
+/*
+ * File operations for the /dev/dxg device
+ */
+
+static int dxgk_open(struct inode *n, struct file *f)
+{
+       int ret = 0;
+       struct dxgprocess *process;
+
+       DXG_TRACE("%p %d %d", f, current->pid, current->tgid);
+
+       /* Find/create a dxgprocess structure for this process */
+       process = dxgglobal_get_current_process();
+
+       if (process) {
+               f->private_data = process;
+       } else {
+               DXG_TRACE("cannot create dxgprocess");
+               ret = -EBADF;
+       }
+
+       return ret;
+}
+
+static int dxgk_release(struct inode *n, struct file *f)
+{
+       struct dxgprocess *process;
+
+       process = (struct dxgprocess *)f->private_data;
+       DXG_TRACE("%p, %p", f, process);
+
+       if (process == NULL)
+               return -EINVAL;
+
+       kref_put(&process->process_kref, dxgprocess_release);
+
+       f->private_data = NULL;
+       return 0;
+}
+
 const struct file_operations dxgk_fops = {
        .owner = THIS_MODULE,
+       .open = dxgk_open,
+       .release = dxgk_release,
+       .compat_ioctl = dxgk_compat_ioctl,
+       .unlocked_ioctl = dxgk_unlocked_ioctl,
 };
 
 /*
@@ -616,7 +710,10 @@ static struct dxgglobal *dxgglobal_create(void)
        if (!dxgglobal)
                return NULL;
 
+       INIT_LIST_HEAD(&dxgglobal->plisthead);
+       mutex_init(&dxgglobal->plistmutex);
        mutex_init(&dxgglobal->device_mutex);
+       mutex_init(&dxgglobal->process_adapter_mutex);
 
        INIT_LIST_HEAD(&dxgglobal->vgpu_ch_list_head);
        INIT_LIST_HEAD(&dxgglobal->adapter_list_head);
diff --git a/drivers/hv/dxgkrnl/dxgprocess.c b/drivers/hv/dxgkrnl/dxgprocess.c
new file mode 100644
index 000000000000..ab9a01e3c8c8
--- /dev/null
+++ b/drivers/hv/dxgkrnl/dxgprocess.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2022, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * DXGPROCESS implementation
+ *
+ */
+
+#include "dxgkrnl.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "dxgk: " fmt
+
+/*
+ * Creates a new dxgprocess object
+ * Must be called when dxgglobal->plistmutex is held
+ */
+struct dxgprocess *dxgprocess_create(void)
+{
+       struct dxgprocess *process;
+       int ret;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       process = kzalloc(sizeof(struct dxgprocess), GFP_KERNEL);
+       if (process != NULL) {
+               DXG_TRACE("new dxgprocess created");
+               process->pid = current->pid;
+               process->tgid = current->tgid;
+               ret = dxgvmb_send_create_process(process);
+               if (ret < 0) {
+                       DXG_TRACE("send_create_process failed");
+                       kfree(process);
+                       process = NULL;
+               } else {
+                       INIT_LIST_HEAD(&process->plistentry);
+                       kref_init(&process->process_kref);
+
+                       mutex_lock(&dxgglobal->plistmutex);
+                       list_add_tail(&process->plistentry,
+                                     &dxgglobal->plisthead);
+                       mutex_unlock(&dxgglobal->plistmutex);
+
+                       hmgrtable_init(&process->handle_table, process);
+                       hmgrtable_init(&process->local_handle_table, process);
+                       INIT_LIST_HEAD(&process->process_adapter_list_head);
+               }
+       }
+       return process;
+}
+
+void dxgprocess_destroy(struct dxgprocess *process)
+{
+       int i;
+       enum hmgrentry_type t;
+       struct d3dkmthandle h;
+       void *o;
+       struct dxgprocess_adapter *entry;
+       struct dxgprocess_adapter *tmp;
+
+       /* Destroy all adapter state */
+       dxgglobal_acquire_process_adapter_lock();
+       list_for_each_entry_safe(entry, tmp,
+                                &process->process_adapter_list_head,
+                                process_adapter_list_entry) {
+               dxgprocess_adapter_destroy(entry);
+       }
+       dxgglobal_release_process_adapter_lock();
+
+       i = 0;
+       while (hmgrtable_next_entry(&process->local_handle_table,
+                                   &i, &t, &h, &o)) {
+               switch (t) {
+               case HMGRENTRY_TYPE_DXGADAPTER:
+                       dxgprocess_close_adapter(process, h);
+                       break;
+               default:
+                       DXG_ERR("invalid entry in handle table %d", t);
+                       break;
+               }
+       }
+
+       hmgrtable_destroy(&process->handle_table);
+       hmgrtable_destroy(&process->local_handle_table);
+}
+
+void dxgprocess_release(struct kref *refcount)
+{
+       struct dxgprocess *process;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       process = container_of(refcount, struct dxgprocess, process_kref);
+
+       mutex_lock(&dxgglobal->plistmutex);
+       list_del(&process->plistentry);
+       mutex_unlock(&dxgglobal->plistmutex);
+
+       dxgprocess_destroy(process);
+
+       if (process->host_handle.v)
+               dxgvmb_send_destroy_process(process->host_handle);
+       kfree(process);
+}
+
+struct dxgprocess_adapter *dxgprocess_get_adapter_info(struct dxgprocess
+                                                      *process,
+                                                      struct dxgadapter
+                                                      *adapter)
+{
+       struct dxgprocess_adapter *entry;
+
+       list_for_each_entry(entry, &process->process_adapter_list_head,
+                           process_adapter_list_entry) {
+               if (adapter == entry->adapter) {
+                       DXG_TRACE("Found process info %p", entry);
+                       return entry;
+               }
+       }
+       return NULL;
+}
+
+/*
+ * Dxgprocess takes references on dxgadapter and dxgprocess_adapter.
+ *
+ * The process_adapter lock is held.
+ *
+ */
+int dxgprocess_open_adapter(struct dxgprocess *process,
+                                       struct dxgadapter *adapter,
+                                       struct d3dkmthandle *h)
+{
+       int ret = 0;
+       struct dxgprocess_adapter *adapter_info;
+       struct d3dkmthandle handle;
+
+       h->v = 0;
+       adapter_info = dxgprocess_get_adapter_info(process, adapter);
+       if (adapter_info == NULL) {
+               DXG_TRACE("creating new process adapter info");
+               adapter_info = dxgprocess_adapter_create(process, adapter);
+               if (adapter_info == NULL) {
+                       ret = -ENOMEM;
+                       goto cleanup;
+               }
+       } else {
+               adapter_info->refcount++;
+       }
+
+       handle = hmgrtable_alloc_handle_safe(&process->local_handle_table,
+                                            adapter, HMGRENTRY_TYPE_DXGADAPTER,
+                                            true);
+       if (handle.v) {
+               *h = handle;
+       } else {
+               DXG_ERR("failed to create adapter handle");
+               ret = -ENOMEM;
+       }
+
+cleanup:
+
+       if (ret < 0) {
+               if (adapter_info)
+                       dxgprocess_adapter_release(adapter_info);
+       }
+
+       return ret;
+}
+
+int dxgprocess_close_adapter(struct dxgprocess *process,
+                            struct d3dkmthandle handle)
+{
+       struct dxgadapter *adapter;
+       struct dxgprocess_adapter *adapter_info;
+       int ret = 0;
+
+       if (handle.v == 0)
+               return 0;
+
+       hmgrtable_lock(&process->local_handle_table, DXGLOCK_EXCL);
+       adapter = dxgprocess_get_adapter(process, handle);
+       if (adapter)
+               hmgrtable_free_handle(&process->local_handle_table,
+                                     HMGRENTRY_TYPE_DXGADAPTER, handle);
+       hmgrtable_unlock(&process->local_handle_table, DXGLOCK_EXCL);
+
+       if (adapter) {
+               adapter_info = dxgprocess_get_adapter_info(process, adapter);
+               if (adapter_info) {
+                       dxgglobal_acquire_process_adapter_lock();
+                       dxgprocess_adapter_release(adapter_info);
+                       dxgglobal_release_process_adapter_lock();
+               } else {
+                       ret = -EINVAL;
+               }
+       } else {
+               DXG_ERR("Adapter not found %x", handle.v);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+struct dxgadapter *dxgprocess_get_adapter(struct dxgprocess *process,
+                                         struct d3dkmthandle handle)
+{
+       struct dxgadapter *adapter;
+
+       adapter = hmgrtable_get_object_by_type(&process->local_handle_table,
+                                              HMGRENTRY_TYPE_DXGADAPTER,
+                                              handle);
+       if (adapter == NULL)
+               DXG_ERR("Adapter not found %x", handle.v);
+       return adapter;
+}
+
+/*
+ * Gets the adapter object from the process handle table.
+ * The adapter object is referenced.
+ * The function acquired the handle table lock shared.
+ */
+struct dxgadapter *dxgprocess_adapter_by_handle(struct dxgprocess *process,
+                                               struct d3dkmthandle handle)
+{
+       struct dxgadapter *adapter;
+
+       hmgrtable_lock(&process->local_handle_table, DXGLOCK_SHARED);
+       adapter = hmgrtable_get_object_by_type(&process->local_handle_table,
+                                              HMGRENTRY_TYPE_DXGADAPTER,
+                                              handle);
+       if (adapter == NULL)
+               DXG_ERR("adapter_by_handle failed %x", handle.v);
+       else if (kref_get_unless_zero(&adapter->adapter_kref) == 0) {
+               DXG_ERR("failed to acquire adapter reference");
+               adapter = NULL;
+       }
+       hmgrtable_unlock(&process->local_handle_table, DXGLOCK_SHARED);
+       return adapter;
+}
+
+void dxgprocess_ht_lock_shared_down(struct dxgprocess *process)
+{
+       hmgrtable_lock(&process->handle_table, DXGLOCK_SHARED);
+}
+
+void dxgprocess_ht_lock_shared_up(struct dxgprocess *process)
+{
+       hmgrtable_unlock(&process->handle_table, DXGLOCK_SHARED);
+}
+
+void dxgprocess_ht_lock_exclusive_down(struct dxgprocess *process)
+{
+       hmgrtable_lock(&process->handle_table, DXGLOCK_EXCL);
+}
+
+void dxgprocess_ht_lock_exclusive_up(struct dxgprocess *process)
+{
+       hmgrtable_unlock(&process->handle_table, DXGLOCK_EXCL);
+}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.c b/drivers/hv/dxgkrnl/dxgvmbus.c
index 6d4b8d9d8d07..0abf45d0d3f7 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.c
+++ b/drivers/hv/dxgkrnl/dxgvmbus.c
@@ -497,6 +497,87 @@ int dxgvmb_send_set_iospace_region(u64 start, u64 len)
        return ret;
 }
 
+int dxgvmb_send_create_process(struct dxgprocess *process)
+{
+       int ret;
+       struct dxgkvmb_command_createprocess *command;
+       struct dxgkvmb_command_createprocess_return result = { 0 };
+       struct dxgvmbusmsg msg;
+       char s[WIN_MAX_PATH];
+       int i;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       ret = init_message(&msg, NULL, process, 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_CREATEPROCESS);
+       command->process = process;
+       command->process_id = process->pid;
+       command->linux_process = 1;
+       s[0] = 0;
+       __get_task_comm(s, WIN_MAX_PATH, current);
+       for (i = 0; i < WIN_MAX_PATH; i++) {
+               command->process_name[i] = s[i];
+               if (s[i] == 0)
+                       break;
+       }
+
+       ret = dxgvmb_send_sync_msg(&dxgglobal->channel, msg.hdr, msg.size,
+                                  &result, sizeof(result));
+       if (ret < 0) {
+               DXG_ERR("create_process failed %d", ret);
+       } else if (result.hprocess.v == 0) {
+               DXG_ERR("create_process returned 0 handle");
+               ret = -ENOTRECOVERABLE;
+       } else {
+               process->host_handle = result.hprocess;
+               DXG_TRACE("create_process returned %x",
+                       process->host_handle.v);
+       }
+
+       dxgglobal_release_channel_lock();
+
+cleanup:
+       free_message(&msg, process);
+       if (ret)
+               DXG_TRACE("err: %d", ret);
+       return ret;
+}
+
+int dxgvmb_send_destroy_process(struct d3dkmthandle process)
+{
+       int ret;
+       struct dxgkvmb_command_destroyprocess *command;
+       struct dxgvmbusmsg msg;
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       ret = init_message(&msg, NULL, 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_init2(&command->hdr, DXGK_VMBCOMMAND_DESTROYPROCESS,
+                                process);
+       ret = dxgvmb_send_sync_msg_ntstatus(&dxgglobal->channel,
+                                           msg.hdr, msg.size);
+       dxgglobal_release_channel_lock();
+
+cleanup:
+       free_message(&msg, NULL);
+       if (ret)
+               DXG_TRACE("err: %d", ret);
+       return ret;
+}
+
 /*
  * Virtual GPU messages to the host
  */
@@ -591,3 +672,86 @@ int dxgvmb_send_get_internal_adapter_info(struct 
dxgadapter *adapter)
                DXG_ERR("Failed to get adapter info: %d", ret);
        return ret;
 }
+
+int dxgvmb_send_query_adapter_info(struct dxgprocess *process,
+                                  struct dxgadapter *adapter,
+                                  struct d3dkmt_queryadapterinfo *args)
+{
+       struct dxgkvmb_command_queryadapterinfo *command;
+       u32 cmd_size = sizeof(*command) + args->private_data_size - 1;
+       int ret;
+       u32 private_data_size;
+       void *private_data;
+       struct dxgvmbusmsg msg = {.hdr = NULL};
+       struct dxgglobal *dxgglobal = dxggbl();
+
+       ret = init_message(&msg, adapter, process, cmd_size);
+       if (ret)
+               goto cleanup;
+       command = (void *)msg.msg;
+
+       ret = copy_from_user(command->private_data,
+                            args->private_data, args->private_data_size);
+       if (ret) {
+               DXG_ERR("Faled to copy private data");
+               ret = -EINVAL;
+               goto cleanup;
+       }
+
+       command_vgpu_to_host_init2(&command->hdr,
+                                  DXGK_VMBCOMMAND_QUERYADAPTERINFO,
+                                  process->host_handle);
+       command->private_data_size = args->private_data_size;
+       command->query_type = args->type;
+
+       if (dxgglobal->vmbus_ver >= DXGK_VMBUS_INTERFACE_VERSION) {
+               private_data = msg.msg;
+               private_data_size = command->private_data_size +
+                                   sizeof(struct ntstatus);
+       } else {
+               private_data = command->private_data;
+               private_data_size = command->private_data_size;
+       }
+
+       ret = dxgvmb_send_sync_msg(msg.channel, msg.hdr, msg.size,
+                                  private_data, private_data_size);
+       if (ret < 0)
+               goto cleanup;
+
+       if (dxgglobal->vmbus_ver >= DXGK_VMBUS_INTERFACE_VERSION) {
+               ret = ntstatus2int(*(struct ntstatus *)private_data);
+               if (ret < 0)
+                       goto cleanup;
+               private_data = (char *)private_data + sizeof(struct ntstatus);
+       }
+
+       switch (args->type) {
+       case _KMTQAITYPE_ADAPTERTYPE:
+       case _KMTQAITYPE_ADAPTERTYPE_RENDER:
+               {
+                       struct d3dkmt_adaptertype *adapter_type =
+                           (void *)private_data;
+                       adapter_type->paravirtualized = 1;
+                       adapter_type->display_supported = 0;
+                       adapter_type->post_device = 0;
+                       adapter_type->indirect_display_device = 0;
+                       adapter_type->acg_supported = 0;
+                       adapter_type->support_set_timings_from_vidpn = 0;
+                       break;
+               }
+       default:
+               break;
+       }
+       ret = copy_to_user(args->private_data, private_data,
+                          args->private_data_size);
+       if (ret) {
+               DXG_ERR("Faled to copy private data to user");
+               ret = -EINVAL;
+       }
+
+cleanup:
+       free_message(&msg, process);
+       if (ret)
+               DXG_TRACE("err: %d", ret);
+       return ret;
+}
diff --git a/drivers/hv/dxgkrnl/dxgvmbus.h b/drivers/hv/dxgkrnl/dxgvmbus.h
index 584cdd3db6c0..a805a396e083 100644
--- a/drivers/hv/dxgkrnl/dxgvmbus.h
+++ b/drivers/hv/dxgkrnl/dxgvmbus.h
@@ -14,7 +14,11 @@
 #ifndef _DXGVMBUS_H
 #define _DXGVMBUS_H
 
+struct dxgprocess;
+struct dxgadapter;
+
 #define DXG_MAX_VM_BUS_PACKET_SIZE     (1024 * 128)
+#define DXG_VM_PROCESS_NAME_LENGTH     260
 
 enum dxgkvmb_commandchanneltype {
        DXGKVMB_VGPU_TO_HOST,
@@ -169,6 +173,26 @@ struct dxgkvmb_command_setiospaceregion {
        u32                             shared_page_gpadl;
 };
 
+struct dxgkvmb_command_createprocess {
+       struct dxgkvmb_command_vm_to_host hdr;
+       void                    *process;
+       u64                     process_id;
+       u16                     process_name[DXG_VM_PROCESS_NAME_LENGTH + 1];
+       u8                      csrss_process:1;
+       u8                      dwm_process:1;
+       u8                      wow64_process:1;
+       u8                      linux_process:1;
+};
+
+struct dxgkvmb_command_createprocess_return {
+       struct d3dkmthandle     hprocess;
+};
+
+// The command returns ntstatus
+struct dxgkvmb_command_destroyprocess {
+       struct dxgkvmb_command_vm_to_host hdr;
+};
+
 struct dxgkvmb_command_openadapter {
        struct dxgkvmb_command_vgpu_to_host hdr;
        u32                             vmbus_interface_version;
@@ -211,4 +235,16 @@ struct dxgkvmb_command_getinternaladapterinfo_return {
        struct winluid                  host_vgpu_luid;
 };
 
+struct dxgkvmb_command_queryadapterinfo {
+       struct dxgkvmb_command_vgpu_to_host hdr;
+       enum kmtqueryadapterinfotype    query_type;
+       u32                             private_data_size;
+       u8                              private_data[1];
+};
+
+struct dxgkvmb_command_queryadapterinfo_return {
+       struct ntstatus                 status;
+       u8                              private_data[1];
+};
+
 #endif /* _DXGVMBUS_H */
diff --git a/drivers/hv/dxgkrnl/hmgr.c b/drivers/hv/dxgkrnl/hmgr.c
new file mode 100644
index 000000000000..526b50f46d96
--- /dev/null
+++ b/drivers/hv/dxgkrnl/hmgr.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (c) 2022, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * Handle manager implementation
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+
+#include "misc.h"
+#include "dxgkrnl.h"
+#include "hmgr.h"
+
+#undef pr_fmt
+#define pr_fmt(fmt)    "dxgk: " fmt
+
+const struct d3dkmthandle zerohandle;
+
+/*
+ * Handle parameters
+ */
+#define HMGRHANDLE_INSTANCE_BITS       6
+#define HMGRHANDLE_INDEX_BITS          24
+#define HMGRHANDLE_UNIQUE_BITS         2
+
+#define HMGRHANDLE_INSTANCE_SHIFT      0
+#define HMGRHANDLE_INDEX_SHIFT \
+       (HMGRHANDLE_INSTANCE_BITS + HMGRHANDLE_INSTANCE_SHIFT)
+#define HMGRHANDLE_UNIQUE_SHIFT        \
+       (HMGRHANDLE_INDEX_BITS + HMGRHANDLE_INDEX_SHIFT)
+
+#define HMGRHANDLE_INSTANCE_MASK \
+       (((1 << HMGRHANDLE_INSTANCE_BITS) - 1) << HMGRHANDLE_INSTANCE_SHIFT)
+#define HMGRHANDLE_INDEX_MASK      \
+       (((1 << HMGRHANDLE_INDEX_BITS)    - 1) << HMGRHANDLE_INDEX_SHIFT)
+#define HMGRHANDLE_UNIQUE_MASK     \
+       (((1 << HMGRHANDLE_UNIQUE_BITS)   - 1) << HMGRHANDLE_UNIQUE_SHIFT)
+
+#define HMGRHANDLE_INSTANCE_MAX        ((1 << HMGRHANDLE_INSTANCE_BITS) - 1)
+#define HMGRHANDLE_INDEX_MAX   ((1 << HMGRHANDLE_INDEX_BITS) - 1)
+#define HMGRHANDLE_UNIQUE_MAX  ((1 << HMGRHANDLE_UNIQUE_BITS) - 1)
+
+/*
+ * Handle entry
+ */
+struct hmgrentry {
+       union {
+               void *object;
+               struct {
+                       u32 prev_free_index;
+                       u32 next_free_index;
+               };
+       };
+       u32 type:HMGRENTRY_TYPE_BITS + 1;
+       u32 unique:HMGRHANDLE_UNIQUE_BITS;
+       u32 instance:HMGRHANDLE_INSTANCE_BITS;
+       u32 destroyed:1;
+};
+
+#define HMGRTABLE_SIZE_INCREMENT       1024
+#define HMGRTABLE_MIN_FREE_ENTRIES 128
+#define HMGRTABLE_INVALID_INDEX (~((1 << HMGRHANDLE_INDEX_BITS) - 1))
+#define HMGRTABLE_SIZE_MAX             0xFFFFFFF
+
+static u32 table_size_increment = HMGRTABLE_SIZE_INCREMENT;
+
+static u32 get_unique(struct d3dkmthandle h)
+{
+       return (h.v & HMGRHANDLE_UNIQUE_MASK) >> HMGRHANDLE_UNIQUE_SHIFT;
+}
+
+static u32 get_index(struct d3dkmthandle h)
+{
+       return (h.v & HMGRHANDLE_INDEX_MASK) >> HMGRHANDLE_INDEX_SHIFT;
+}
+
+static bool is_handle_valid(struct hmgrtable *table, struct d3dkmthandle h,
+                           bool ignore_destroyed, enum hmgrentry_type t)
+{
+       u32 index = get_index(h);
+       u32 unique = get_unique(h);
+       struct hmgrentry *entry;
+
+       if (index >= table->table_size) {
+               DXG_ERR("Invalid index %x %d", h.v, index);
+               return false;
+       }
+
+       entry = &table->entry_table[index];
+       if (unique != entry->unique) {
+               DXG_ERR("Invalid unique %x %d %d %d %p",
+                       h.v, unique, entry->unique, index, entry->object);
+               return false;
+       }
+
+       if (entry->destroyed && !ignore_destroyed) {
+               DXG_ERR("Invalid destroyed value");
+               return false;
+       }
+
+       if (entry->type == HMGRENTRY_TYPE_FREE) {
+               DXG_ERR("Entry is freed %x %d", h.v, index);
+               return false;
+       }
+
+       if (t != HMGRENTRY_TYPE_FREE && t != entry->type) {
+               DXG_ERR("type mismatch %x %d %d", h.v, t, entry->type);
+               return false;
+       }
+
+       return true;
+}
+
+static struct d3dkmthandle build_handle(u32 index, u32 unique, u32 instance)
+{
+       struct d3dkmthandle handle;
+
+       handle.v = (index << HMGRHANDLE_INDEX_SHIFT) & HMGRHANDLE_INDEX_MASK;
+       handle.v |= (unique << HMGRHANDLE_UNIQUE_SHIFT) &
+           HMGRHANDLE_UNIQUE_MASK;
+       handle.v |= (instance << HMGRHANDLE_INSTANCE_SHIFT) &
+           HMGRHANDLE_INSTANCE_MASK;
+
+       return handle;
+}
+
+inline u32 hmgrtable_get_used_entry_count(struct hmgrtable *table)
+{
+       DXGKRNL_ASSERT(table->table_size >= table->free_count);
+       return (table->table_size - table->free_count);
+}
+
+bool hmgrtable_mark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
+{
+       if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+               return false;
+
+       table->entry_table[get_index(h)].destroyed = true;
+       return true;
+}
+
+bool hmgrtable_unmark_destroyed(struct hmgrtable *table, struct d3dkmthandle h)
+{
+       if (!is_handle_valid(table, h, true, HMGRENTRY_TYPE_FREE))
+               return true;
+
+       DXGKRNL_ASSERT(table->entry_table[get_index(h)].destroyed);
+       table->entry_table[get_index(h)].destroyed = 0;
+       return true;
+}
+
+static bool expand_table(struct hmgrtable *table, u32 NumEntries)
+{
+       u32 new_table_size;
+       struct hmgrentry *new_entry;
+       u32 table_index;
+       u32 new_free_count;
+       u32 prev_free_index;
+       u32 tail_index = table->free_handle_list_tail;
+
+       /* The tail should point to the last free element in the list */
+       if (table->free_count != 0) {
+               if (tail_index >= table->table_size ||
+                   table->entry_table[tail_index].next_free_index !=
+                   HMGRTABLE_INVALID_INDEX) {
+                       DXG_ERR("corruption");
+                       DXG_ERR("tail_index: %x", tail_index);
+                       DXG_ERR("table size: %x", table->table_size);
+                       DXG_ERR("free_count: %d", table->free_count);
+                       DXG_ERR("NumEntries: %x", NumEntries);
+                       return false;
+               }
+       }
+
+       new_free_count = table_size_increment + table->free_count;
+       new_table_size = table->table_size + table_size_increment;
+       if (new_table_size < NumEntries) {
+               new_free_count += NumEntries - new_table_size;
+               new_table_size = NumEntries;
+       }
+
+       if (new_table_size > HMGRHANDLE_INDEX_MAX) {
+               DXG_ERR("Invalid new table size");
+               return false;
+       }
+
+       new_entry = (struct hmgrentry *)
+           vzalloc(new_table_size * sizeof(struct hmgrentry));
+       if (new_entry == NULL) {
+               DXG_ERR("allocation failed");
+               return false;
+       }
+
+       if (table->entry_table) {
+               memcpy(new_entry, table->entry_table,
+                      table->table_size * sizeof(struct hmgrentry));
+               vfree(table->entry_table);
+       } else {
+               table->free_handle_list_head = 0;
+       }
+
+       table->entry_table = new_entry;
+
+       /* Initialize new table entries and add to the free list */
+       table_index = table->table_size;
+
+       prev_free_index = table->free_handle_list_tail;
+
+       while (table_index < new_table_size) {
+               struct hmgrentry *entry = &table->entry_table[table_index];
+
+               entry->prev_free_index = prev_free_index;
+               entry->next_free_index = table_index + 1;
+               entry->type = HMGRENTRY_TYPE_FREE;
+               entry->unique = 1;
+               entry->instance = 0;
+               prev_free_index = table_index;
+
+               table_index++;
+       }
+
+       table->entry_table[table_index - 1].next_free_index =
+           (u32) HMGRTABLE_INVALID_INDEX;
+
+       if (table->free_count != 0) {
+               /* Link the current free list with the new entries */
+               struct hmgrentry *entry;
+
+               entry = &table->entry_table[table->free_handle_list_tail];
+               entry->next_free_index = table->table_size;
+       }
+       table->free_handle_list_tail = new_table_size - 1;
+       if (table->free_handle_list_head == HMGRTABLE_INVALID_INDEX)
+               table->free_handle_list_head = table->table_size;
+
+       table->table_size = new_table_size;
+       table->free_count = new_free_count;
+
+       return true;
+}
+
+void hmgrtable_init(struct hmgrtable *table, struct dxgprocess *process)
+{
+       table->process = process;
+       table->entry_table = NULL;
+       table->table_size = 0;
+       table->free_handle_list_head = HMGRTABLE_INVALID_INDEX;
+       table->free_handle_list_tail = HMGRTABLE_INVALID_INDEX;
+       table->free_count = 0;
+       init_rwsem(&table->table_lock);
+}
+
+void hmgrtable_destroy(struct hmgrtable *table)
+{
+       if (table->entry_table) {
+               vfree(table->entry_table);
+               table->entry_table = NULL;
+       }
+}
+
+void hmgrtable_lock(struct hmgrtable *table, enum dxglockstate state)
+{
+       if (state == DXGLOCK_EXCL)
+               down_write(&table->table_lock);
+       else
+               down_read(&table->table_lock);
+}
+
+void hmgrtable_unlock(struct hmgrtable *table, enum dxglockstate state)
+{
+       if (state == DXGLOCK_EXCL)
+               up_write(&table->table_lock);
+       else
+               up_read(&table->table_lock);
+}
+
+struct d3dkmthandle hmgrtable_alloc_handle(struct hmgrtable *table,
+                                          void *object,
+                                          enum hmgrentry_type type,
+                                          bool make_valid)
+{
+       u32 index;
+       struct hmgrentry *entry;
+       u32 unique;
+
+       DXGKRNL_ASSERT(type <= HMGRENTRY_TYPE_LIMIT);
+       DXGKRNL_ASSERT(type > HMGRENTRY_TYPE_FREE);
+
+       if (table->free_count <= HMGRTABLE_MIN_FREE_ENTRIES) {
+               if (!expand_table(table, 0)) {
+                       DXG_ERR("hmgrtable expand_table failed");
+                       return zerohandle;
+               }
+       }
+
+       if (table->free_handle_list_head >= table->table_size) {
+               DXG_ERR("hmgrtable corrupted handle table head");
+               return zerohandle;
+       }
+
+       index = table->free_handle_list_head;
+       entry = &table->entry_table[index];
+
+       if (entry->type != HMGRENTRY_TYPE_FREE) {
+               DXG_ERR("hmgrtable expected free handle");
+               return zerohandle;
+       }
+
+       table->free_handle_list_head = entry->next_free_index;
+
+       if (entry->next_free_index != table->free_handle_list_tail) {
+               if (entry->next_free_index >= table->table_size) {
+                       DXG_ERR("hmgrtable invalid next free index");
+                       return zerohandle;
+               }
+               table->entry_table[entry->next_free_index].prev_free_index =
+                   HMGRTABLE_INVALID_INDEX;
+       }
+
+       unique = table->entry_table[index].unique;
+
+       table->entry_table[index].object = object;
+       table->entry_table[index].type = type;
+       table->entry_table[index].instance = 0;
+       table->entry_table[index].destroyed = !make_valid;
+       table->free_count--;
+       DXGKRNL_ASSERT(table->free_count <= table->table_size);
+
+       return build_handle(index, unique, table->entry_table[index].instance);
+}
+
+int hmgrtable_assign_handle_safe(struct hmgrtable *table,
+                                void *object,
+                                enum hmgrentry_type type,
+                                struct d3dkmthandle h)
+{
+       int ret;
+
+       hmgrtable_lock(table, DXGLOCK_EXCL);
+       ret = hmgrtable_assign_handle(table, object, type, h);
+       hmgrtable_unlock(table, DXGLOCK_EXCL);
+       return ret;
+}
+
+int hmgrtable_assign_handle(struct hmgrtable *table, void *object,
+                           enum hmgrentry_type type, struct d3dkmthandle h)
+{
+       u32 index = get_index(h);
+       u32 unique = get_unique(h);
+       struct hmgrentry *entry = NULL;
+
+       DXG_TRACE("%x, %d %p, %p", h.v, index, object, table);
+
+       if (index >= HMGRHANDLE_INDEX_MAX) {
+               DXG_ERR("handle index is too big: %x %d", h.v, index);
+               return -EINVAL;
+       }
+
+       if (index >= table->table_size) {
+               u32 new_size = index + table_size_increment;
+
+               if (new_size > HMGRHANDLE_INDEX_MAX)
+                       new_size = HMGRHANDLE_INDEX_MAX;
+               if (!expand_table(table, new_size)) {
+                       DXG_ERR("failed to expand handle table %d",
+                               new_size);
+                       return -ENOMEM;
+               }
+       }
+
+       entry = &table->entry_table[index];
+
+       if (entry->type != HMGRENTRY_TYPE_FREE) {
+               DXG_ERR("the entry is not free: %d %x", entry->type,
+                       hmgrtable_build_entry_handle(table, index).v);
+               return -EINVAL;
+       }
+
+       if (index != table->free_handle_list_tail) {
+               if (entry->next_free_index >= table->table_size) {
+                       DXG_ERR("hmgr: invalid next free index %d",
+                               entry->next_free_index);
+                       return -EINVAL;
+               }
+               table->entry_table[entry->next_free_index].prev_free_index =
+                   entry->prev_free_index;
+       } else {
+               table->free_handle_list_tail = entry->prev_free_index;
+       }
+
+       if (index != table->free_handle_list_head) {
+               if (entry->prev_free_index >= table->table_size) {
+                       DXG_ERR("hmgr: invalid next prev index %d",
+                               entry->prev_free_index);
+                       return -EINVAL;
+               }
+               table->entry_table[entry->prev_free_index].next_free_index =
+                   entry->next_free_index;
+       } else {
+               table->free_handle_list_head = entry->next_free_index;
+       }
+
+       entry->prev_free_index = HMGRTABLE_INVALID_INDEX;
+       entry->next_free_index = HMGRTABLE_INVALID_INDEX;
+       entry->object = object;
+       entry->type = type;
+       entry->instance = 0;
+       entry->unique = unique;
+       entry->destroyed = false;
+
+       table->free_count--;
+       DXGKRNL_ASSERT(table->free_count <= table->table_size);
+       return 0;
+}
+
+struct d3dkmthandle hmgrtable_alloc_handle_safe(struct hmgrtable *table,
+                                               void *obj,
+                                               enum hmgrentry_type type,
+                                               bool make_valid)
+{
+       struct d3dkmthandle h;
+
+       hmgrtable_lock(table, DXGLOCK_EXCL);
+       h = hmgrtable_alloc_handle(table, obj, type, make_valid);
+       hmgrtable_unlock(table, DXGLOCK_EXCL);
+       return h;
+}
+
+void hmgrtable_free_handle(struct hmgrtable *table, enum hmgrentry_type t,
+                          struct d3dkmthandle h)
+{
+       struct hmgrentry *entry;
+       u32 i = get_index(h);
+
+       DXG_TRACE("%p %x", table, h.v);
+
+       /* Ignore the destroyed flag when checking the handle */
+       if (is_handle_valid(table, h, true, t)) {
+               DXGKRNL_ASSERT(table->free_count < table->table_size);
+               entry = &table->entry_table[i];
+               entry->unique = 1;
+               entry->type = HMGRENTRY_TYPE_FREE;
+               entry->destroyed = 0;
+               if (entry->unique != HMGRHANDLE_UNIQUE_MAX)
+                       entry->unique += 1;
+               else
+                       entry->unique = 1;
+
+               table->free_count++;
+               DXGKRNL_ASSERT(table->free_count <= table->table_size);
+
+               /*
+                * Insert the index to the free list at the tail.
+                */
+               entry->next_free_index = HMGRTABLE_INVALID_INDEX;
+               entry->prev_free_index = table->free_handle_list_tail;
+               entry = &table->entry_table[table->free_handle_list_tail];
+               entry->next_free_index = i;
+               table->free_handle_list_tail = i;
+       } else {
+               DXG_ERR("Invalid handle to free: %d %x", i, h.v);
+       }
+}
+
+void hmgrtable_free_handle_safe(struct hmgrtable *table, enum hmgrentry_type t,
+                               struct d3dkmthandle h)
+{
+       hmgrtable_lock(table, DXGLOCK_EXCL);
+       hmgrtable_free_handle(table, t, h);
+       hmgrtable_unlock(table, DXGLOCK_EXCL);
+}
+
+struct d3dkmthandle hmgrtable_build_entry_handle(struct hmgrtable *table,
+                                                u32 index)
+{
+       DXGKRNL_ASSERT(index < table->table_size);
+
+       return build_handle(index, table->entry_table[index].unique,
+                           table->entry_table[index].instance);
+}
+
+void *hmgrtable_get_object(struct hmgrtable *table, struct d3dkmthandle h)
+{
+       if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+               return NULL;
+
+       return table->entry_table[get_index(h)].object;
+}
+
+void *hmgrtable_get_object_by_type(struct hmgrtable *table,
+                                  enum hmgrentry_type type,
+                                  struct d3dkmthandle h)
+{
+       if (!is_handle_valid(table, h, false, type)) {
+               DXG_ERR("Invalid handle %x", h.v);
+               return NULL;
+       }
+       return table->entry_table[get_index(h)].object;
+}
+
+void *hmgrtable_get_entry_object(struct hmgrtable *table, u32 index)
+{
+       DXGKRNL_ASSERT(index < table->table_size);
+       DXGKRNL_ASSERT(table->entry_table[index].type != HMGRENTRY_TYPE_FREE);
+
+       return table->entry_table[index].object;
+}
+
+static enum hmgrentry_type hmgrtable_get_entry_type(struct hmgrtable *table,
+                                                   u32 index)
+{
+       DXGKRNL_ASSERT(index < table->table_size);
+       return (enum hmgrentry_type)table->entry_table[index].type;
+}
+
+enum hmgrentry_type hmgrtable_get_object_type(struct hmgrtable *table,
+                                             struct d3dkmthandle h)
+{
+       if (!is_handle_valid(table, h, false, HMGRENTRY_TYPE_FREE))
+               return HMGRENTRY_TYPE_FREE;
+
+       return hmgrtable_get_entry_type(table, get_index(h));
+}
+
+void *hmgrtable_get_object_ignore_destroyed(struct hmgrtable *table,
+                                           struct d3dkmthandle h,
+                                           enum hmgrentry_type type)
+{
+       if (!is_handle_valid(table, h, true, type))
+               return NULL;
+       return table->entry_table[get_index(h)].object;
+}
+
+bool hmgrtable_next_entry(struct hmgrtable *tbl,
+                         u32 *index,
+                         enum hmgrentry_type *type,
+                         struct d3dkmthandle *handle,
+                         void **object)
+{
+       u32 i;
+       struct hmgrentry *entry;
+
+       for (i = *index; i < tbl->table_size; i++) {
+               entry = &tbl->entry_table[i];
+               if (entry->type != HMGRENTRY_TYPE_FREE) {
+                       *index = i + 1;
+                       *object = entry->object;
+                       *handle = build_handle(i, entry->unique,
+                                              entry->instance);
+                       *type = entry->type;
+                       return true;
+               }
+       }
+       return false;
+}
diff --git a/drivers/hv/dxgkrnl/hmgr.h b/drivers/hv/dxgkrnl/hmgr.h
new file mode 100644
index 000000000000..23eec301137f
--- /dev/null
+++ b/drivers/hv/dxgkrnl/hmgr.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2022, Microsoft Corporation.
+ *
+ * Author:
+ *   Iouri Tarassov <[email protected]>
+ *
+ * Dxgkrnl Graphics Driver
+ * Handle manager definitions
+ *
+ */
+
+#ifndef _HMGR_H_
+#define _HMGR_H_
+
+#include "misc.h"
+
+struct hmgrentry;
+
+/*
+ * Handle manager table.
+ *
+ * Implementation notes:
+ *   A list of free handles is built on top of the array of table entries.
+ *   free_handle_list_head is the index of the first entry in the list.
+ *   m_FreeHandleListTail is the index of an entry in the list, which is
+ *   HMGRTABLE_MIN_FREE_ENTRIES from the head. It means that when a handle is
+ *   freed, the next time the handle can be re-used is after allocating
+ *   HMGRTABLE_MIN_FREE_ENTRIES number of handles.
+ *   Handles are allocated from the start of the list and free handles are
+ *   inserted after the tail of the list.
+ *
+ */
+struct hmgrtable {
+       struct dxgprocess       *process;
+       struct hmgrentry        *entry_table;
+       u32                     free_handle_list_head;
+       u32                     free_handle_list_tail;
+       u32                     table_size;
+       u32                     free_count;
+       struct rw_semaphore     table_lock;
+};
+
+/*
+ * Handle entry data types.
+ */
+#define HMGRENTRY_TYPE_BITS 5
+
+enum hmgrentry_type {
+       HMGRENTRY_TYPE_FREE                             = 0,
+       HMGRENTRY_TYPE_DXGADAPTER                       = 1,
+       HMGRENTRY_TYPE_DXGSHAREDRESOURCE                = 2,
+       HMGRENTRY_TYPE_DXGDEVICE                        = 3,
+       HMGRENTRY_TYPE_DXGRESOURCE                      = 4,
+       HMGRENTRY_TYPE_DXGALLOCATION                    = 5,
+       HMGRENTRY_TYPE_DXGOVERLAY                       = 6,
+       HMGRENTRY_TYPE_DXGCONTEXT                       = 7,
+       HMGRENTRY_TYPE_DXGSYNCOBJECT                    = 8,
+       HMGRENTRY_TYPE_DXGKEYEDMUTEX                    = 9,
+       HMGRENTRY_TYPE_DXGPAGINGQUEUE                   = 10,
+       HMGRENTRY_TYPE_DXGDEVICESYNCOBJECT              = 11,
+       HMGRENTRY_TYPE_DXGPROCESS                       = 12,
+       HMGRENTRY_TYPE_DXGSHAREDVMOBJECT                = 13,
+       HMGRENTRY_TYPE_DXGPROTECTEDSESSION              = 14,
+       HMGRENTRY_TYPE_DXGHWQUEUE                       = 15,
+       HMGRENTRY_TYPE_DXGREMOTEBUNDLEOBJECT            = 16,
+       HMGRENTRY_TYPE_DXGCOMPOSITIONSURFACEOBJECT      = 17,
+       HMGRENTRY_TYPE_DXGCOMPOSITIONSURFACEPROXY       = 18,
+       HMGRENTRY_TYPE_DXGTRACKEDWORKLOAD               = 19,
+       HMGRENTRY_TYPE_LIMIT            = ((1 << HMGRENTRY_TYPE_BITS) - 1),
+       HMGRENTRY_TYPE_MONITOREDFENCE   = HMGRENTRY_TYPE_LIMIT + 1,
+};
+
+void hmgrtable_init(struct hmgrtable *tbl, struct dxgprocess *process);
+void hmgrtable_destroy(struct hmgrtable *tbl);
+void hmgrtable_lock(struct hmgrtable *tbl, enum dxglockstate state);
+void hmgrtable_unlock(struct hmgrtable *tbl, enum dxglockstate state);
+struct d3dkmthandle hmgrtable_alloc_handle(struct hmgrtable *tbl, void *object,
+                                    enum hmgrentry_type t, bool make_valid);
+struct d3dkmthandle hmgrtable_alloc_handle_safe(struct hmgrtable *tbl,
+                                               void *obj,
+                                               enum hmgrentry_type t,
+                                               bool reserve);
+int hmgrtable_assign_handle(struct hmgrtable *tbl, void *obj,
+                           enum hmgrentry_type, struct d3dkmthandle h);
+int hmgrtable_assign_handle_safe(struct hmgrtable *tbl, void *obj,
+                                enum hmgrentry_type t, struct d3dkmthandle h);
+void hmgrtable_free_handle(struct hmgrtable *tbl, enum hmgrentry_type t,
+                          struct d3dkmthandle h);
+void hmgrtable_free_handle_safe(struct hmgrtable *tbl, enum hmgrentry_type t,
+                               struct d3dkmthandle h);
+struct d3dkmthandle hmgrtable_build_entry_handle(struct hmgrtable *tbl,
+                                                u32 index);
+enum hmgrentry_type hmgrtable_get_object_type(struct hmgrtable *tbl,
+                                             struct d3dkmthandle h);
+void *hmgrtable_get_object(struct hmgrtable *tbl, struct d3dkmthandle h);
+void *hmgrtable_get_object_by_type(struct hmgrtable *tbl, enum hmgrentry_type 
t,
+                                  struct d3dkmthandle h);
+void *hmgrtable_get_object_ignore_destroyed(struct hmgrtable *tbl,
+                                           struct d3dkmthandle h,
+                                           enum hmgrentry_type t);
+bool hmgrtable_mark_destroyed(struct hmgrtable *tbl, struct d3dkmthandle h);
+bool hmgrtable_unmark_destroyed(struct hmgrtable *tbl, struct d3dkmthandle h);
+void *hmgrtable_get_entry_object(struct hmgrtable *tbl, u32 index);
+bool hmgrtable_next_entry(struct hmgrtable *tbl,
+                         u32 *start_index,
+                         enum hmgrentry_type *type,
+                         struct d3dkmthandle *handle,
+                         void **object);
+
+#endif
diff --git a/drivers/hv/dxgkrnl/ioctl.c b/drivers/hv/dxgkrnl/ioctl.c
index 23ecd15b0cd7..60e38d104517 100644
--- a/drivers/hv/dxgkrnl/ioctl.c
+++ b/drivers/hv/dxgkrnl/ioctl.c
@@ -22,3 +22,63 @@
 
 #undef pr_fmt
 #define pr_fmt(fmt)    "dxgk: " fmt
+
+struct ioctl_desc {
+       int (*ioctl_callback)(struct dxgprocess *p, void __user *arg);
+       u32 ioctl;
+       u32 arg_size;
+};
+
+static struct ioctl_desc ioctls[] = {
+
+};
+
+/*
+ * IOCTL processing
+ * The driver IOCTLs return
+ * - 0 in case of success
+ * - positive values, which are Windows NTSTATUS (for example, STATUS_PENDING).
+ *   Positive values are success codes.
+ * - Linux negative error codes
+ */
+static int dxgk_ioctl(struct file *f, unsigned int p1, unsigned long p2)
+{
+       int code = _IOC_NR(p1);
+       int status;
+       struct dxgprocess *process;
+
+       if (code < 1 ||  code >= ARRAY_SIZE(ioctls)) {
+               DXG_ERR("bad ioctl %x %x %x %x",
+                       code, _IOC_TYPE(p1), _IOC_SIZE(p1), _IOC_DIR(p1));
+               return -ENOTTY;
+       }
+       if (ioctls[code].ioctl_callback == NULL) {
+               DXG_ERR("ioctl callback is NULL %x", code);
+               return -ENOTTY;
+       }
+       if (ioctls[code].ioctl != p1) {
+               DXG_ERR("ioctl mismatch. Code: %x User: %x Kernel: %x",
+                       code, p1, ioctls[code].ioctl);
+               return -ENOTTY;
+       }
+       process = (struct dxgprocess *)f->private_data;
+       if (process->tgid != current->tgid) {
+               DXG_ERR("Call from a wrong process: %d %d",
+                       process->tgid, current->tgid);
+               return -ENOTTY;
+       }
+       status = ioctls[code].ioctl_callback(process, (void *__user)p2);
+       return status;
+}
+
+long dxgk_compat_ioctl(struct file *f, unsigned int p1, unsigned long p2)
+{
+       DXG_TRACE("compat ioctl %x", p1);
+       return dxgk_ioctl(f, p1, p2);
+}
+
+long dxgk_unlocked_ioctl(struct file *f, unsigned int p1, unsigned long p2)
+{
+       DXG_TRACE("unlocked ioctl %x Code:%d", p1, _IOC_NR(p1));
+       return dxgk_ioctl(f, p1, p2);
+}
diff --git a/drivers/hv/dxgkrnl/misc.h b/drivers/hv/dxgkrnl/misc.h
index d292e9a9bb7f..dc849a8ed3f2 100644
--- a/drivers/hv/dxgkrnl/misc.h
+++ b/drivers/hv/dxgkrnl/misc.h
@@ -27,10 +27,11 @@ extern const struct d3dkmthandle zerohandle;
  *
  * channel_lock (VMBus channel lock)
  * fd_mutex
- * plistmutex (process list mutex)
- * table_lock (handle table lock)
- * core_lock (dxgadapter lock)
- * device_lock (dxgdevice lock)
+ * plistmutex
+ * table_lock
+ * core_lock
+ * device_lock
+ * process_adapter_mutex
  * adapter_list_lock
  * device_mutex (dxgglobal mutex)
  */
diff --git a/include/uapi/misc/d3dkmthk.h b/include/uapi/misc/d3dkmthk.h
index 2ea04cc02a1f..c675d5827ed5 100644
--- a/include/uapi/misc/d3dkmthk.h
+++ b/include/uapi/misc/d3dkmthk.h
@@ -58,4 +58,107 @@ struct winluid {
        __u32 b;
 };
 
+#define D3DKMT_ADAPTERS_MAX                    64
+
+struct d3dkmt_adapterinfo {
+       struct d3dkmthandle             adapter_handle;
+       struct winluid                  adapter_luid;
+       __u32                           num_sources;
+       __u32                           present_move_regions_preferred;
+};
+
+struct d3dkmt_enumadapters2 {
+       __u32                           num_adapters;
+       __u32                           reserved;
+#ifdef __KERNEL__
+       struct d3dkmt_adapterinfo       *adapters;
+#else
+       __u64                           *adapters;
+#endif
+};
+
+struct d3dkmt_closeadapter {
+       struct d3dkmthandle             adapter_handle;
+};
+
+struct d3dkmt_openadapterfromluid {
+       struct winluid                  adapter_luid;
+       struct d3dkmthandle             adapter_handle;
+};
+
+struct d3dkmt_adaptertype {
+       union {
+               struct {
+                       __u32           render_supported:1;
+                       __u32           display_supported:1;
+                       __u32           software_device:1;
+                       __u32           post_device:1;
+                       __u32           hybrid_discrete:1;
+                       __u32           hybrid_integrated:1;
+                       __u32           indirect_display_device:1;
+                       __u32           paravirtualized:1;
+                       __u32           acg_supported:1;
+                       __u32           support_set_timings_from_vidpn:1;
+                       __u32           detachable:1;
+                       __u32           compute_only:1;
+                       __u32           prototype:1;
+                       __u32           reserved:19;
+               };
+               __u32                   value;
+       };
+};
+
+enum kmtqueryadapterinfotype {
+       _KMTQAITYPE_UMDRIVERPRIVATE     = 0,
+       _KMTQAITYPE_ADAPTERTYPE         = 15,
+       _KMTQAITYPE_ADAPTERTYPE_RENDER  = 57
+};
+
+struct d3dkmt_queryadapterinfo {
+       struct d3dkmthandle             adapter;
+       enum kmtqueryadapterinfotype    type;
+#ifdef __KERNEL__
+       void                            *private_data;
+#else
+       __u64                           private_data;
+#endif
+       __u32                           private_data_size;
+};
+
+union d3dkmt_enumadapters_filter {
+       struct {
+               __u64   include_compute_only:1;
+               __u64   include_display_only:1;
+               __u64   reserved:62;
+       };
+       __u64           value;
+};
+
+struct d3dkmt_enumadapters3 {
+       union d3dkmt_enumadapters_filter        filter;
+       __u32                                   adapter_count;
+       __u32                                   reserved;
+#ifdef __KERNEL__
+       struct d3dkmt_adapterinfo               *adapters;
+#else
+       __u64                                   adapters;
+#endif
+};
+
+/*
+ * Dxgkrnl Graphics Port Driver ioctl definitions
+ *
+ */
+
+#define LX_DXOPENADAPTERFROMLUID       \
+       _IOWR(0x47, 0x01, struct d3dkmt_openadapterfromluid)
+#define LX_DXQUERYADAPTERINFO          \
+       _IOWR(0x47, 0x09, struct d3dkmt_queryadapterinfo)
+#define LX_DXENUMADAPTERS2             \
+       _IOWR(0x47, 0x14, struct d3dkmt_enumadapters2)
+#define LX_DXCLOSEADAPTER              \
+       _IOWR(0x47, 0x15, struct d3dkmt_closeadapter)
+#define LX_DXENUMADAPTERS3             \
+       _IOWR(0x47, 0x3e, struct d3dkmt_enumadapters3)
+
 #endif /* _D3DKMTHK_H */

Reply via email to