diff options
author | Roger Pau Monné <royger@FreeBSD.org> | 2019-01-30 11:34:52 +0000 |
---|---|---|
committer | Roger Pau Monné <royger@FreeBSD.org> | 2019-01-30 11:34:52 +0000 |
commit | 27c36a12f1584b53d2454dac238eeed3dedc82ba (patch) | |
tree | d8f6a7ee7680245e6d2a7cd1a0c7be17f13b63f9 /sys | |
parent | 21be80ae8096c91d543b78883f262ef3d7b8b12c (diff) | |
download | src-test2-27c36a12f1584b53d2454dac238eeed3dedc82ba.tar.gz src-test2-27c36a12f1584b53d2454dac238eeed3dedc82ba.zip |
Notes
Diffstat (limited to 'sys')
-rw-r--r-- | sys/x86/xen/hvm.c | 47 | ||||
-rw-r--r-- | sys/x86/xen/xen_intr.c | 5 | ||||
-rw-r--r-- | sys/xen/hvm.h | 1 |
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__ */ |