Support better tracking of AP stack usage.

This change allows us to figure out how much of the AP stacks we are
using, as well as to catch any case of an AP overrunning its stack.
Also, the stack is poisoned, which is a good way to catch programming
errors -- code should never count on auto variables being zerod.

The stack bases are recorded in a new array, stacks. At the end,
when all APs are initialized, the stacks are walked and the
lowest level of the stack that is reached is printed.

Build and boot and look for output like this:

CPU1: stack allocated from 00148000 to 00148ff4:\
	lowest stack address was 00148c4c
CPU2: stack allocated from 00147000 to 00147ff4:\
	lowest stack address was 00147c4c
CPU3: stack allocated from 00146000 to 00146ff4:\
	lowest stack address was 00146c4c

Note that we used only about 1K of stack, even though in this
case we allocated 4K (and in the main branch, we allocate 32K!)

Change-Id: I99b7b9086848496feb3ecd207f64203fa69fadf5
Signed-off-by: Ronald G. Minnich <rminnich@chromium.org>
Reviewed-on: http://review.coreboot.org/1818
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Tested-by: build bot (Jenkins)
This commit is contained in:
Ronald G. Minnich 2012-06-06 13:00:24 -07:00 committed by Stefan Reinauer
parent 5b635795cc
commit 000bf83c93
1 changed files with 31 additions and 4 deletions

View File

@ -16,7 +16,7 @@
#include <cpu/cpu.h> #include <cpu/cpu.h>
#include <cpu/intel/speedstep.h> #include <cpu/intel/speedstep.h>
#if CONFIG_SMP #if CONFIG_SMP && CONFIG_MAX_CPUS > 1
/* This is a lot more paranoid now, since Linux can NOT handle /* This is a lot more paranoid now, since Linux can NOT handle
* being told there is a CPU when none exists. So any errors * being told there is a CPU when none exists. So any errors
* will return 0, meaning no CPU. * will return 0, meaning no CPU.
@ -216,15 +216,19 @@ static atomic_t active_cpus = ATOMIC_INIT(1);
static spinlock_t start_cpu_lock = SPIN_LOCK_UNLOCKED; static spinlock_t start_cpu_lock = SPIN_LOCK_UNLOCKED;
static unsigned last_cpu_index = 0; static unsigned last_cpu_index = 0;
volatile unsigned long secondary_stack; volatile unsigned long secondary_stack;
void *stacks[CONFIG_MAX_CPUS];
int start_cpu(device_t cpu) int start_cpu(device_t cpu)
{ {
extern unsigned char _estack[]; extern unsigned char _estack[];
struct cpu_info *info; struct cpu_info *info;
unsigned long stack_end; unsigned long stack_end;
unsigned long stack_base;
unsigned long *stack;
unsigned long apicid; unsigned long apicid;
unsigned long index; unsigned long index;
unsigned long count; unsigned long count;
int i;
int result; int result;
spin_lock(&start_cpu_lock); spin_lock(&start_cpu_lock);
@ -238,6 +242,13 @@ int start_cpu(device_t cpu)
/* Find end of the new processors stack */ /* Find end of the new processors stack */
stack_end = ((unsigned long)_estack) - (CONFIG_STACK_SIZE*index) - sizeof(struct cpu_info); stack_end = ((unsigned long)_estack) - (CONFIG_STACK_SIZE*index) - sizeof(struct cpu_info);
stack_base = ((unsigned long)_estack) - (CONFIG_STACK_SIZE*(index+1));
printk(BIOS_SPEW, "CPU%ld: stack_base %p, stack_end %p\n", index,
(void *)stack_base, (void *)stack_end);
/* poison the stack */
for(stack = (void *)stack_base, i = 0; i < CONFIG_STACK_SIZE; i++)
stack[i/sizeof(*stack)] = 0xDEADBEEF;
stacks[index] = stack;
/* Record the index and which cpu structure we are using */ /* Record the index and which cpu structure we are using */
info = (struct cpu_info *)stack_end; info = (struct cpu_info *)stack_end;
info->index = index; info->index = index;
@ -440,6 +451,7 @@ static void wait_other_cpus_stop(struct bus *cpu_bus)
device_t cpu; device_t cpu;
int old_active_count, active_count; int old_active_count, active_count;
long loopcount = 0; long loopcount = 0;
int i;
/* Now loop until the other cpus have finished initializing */ /* Now loop until the other cpus have finished initializing */
old_active_count = 1; old_active_count = 1;
@ -466,6 +478,21 @@ static void wait_other_cpus_stop(struct bus *cpu_bus)
} }
} }
printk(BIOS_DEBUG, "All AP CPUs stopped (%ld loops)\n", loopcount); printk(BIOS_DEBUG, "All AP CPUs stopped (%ld loops)\n", loopcount);
for(i = 1; i <= last_cpu_index; i++){
unsigned long *stack = stacks[i];
int lowest;
int maxstack = (CONFIG_STACK_SIZE - sizeof(struct cpu_info))
/sizeof(*stack) - 1;
if (stack[0] != 0xDEADBEEF)
printk(BIOS_ERR, "CPU%d overran its stack\n", i);
for(lowest = 0; lowest < maxstack; lowest++)
if (stack[lowest] != 0xDEADBEEF)
break;
printk(BIOS_SPEW, "CPU%d: stack allocated from %p to %p:", i,
stack, &stack[maxstack]);
printk(BIOS_SPEW, "lowest stack address was %p\n", &stack[lowest]);
}
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
@ -494,7 +521,7 @@ void initialize_cpus(struct bus *cpu_bus)
/* Find the device structure for the boot cpu */ /* Find the device structure for the boot cpu */
info->cpu = alloc_find_dev(cpu_bus, &cpu_path); info->cpu = alloc_find_dev(cpu_bus, &cpu_path);
#if CONFIG_SMP #if CONFIG_SMP && CONFIG_MAX_CPUS > 1
copy_secondary_start_to_1m_below(); // why here? In case some day we can start core1 in amd_sibling_init copy_secondary_start_to_1m_below(); // why here? In case some day we can start core1 in amd_sibling_init
#endif #endif
@ -502,7 +529,7 @@ void initialize_cpus(struct bus *cpu_bus)
smm_init(); smm_init();
#endif #endif
#if CONFIG_SMP #if CONFIG_SMP && CONFIG_MAX_CPUS > 1
#if !CONFIG_SERIAL_CPU_INIT #if !CONFIG_SERIAL_CPU_INIT
/* start all aps at first, so we can init ECC all together */ /* start all aps at first, so we can init ECC all together */
start_other_cpus(cpu_bus, info->cpu); start_other_cpus(cpu_bus, info->cpu);
@ -512,7 +539,7 @@ void initialize_cpus(struct bus *cpu_bus)
/* Initialize the bootstrap processor */ /* Initialize the bootstrap processor */
cpu_initialize(); cpu_initialize();
#if CONFIG_SMP #if CONFIG_SMP && CONFIG_MAX_CPUS > 1
#if CONFIG_SERIAL_CPU_INIT #if CONFIG_SERIAL_CPU_INIT
start_other_cpus(cpu_bus, info->cpu); start_other_cpus(cpu_bus, info->cpu);
#endif #endif