diff options
author | royger <royger@FreeBSD.org> | 2014-03-11 10:27:57 +0000 |
---|---|---|
committer | royger <royger@FreeBSD.org> | 2014-03-11 10:27:57 +0000 |
commit | 446e208ee2930dfe281158c48b8376365820cab9 (patch) | |
tree | 304558b63ac3bbc1d43d45c1ae1433a290ddc2cc | |
parent | b9559720d5e98dec119505471ec9840fc1b3a64b (diff) | |
download | FreeBSD-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.c | 1 | ||||
-rw-r--r-- | sys/amd64/amd64/mp_machdep.c | 12 | ||||
-rw-r--r-- | sys/amd64/include/smp.h | 1 | ||||
-rw-r--r-- | sys/x86/include/init.h | 1 | ||||
-rw-r--r-- | sys/x86/xen/pv.c | 96 |
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. |