xen: add hooks for Xen PV APIC
Create the necessary hooks in order to provide a Xen PV APIC implementation that can be used on PVH. Most of the lapic ops shouldn't be called on Xen, since we trap those operations at a higher layer. Sponsored by: Citrix Systems R&D Approved by: gibbs x86/xen/hvm.c: x86/xen/xen_apic.c: - Move IPI related code to xen_apic.c x86/xen/xen_apic.c: - Introduce Xen PV APIC implementation, most of the functions of the lapic interface should never be called when running as PV(H) guest, so make sure FreeBSD panics when trying to use one of those. - Define the Xen APIC implementation in xen_apic_ops. xen/xen_pv.h: - Extern declaration of the xen_apic struct. x86/xen/pv.c: - Use xen_apic_ops as apic_ops when running as PVH guest. conf/files.amd64: conf/files.i386: - Include the xen_apic.c file in the build of i386/amd64 kernels using XENHVM.
This commit is contained in:
parent
ef409ede7b
commit
842471b331
@ -557,3 +557,4 @@ x86/xen/hvm.c optional xenhvm
|
||||
x86/xen/xen_intr.c optional xen | xenhvm
|
||||
x86/xen/pv.c optional xenhvm
|
||||
x86/xen/pvcpu_enum.c optional xenhvm
|
||||
x86/xen/xen_apic.c optional xenhvm
|
||||
|
@ -594,3 +594,4 @@ x86/x86/tsc.c standard
|
||||
x86/x86/delay.c standard
|
||||
x86/xen/hvm.c optional xenhvm
|
||||
x86/xen/xen_intr.c optional xen | xenhvm
|
||||
x86/xen/xen_apic.c optional xenhvm
|
||||
|
@ -59,37 +59,14 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
/*--------------------------- Forward Declarations ---------------------------*/
|
||||
#ifdef SMP
|
||||
static driver_filter_t xen_smp_rendezvous_action;
|
||||
static driver_filter_t xen_invltlb;
|
||||
static driver_filter_t xen_invlpg;
|
||||
static driver_filter_t xen_invlrng;
|
||||
static driver_filter_t xen_invlcache;
|
||||
#ifdef __i386__
|
||||
static driver_filter_t xen_lazypmap;
|
||||
#endif
|
||||
static driver_filter_t xen_ipi_bitmap_handler;
|
||||
static driver_filter_t xen_cpustop_handler;
|
||||
static driver_filter_t xen_cpususpend_handler;
|
||||
static driver_filter_t xen_cpustophard_handler;
|
||||
static void xen_ipi_vectored(u_int vector, int dest);
|
||||
static void xen_hvm_cpu_resume(void);
|
||||
#endif
|
||||
static void xen_hvm_cpu_init(void);
|
||||
|
||||
/*---------------------------- Extern Declarations ---------------------------*/
|
||||
#ifdef __i386__
|
||||
extern void pmap_lazyfix_action(void);
|
||||
#endif
|
||||
#ifdef __amd64__
|
||||
extern int pmap_pcid_enabled;
|
||||
#endif
|
||||
|
||||
/* Variables used by mp_machdep to perform the bitmap IPI */
|
||||
extern volatile u_int cpu_ipi_pending[MAXCPU];
|
||||
|
||||
/*---------------------------------- Macros ----------------------------------*/
|
||||
#define IPI_TO_IDX(ipi) ((ipi) - APIC_IPI_INTS)
|
||||
|
||||
/*-------------------------------- Local Types -------------------------------*/
|
||||
enum xen_hvm_init_type {
|
||||
XEN_HVM_INIT_COLD,
|
||||
@ -97,12 +74,6 @@ enum xen_hvm_init_type {
|
||||
XEN_HVM_INIT_RESUME
|
||||
};
|
||||
|
||||
struct xen_ipi_handler
|
||||
{
|
||||
driver_filter_t *filter;
|
||||
const char *description;
|
||||
};
|
||||
|
||||
/*-------------------------------- Global Data -------------------------------*/
|
||||
enum xen_domain_type xen_domain_type = XEN_NATIVE;
|
||||
|
||||
@ -115,24 +86,6 @@ struct cpu_ops xen_hvm_cpu_ops = {
|
||||
|
||||
static MALLOC_DEFINE(M_XENHVM, "xen_hvm", "Xen HVM PV Support");
|
||||
|
||||
#ifdef SMP
|
||||
static struct xen_ipi_handler xen_ipis[] =
|
||||
{
|
||||
[IPI_TO_IDX(IPI_RENDEZVOUS)] = { xen_smp_rendezvous_action, "r" },
|
||||
[IPI_TO_IDX(IPI_INVLTLB)] = { xen_invltlb, "itlb"},
|
||||
[IPI_TO_IDX(IPI_INVLPG)] = { xen_invlpg, "ipg" },
|
||||
[IPI_TO_IDX(IPI_INVLRNG)] = { xen_invlrng, "irg" },
|
||||
[IPI_TO_IDX(IPI_INVLCACHE)] = { xen_invlcache, "ic" },
|
||||
#ifdef __i386__
|
||||
[IPI_TO_IDX(IPI_LAZYPMAP)] = { xen_lazypmap, "lp" },
|
||||
#endif
|
||||
[IPI_TO_IDX(IPI_BITMAP_VECTOR)] = { xen_ipi_bitmap_handler, "b" },
|
||||
[IPI_TO_IDX(IPI_STOP)] = { xen_cpustop_handler, "st" },
|
||||
[IPI_TO_IDX(IPI_SUSPEND)] = { xen_cpususpend_handler, "sp" },
|
||||
[IPI_TO_IDX(IPI_STOP_HARD)] = { xen_cpustophard_handler, "sth" },
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If non-zero, the hypervisor has been configured to use a direct
|
||||
* IDT event callback for interrupt injection.
|
||||
@ -142,9 +95,6 @@ int xen_vector_callback_enabled;
|
||||
/*------------------------------- Per-CPU Data -------------------------------*/
|
||||
DPCPU_DEFINE(struct vcpu_info, vcpu_local_info);
|
||||
DPCPU_DEFINE(struct vcpu_info *, vcpu_info);
|
||||
#ifdef SMP
|
||||
DPCPU_DEFINE(xen_intr_handle_t, ipi_handle[nitems(xen_ipis)]);
|
||||
#endif
|
||||
|
||||
/*------------------ Hypervisor Access Shared Memory Regions -----------------*/
|
||||
/** Hypercall table accessed via HYPERVISOR_*_op() methods. */
|
||||
@ -153,156 +103,6 @@ shared_info_t *HYPERVISOR_shared_info;
|
||||
start_info_t *HYPERVISOR_start_info;
|
||||
|
||||
#ifdef SMP
|
||||
/*---------------------------- XEN PV IPI Handlers ---------------------------*/
|
||||
/*
|
||||
* This are C clones of the ASM functions found in apic_vector.s
|
||||
*/
|
||||
static int
|
||||
xen_ipi_bitmap_handler(void *arg)
|
||||
{
|
||||
struct trapframe *frame;
|
||||
|
||||
frame = arg;
|
||||
ipi_bitmap_handler(*frame);
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
xen_smp_rendezvous_action(void *arg)
|
||||
{
|
||||
#ifdef COUNT_IPIS
|
||||
(*ipi_rendezvous_counts[PCPU_GET(cpuid)])++;
|
||||
#endif /* COUNT_IPIS */
|
||||
|
||||
smp_rendezvous_action();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
xen_invltlb(void *arg)
|
||||
{
|
||||
|
||||
invltlb_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
#ifdef __amd64__
|
||||
static int
|
||||
xen_invltlb_pcid(void *arg)
|
||||
{
|
||||
|
||||
invltlb_pcid_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
xen_invlpg(void *arg)
|
||||
{
|
||||
|
||||
invlpg_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
#ifdef __amd64__
|
||||
static int
|
||||
xen_invlpg_pcid(void *arg)
|
||||
{
|
||||
|
||||
invlpg_pcid_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
xen_invlrng(void *arg)
|
||||
{
|
||||
|
||||
invlrng_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
xen_invlcache(void *arg)
|
||||
{
|
||||
|
||||
invlcache_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
static int
|
||||
xen_lazypmap(void *arg)
|
||||
{
|
||||
|
||||
pmap_lazyfix_action();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
xen_cpustop_handler(void *arg)
|
||||
{
|
||||
|
||||
cpustop_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
xen_cpususpend_handler(void *arg)
|
||||
{
|
||||
|
||||
cpususpend_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
static int
|
||||
xen_cpustophard_handler(void *arg)
|
||||
{
|
||||
|
||||
ipi_nmi_handler();
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
/* Xen PV IPI sender */
|
||||
static void
|
||||
xen_ipi_vectored(u_int vector, int dest)
|
||||
{
|
||||
xen_intr_handle_t *ipi_handle;
|
||||
int ipi_idx, to_cpu, self;
|
||||
|
||||
ipi_idx = IPI_TO_IDX(vector);
|
||||
if (ipi_idx > nitems(xen_ipis))
|
||||
panic("IPI out of range");
|
||||
|
||||
switch(dest) {
|
||||
case APIC_IPI_DEST_SELF:
|
||||
ipi_handle = DPCPU_GET(ipi_handle);
|
||||
xen_intr_signal(ipi_handle[ipi_idx]);
|
||||
break;
|
||||
case APIC_IPI_DEST_ALL:
|
||||
CPU_FOREACH(to_cpu) {
|
||||
ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
|
||||
xen_intr_signal(ipi_handle[ipi_idx]);
|
||||
}
|
||||
break;
|
||||
case APIC_IPI_DEST_OTHERS:
|
||||
self = PCPU_GET(cpuid);
|
||||
CPU_FOREACH(to_cpu) {
|
||||
if (to_cpu != self) {
|
||||
ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
|
||||
xen_intr_signal(ipi_handle[ipi_idx]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
to_cpu = apic_cpuid(dest);
|
||||
ipi_handle = DPCPU_ID_GET(to_cpu, ipi_handle);
|
||||
xen_intr_signal(ipi_handle[ipi_idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* XEN diverged cpu operations */
|
||||
static void
|
||||
xen_hvm_cpu_resume(void)
|
||||
@ -318,56 +118,7 @@ xen_hvm_cpu_resume(void)
|
||||
/* register vcpu_info area */
|
||||
xen_hvm_cpu_init();
|
||||
}
|
||||
|
||||
static void
|
||||
xen_cpu_ipi_init(int cpu)
|
||||
{
|
||||
xen_intr_handle_t *ipi_handle;
|
||||
const struct xen_ipi_handler *ipi;
|
||||
device_t dev;
|
||||
int idx, rc;
|
||||
|
||||
ipi_handle = DPCPU_ID_GET(cpu, ipi_handle);
|
||||
dev = pcpu_find(cpu)->pc_device;
|
||||
KASSERT((dev != NULL), ("NULL pcpu device_t"));
|
||||
|
||||
for (ipi = xen_ipis, idx = 0; idx < nitems(xen_ipis); ipi++, idx++) {
|
||||
|
||||
if (ipi->filter == NULL) {
|
||||
ipi_handle[idx] = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = xen_intr_alloc_and_bind_ipi(dev, cpu, ipi->filter,
|
||||
INTR_TYPE_TTY, &ipi_handle[idx]);
|
||||
if (rc != 0)
|
||||
panic("Unable to allocate a XEN IPI port");
|
||||
xen_intr_describe(ipi_handle[idx], "%s", ipi->description);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xen_setup_cpus(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!xen_vector_callback_enabled)
|
||||
return;
|
||||
|
||||
#ifdef __amd64__
|
||||
if (pmap_pcid_enabled) {
|
||||
xen_ipis[IPI_TO_IDX(IPI_INVLTLB)].filter = xen_invltlb_pcid;
|
||||
xen_ipis[IPI_TO_IDX(IPI_INVLPG)].filter = xen_invlpg_pcid;
|
||||
}
|
||||
#endif
|
||||
CPU_FOREACH(i)
|
||||
xen_cpu_ipi_init(i);
|
||||
|
||||
/* Set the xen pv ipi ops to replace the native ones */
|
||||
apic_ops.ipi_vectored = xen_ipi_vectored;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*---------------------- XEN Hypervisor Probe and Setup ----------------------*/
|
||||
static uint32_t
|
||||
xen_hvm_cpuid_base(void)
|
||||
@ -654,9 +405,5 @@ xen_hvm_cpu_init(void)
|
||||
}
|
||||
|
||||
SYSINIT(xen_hvm_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, xen_hvm_sysinit, NULL);
|
||||
#ifdef SMP
|
||||
/* We need to setup IPIs before APs are started */
|
||||
SYSINIT(xen_setup_cpus, SI_SUB_SMP-1, SI_ORDER_FIRST, xen_setup_cpus, NULL);
|
||||
#endif
|
||||
SYSINIT(xen_hvm_cpu_init, SI_SUB_INTR, SI_ORDER_FIRST, xen_hvm_cpu_init, NULL);
|
||||
SYSINIT(xen_set_vcpu_id, SI_SUB_CPU, SI_ORDER_ANY, xen_set_vcpu_id, NULL);
|
||||
|
@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <xen/xen-os.h>
|
||||
#include <xen/hypervisor.h>
|
||||
#include <xen/xenstore/xenstorevar.h>
|
||||
#include <xen/xen_pv.h>
|
||||
|
||||
#include <xen/interface/vcpu.h>
|
||||
|
||||
@ -180,6 +181,7 @@ hammer_time_xen(start_info_t *si, uint64_t xenstack)
|
||||
|
||||
/* Set the hooks for early functions that diverge from bare metal */
|
||||
init_ops = xen_init_ops;
|
||||
apic_ops = xen_apic_ops;
|
||||
|
||||
/* Now we can jump into the native init function */
|
||||
return (hammer_time(0, physfree));
|
||||
|
Loading…
Reference in New Issue
Block a user