// Copyright 2016 The Fuchsia Authors // Copyright (c) 2014 Travis Geiselbrecht // // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file or at // https://opensource.org/licenses/MIT #include #include #define HCR_EL2_RW (1 << 31) #define SCR_EL3_NS (1 << 0) #define SCR_EL3_HCE (1 << 8) #define SCR_EL3_RW (1 << 10) /* void arm64_context_switch(vaddr_t *old_sp, vaddr_t new_sp); */ FUNCTION(arm64_context_switch) /* save old frame */ /* This layout should match struct context_switch_frame */ push_regs x29, x30 push_regs x27, x28 push_regs x25, x26 push_regs x23, x24 push_regs x21, x22 push_regs x19, x20 mrs x19, tpidr_el0 mrs x20, tpidrro_el0 push_regs x19, x20 /* save old sp */ mov x15, sp str x15, [x0] /* load new sp */ mov sp, x1 /* restore new frame */ pop_regs x19, x20 msr tpidr_el0, x19 msr tpidrro_el0, x20 pop_regs x19, x20 pop_regs x21, x22 pop_regs x23, x24 pop_regs x25, x26 pop_regs x27, x28 pop_regs x29, x30 ret END_FUNCTION(arm64_context_switch) FUNCTION(arm64_elX_to_el1) mrs x9, CurrentEL cmp x9, #(0b01 << 2) bne .notEL1 /* Already in EL1 */ ret .notEL1: cmp x9, #(0b10 << 2) beq .inEL2 /* set EL2 to 64bit and enable HVC instruction */ mrs x9, scr_el3 orr x9, x9, #SCR_EL3_NS orr x9, x9, #SCR_EL3_HCE orr x9, x9, #SCR_EL3_RW msr scr_el3, x9 adr x9, .Ltarget msr elr_el3, x9 mov x9, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ msr spsr_el3, x9 b .confEL1 .inEL2: /* Setup the init vector table for EL2. */ adr_global x9, arm64_el2_init_table msr vbar_el2, x9 /* Ensure EL1 timers are properly configured, disable EL2 trapping of EL1 access to timer control registers. Also clear virtual offset. */ mrs x9, cnthctl_el2 orr x9, x9, #3 msr cnthctl_el2, x9 msr cntvoff_el2, xzr /* clear out stage 2 translations */ msr vttbr_el2, xzr adr x9, .Ltarget msr elr_el2, x9 mov x9, #((0b1111 << 6) | (0b0101)) /* EL1h runlevel */ msr spsr_el2, x9 .confEL1: /* disable EL2 coprocessor traps */ mov x9, #0x33ff msr cptr_el2, x9 /* set EL1 to 64bit */ mov x9, #HCR_EL2_RW msr hcr_el2, x9 /* disable EL1 FPU traps */ mov x9, #(0b11<<20) msr cpacr_el1, x9 /* set up the EL1 bounce interrupt */ mov x9, sp msr sp_el1, x9 isb eret .Ltarget: ret END_FUNCTION(arm64_elX_to_el1) FUNCTION(arm64_get_secondary_sp) mrs x9, mpidr_el1 and x9, x9, #0xffff /* only use id/cluster */ mov x10, #SMP_MAX_CPUS adr_global x11, arm64_secondary_sp_list .Lsp_loop: ldr x12, [x11, #0] cmp x12, x9 beq .Lsp_found add x11, x11, #32 subs x10, x10, #1 bne .Lsp_loop mov x0, xzr mov x1, xzr ret .Lsp_found: ldr x0, [x11, #8] add x1, x11, #32 ret END_FUNCTION(arm64_get_secondary_sp)