--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1539,13 +1539,13 @@ int xc_get_device_group(
 
 int xc_test_assign_device(
     xc_interface *xch,
-    uint32_t domid,
+    uint32_t domid, /* ignored */
     uint32_t machine_sbdf)
 {
     DECLARE_DOMCTL;
 
     domctl.cmd = XEN_DOMCTL_test_assign_device;
-    domctl.domain = domid;
+    domctl.domain = DOMID_INVALID;
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
     domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
     domctl.u.assign_device.flags = 0;
@@ -1603,7 +1603,7 @@ int xc_assign_dt_device(
 
 int xc_test_assign_dt_device(
     xc_interface *xch,
-    uint32_t domid,
+    uint32_t domid, /* ignored */
     char *path)
 {
     int rc;
@@ -1615,7 +1615,7 @@ int xc_test_assign_dt_device(
         return -1;
 
     domctl.cmd = XEN_DOMCTL_test_assign_device;
-    domctl.domain = (domid_t)domid;
+    domctl.domain = DOMID_INVALID;
 
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
     domctl.u.assign_device.u.dt.size = size;
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -391,11 +391,15 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xe
 
     switch ( op->cmd )
     {
-    case XEN_DOMCTL_createdomain:
     case XEN_DOMCTL_test_assign_device:
+        if ( op->domain == DOMID_INVALID )
+        {
+    case XEN_DOMCTL_createdomain:
     case XEN_DOMCTL_gdbsx_guestmemio:
-        d = NULL;
-        break;
+            d = NULL;
+            break;
+        }
+        /* fall through */
     default:
         d = rcu_lock_domain_by_id(op->domain);
         if ( !d && op->cmd != XEN_DOMCTL_getdomaininfo )
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -93,7 +93,8 @@ fail:
     return rc;
 }
 
-static bool_t iommu_dt_device_is_assigned(const struct dt_device_node *dev)
+static bool_t iommu_dt_device_is_assigned(const struct domain *d,
+                                          const struct dt_device_node *dev)
 {
     bool_t assigned = 0;
 
@@ -101,7 +102,8 @@ static bool_t iommu_dt_device_is_assigne
         return 0;
 
     spin_lock(&dtdevs_lock);
-    assigned = !list_empty(&dev->domain_list);
+    assigned = d ? dt_device_used_by(dev) == d->domain_id
+                 : !list_empty(&dev->domain_list);
     spin_unlock(&dtdevs_lock);
 
     return assigned;
@@ -209,11 +211,11 @@ int iommu_do_dt_domctl(struct xen_domctl
         if ( ret )
             break;
 
-        ret = xsm_test_assign_dtdevice(XSM_HOOK, dt_node_full_name(dev));
+        ret = xsm_test_assign_dtdevice(XSM_HOOK, d, dt_node_full_name(dev));
         if ( ret )
             break;
 
-        if ( iommu_dt_device_is_assigned(dev) )
+        if ( iommu_dt_device_is_assigned(d, dev) )
         {
             printk(XENLOG_G_ERR "%s already assigned.\n",
                    dt_node_full_name(dev));
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -522,7 +522,7 @@ struct pci_dev *pci_get_real_pdev(int se
 }
 
 struct pci_dev *pci_get_pdev_by_domain(
-    struct domain *d, int seg, int bus, int devfn)
+    const struct domain *d, int seg, int bus, int devfn)
 {
     struct pci_seg *pseg = get_pseg(seg);
     struct pci_dev *pdev = NULL;
@@ -1337,12 +1337,12 @@ int iommu_remove_device(struct pci_dev *
  * If the device isn't owned by the hardware domain, it means it already
  * has been assigned to other domain, or it doesn't exist.
  */
-static int device_assigned(u16 seg, u8 bus, u8 devfn)
+static int device_assigned(const struct domain *d, u16 seg, u8 bus, u8 devfn)
 {
-    struct pci_dev *pdev;
+    const struct pci_dev *pdev;
 
     pcidevs_lock();
-    pdev = pci_get_pdev_by_domain(hardware_domain, seg, bus, devfn);
+    pdev = pci_get_pdev_by_domain(d ?: hardware_domain, seg, bus, devfn);
     pcidevs_unlock();
 
     return pdev ? 0 : -EBUSY;
@@ -1590,7 +1590,7 @@ int iommu_do_pci_domctl(
 
         machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
 
-        ret = xsm_test_assign_device(XSM_HOOK, machine_sbdf);
+        ret = xsm_test_assign_device(XSM_HOOK, d, machine_sbdf);
         if ( ret )
             break;
 
@@ -1598,13 +1598,12 @@ int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
-        if ( device_assigned(seg, bus, devfn) )
-        {
+        ret = device_assigned(d, seg, bus, devfn);
+        if ( ret && !d )
             printk(XENLOG_G_INFO
                    "%04x:%02x:%02x.%u already assigned, or non-existent\n",
                    seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-            ret = -EINVAL;
-        }
+
         break;
 
     case XEN_DOMCTL_assign_device:
@@ -1634,7 +1633,7 @@ int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
-        ret = device_assigned(seg, bus, devfn) ?:
+        ret = device_assigned(NULL, seg, bus, devfn) ?:
               assign_device(d, seg, bus, devfn, flags);
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -506,7 +506,11 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendt
 
 /* Assign a device to a guest. Sets up IOMMU structures. */
 /* XEN_DOMCTL_assign_device */
-/* XEN_DOMCTL_test_assign_device */
+/*
+ * XEN_DOMCTL_test_assign_device: Pass DOMID_INVALID to find out whether the
+ * given device is assigned to a DomU at all. Pass a specific domain ID to
+ * find out whether the given device is assigned to that domain.
+ */
 /*
  * XEN_DOMCTL_deassign_device: The behavior of this DOMCTL differs
  * between the different type of device:
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -125,8 +125,8 @@ int pci_ro_device(int seg, int bus, int
 int pci_hide_device(int bus, int devfn);
 struct pci_dev *pci_get_pdev(int seg, int bus, int devfn);
 struct pci_dev *pci_get_real_pdev(int seg, int bus, int devfn);
-struct pci_dev *pci_get_pdev_by_domain(
-    struct domain *, int seg, int bus, int devfn);
+struct pci_dev *pci_get_pdev_by_domain(const struct domain *,
+                                       int seg, int bus, int devfn);
 void pci_check_disable_device(u16 seg, u8 bus, u8 devfn);
 
 uint8_t pci_conf_read8(
--- a/xen/include/xsm/dummy.h
+++ b/xen/include/xsm/dummy.h
@@ -337,10 +337,11 @@ static XSM_INLINE int xsm_get_device_gro
     return xsm_default_action(action, current->domain, NULL);
 }
 
-static XSM_INLINE int xsm_test_assign_device(XSM_DEFAULT_ARG uint32_t machine_bdf)
+static XSM_INLINE int xsm_test_assign_device(XSM_DEFAULT_ARG struct domain *d,
+                                             uint32_t machine_bdf)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
-    return xsm_default_action(action, current->domain, NULL);
+    return xsm_default_action(action, current->domain, d);
 }
 
 static XSM_INLINE int xsm_assign_device(XSM_DEFAULT_ARG struct domain *d, uint32_t machine_bdf)
@@ -358,10 +359,11 @@ static XSM_INLINE int xsm_deassign_devic
 #endif /* HAS_PASSTHROUGH && HAS_PCI */
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-static XSM_INLINE int xsm_test_assign_dtdevice(XSM_DEFAULT_ARG const char *dtpath)
+static XSM_INLINE int xsm_test_assign_dtdevice(XSM_DEFAULT_ARG struct domain *d,
+                                               const char *dtpath)
 {
     XSM_ASSERT_ACTION(XSM_HOOK);
-    return xsm_default_action(action, current->domain, NULL);
+    return xsm_default_action(action, current->domain, d);
 }
 
 static XSM_INLINE int xsm_assign_dtdevice(XSM_DEFAULT_ARG struct domain *d,
--- a/xen/include/xsm/xsm.h
+++ b/xen/include/xsm/xsm.h
@@ -109,13 +109,13 @@ struct xsm_operations {
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_PCI)
     int (*get_device_group) (uint32_t machine_bdf);
-    int (*test_assign_device) (uint32_t machine_bdf);
+    int (*test_assign_device) (struct domain *d, uint32_t machine_bdf);
     int (*assign_device) (struct domain *d, uint32_t machine_bdf);
     int (*deassign_device) (struct domain *d, uint32_t machine_bdf);
 #endif
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-    int (*test_assign_dtdevice) (const char *dtpath);
+    int (*test_assign_dtdevice) (struct domain *d, const char *dtpath);
     int (*assign_dtdevice) (struct domain *d, const char *dtpath);
     int (*deassign_dtdevice) (struct domain *d, const char *dtpath);
 #endif
@@ -465,9 +465,9 @@ static inline int xsm_get_device_group(x
     return xsm_ops->get_device_group(machine_bdf);
 }
 
-static inline int xsm_test_assign_device(xsm_default_t def, uint32_t machine_bdf)
+static inline int xsm_test_assign_device(xsm_default_t def, struct domain *d, uint32_t machine_bdf)
 {
-    return xsm_ops->test_assign_device(machine_bdf);
+    return xsm_ops->test_assign_device(d, machine_bdf);
 }
 
 static inline int xsm_assign_device(xsm_default_t def, struct domain *d, uint32_t machine_bdf)
@@ -488,10 +488,10 @@ static inline int xsm_assign_dtdevice(xs
     return xsm_ops->assign_dtdevice(d, dtpath);
 }
 
-static inline int xsm_test_assign_dtdevice(xsm_default_t def,
+static inline int xsm_test_assign_dtdevice(xsm_default_t def, struct domain *d,
                                            const char *dtpath)
 {
-    return xsm_ops->test_assign_dtdevice(dtpath);
+    return xsm_ops->test_assign_dtdevice(d, dtpath);
 }
 
 static inline int xsm_deassign_dtdevice(xsm_default_t def, struct domain *d,
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -1260,7 +1260,7 @@ static int flask_get_device_group(uint32
     return avc_current_has_perm(rsid, SECCLASS_RESOURCE, RESOURCE__STAT_DEVICE, NULL);
 }
 
-static int flask_test_assign_device(uint32_t machine_bdf)
+static int flask_test_assign_device(struct domain *d, uint32_t machine_bdf)
 {
     u32 rsid;
     int rc = -EPERM;
@@ -1314,7 +1314,7 @@ static int flask_deassign_device(struct
 #endif /* HAS_PASSTHROUGH && HAS_PCI */
 
 #if defined(CONFIG_HAS_PASSTHROUGH) && defined(CONFIG_HAS_DEVICE_TREE)
-static int flask_test_assign_dtdevice(const char *dtpath)
+static int flask_test_assign_dtdevice(struct domain *d, const char *dtpath)
 {
     u32 rsid;
     int rc = -EPERM;
