hw: add CPU wake up code for rpi3

Moved code waking up processors for Cortex A53 before changing privilege
level because sending events to higher privilege levels is not allowed.

Fixed enable_mmu for Cortex A53 to properly return cpu id.

Fixed starting code for secondary cores to properly initialize stacks.

Added code to wake up secondary cores on rpi3.

Ref #3573
This commit is contained in:
Tomasz Gajewski 2020-01-12 21:34:40 +01:00 committed by Christian Helmuth
parent 202333c881
commit 4f217b19a9
3 changed files with 35 additions and 17 deletions

View File

@ -16,7 +16,7 @@
using Board::Cpu;
extern "C" void * _crt0_enable_fpu;
extern "C" void * _crt0_start_secondary;
static inline void prepare_non_secure_world()
{
@ -144,6 +144,9 @@ unsigned Bootstrap::Platform::enable_mmu()
Cpu::Ttbr::access_t ttbr =
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
/* primary cpu wakes up all others */
if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_start_secondary);
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
prepare_non_secure_world();
@ -153,9 +156,6 @@ unsigned Bootstrap::Platform::enable_mmu()
}
}
/* primary cpu wakes up all others */
if (primary && NR_OF_CPUS > 1) Cpu::wake_up_all_cpus(&_crt0_enable_fpu);
/* enable performance counter for user-land */
Cpu::Pmuserenr_el0::write(0b1111);
Cpu::Pmcr_el0::access_t pmcr = Cpu::Pmcr_el0::read();
@ -201,5 +201,5 @@ unsigned Bootstrap::Platform::enable_mmu()
Cpu::Sctlr::Uct::set(sctlr, 1);
Cpu::Sctlr_el1::write(sctlr);
return 0;
return (Cpu::Mpidr::read() & 0xff);
}

View File

@ -11,22 +11,25 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/**
* Store CPU number in register x0
*/
.macro _cpu_number
mrs x0, mpidr_el1
and x0, x0, #0b11111111
.endm
.section ".text.crt0"
.global _start
_start:
/***********************
** Detect CPU number **
***********************/
mrs x0, mpidr_el1
and x0, x0, #0b11111111
cbz x0, _crt0_fill_bss_zero
/**
* Hack for Qemu, which starts all cpus at once
* only first CPU runs through, all others wait for wakeup
*/
_cpu_number
cbz x0, _crt0_fill_bss_zero
1:
ldr x1, =_crt0_qemu_start_secondary_cpus
ldr w1, [x1]
@ -52,11 +55,18 @@
b 1b
/************************************
** Common Entrypoint for all CPUs **
************************************/
.global _crt0_start_secondary
_crt0_start_secondary:
/****************
** Enable FPU **
****************/
.global _crt0_enable_fpu
_crt0_enable_fpu:
mov x1, #0b11
lsl x1, x1, #20
@ -69,6 +79,7 @@
.set STACK_SIZE, 0x2000
_cpu_number
ldr x1, =_crt0_start_stack
ldr x2, [x1]
mul x0, x0, x2
@ -82,4 +93,3 @@
.endr
_crt0_start_stack:
.long STACK_SIZE

View File

@ -30,8 +30,16 @@ Bootstrap::Platform::Board::Board()
extern unsigned int _crt0_qemu_start_secondary_cpus;
void Board::Cpu::wake_up_all_cpus(void *)
void Board::Cpu::wake_up_all_cpus(void * ip)
{
/* start when in qemu */
_crt0_qemu_start_secondary_cpus = 1;
asm volatile("dsb #0; sev");
/* start on real hardware */
*((void * volatile *) 0xe0) = ip; /* cpu 1 */
*((void * volatile *) 0xe8) = ip; /* cpu 2 */
*((void * volatile *) 0xf0) = ip; /* cpu 3 */
/* send event for both variants */
asm volatile("dsb #15; sev");
}