x86/xen: use x{2}APIC if virtualized by hardware

Instead of using event channels or hypercalls to deal with IPIs and
NMIs.

Using a hardware virtualized APIC should be faster than using any PV
interface, since the VM exit can be avoided.

Xen exposes whether the domain is using hardware assisted x{2}APIC
emulation in a CPUID bit.

Sponsored by: Citrix Systems R&D
This commit is contained in:
Roger Pau Monné 2022-01-13 14:57:07 +01:00
parent cc68614da8
commit 2450da6776
3 changed files with 23 additions and 8 deletions

View File

@ -49,6 +49,8 @@ extern int xen_disable_pv_disks;
/* tunable for disabling PV nics */ /* tunable for disabling PV nics */
extern int xen_disable_pv_nics; extern int xen_disable_pv_nics;
extern uint32_t xen_cpuid_base;
static inline bool static inline bool
xen_has_percpu_evtchn(void) xen_has_percpu_evtchn(void)
{ {

View File

@ -110,7 +110,7 @@ TUNABLE_INT("hw.xen.disable_pv_nics", &xen_disable_pv_nics);
/*---------------------- XEN Hypervisor Probe and Setup ----------------------*/ /*---------------------- XEN Hypervisor Probe and Setup ----------------------*/
static uint32_t cpuid_base; uint32_t xen_cpuid_base;
static uint32_t static uint32_t
xen_hvm_cpuid_base(void) xen_hvm_cpuid_base(void)
@ -153,7 +153,7 @@ hypervisor_version(void)
uint32_t regs[4]; uint32_t regs[4];
int major, minor; int major, minor;
do_cpuid(cpuid_base + 1, regs); do_cpuid(xen_cpuid_base + 1, regs);
major = regs[0] >> 16; major = regs[0] >> 16;
minor = regs[0] & 0xffff; minor = regs[0] & 0xffff;
@ -171,9 +171,9 @@ xen_hvm_init_hypercall_stubs(enum xen_hvm_init_type init_type)
uint32_t regs[4]; uint32_t regs[4];
/* Legacy PVH will get here without the cpuid leaf being set. */ /* Legacy PVH will get here without the cpuid leaf being set. */
if (cpuid_base == 0) if (xen_cpuid_base == 0)
cpuid_base = xen_hvm_cpuid_base(); xen_cpuid_base = xen_hvm_cpuid_base();
if (cpuid_base == 0) if (xen_cpuid_base == 0)
return (ENXIO); return (ENXIO);
if (xen_domain() && init_type == XEN_HVM_INIT_LATE) { if (xen_domain() && init_type == XEN_HVM_INIT_LATE) {
@ -192,7 +192,7 @@ xen_hvm_init_hypercall_stubs(enum xen_hvm_init_type init_type)
/* /*
* Find the hypercall pages. * Find the hypercall pages.
*/ */
do_cpuid(cpuid_base + 2, regs); do_cpuid(xen_cpuid_base + 2, regs);
if (regs[0] != 1) if (regs[0] != 1)
return (EINVAL); return (EINVAL);
@ -448,8 +448,8 @@ xen_hvm_cpu_init(void)
* Set vCPU ID. If available fetch the ID from CPUID, if not just use * Set vCPU ID. If available fetch the ID from CPUID, if not just use
* the ACPI ID. * the ACPI ID.
*/ */
KASSERT(cpuid_base != 0, ("Invalid base Xen CPUID leaf")); KASSERT(xen_cpuid_base != 0, ("Invalid base Xen CPUID leaf"));
cpuid_count(cpuid_base + 4, 0, regs); cpuid_count(xen_cpuid_base + 4, 0, regs);
KASSERT((regs[0] & XEN_HVM_CPUID_VCPU_ID_PRESENT) || KASSERT((regs[0] & XEN_HVM_CPUID_VCPU_ID_PRESENT) ||
!xen_pv_domain(), !xen_pv_domain(),
("Xen PV domain without vcpu_id in cpuid")); ("Xen PV domain without vcpu_id in cpuid"));

View File

@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <xen/hvm.h> #include <xen/hvm.h>
#include <xen/xen_intr.h> #include <xen/xen_intr.h>
#include <xen/interface/arch-x86/cpuid.h>
#include <xen/interface/vcpu.h> #include <xen/interface/vcpu.h>
/*--------------------------------- Macros -----------------------------------*/ /*--------------------------------- Macros -----------------------------------*/
@ -601,11 +602,23 @@ xen_cpu_ipi_init(int cpu)
static void static void
xen_setup_cpus(void) xen_setup_cpus(void)
{ {
uint32_t regs[4];
int i; int i;
if (!xen_vector_callback_enabled) if (!xen_vector_callback_enabled)
return; return;
/*
* Check whether the APIC virtualization is hardware assisted, as
* that's faster than using event channels because it avoids the VM
* exit.
*/
KASSERT(xen_cpuid_base != 0, ("Invalid base Xen CPUID leaf"));
cpuid_count(xen_cpuid_base + 4, 0, regs);
if ((x2apic_mode && (regs[0] & XEN_HVM_CPUID_X2APIC_VIRT)) ||
(!x2apic_mode && (regs[0] & XEN_HVM_CPUID_APIC_ACCESS_VIRT)))
return;
CPU_FOREACH(i) CPU_FOREACH(i)
xen_cpu_ipi_init(i); xen_cpu_ipi_init(i);