Debugging a Multicore Kernel Initialization on Raspberry Pi 3B

  Kiến thức lập trình

I am developing a simple kernel for Raspberry Pi 3B intended to run basic tasks on all four cores. However, it appears that only the primary core is running kernel_init, and the other cores never start. Here’s the relevant part of my code:

.globl _start
_start:
    mrs    x0, mpidr_el1
    and    x0, x0,#0xFF        // Check processor id
    cbz    x0, el1_entry        // Hang for all non-primary CPU
    b    proc_hang

proc_hang: 
    wfe
    b      proc_hang

el1_entry:
    adr    x0, bss_begin
    adr    x1, bss_end
    sub    x1, x1, x0
    bl     memzero

    mov    sp, #LOW_MEMORY
     // Initialize and start secondary cores on Raspberry Pi 3
    ldr x1, =start_core_1    // Address to jump to for secondary cores
    ldr x2, =0xE0                // Mailbox register for Core 1
    str x1, [x2]

    ldr x1, =start_core_2    // Address to jump to for secondary cores
    ldr x2, =0xE8                // Mailbox register for Core 2
    str x1, [x2]
    
    ldr x1, =start_core_3    // Address to jump to for secondary cores
    ldr x2, =0xF0                // Mailbox register for Core 3
    str x1, [x2]
    sev                           // Send event to wake up all cores

    bl    kernel_init
    b     proc_hang        // should never come here

start_core_1:
    ldr    x1, =LOW_MEMORY
    ldr    x2, =PAGE_SIZE
    add    sp, x1, x2          // sp = LOW_MEMORY + PAGE_SIZE
    bl     kernel_init
    b      start_core_1

start_core_2:
    ldr    x1, =LOW_MEMORY
    ldr    x2, =PAGE_SIZE
    add    sp, x1, x2, lsl #1  // sp = LOW_MEMORY + 2*PAGE_SIZE
    bl     kernel_init
    b      start_core_2

start_core_3:
    ldr    x1, =LOW_MEMORY
    ldr    x2, =PAGE_SIZE
    mov    x3, #3
    mul    x2, x2, x3          // x2 = 3 * PAGE_SIZE
    add    sp, x1, x2          // sp = LOW_MEMORY + 3*PAGE_SIZE
    bl     kernel_init
    b      start_core_3
extern "C" void kernel_init(void)
{
    uart_init();
    init_printf(0, putc);
    printf("processor ID: %dn", get_core_number());
    while (1)
    {
        uart_send(uart_recv());
    }
}
.global get_core_number
    get_core_number:
    mrs x0, MPIDR_EL1      // Read MPIDR_EL1 into x0
    and x0, x0, #0xff      // Check processor id
    ret                    // Return, with the result in x0

Despite writing to the correct mailbox registers to wake up the secondary cores, the UART output shows only “processor ID: 0”, and it seems like the secondary core-specific code never starts running. Based on my understanding of multicore programming, the output should be something like this if all of the cores are running:

processor ID: 0
processor ID: 2
processor ID: 1
processor ID: 3 (in random order of course)

I have tried setting different stack pointers for each core, as seen in the initialization code for start_core_X, but still, only the primary core seems active.

What I have tried is just doing something like this:

_start:
    adr    x0, bss_begin
    adr    x1, bss_end
    sub    x1, x1, x0
    bl     memzero
    mov    sp, #LOW_MEMORY
    bl    kernel_init

With this setup, I expected all cores to execute kernel_init as there’s no logic to differentiate between cores (like checking MPIDR_EL1 to filter out non-primary cores). However, it seems that only the primary core is executing kernel_init, based on the output I’m getting:

processor ID: 0

Any insights or suggestions on why this is happening or how to ensure all cores run the initialization code would be greatly appreciated!

New contributor

Diego A Wearden is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

LEAVE A COMMENT