[PATCH v4 1/5] hyperv: Introduce new hypercall interfaces used by Hyper-V guest IOMMU
From: Yu Zhang
Date: Fri Aug 21 2026 - 09:29:52 EST
From: Wei Liu <wei.liu@xxxxxxxxxx>
Hyper-V guest IOMMU is a para-virtualized IOMMU based on hypercalls.
Introduce the hypercalls used by the child partition to interact with
this facility.
These hypercalls fall into below categories:
- Detection and capability: HVCALL_GET_IOMMU_CAPABILITIES is used to
detect the existence and capabilities of the guest IOMMU.
- Device management: HVCALL_GET_LOGICAL_DEVICE_PROPERTY is used to
check whether an endpoint device is managed by the guest IOMMU.
- Domain management: A set of hypercalls is provided to handle the
creation, configuration, and deletion of guest domains, as well as
the attachment/detachment of endpoint devices to/from those domains.
- IOTLB flushing: HVCALL_FLUSH_DEVICE_DOMAIN is used to ask Hyper-V
for a domain-selective IOTLB flush (which in its handler may flush
the device TLB as well).
Signed-off-by: Wei Liu <wei.liu@xxxxxxxxxx>
Co-developed-by: Easwar Hariharan <easwar.hariharan@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Easwar Hariharan <easwar.hariharan@xxxxxxxxxxxxxxxxxxx>
Co-developed-by: Yu Zhang <zhangyu1@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Yu Zhang <zhangyu1@xxxxxxxxxxxxxxxxxxx>
Reviewed-by: Jacob Pan <jacob.pan@xxxxxxxxxxxxxxxxxxx>
---
drivers/hv/hv_common.c | 1 +
include/hyperv/hvgdk_mini.h | 9 +++
include/hyperv/hvhdk_mini.h | 137 ++++++++++++++++++++++++++++++++++++
3 files changed, 147 insertions(+)
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
index 6b67ac616789..b5d2d6cd65ae 100644
--- a/drivers/hv/hv_common.c
+++ b/drivers/hv/hv_common.c
@@ -810,6 +810,7 @@ static const struct hv_status_info hv_status_infos[] = {
_STATUS_INFO(HV_STATUS_INVALID_REGISTER_VALUE, -EINVAL),
_STATUS_INFO(HV_STATUS_INVALID_LP_INDEX, -EIO),
_STATUS_INFO(HV_STATUS_INVALID_REGISTER_VALUE, -EIO),
+ _STATUS_INFO(HV_STATUS_DEVICE_ALREADY_IN_DOMAIN, -EEXIST),
_STATUS_INFO(HV_STATUS_OPERATION_FAILED, -EIO),
_STATUS_INFO(HV_STATUS_TIME_OUT, -EIO),
_STATUS_INFO(HV_STATUS_CALL_PENDING, -EIO),
diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h
index 6a4e8b9d570f..5d1338197eee 100644
--- a/include/hyperv/hvgdk_mini.h
+++ b/include/hyperv/hvgdk_mini.h
@@ -37,6 +37,7 @@ struct hv_u128 {
#define HV_STATUS_PROCESSOR_FEATURE_NOT_SUPPORTED 0x20
#define HV_STATUS_INVALID_LP_INDEX 0x41
#define HV_STATUS_INVALID_REGISTER_VALUE 0x50
+#define HV_STATUS_DEVICE_ALREADY_IN_DOMAIN 0x66
#define HV_STATUS_OPERATION_FAILED 0x71
#define HV_STATUS_INSUFFICIENT_ROOT_MEMORY 0x73
#define HV_STATUS_INSUFFICIENT_CONTIGUOUS_MEMORY 0x75
@@ -486,10 +487,16 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
#define HVCALL_GET_VP_INDEX_FROM_APIC_ID 0x009a
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE 0x00af
#define HVCALL_FLUSH_GUEST_PHYSICAL_ADDRESS_LIST 0x00b0
+#define HVCALL_CREATE_DEVICE_DOMAIN 0x00b1
+#define HVCALL_ATTACH_DEVICE_DOMAIN 0x00b2
#define HVCALL_SIGNAL_EVENT_DIRECT 0x00c0
#define HVCALL_POST_MESSAGE_DIRECT 0x00c1
#define HVCALL_DISPATCH_VP 0x00c2
+#define HVCALL_DETACH_DEVICE_DOMAIN 0x00c4
+#define HVCALL_DELETE_DEVICE_DOMAIN 0x00c5
#define HVCALL_GET_GPA_PAGES_ACCESS_STATES 0x00c9
+#define HVCALL_CONFIGURE_DEVICE_DOMAIN 0x00ce
+#define HVCALL_FLUSH_DEVICE_DOMAIN 0x00d0
#define HVCALL_ACQUIRE_SPARSE_SPA_PAGE_HOST_ACCESS 0x00d7
#define HVCALL_RELEASE_SPARSE_SPA_PAGE_HOST_ACCESS 0x00d8
#define HVCALL_MODIFY_SPARSE_GPA_PAGE_HOST_VISIBILITY 0x00db
@@ -502,6 +509,8 @@ union hv_vp_assist_msr_contents { /* HV_REGISTER_VP_ASSIST_PAGE */
#define HVCALL_MMIO_READ 0x0106
#define HVCALL_MMIO_WRITE 0x0107
#define HVCALL_DISABLE_HYP_EX 0x010f
+#define HVCALL_GET_IOMMU_CAPABILITIES 0x0125
+#define HVCALL_GET_LOGICAL_DEVICE_PROPERTY 0x0127
#define HVCALL_MAP_STATS_PAGE2 0x0131
/* HV_HYPERCALL_INPUT */
diff --git a/include/hyperv/hvhdk_mini.h b/include/hyperv/hvhdk_mini.h
index 035ba20870f7..7b9f43b320cd 100644
--- a/include/hyperv/hvhdk_mini.h
+++ b/include/hyperv/hvhdk_mini.h
@@ -548,4 +548,141 @@ union hv_device_id { /* HV_DEVICE_ID */
} acpi;
} __packed;
+/* Device domain types */
+#define HV_DEVICE_DOMAIN_TYPE_S1 1 /* HV_DEVICE_DOMAIN_ID_TYPE_S1 */
+
+/* ID for default domain and NULL domain */
+#define HV_DEVICE_DOMAIN_ID_DEFAULT 0
+#define HV_DEVICE_DOMAIN_ID_NULL 0xFFFFFFFFULL
+
+union hv_device_domain_id { /* HV_DEVICE_DOMAIN_ID */
+ u64 as_uint64;
+ struct {
+ u32 type: 4;
+ u32 reserved: 28;
+ u32 id;
+ } __packed;
+};
+
+struct hv_input_device_domain { /* HV_INPUT_DEVICE_DOMAIN */
+ u64 partition_id;
+ union hv_input_vtl owner_vtl;
+ u8 padding[7];
+ union hv_device_domain_id domain_id;
+} __packed;
+
+/* HV_CREATE_DEVICE_DOMAIN_FLAGS */
+union hv_create_device_domain_flags {
+ u32 as_uint32;
+ struct {
+ u32 forward_progress_required: 1;
+ u32 inherit_owning_vtl: 1;
+ u32 reserved: 30;
+ } __packed;
+};
+
+/* HV_INPUT_CREATE_DEVICE_DOMAIN */
+struct hv_input_create_device_domain {
+ struct hv_input_device_domain device_domain;
+ union hv_create_device_domain_flags create_device_domain_flags;
+ u32 padding;
+} __packed;
+
+/* HV_INPUT_DELETE_DEVICE_DOMAIN */
+struct hv_input_delete_device_domain {
+ struct hv_input_device_domain device_domain;
+} __packed;
+
+/* HV_INPUT_ATTACH_DEVICE_DOMAIN */
+struct hv_input_attach_device_domain {
+ struct hv_input_device_domain device_domain;
+ union hv_device_id device_id;
+} __packed;
+
+/* HV_INPUT_DETACH_DEVICE_DOMAIN */
+struct hv_input_detach_device_domain {
+ u64 partition_id;
+ union hv_device_id device_id;
+} __packed;
+
+struct hv_device_domain_settings { /* HV_DEVICE_DOMAIN_SETTINGS */
+ struct {
+ /*
+ * Enable translations. If not enabled, all transaction bypass
+ * S1 translations.
+ */
+ u64 translation_enabled: 1;
+ u64 blocked: 1;
+ /*
+ * First stage address translation paging mode:
+ * 0: 4-level paging (default)
+ * 1: 5-level paging
+ */
+ u64 first_stage_paging_mode: 1;
+ u64 reserved: 61;
+ } flags;
+
+ /* Address of translation table */
+ u64 page_table_root;
+} __packed;
+
+/* HV_INPUT_CONFIGURE_DEVICE_DOMAIN */
+struct hv_input_configure_device_domain {
+ struct hv_input_device_domain device_domain;
+ struct hv_device_domain_settings settings;
+} __packed;
+
+/* HV_INPUT_GET_IOMMU_CAPABILITIES */
+struct hv_input_get_iommu_capabilities {
+ u64 partition_id;
+ u64 reserved;
+} __packed;
+
+/* HV_OUTPUT_GET_IOMMU_CAPABILITIES */
+struct hv_output_get_iommu_capabilities {
+ u32 size;
+ u16 reserved;
+ u8 max_iova_width;
+ u8 max_pasid_width;
+
+#define HV_IOMMU_CAP_PRESENT BIT_ULL(0)
+#define HV_IOMMU_CAP_S2 BIT_ULL(1)
+#define HV_IOMMU_CAP_S1 BIT_ULL(2)
+#define HV_IOMMU_CAP_S1_5LVL BIT_ULL(3)
+#define HV_IOMMU_CAP_PASID BIT_ULL(4)
+#define HV_IOMMU_CAP_ATS BIT_ULL(5)
+#define HV_IOMMU_CAP_PRI BIT_ULL(6)
+
+ u64 iommu_cap;
+ u64 pgsize_bitmap;
+} __packed;
+
+/* HV_LOGICAL_DEVICE_PROPERTY_CODE */
+enum hv_logical_device_property_code {
+ HV_LOGICAL_DEVICE_PROPERTY_PVIOMMU = 10,
+};
+
+/* HV_INPUT_GET_LOGICAL_DEVICE_PROPERTY */
+struct hv_input_get_logical_device_property {
+ u64 partition_id;
+ u64 logical_device_id;
+ /* Takes values from enum hv_logical_device_property_code. */
+ u32 code;
+ u32 reserved;
+} __packed;
+
+/* HV_OUTPUT_GET_LOGICAL_DEVICE_PROPERTY */
+struct hv_output_get_logical_device_property {
+#define HV_DEVICE_IOMMU_ENABLED BIT_ULL(0)
+ u64 device_iommu;
+ u64 reserved;
+} __packed;
+
+/* HV_INPUT_FLUSH_DEVICE_DOMAIN */
+struct hv_input_flush_device_domain {
+ struct hv_input_device_domain device_domain;
+ u32 flags;
+ u32 reserved;
+} __packed;
+
#endif /* _HV_HVHDK_MINI_H */
--
2.52.0