summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroyger <royger@FreeBSD.org>2014-03-11 10:27:57 +0000
committerroyger <royger@FreeBSD.org>2014-03-11 10:27:57 +0000
commit446e208ee2930dfe281158c48b8376365820cab9 (patch)
tree304558b63ac3bbc1d43d45c1ae1433a290ddc2cc
parentb9559720d5e98dec119505471ec9840fc1b3a64b (diff)
downloadFreeBSD-src-446e208ee2930dfe281158c48b8376365820cab9.zip
FreeBSD-src-446e208ee2930dfe281158c48b8376365820cab9.tar.gz
xen: add a hook to perform AP startup
AP startup on PVH follows the PV method, so we need to add a hook in order to diverge from bare metal. Approved by: gibbs Sponsored by: Citrix Systems R&D amd64/amd64/machdep.c: - Add hook for start_all_aps on native (using native_start_all_aps defined in mp_machdep). amd64/amd64/mp_machdep.c: - Make some variables global because they will also be used by the Xen PVH AP startup code. - Use the start_all_aps hook to start APs. - Rename start_all_aps to native_start_all_aps. amd64/include/smp.h: - Add declaration for native_start_all_aps. x86/include/init.h: - Declare start_all_aps hook in init_ops. x86/xen/pv.c: - Pick external declarations from mp_machdep. - Introduce Xen PV code to start APs on PVH. - Set start_all_aps init hook to use the Xen PVH implementation.
-rw-r--r--sys/amd64/amd64/machdep.c1
-rw-r--r--sys/amd64/amd64/mp_machdep.c12
-rw-r--r--sys/amd64/include/smp.h1
-rw-r--r--sys/x86/include/init.h1
-rw-r--r--sys/x86/xen/pv.c96
5 files changed, 105 insertions, 6 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index d2780fe..94dc278 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -180,6 +180,7 @@ struct init_ops init_ops = {
.parse_memmap = native_parse_memmap,
#ifdef SMP
.mp_bootaddress = mp_bootaddress,
+ .start_all_aps = native_start_all_aps,
#endif
};
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 9f03e4c..80b4e12 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <machine/specialreg.h>
#include <machine/tss.h>
#include <machine/cpu.h>
+#include <x86/init.h>
#define WARMBOOT_TARGET 0
#define WARMBOOT_OFF (KERNBASE + 0x0467)
@@ -90,7 +91,7 @@ extern struct pcpu __pcpu[];
/* AP uses this during bootstrap. Do not staticize. */
char *bootSTK;
-static int bootAP;
+int bootAP;
/* Free these after use */
void *bootstacks[MAXCPU];
@@ -139,7 +140,7 @@ extern int pmap_pcid_enabled;
static volatile cpuset_t ipi_nmi_pending;
/* used to hold the AP's until we are ready to release them */
-static struct mtx ap_boot_mtx;
+struct mtx ap_boot_mtx;
/* Set to 1 once we're ready to let the APs out of the pen. */
static volatile int aps_ready = 0;
@@ -166,7 +167,6 @@ static int cpu_cores; /* cores per package */
static void assign_cpu_ids(void);
static void set_interrupt_apic_ids(void);
-static int start_all_aps(void);
static int start_ap(int apic_id);
static void release_aps(void *dummy);
@@ -570,7 +570,7 @@ cpu_mp_start(void)
assign_cpu_ids();
/* Start each Application Processor */
- start_all_aps();
+ init_ops.start_all_aps();
set_interrupt_apic_ids();
}
@@ -909,8 +909,8 @@ assign_cpu_ids(void)
/*
* start each AP in our list
*/
-static int
-start_all_aps(void)
+int
+native_start_all_aps(void)
{
vm_offset_t va = boot_address + KERNBASE;
u_int64_t *pt4, *pt3, *pt2;
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 1b8a2cf..99bf1e4 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -85,6 +85,7 @@ void smp_masked_invlpg_range(cpuset_t mask, struct pmap *pmap,
vm_offset_t startva, vm_offset_t endva);
void smp_invltlb(struct pmap *pmap);
void smp_masked_invltlb(cpuset_t mask, struct pmap *pmap);
+int native_start_all_aps(void);
#endif /* !LOCORE */
#endif /* SMP */
diff --git a/sys/x86/include/init.h b/sys/x86/include/init.h
index edc8418..e1ff5cf 100644
--- a/sys/x86/include/init.h
+++ b/sys/x86/include/init.h
@@ -40,6 +40,7 @@ struct init_ops {
void (*early_delay)(int);
void (*parse_memmap)(caddr_t, vm_paddr_t *, int *);
u_int (*mp_bootaddress)(u_int);
+ int (*start_all_aps)(void);
};
extern struct init_ops init_ops;
diff --git a/sys/x86/xen/pv.c b/sys/x86/xen/pv.c
index f7d5e47..96420e3 100644
--- a/sys/x86/xen/pv.c
+++ b/sys/x86/xen/pv.c
@@ -34,10 +34,13 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/reboot.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <sys/boot.h>
#include <sys/ctype.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/vm_extern.h>
@@ -50,10 +53,13 @@ __FBSDID("$FreeBSD$");
#include <x86/init.h>
#include <machine/pc/bios.h>
+#include <machine/smp.h>
#include <xen/xen-os.h>
#include <xen/hypervisor.h>
+#include <xen/interface/vcpu.h>
+
#include <dev/xen/timer/timer.h>
/* Native initial function */
@@ -67,6 +73,22 @@ uint64_t hammer_time_xen(start_info_t *, uint64_t);
static caddr_t xen_pv_parse_preload_data(u_int64_t);
static void xen_pv_parse_memmap(caddr_t, vm_paddr_t *, int *);
+#ifdef SMP
+static int xen_pv_start_all_aps(void);
+#endif
+
+/*---------------------------- Extern Declarations ---------------------------*/
+#ifdef SMP
+/* Variables used by amd64 mp_machdep to start APs */
+extern struct mtx ap_boot_mtx;
+extern void *bootstacks[];
+extern char *doublefault_stack;
+extern char *nmi_stack;
+extern void *dpcpu;
+extern int bootAP;
+extern char *bootSTK;
+#endif
+
/*-------------------------------- Global Data -------------------------------*/
/* Xen init_ops implementation. */
struct init_ops xen_init_ops = {
@@ -74,6 +96,9 @@ struct init_ops xen_init_ops = {
.early_clock_source_init = xen_clock_init,
.early_delay = xen_delay,
.parse_memmap = xen_pv_parse_memmap,
+#ifdef SMP
+ .start_all_aps = xen_pv_start_all_aps,
+#endif
};
static struct bios_smap xen_smap[MAX_E820_ENTRIES];
@@ -151,6 +176,77 @@ hammer_time_xen(start_info_t *si, uint64_t xenstack)
}
/*-------------------------------- PV specific -------------------------------*/
+#ifdef SMP
+static bool
+start_xen_ap(int cpu)
+{
+ struct vcpu_guest_context *ctxt;
+ int ms, cpus = mp_naps;
+ const size_t stacksize = KSTACK_PAGES * PAGE_SIZE;
+
+ /* allocate and set up an idle stack data page */
+ bootstacks[cpu] =
+ (void *)kmem_malloc(kernel_arena, stacksize, M_WAITOK | M_ZERO);
+ doublefault_stack =
+ (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO);
+ nmi_stack =
+ (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO);
+ dpcpu =
+ (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, M_WAITOK | M_ZERO);
+
+ bootSTK = (char *)bootstacks[cpu] + KSTACK_PAGES * PAGE_SIZE - 8;
+ bootAP = cpu;
+
+ ctxt = malloc(sizeof(*ctxt), M_TEMP, M_WAITOK | M_ZERO);
+ if (ctxt == NULL)
+ panic("unable to allocate memory");
+
+ ctxt->flags = VGCF_IN_KERNEL;
+ ctxt->user_regs.rip = (unsigned long) init_secondary;
+ ctxt->user_regs.rsp = (unsigned long) bootSTK;
+
+ /* Set the AP to use the same page tables */
+ ctxt->ctrlreg[3] = KPML4phys;
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
+ panic("unable to initialize AP#%d", cpu);
+
+ free(ctxt, M_TEMP);
+
+ /* Launch the vCPU */
+ if (HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
+ panic("unable to start AP#%d", cpu);
+
+ /* Wait up to 5 seconds for it to start. */
+ for (ms = 0; ms < 5000; ms++) {
+ if (mp_naps > cpus)
+ return (true);
+ DELAY(1000);
+ }
+
+ return (false);
+}
+
+static int
+xen_pv_start_all_aps(void)
+{
+ int cpu;
+
+ mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+
+ for (cpu = 1; cpu < mp_ncpus; cpu++) {
+
+ /* attempt to start the Application Processor */
+ if (!start_xen_ap(cpu))
+ panic("AP #%d failed to start!", cpu);
+
+ CPU_SET(cpu, &all_cpus); /* record AP in CPU map */
+ }
+
+ return (mp_naps);
+}
+#endif /* SMP */
+
/*
* Functions to convert the "extra" parameters passed by Xen
* into FreeBSD boot options.
OpenPOWER on IntegriCloud