From 000bf83c934880490d6b1b4c16465cbe7f4f377c Mon Sep 17 00:00:00 2001 From: "Ronald G. Minnich" Date: Wed, 6 Jun 2012 13:00:24 -0700 Subject: [PATCH] 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 Reviewed-on: http://review.coreboot.org/1818 Reviewed-by: Ronald G. Minnich Tested-by: build bot (Jenkins) --- src/cpu/x86/lapic/lapic_cpu_init.c | 35 ++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c b/src/cpu/x86/lapic/lapic_cpu_init.c index b721e8f9b0..256066f309 100644 --- a/src/cpu/x86/lapic/lapic_cpu_init.c +++ b/src/cpu/x86/lapic/lapic_cpu_init.c @@ -16,7 +16,7 @@ #include #include -#if CONFIG_SMP +#if CONFIG_SMP && CONFIG_MAX_CPUS > 1 /* This is a lot more paranoid now, since Linux can NOT handle * being told there is a CPU when none exists. So any errors * 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 unsigned last_cpu_index = 0; volatile unsigned long secondary_stack; +void *stacks[CONFIG_MAX_CPUS]; int start_cpu(device_t cpu) { extern unsigned char _estack[]; struct cpu_info *info; unsigned long stack_end; + unsigned long stack_base; + unsigned long *stack; unsigned long apicid; unsigned long index; unsigned long count; + int i; int result; spin_lock(&start_cpu_lock); @@ -238,6 +242,13 @@ int start_cpu(device_t cpu) /* Find end of the new processors stack */ 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 */ info = (struct cpu_info *)stack_end; info->index = index; @@ -440,6 +451,7 @@ static void wait_other_cpus_stop(struct bus *cpu_bus) device_t cpu; int old_active_count, active_count; long loopcount = 0; + int i; /* Now loop until the other cpus have finished initializing */ 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); + 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 */ @@ -494,7 +521,7 @@ void initialize_cpus(struct bus *cpu_bus) /* Find the device structure for the boot cpu */ 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 #endif @@ -502,7 +529,7 @@ void initialize_cpus(struct bus *cpu_bus) smm_init(); #endif -#if CONFIG_SMP +#if CONFIG_SMP && CONFIG_MAX_CPUS > 1 #if !CONFIG_SERIAL_CPU_INIT /* start all aps at first, so we can init ECC all together */ start_other_cpus(cpu_bus, info->cpu); @@ -512,7 +539,7 @@ void initialize_cpus(struct bus *cpu_bus) /* Initialize the bootstrap processor */ cpu_initialize(); -#if CONFIG_SMP +#if CONFIG_SMP && CONFIG_MAX_CPUS > 1 #if CONFIG_SERIAL_CPU_INIT start_other_cpus(cpu_bus, info->cpu); #endif