blob: 4793b840c28ecd8eca622af9bd7bee21be7301c0 [file] [log] [blame]
Furquan Shaikh668316b2014-08-30 21:59:11 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Furquan Shaikh668316b2014-08-30 21:59:11 -070014 */
15
16#ifndef __ARCH_ARM64_TRANSITION_H__
17#define __ARCH_ARM64_TRANSITION_H__
18
19/* ======================== Transition Library =================================
20 * Transition library provides two main functionalities:
21 * 1) It allows any program X to be executed at EL Y using the state Z. It
22 * provides struct exc_state which holds the state of the EL to which we want to
23 * execute X at. Before performing an eret to the entry point of the program X,
24 * it initializes required registers using this exc_state structure. Here, X0 =
25 * args to the program X. IMP!!! : We do not initialize SP_EL0 for the program
26 * X, the program will have to handle that on its own. This is because while
27 * performing an eret to X, we could make SP_EL0 point to regs structure which
28 * then follows common exception exit path.
29 * 2) It serves as a common mechanism for handling exception entry and exit at
30 * any given EL. On entry to an exception, SP_ELx is selected by default. The
31 * exc entry routine stores all xregs and jumps to exc_entry which
32 * saves ELR, SPSR, EL, Mode and other information about the state from which
33 * exception was generated. On exit, xregs are restored by unwinding of SP_ELx.
34 * =============================================================================
35 */
36
37/* Macros for EL mode in SPSR */
38#define STACK_POP_BYTES 16
39#define STACK_PUSH_BYTES -16
40
Aaron Durbin4f89d972014-09-16 22:23:57 -050041#define EXC_VID_CUR_SP_EL0_SYNC 0
42#define EXC_VID_CUR_SP_EL0_IRQ 1
43#define EXC_VID_CUR_SP_EL0_FIRQ 2
44#define EXC_VID_CUR_SP_EL0_SERR 3
45#define EXC_VID_CUR_SP_ELX_SYNC 4
46#define EXC_VID_CUR_SP_ELX_IRQ 5
47#define EXC_VID_CUR_SP_ELX_FIQ 6
48#define EXC_VID_CUR_SP_ELX_SERR 7
49#define EXC_VID_LOW64_SYNC 8
50#define EXC_VID_LOW64_IRQ 9
51#define EXC_VID_LOW64_FIQ 10
52#define EXC_VID_LOW64_SERR 11
53#define EXC_VID_LOW32_SYNC 12
54#define EXC_VID_LOW32_IRQ 13
55#define EXC_VID_LOW32_FIQ 14
56#define EXC_VID_LOW32_SERR 15
57#define NUM_EXC_VIDS 16
58
Furquan Shaikh668316b2014-08-30 21:59:11 -070059#ifndef __ASSEMBLY__
60
61#include <stdint.h>
62#include <arch/lib_helpers.h>
63
64#define XI_INDEX(i) X##i##_INDEX = i
65
66enum {
67 XI_INDEX(0),
68 XI_INDEX(1),
69 XI_INDEX(2),
70 XI_INDEX(3),
71 XI_INDEX(4),
72 XI_INDEX(5),
73 XI_INDEX(6),
74 XI_INDEX(7),
75 XI_INDEX(8),
76 XI_INDEX(9),
77 XI_INDEX(10),
78 XI_INDEX(11),
79 XI_INDEX(12),
80 XI_INDEX(13),
81 XI_INDEX(14),
82 XI_INDEX(15),
83 XI_INDEX(16),
84 XI_INDEX(17),
85 XI_INDEX(18),
86 XI_INDEX(19),
87 XI_INDEX(20),
88 XI_INDEX(21),
89 XI_INDEX(22),
90 XI_INDEX(23),
91 XI_INDEX(24),
92 XI_INDEX(25),
93 XI_INDEX(26),
94 XI_INDEX(27),
95 XI_INDEX(28),
96 XI_INDEX(29),
97 XI_INDEX(30),
98 XMAX_INDEX,
99};
100
101/*
102 * Important: Any changes made to the two structures below should reflect in the
103 * exc_prologue and exc_exit routines in transition_asm.S
104 */
105struct regs {
106 uint64_t sp;
107 uint64_t x[31];
108};
109
110struct elx_state {
111 uint64_t spsr;
112 uint64_t sp_el0;
113 uint64_t sp_elx;
114 uint64_t elr;
115};
116
117struct exc_state {
118 struct elx_state elx;
119 struct regs regs;
120};
121
122/*
123 * get_eret_EL returns the value of the exception state to which we will be
124 * returning. This value is saved in SPSR before performing an eret.
125 *
126 * Exception mode is defined by M[3:0] bits in SPSR:
127 * ( M[3:2] = EL, M[1] = unused, M[0] = t/h mode for stack
128 *
129 * 0b0000 EL0t
130 * 0b0100 EL1t
131 * 0b0101 EL1h
132 * 0b1000 EL2t
133 * 0b1001 EL2h
134 * 0b1100 EL3t
135 * 0b1101 EL3h
136 */
137
138static inline uint8_t get_eret_el(uint8_t el, uint8_t l_or_h)
139{
140 uint8_t el_mode = el << CURRENT_EL_SHIFT;
141
142 el_mode |= l_or_h;
143
144 return el_mode;
145}
146
147static inline uint8_t get_el_from_spsr(uint64_t spsr)
148{
149 return ((spsr >> CURRENT_EL_SHIFT) & CURRENT_EL_MASK);
150}
151
152static inline uint8_t get_mode_from_spsr(uint64_t spsr)
153{
154 return (spsr & SPSR_L_H_MASK);
155}
156
157/* Transitions supported are:
158 * 1. elx --> elx - 1
159 * 2. Transitions to aarch64 state
160 *
161 * Other than this, if any transition needs to be supported, relevant changes
162 * need to be done to hcr/scr registers.
163 */
164
165/*
166 * User of transition library can make a call to transition_with_entry and pass
167 * the entry point and its argument which are put into elr and x0 by this
168 * function. After that it makes a call to transition.
169 */
170void transition_with_entry(void *entry, void *arg, struct exc_state *exc_state);
171/*
172 * transition function sets up all the registers as per the struct elx_state
173 * before jumping to trans_switch.
174 */
175void transition(struct exc_state *exc_state);
176
177/*
178 * exc_exit it called while returning from an exception. It expects pointer to
179 * the regs structure on stack so that it can unwind the used stack.
180 */
181void exc_exit(struct regs *regs);
182/*
183 * trans_switch is called by the non-exception path i.e. transition C code
184 * while making a transition to lower EL. It select L mode so that SP_EL0 is
185 * used during the unwinding in exc_exit.
186 */
187void trans_switch(struct regs *regs);
188/* exc_set_vbar sets up the vbar for exception vectors. */
189void exc_set_vbar(void);
190
191/* exc_dispatch is the user-defined exception handler. */
192void exc_dispatch(struct exc_state *exc_state, uint64_t id);
193/*
194 * exc_entry is the C based component of the exception entry before we
195 * jump to user-defined handler. This initializes all the regs in elx_state and
196 * also sets the sp value in regs structure.
197 */
198void exc_entry(struct exc_state *exc_state, uint64_t id);
199
200#endif /* __ASSEMBLY__ */
201
202#endif /* __ARCH_ARM64_TRANSITION_H__ */