diff options
author | Furquan Shaikh <furquan@google.com> | 2014-08-30 21:59:11 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2015-03-28 07:04:44 +0100 |
commit | 668316bdccdb0372c7e450398ad1c81a9205d158 (patch) | |
tree | c6d3a3da429fd32b3528de8cdca7852567ada87e /src/arch/arm64/transition.c | |
parent | 0b606730c97ee2599b9992f6e5c4aa7d91176523 (diff) |
arm64: Add support for transition library
Transition library provides the following functionalities:
1) Setup the environment for switching to any particular EL and jump to the
loaded program at that EL. In short "Execute program X at exception level Y
using the state Z"
2) Provides routines for exception entry and exception exit that can be used by
any program to implement exception handling. The only routine required by the
program would be exc_dispatch which handles the exception in its own required
way and returns by making a call to exc_exit. On exc_exit, the transition
library unwinds the whole stack by popping out the saved state of xregs
BUG=chrome-os-partner:30785
BRANCH=None
TEST=Compiles successfully and exceptions are tested for ramstage on ryu
Change-Id: I8116556109665e61a53e4b3987d649e3cfed64a1
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 8ab888e8cae0c5f1e79b0e16ca292869f16f1cca
Original-Change-Id: I90f664ac657258724dc0c79bd9f6ceef70064f90
Original-Signed-off-by: Furquan Shaikh <furquan@google.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/216375
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Original-Tested-by: Furquan Shaikh <furquan@chromium.org>
Original-Commit-Queue: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: http://review.coreboot.org/9070
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/arch/arm64/transition.c')
-rw-r--r-- | src/arch/arm64/transition.c | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/arch/arm64/transition.c b/src/arch/arm64/transition.c new file mode 100644 index 0000000000..523960e741 --- /dev/null +++ b/src/arch/arm64/transition.c @@ -0,0 +1,134 @@ +/* + * 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 + */ + +#include <arch/lib_helpers.h> +#include <arch/transition.h> +#include <console/console.h> + +/* Mask out debug exceptions, serror, irq and fiq */ +#define SPSR_MASK (SPSR_FIQ_MASK | SPSR_IRQ_MASK | SPSR_SERROR_MASK | \ + SPSR_DEBUG_MASK) +/* Litte-endian, No XN-forced, Instr cache disabled, + * Stack alignment disabled, Data and unified cache + * disabled, Alignment check disabled, MMU disabled + */ +#define SCTLR_MASK (SCTLR_MMU_DISABLE | SCTLR_ACE_DISABLE | \ + SCTLR_CACHE_DISABLE | SCTLR_SAE_DISABLE | SCTLR_RES1 | \ + SCTLR_ICE_DISABLE | SCTLR_WXN_DISABLE | SCTLR_LITTLE_END) + +void __attribute__((weak)) exc_dispatch(struct exc_state *exc_state, uint64_t id) +{ + /* Default weak implementation does nothing. */ +} + +void exc_entry(struct exc_state *exc_state, uint64_t id) +{ + struct elx_state *elx = &exc_state->elx; + struct regs *regs = &exc_state->regs; + uint8_t elx_mode, elx_el; + + elx->spsr = raw_read_spsr_current(); + elx_mode = get_mode_from_spsr(elx->spsr); + elx_el = get_el_from_spsr(elx->spsr); + + if (elx_mode == SPSR_USE_H) { + if (elx_el == get_current_el()) + regs->sp = (uint64_t)&exc_state[1]; + else + regs->sp = raw_read_sp_elx(elx_el); + } else { + regs->sp = raw_read_sp_el0(); + } + + elx->elr = raw_read_elr_current(); + + exc_dispatch(exc_state, id); +} + +void transition_with_entry(void *entry, void *arg, struct exc_state *exc_state) +{ + /* Argument to entry point goes into X0 */ + exc_state->regs.x[X0_INDEX] = (uint64_t)arg; + /* Entry point goes into ELR */ + exc_state->elx.elr = (uint64_t)entry; + + transition(exc_state); +} + +void transition(struct exc_state *exc_state) +{ + uint32_t scr_mask; + uint64_t hcr_mask; + uint64_t sctlr; + uint32_t current_el = get_current_el(); + + struct elx_state *elx = &exc_state->elx; + struct regs *regs = &exc_state->regs; + + uint8_t elx_el = get_el_from_spsr(elx->spsr); + + /* + * Policies enforced: + * 1. We support only elx --> (elx - 1) transitions + * 2. We support transitions to Aarch64 mode only + * + * If any of the above conditions holds false, then we need a proper way + * to update SCR/HCR before removing the checks below + */ + if ((current_el - elx_el) != 1) + die("ARM64 Error: Do not support transition\n"); + + if (elx->spsr & SPSR_ERET_32) + die("ARM64 Error: Do not support eret to Aarch32\n"); + else { + scr_mask = SCR_LOWER_AARCH64; + hcr_mask = HCR_LOWER_AARCH64; + } + + /* SPSR: Mask out debug exceptions, serror, irq, fiq */ + elx->spsr |= SPSR_MASK; + raw_write_spsr_current(elx->spsr); + + /* SCR: Write to SCR if current EL is EL3 */ + if (current_el == EL3) { + uint32_t scr = raw_read_scr_el3(); + scr |= scr_mask; + raw_write_scr_el3(scr); + } + /* HCR: Write to HCR if current EL is EL2 */ + else if (current_el == EL2) { + uint64_t hcr = raw_read_hcr_el2(); + hcr |= hcr_mask; + raw_write_hcr_el2(hcr); + } + + /* ELR: Write entry point of program */ + raw_write_elr_current(elx->elr); + + /* SCTLR: Initialize EL with selected properties */ + sctlr = raw_read_sctlr(elx_el); + sctlr &= SCTLR_MASK; + raw_write_sctlr(sctlr, elx_el); + + /* SP_ELx: Initialize stack pointer */ + raw_write_sp_elx(elx->sp_elx, elx_el); + + /* Eret to the entry point */ + trans_switch(regs); +} |