1 /* 2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <assert.h> 33 #include <bakery_lock.h> 34 #include <bl_common.h> 35 #include <context.h> 36 #include <context_mgmt.h> 37 #include <debug.h> 38 #include <denver.h> 39 #include <gic_v2.h> 40 #include <interrupt_mgmt.h> 41 #include <platform.h> 42 #include <tegra_def.h> 43 #include <tegra_private.h> 44 45 DEFINE_BAKERY_LOCK(tegra_fiq_lock); 46 47 /******************************************************************************* 48 * Static variables 49 ******************************************************************************/ 50 static uint64_t ns_fiq_handler_addr; 51 static unsigned int fiq_handler_active; 52 static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; 53 54 /******************************************************************************* 55 * Handler for FIQ interrupts 56 ******************************************************************************/ 57 static uint64_t tegra_fiq_interrupt_handler(uint32_t id, 58 uint32_t flags, 59 void *handle, 60 void *cookie) 61 { 62 cpu_context_t *ctx = cm_get_context(NON_SECURE); 63 el3_state_t *el3state_ctx = get_el3state_ctx(ctx); 64 int cpu = plat_my_core_pos(); 65 uint32_t irq; 66 67 bakery_lock_get(&tegra_fiq_lock); 68 69 /* 70 * The FIQ was generated when the execution was in the non-secure 71 * world. Save the context registers to start with. 72 */ 73 cm_el1_sysregs_context_save(NON_SECURE); 74 75 /* 76 * Save elr_el3 and spsr_el3 from the saved context, and overwrite 77 * the context with the NS fiq_handler_addr and SPSR value. 78 */ 79 fiq_state[cpu].elr_el3 = read_ctx_reg(el3state_ctx, CTX_ELR_EL3); 80 fiq_state[cpu].spsr_el3 = read_ctx_reg(el3state_ctx, CTX_SPSR_EL3); 81 82 /* 83 * Set the new ELR to continue execution in the NS world using the 84 * FIQ handler registered earlier. 85 */ 86 assert(ns_fiq_handler_addr); 87 write_ctx_reg(el3state_ctx, CTX_ELR_EL3, ns_fiq_handler_addr); 88 89 /* 90 * Mark this interrupt as complete to avoid a FIQ storm. 91 */ 92 irq = plat_ic_acknowledge_interrupt(); 93 if (irq < 1022) 94 plat_ic_end_of_interrupt(irq); 95 96 bakery_lock_release(&tegra_fiq_lock); 97 98 return 0; 99 } 100 101 /******************************************************************************* 102 * Setup handler for FIQ interrupts 103 ******************************************************************************/ 104 void tegra_fiq_handler_setup(void) 105 { 106 uint64_t flags; 107 int rc; 108 109 /* return if already registered */ 110 if (fiq_handler_active) 111 return; 112 113 /* 114 * Register an interrupt handler for FIQ interrupts generated for 115 * NS interrupt sources 116 */ 117 flags = 0; 118 set_interrupt_rm_flag(flags, NON_SECURE); 119 rc = register_interrupt_type_handler(INTR_TYPE_EL3, 120 tegra_fiq_interrupt_handler, 121 flags); 122 if (rc) 123 panic(); 124 125 /* handler is now active */ 126 fiq_handler_active = 1; 127 } 128 129 /******************************************************************************* 130 * Validate and store NS world's entrypoint for FIQ interrupts 131 ******************************************************************************/ 132 void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) 133 { 134 ns_fiq_handler_addr = entrypoint; 135 } 136 137 /******************************************************************************* 138 * Handler to return the NS EL1/EL0 CPU context 139 ******************************************************************************/ 140 int tegra_fiq_get_intr_context(void) 141 { 142 cpu_context_t *ctx = cm_get_context(NON_SECURE); 143 gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); 144 el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); 145 int cpu = plat_my_core_pos(); 146 uint64_t val; 147 148 /* 149 * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so 150 * that el3_exit() sends these values back to the NS world. 151 */ 152 write_ctx_reg(gpregs_ctx, CTX_GPREG_X0, fiq_state[cpu].elr_el3); 153 write_ctx_reg(gpregs_ctx, CTX_GPREG_X1, fiq_state[cpu].spsr_el3); 154 155 val = read_ctx_reg(gpregs_ctx, CTX_GPREG_SP_EL0); 156 write_ctx_reg(gpregs_ctx, CTX_GPREG_X2, val); 157 158 val = read_ctx_reg(el1state_ctx, CTX_SP_EL1); 159 write_ctx_reg(gpregs_ctx, CTX_GPREG_X3, val); 160 161 return 0; 162 } 163