@@ -2175,6 +2175,12 @@ ticks and hence enabling this group will ensure that ticks will be
consistent with use of an enlightened time source (B<time_ref_count> or
B<reference_tsc>).
+=item B<hcall_ipi>
+
+This set incorporates use of a hypercall for interprocessor interrupts.
+This enlightenment may improve performance of Windows guests with multiple
+virtual CPUs.
+
=item B<defaults>
This is a special value that enables the default set of groups, which
@@ -330,6 +330,12 @@
*/
#define LIBXL_HAVE_VIRIDIAN_STIMER 1
+/*
+ * LIBXL_HAVE_VIRIDIAN_HCALL_IPI indicates that the 'hcall_ipi' value
+ * is present in the viridian enlightenment enumeration.
+ */
+#define LIBXL_HAVE_VIRIDIAN_HCALL_IPI 1
+
/*
* LIBXL_HAVE_BUILDINFO_HVM_ACPI_LAPTOP_SLATE indicates that
* libxl_domain_build_info has the u.hvm.acpi_laptop_slate field.
@@ -324,6 +324,9 @@ static int hvm_set_viridian_features(libxl__gc *gc, uint32_t domid,
if (libxl_bitmap_test(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_STIMER))
mask |= HVMPV_time_ref_count | HVMPV_synic | HVMPV_stimer;
+ if (libxl_bitmap_test(&enlightenments, LIBXL_VIRIDIAN_ENLIGHTENMENT_HCALL_IPI))
+ mask |= HVMPV_hcall_ipi;
+
if (mask != 0 &&
xc_hvm_param_set(CTX->xch,
domid,
@@ -237,6 +237,7 @@ libxl_viridian_enlightenment = Enumeration("viridian_enlightenment", [
(6, "crash_ctl"),
(7, "synic"),
(8, "stimer"),
+ (9, "hcall_ipi"),
])
libxl_hdtype = Enumeration("hdtype", [
@@ -28,6 +28,7 @@
#define HvFlushVirtualAddressSpace 0x0002
#define HvFlushVirtualAddressList 0x0003
#define HvNotifyLongSpinWait 0x0008
+#define HvSendSyntheticClusterIpi 0x000b
#define HvGetPartitionId 0x0046
#define HvExtCallQueryCapabilities 0x8001
@@ -95,6 +96,7 @@ typedef union _HV_CRASH_CTL_REG_CONTENTS
#define CPUID4A_HCALL_REMOTE_TLB_FLUSH (1 << 2)
#define CPUID4A_MSR_BASED_APIC (1 << 3)
#define CPUID4A_RELAX_TIMER_INT (1 << 5)
+#define CPUID4A_SYNTHETIC_CLUSTER_IPI (1 << 10)
/* Viridian CPUID leaf 6: Implementation HW features detected and in use */
#define CPUID6A_APIC_OVERLAY (1 << 0)
@@ -206,6 +208,8 @@ void cpuid_viridian_leaves(const struct vcpu *v, uint32_t leaf,
res->a |= CPUID4A_HCALL_REMOTE_TLB_FLUSH;
if ( !cpu_has_vmx_apic_reg_virt )
res->a |= CPUID4A_MSR_BASED_APIC;
+ if ( viridian_feature_mask(d) & HVMPV_hcall_ipi )
+ res->a |= CPUID4A_SYNTHETIC_CLUSTER_IPI;
/*
* This value is the recommended number of attempts to try to
@@ -628,6 +632,65 @@ int viridian_hypercall(struct cpu_user_regs *regs)
break;
}
+ case HvSendSyntheticClusterIpi:
+ {
+ struct vcpu *v;
+ uint32_t vector;
+ uint64_t vcpu_mask;
+
+ status = HV_STATUS_INVALID_PARAMETER;
+
+ /* Get input parameters. */
+ if ( input.fast )
+ {
+ if ( input_params_gpa >> 32 )
+ break;
+
+ vector = input_params_gpa;
+ vcpu_mask = output_params_gpa;
+ }
+ else
+ {
+ struct {
+ uint32_t vector;
+ uint8_t target_vtl;
+ uint8_t reserved_zero[3];
+ uint64_t vcpu_mask;
+ } input_params;
+
+ if ( hvm_copy_from_guest_phys(&input_params, input_params_gpa,
+ sizeof(input_params)) !=
+ HVMTRANS_okay )
+ break;
+
+ if ( input_params.target_vtl ||
+ input_params.reserved_zero[0] ||
+ input_params.reserved_zero[1] ||
+ input_params.reserved_zero[2] )
+ break;
+
+ vector = input_params.vector;
+ vcpu_mask = input_params.vcpu_mask;
+ }
+
+ if ( vector < 0x10 || vector > 0xff )
+ break;
+
+ for_each_vcpu ( currd, v )
+ {
+ if ( v->vcpu_id >= (sizeof(vcpu_mask) * 8) )
+ break;
+
+ if ( !(vcpu_mask & (1ul << v->vcpu_id)) )
+ continue;
+
+ vlapic_set_irq(vcpu_vlapic(v), vector, 0);
+ }
+
+ status = HV_STATUS_SUCCESS;
+ break;
+ }
+
default:
gprintk(XENLOG_WARNING, "unimplemented hypercall %04x\n",
input.call_code);
@@ -154,6 +154,10 @@
#define _HVMPV_stimer 8
#define HVMPV_stimer (1 << _HVMPV_stimer)
+/* Use Synthetic Cluster IPI Hypercall */
+#define _HVMPV_hcall_ipi 9
+#define HVMPV_hcall_ipi (1 << _HVMPV_hcall_ipi)
+
#define HVMPV_feature_mask \
(HVMPV_base_freq | \
HVMPV_no_freq | \
@@ -163,7 +167,8 @@
HVMPV_apic_assist | \
HVMPV_crash_ctl | \
HVMPV_synic | \
- HVMPV_stimer)
+ HVMPV_stimer | \
+ HVMPV_hcall_ipi)
#endif