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:
Roger Pau Monné 2014-06-16 08:43:45 +00:00
parent ef409ede7b
commit 842471b331
4 changed files with 4 additions and 253 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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));