summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorRoger Pau Monné <royger@FreeBSD.org>2019-01-30 11:34:52 +0000
committerRoger Pau Monné <royger@FreeBSD.org>2019-01-30 11:34:52 +0000
commit27c36a12f1584b53d2454dac238eeed3dedc82ba (patch)
treed8f6a7ee7680245e6d2a7cd1a0c7be17f13b63f9 /sys
parent21be80ae8096c91d543b78883f262ef3d7b8b12c (diff)
downloadsrc-test2-27c36a12f1584b53d2454dac238eeed3dedc82ba.tar.gz
src-test2-27c36a12f1584b53d2454dac238eeed3dedc82ba.zip
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/x86/xen/hvm.c47
-rw-r--r--sys/x86/xen/xen_intr.c5
-rw-r--r--sys/xen/hvm.h1
3 files changed, 51 insertions, 2 deletions
diff --git a/sys/x86/xen/hvm.c b/sys/x86/xen/hvm.c
index 6983a20ecf82..a0a0e4b75153 100644
--- a/sys/x86/xen/hvm.c
+++ b/sys/x86/xen/hvm.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <x86/apicreg.h>
#include <xen/xen-os.h>
+#include <xen/error.h>
#include <xen/features.h>
#include <xen/gnttab.h>
#include <xen/hypervisor.h>
@@ -88,6 +89,12 @@ int xen_vector_callback_enabled;
*/
uint32_t hvm_start_flags;
+/**
+ * Signal whether the vector injected for the event channel upcall requires to
+ * be EOI'ed on the local APIC.
+ */
+bool xen_evtchn_needs_ack;
+
/*------------------------------- Per-CPU Data -------------------------------*/
DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
@@ -223,6 +230,19 @@ xen_hvm_init_shared_info_page(void)
panic("HYPERVISOR_memory_op failed");
}
+static int
+set_percpu_callback(unsigned int vcpu)
+{
+ struct xen_hvm_evtchn_upcall_vector vec;
+ int error;
+
+ vec.vcpu = vcpu;
+ vec.vector = IDT_EVTCHN;
+ error = HYPERVISOR_hvm_op(HVMOP_set_evtchn_upcall_vector, &vec);
+
+ return (error != 0 ? xen_translate_error(error) : 0);
+}
+
/*
* Tell the hypervisor how to contact us for event channel callbacks.
*/
@@ -240,12 +260,20 @@ xen_hvm_set_callback(device_t dev)
if (xen_feature(XENFEAT_hvm_callback_vector) != 0) {
int error;
- xhp.value = HVM_CALLBACK_VECTOR(IDT_EVTCHN);
+ error = set_percpu_callback(0);
+ if (error == 0) {
+ xen_evtchn_needs_ack = true;
+ /* Trick toolstack to think we are enlightened */
+ xhp.value = 1;
+ } else
+ xhp.value = HVM_CALLBACK_VECTOR(IDT_EVTCHN);
error = HYPERVISOR_hvm_op(HVMOP_set_param, &xhp);
if (error == 0) {
xen_vector_callback_enabled = 1;
return;
- }
+ } else if (xen_evtchn_needs_ack)
+ panic("Unable to setup fake HVM param: %d", error);
+
printf("Xen HVM callback vector registration failed (%d). "
"Falling back to emulated device interrupt\n", error);
}
@@ -360,6 +388,7 @@ xen_hvm_init(enum xen_hvm_init_type init_type)
}
xen_vector_callback_enabled = 0;
+ xen_evtchn_needs_ack = false;
xen_hvm_set_callback(NULL);
/*
@@ -427,6 +456,20 @@ xen_hvm_cpu_init(void)
PCPU_SET(vcpu_id, (regs[0] & XEN_HVM_CPUID_VCPU_ID_PRESENT) ?
regs[1] : PCPU_GET(acpi_id));
+ if (xen_evtchn_needs_ack && !IS_BSP()) {
+ /*
+ * Setup the per-vpcu event channel upcall vector. This is only
+ * required when using the new HVMOP_set_evtchn_upcall_vector
+ * hypercall, which allows using a different vector for each
+ * vCPU. Note that FreeBSD uses the same vector for all vCPUs
+ * because it's not dynamically allocated.
+ */
+ rc = set_percpu_callback(PCPU_GET(vcpu_id));
+ if (rc != 0)
+ panic("Event channel upcall vector setup failed: %d",
+ rc);
+ }
+
/*
* Set the vCPU info.
*
diff --git a/sys/x86/xen/xen_intr.c b/sys/x86/xen/xen_intr.c
index d366a61dc9ec..f230794d3a50 100644
--- a/sys/x86/xen/xen_intr.c
+++ b/sys/x86/xen/xen_intr.c
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <machine/xen/xen-os.h>
#include <xen/xen-os.h>
+#include <xen/hvm.h>
#include <xen/hypervisor.h>
#include <xen/xen_intr.h>
#include <xen/evtchn/evtchnvar.h>
@@ -620,6 +621,10 @@ xen_intr_handle_upcall(struct trapframe *trap_frame)
l1 &= ~(1UL << l1i);
}
}
+
+ if (xen_evtchn_needs_ack)
+ lapic_eoi();
+
critical_exit();
}
diff --git a/sys/xen/hvm.h b/sys/xen/hvm.h
index bc7518d26575..e34a552dc714 100644
--- a/sys/xen/hvm.h
+++ b/sys/xen/hvm.h
@@ -104,5 +104,6 @@ void xen_hvm_suspend(void);
void xen_hvm_resume(bool suspend_cancelled);
extern uint32_t hvm_start_flags;
+extern bool xen_evtchn_needs_ack;
#endif /* __XEN_HVM_H__ */