/* * Copyright (C) 2018 The Android Open Source Project * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, * modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ .text #define MAX_CPU_COUNT (4) #define STACK_SIZE (4096) #define GICD_BASE (0x08000000) #define GICD_SGIR (0xf00) .macro get_cpu_num, reg /* Get cpu number */ mrs \reg, mpidr_el1 bic \reg, \reg, #(1<<24) /* Clear MT */ bic \reg, \reg, #(3<<30) /* Clear RES1 and U */ .endm .macro get_secondary_cpu_count, reg mrs \reg, S3_1_C11_C0_2 /*l2ctlr_el1*/ lsr \reg, \reg, #24 .endm .globl _start _start: /* Set exception vector base */ adr x0, _start mrs x1, CurrentEL and x1, x1, #0xc cmp x1, #0x8 bne vbar_setup_not_el2 msr vbar_el2, x0 b vbar_setup_done vbar_setup_not_el2: msr vbar_el1, x0 vbar_setup_done: get_cpu_num x0 /* Setup stack */ mov x1, #STACK_SIZE mul x1, x1, x0 adr x2, stack add x2, x2, x1 adr x1, stack_space_end cmp x2, x1 bhi error adr x1, cpu_ready strb w0, [x1, x0] /* cpu_ready[cpuid] = cpuid */ dmb st sev mov sp, x2 /* Jump to c-code */ bl boot /* fall-through */ error: mov x0, #0x18 adr x1, exit_params /* fall-through */ semihosting: hlt 0xf000 ret exit_params: .quad 0x20026 /* ADP_Stopped_ApplicationExit */ .quad 2 /* exit code */ /* * Catch exceptions (except sync-sp_el0 as we don't use that mode and it would * jump to our entry point) and exit in case there is a bug. */ .macro exception, addr .org \addr b error .endm exception 0x080 exception 0x100 exception 0x180 exception 0x200 exception 0x280 exception 0x300 exception 0x380 exception 0x400 exception 0x480 exception 0x500 exception 0x580 exception 0x600 exception 0x680 exception 0x700 exception 0x780 .globl trusty_idle trusty_idle: // x1 = event_poll adr x0, skip_cpu0_wfi // x0 = &skip_cpu0_wfi get_cpu_num x2 // x2 = cpunum cbz x2, cpu0_idle // if cpunum == 0 goto cpu0_idle // skip_cpu0_wfi = cpunum (any value non-0 would work) stlr x2, [x0] #if GIC_VERSION > 2 // Send int 0 to cpu 0 to take it out of wfi ldr x4, =(0 << 24) | 1 msr icc_sgi1r_el1, x4 #else // Send int 15 to cpu 0 to take it out of wfi ldr x3, =GICD_BASE ldr x4, =0x1800f str x4, [x3, GICD_SGIR] #endif cbnz x1, no_wfi // also use event_poll to skip wfi on secondary cpus b wfi cpu0_idle: cbz x1, wfi // only clear and skip event_poll wfi ldaxr x3, [x0] // x1 = skip_cpu0_wfi stxr w4, xzr, [x0] // skip_cpu0_wfi = 0 cbnz x3, no_wfi wfi: wfi no_wfi: ret #if GIC_VERSION > 2 .globl trusty_local_irq_disable trusty_local_irq_disable: /* * Clear doorbell interrupt from trusty or ipi sent from secondary cores in * trusty_idle above. */ mrs x0, icc_iar1_el1 cmp x0, #1020 b.hs .trusty_local_irq_disable_done msr icc_eoir1_el1, x0 b trusty_local_irq_disable .trusty_local_irq_disable_done: ret #endif .globl arch_start_secondary_cpus arch_start_secondary_cpus: sub sp, sp, #16 mov x1, #1 get_secondary_cpu_count x2 cmp x2, #MAX_CPU_COUNT blo .cpu_count_ok mov x2, #(MAX_CPU_COUNT - 1) .cpu_count_ok: stp x1, x2, [sp] start_secondary_cpu_loop: ldr x0, =0xC4000003 /* psci CPU_ON */ adr x2, _start mov x3, #0 smc 0 cbnz x0, .start_secondary_cpu_failed ldp x1, x2, [sp] add x1, x1, #1 stp x1, x2, [sp] cmp x1, x2 bls start_secondary_cpu_loop add sp, sp, #16 mov x1, #0 .wait_for_secondary_cpu_loop: wfe dmb ld adr x4, cpu_ready ldrb w3, [x4, x1] cmp x3, x1 b.ne .wait_for_secondary_cpu_loop add x1, x1, #1 cmp x1, x2 bls .wait_for_secondary_cpu_loop mov x0, 0 .start_secondary_cpu_failed: ret .data .space STACK_SIZE stack: .space STACK_SIZE * (MAX_CPU_COUNT - 1) stack_space_end: cpu_ready: .space MAX_CPU_COUNT .align 3 skip_cpu0_wfi: .long 0