I suppose that there is a race-condition between the setting of the stack pointer and setting the instruction-pointer when enabling the second CPU in SysBIOS 6.37.02.27. The code from packages/ti/sysbios/family/arm/ducati/Core_smp.c:
Void Core_startCore1() { if (Core_getId() != 0) { return; } /* put C stack in the middle of core 1's Hwi stack to avoid collision */ *(Char **)(0x0008) = &Core_module->core1HwiStack[Core_core1HwiStackSize/2]; *(UInt32 *)(0x000C) = (UInt32)Core_core1Startup; }
The stack pointer is written to 0x8 and the instruction pointer to 0xC.
However, there is nothing that prevent the compiler from doing the store to set the stack pointer AFTER the store to set the instruction pointer. This is what happened in my case (TI compiler v5.1.11). See the disassembly view:
The code for CPU core 1 loops until the instruction pointer is set to something else than zero and then (after a few instructions) also loads the stack pointer. Code from Power_resumeCpu.sv7M:
.sect ".ducatiPowerBoot" ; reset vectors vecbase: .long 0 ; sp = not used ; address 0x0 .long _ti_sysbios_family_arm_ducati_smp_Power_reset ; address 0x4 core1sp: .long 0 ; Core 1 sp ; address 0x8 core1vec: .long 0 ; Core 1 resetVec ; address 0xC [...] core1: ; Core 1 waits for "a while" to let core 0 init the system ldr r0, core1vec cmp r0, #0 beq core1 ; loop until core 0 unleashes us mov r2, #core1vec-vecbase mov r1, #0 str r1, [r2] ; clean up for next reset ldr sp, core1sp bx r0 ; jump to core1's c_int00
So, the CPU core 1 could be running with some uninitialized stack pointer because the store to the stack pointer location is executed by CPU core 0 after releasing CPU core 1.
Possible solutions are to fix the code in Core_startCore1():
1. Use the qualifier "volatile" for both stores. This forbids compiler reordering. However, if this does not prevent the CPU from reordering during runtime (in case of ARM v7) unless the CPU doesn't do this at all (for instance, the Cortex M4 does strict in-order processing). This won't help on a Cortex A15.
2. Use a memory barrier instruction for ordering (e.g. "DMB" for ARM v7):
*(Char **)(0x0008) = &Core_module->core1HwiStack[Core_core1HwiStackSize/2]; __asm("\tDMB\r\n"); *(UInt32 *)(0x000C) = (UInt32)Core_core1Startup;
This is probably the safest solution, but not particularly nice.
3. AFAIR with ARM v7 there is a possibility to enforce strict ordering of memory instructions via the page-tables. This is usually done for I/O memory. Together with the "volatile" keyword, this prevents reordering by the compiler and during runtime.
Comments?