arch/x86_64: Add a per-CPU SMP bringup API

The previous scheme where the xuk layer would call out to the to
"fetch" the stack for a SMP CPU at startup was sorta weird, and an
impedance mismatch with Zephyr which has a "start this CPU" call
instead.  It also got broken when x86_64 started launching CPUs
(correctly) on their interrupt stacks instead of a temporary area;
they weren't ready yet when xuk initialization was happening and the
system would deadlock waiting for code that can't run yet to provide a
stack.

Note that this preserves the somewhat quirky behavior that Zephyr's
CPU numbering is just the order in which the SMP CPUs emerge from
initialization and not a hardware ID.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2019-02-14 15:20:28 -08:00 committed by Anas Nashif
commit cf2879200b
4 changed files with 20 additions and 30 deletions

View file

@ -46,11 +46,6 @@ void test_timers(void)
printf("tsc %d apic %d\n", tsc1 - tsc0, apic0 - apic1);
}
unsigned int _init_cpu_stack(int cpu)
{
return (long)alloc_page(0) + 4096;
}
void handler_timer(void *arg, int err)
{
printf("Timer expired on CPU%d\n", (int)(long)xuk_get_f_ptr());
@ -159,6 +154,7 @@ void _cpu_start(int cpu)
test_timers();
if (cpu == 0) {
xuk_start_cpu(1, (long)alloc_page(0) + 4096);
xuk_set_isr(0x1f3, 0, (void *)handler_f3, (void *)0x12345678);
}

View file

@ -72,15 +72,15 @@ void *_isr_exit_restore_stack(void *interrupted)
struct {
void (*fn)(int, void*);
void *arg;
unsigned int esp;
} cpu_init[CONFIG_MP_NUM_CPUS];
/* Called from Zephyr initialization */
void z_arch_start_cpu(int cpu_num, k_thread_stack_t *stack, int sz,
void (*fn)(int, void *), void *arg)
{
xuk_start_cpu(cpu_num, (int)(sz + (char *)stack));
cpu_init[cpu_num].arg = arg;
cpu_init[cpu_num].esp = (int)(long)(sz + (char *)stack);
/* This is our flag to the spinning CPU. Do this last */
cpu_init[cpu_num].fn = fn;
@ -155,18 +155,9 @@ void _cpu_start(int cpu)
}
}
/* Returns the initial stack to use for CPU startup on auxiliary (not
* cpu 0) processors to the xuk layer, which gets selected by the
* non-arch Zephyr kernel and stashed by z_arch_start_cpu()
*/
unsigned int _init_cpu_stack(int cpu)
{
return cpu_init[cpu].esp;
}
int z_arch_irq_connect_dynamic(unsigned int irq, unsigned int priority,
void (*routine)(void *parameter), void *parameter,
u32_t flags)
void (*routine)(void *parameter), void *parameter,
u32_t flags)
{
ARG_UNUSED(flags);
__ASSERT(priority >= 2 && priority <= 15,

View file

@ -492,15 +492,17 @@ static void smp_init(void)
};
while (_apic.ICR_LO.send_pending) {
}
}
for (int i = 1; i < CONFIG_MP_NUM_CPUS; i++) {
_shared.smpinit_stack = _init_cpu_stack(i);
printf("Granting stack @ %xh to CPU %d\n",
_shared.smpinit_stack, i);
void xuk_start_cpu(int cpu, unsigned int stack)
{
int act = _shared.num_active_cpus;
while (_shared.num_active_cpus <= i) {
__asm__("pause");
}
printf("Granting stack @ %xh to CPU %d\n", stack, cpu);
_shared.smpinit_stack = stack;
while (_shared.num_active_cpus == act) {
__asm__ volatile("pause");
}
}

View file

@ -138,15 +138,16 @@ struct xuk_stack_frame {
long xuk_setup_stack(long sp, void *fn, unsigned int eflags,
long *args, int nargs);
/* Starts the numbered CPU running with the specified initial stack
* pointer
*/
void xuk_start_cpu(int cpu, unsigned int stack);
/*
* OS-defined utilities required by the xuk layer:
*/
/* Returns the address of a stack pointer in 32 bit memory to be used
* by AP processor bootstraping and startup.
*/
unsigned int _init_cpu_stack(int cpu);
/* OS CPU startup entry point, running on the stack returned by
* init_cpu_stack()
*/