diff options
Diffstat (limited to 'bl31/aarch64/exception_handlers.c')
-rw-r--r-- | bl31/aarch64/exception_handlers.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/bl31/aarch64/exception_handlers.c b/bl31/aarch64/exception_handlers.c new file mode 100644 index 00000000..860d8ebc --- /dev/null +++ b/bl31/aarch64/exception_handlers.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2013, ARM Limited. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <arch_helpers.h> +#include <platform.h> +#include <bl_common.h> +#include <bl31.h> +#include <psci.h> +#include <assert.h> +#include <runtime_svc.h> + +/******************************************************************************* + * This function checks whether this is a valid smc e.g. + * the function id is correct, top word of args are zeroed + * when aarch64 makes an aarch32 call etc. + ******************************************************************************/ +int validate_smc(gp_regs *regs) +{ + unsigned int rw = GET_RW(regs->spsr); + unsigned int cc = GET_SMC_CC(regs->x0); + + /* Check if there is a difference in the caller RW and SMC CC */ + if (rw == cc) { + + /* Check whether the caller has chosen the right func. id */ + if (cc == SMC_64) { + regs->x0 = SMC_UNK; + return SMC_UNK; + } + + /* + * Paranoid check to zero the top word of passed args + * irrespective of caller's register width. + * + * TODO: Check if this needed if the caller is aarch32 + */ + regs->x0 &= (unsigned int) 0xFFFFFFFF; + regs->x1 &= (unsigned int) 0xFFFFFFFF; + regs->x2 &= (unsigned int) 0xFFFFFFFF; + regs->x3 &= (unsigned int) 0xFFFFFFFF; + regs->x4 &= (unsigned int) 0xFFFFFFFF; + regs->x5 &= (unsigned int) 0xFFFFFFFF; + regs->x6 &= (unsigned int) 0xFFFFFFFF; + } + + return 0; +} + +/* TODO: Break down the SMC handler into fast and standard SMC handlers. */ +void smc_handler(unsigned type, unsigned long esr, gp_regs *regs) +{ + /* Check if the SMC has been correctly called */ + if (validate_smc(regs) != 0) + return; + + switch (regs->x0) { + case PSCI_VERSION: + regs->x0 = psci_version(); + break; + + case PSCI_CPU_OFF: + regs->x0 = __psci_cpu_off(); + break; + + case PSCI_CPU_SUSPEND_AARCH64: + case PSCI_CPU_SUSPEND_AARCH32: + regs->x0 = __psci_cpu_suspend(regs->x1, regs->x2, regs->x3); + break; + + case PSCI_CPU_ON_AARCH64: + case PSCI_CPU_ON_AARCH32: + regs->x0 = psci_cpu_on(regs->x1, regs->x2, regs->x3); + break; + + case PSCI_AFFINITY_INFO_AARCH32: + case PSCI_AFFINITY_INFO_AARCH64: + regs->x0 = psci_affinity_info(regs->x1, regs->x2); + break; + + default: + regs->x0 = SMC_UNK; + } + + return; +} + +void irq_handler(unsigned type, unsigned long esr, gp_regs *regs) +{ + plat_report_exception(type); + assert(0); +} + +void fiq_handler(unsigned type, unsigned long esr, gp_regs *regs) +{ + plat_report_exception(type); + assert(0); +} + +void serror_handler(unsigned type, unsigned long esr, gp_regs *regs) +{ + plat_report_exception(type); + assert(0); +} + +void sync_exception_handler(unsigned type, gp_regs *regs) +{ + unsigned long esr = read_esr(); + unsigned int ec = EC_BITS(esr); + + switch (ec) { + + case EC_AARCH32_SMC: + case EC_AARCH64_SMC: + smc_handler(type, esr, regs); + break; + + default: + plat_report_exception(type); + assert(0); + } + return; +} + +void async_exception_handler(unsigned type, gp_regs *regs) +{ + unsigned long esr = read_esr(); + + switch (type) { + + case IRQ_SP_EL0: + case IRQ_SP_ELX: + case IRQ_AARCH64: + case IRQ_AARCH32: + irq_handler(type, esr, regs); + break; + + case FIQ_SP_EL0: + case FIQ_SP_ELX: + case FIQ_AARCH64: + case FIQ_AARCH32: + fiq_handler(type, esr, regs); + break; + + case SERROR_SP_EL0: + case SERROR_SP_ELX: + case SERROR_AARCH64: + case SERROR_AARCH32: + serror_handler(type, esr, regs); + break; + + default: + plat_report_exception(type); + assert(0); + } + + return; +} |