diff options
Diffstat (limited to 'src/arch/arm64/include')
-rw-r--r-- | src/arch/arm64/include/arch/transition.h | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/arch/arm64/include/arch/transition.h b/src/arch/arm64/include/arch/transition.h new file mode 100644 index 0000000000..e8ded5f2aa --- /dev/null +++ b/src/arch/arm64/include/arch/transition.h @@ -0,0 +1,188 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ARCH_ARM64_TRANSITION_H__ +#define __ARCH_ARM64_TRANSITION_H__ + +/* ======================== Transition Library ================================= + * Transition library provides two main functionalities: + * 1) It allows any program X to be executed at EL Y using the state Z. It + * provides struct exc_state which holds the state of the EL to which we want to + * execute X at. Before performing an eret to the entry point of the program X, + * it initializes required registers using this exc_state structure. Here, X0 = + * args to the program X. IMP!!! : We do not initialize SP_EL0 for the program + * X, the program will have to handle that on its own. This is because while + * performing an eret to X, we could make SP_EL0 point to regs structure which + * then follows common exception exit path. + * 2) It serves as a common mechanism for handling exception entry and exit at + * any given EL. On entry to an exception, SP_ELx is selected by default. The + * exc entry routine stores all xregs and jumps to exc_entry which + * saves ELR, SPSR, EL, Mode and other information about the state from which + * exception was generated. On exit, xregs are restored by unwinding of SP_ELx. + * ============================================================================= + */ + +/* Macros for EL mode in SPSR */ +#define STACK_POP_BYTES 16 +#define STACK_PUSH_BYTES -16 + +#ifndef __ASSEMBLY__ + +#include <stdint.h> +#include <arch/lib_helpers.h> + +#define XI_INDEX(i) X##i##_INDEX = i + +enum { + XI_INDEX(0), + XI_INDEX(1), + XI_INDEX(2), + XI_INDEX(3), + XI_INDEX(4), + XI_INDEX(5), + XI_INDEX(6), + XI_INDEX(7), + XI_INDEX(8), + XI_INDEX(9), + XI_INDEX(10), + XI_INDEX(11), + XI_INDEX(12), + XI_INDEX(13), + XI_INDEX(14), + XI_INDEX(15), + XI_INDEX(16), + XI_INDEX(17), + XI_INDEX(18), + XI_INDEX(19), + XI_INDEX(20), + XI_INDEX(21), + XI_INDEX(22), + XI_INDEX(23), + XI_INDEX(24), + XI_INDEX(25), + XI_INDEX(26), + XI_INDEX(27), + XI_INDEX(28), + XI_INDEX(29), + XI_INDEX(30), + XMAX_INDEX, +}; + +/* + * Important: Any changes made to the two structures below should reflect in the + * exc_prologue and exc_exit routines in transition_asm.S + */ +struct regs { + uint64_t sp; + uint64_t x[31]; +}; + +struct elx_state { + uint64_t spsr; + uint64_t sp_el0; + uint64_t sp_elx; + uint64_t elr; +}; + +struct exc_state { + struct elx_state elx; + struct regs regs; +}; + +/* + * get_eret_EL returns the value of the exception state to which we will be + * returning. This value is saved in SPSR before performing an eret. + * + * Exception mode is defined by M[3:0] bits in SPSR: + * ( M[3:2] = EL, M[1] = unused, M[0] = t/h mode for stack + * + * 0b0000 EL0t + * 0b0100 EL1t + * 0b0101 EL1h + * 0b1000 EL2t + * 0b1001 EL2h + * 0b1100 EL3t + * 0b1101 EL3h + */ + +static inline uint8_t get_eret_el(uint8_t el, uint8_t l_or_h) +{ + uint8_t el_mode = el << CURRENT_EL_SHIFT; + + el_mode |= l_or_h; + + return el_mode; +} + +static inline uint8_t get_el_from_spsr(uint64_t spsr) +{ + return ((spsr >> CURRENT_EL_SHIFT) & CURRENT_EL_MASK); +} + +static inline uint8_t get_mode_from_spsr(uint64_t spsr) +{ + return (spsr & SPSR_L_H_MASK); +} + +/* Transitions supported are: + * 1. elx --> elx - 1 + * 2. Transitions to aarch64 state + * + * Other than this, if any transition needs to be supported, relevant changes + * need to be done to hcr/scr registers. + */ + +/* + * User of transition library can make a call to transition_with_entry and pass + * the entry point and its argument which are put into elr and x0 by this + * function. After that it makes a call to transition. + */ +void transition_with_entry(void *entry, void *arg, struct exc_state *exc_state); +/* + * transition function sets up all the registers as per the struct elx_state + * before jumping to trans_switch. + */ +void transition(struct exc_state *exc_state); + +/* + * exc_exit it called while returning from an exception. It expects pointer to + * the regs structure on stack so that it can unwind the used stack. + */ +void exc_exit(struct regs *regs); +/* + * trans_switch is called by the non-exception path i.e. transition C code + * while making a transition to lower EL. It select L mode so that SP_EL0 is + * used during the unwinding in exc_exit. + */ +void trans_switch(struct regs *regs); +/* exc_set_vbar sets up the vbar for exception vectors. */ +void exc_set_vbar(void); + +/* exc_dispatch is the user-defined exception handler. */ +void exc_dispatch(struct exc_state *exc_state, uint64_t id); +/* + * exc_entry is the C based component of the exception entry before we + * jump to user-defined handler. This initializes all the regs in elx_state and + * also sets the sp value in regs structure. + */ +void exc_entry(struct exc_state *exc_state, uint64_t id); + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM64_TRANSITION_H__ */ |