source: mainline/kernel/arch/arm64/src/exception.c

Last change on this file was 84176f3, checked in by Jakub Jermář <jakub@…>, 6 years ago

arm64: Add support for the architecture

This changeset adds basic support to run HelenOS on AArch64, targeting
the QEMU virt platform.

Boot:

  • Boot relies on the EDK II firmware, GRUB2 for EFI and the HelenOS bootloader (UEFI application). EDK II loads GRUB2 from a CD, GRUB2 loads the HelenOS bootloader (via UEFI) which loads OS components.
  • UEFI applications use the PE/COFF format and must be relocatable. The first problem is solved by manually having the PE/COFF headers and tables written in assembler. The relocatable requirement is addressed by compiling the code with -fpic and having the bootloader relocate itself at its startup.

Kernel:

  • Kernel code for AArch64 consists mostly of stubbing out various architecture-specific hooks: virtual memory management, interrupt and exception handling, context switching (including FPU lazy switching), support for virtual timer, atomic sequences and barriers, cache and TLB maintenance, thread and process initialization.
  • The patch adds a kernel driver for GICv2 (interrupt controller).
  • The PL011 kernel driver is extended to allow userspace to take ownership of the console.
  • The current code is not able to dynamically obtain information about available devices on the underlying machine. The port instead implements a machine-func interface similar to the one implemented by arm32. It defines a machine for the QEMU AArch64 virt platform. The configuration (device addresses and IRQ numbers) is then baked into the machine definition.

User space:

  • Uspace code for AArch64 similarly mostly implements architecture-specific hooks: context saving/restoring, syscall support, TLS support.

The patchset allows to boot the system but user interaction with the OS
is not yet possible.

  • Property mode set to 100644
File size: 11.4 KB
Line 
1/*
2 * Copyright (c) 2015 Petr Pavlu
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_arm64
30 * @{
31 */
32/** @file
33 * @brief Exception handlers and exception initialization routines.
34 */
35
36#include <arch/asm.h>
37#include <arch/exception.h>
38#include <arch/machine_func.h>
39#include <arch/regutils.h>
40#include <interrupt.h>
41#include <mm/as.h>
42#include <stdio.h>
43#include <syscall/syscall.h>
44
45static void current_el_sp_sel0_synch_exception(unsigned int exc_no,
46 istate_t *istate)
47{
48 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
49 "SP_SEL0, Synch, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
50 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
51}
52
53static void current_el_sp_sel0_irq_exception(unsigned int exc_no,
54 istate_t *istate)
55{
56 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
57 "SP_SEL0, IRQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
58 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
59}
60
61static void current_el_sp_sel0_fiq_exception(unsigned int exc_no,
62 istate_t *istate)
63{
64 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
65 "SP_SEL0, FIQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
66 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
67}
68
69static void current_el_sp_sel0_serror_exception(unsigned int exc_no,
70 istate_t *istate)
71{
72 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
73 "SP_SEL0, SError, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64
74 ".", (uint32_t) ESR_EL1_read(), FAR_EL1_read());
75}
76
77static void current_el_sp_selx_synch_exception(unsigned int exc_no,
78 istate_t *istate)
79{
80 uint64_t esr_el1 = ESR_EL1_read();
81 uint64_t far_el1 = FAR_EL1_read();
82 pf_access_t access;
83
84 switch ((esr_el1 & ESR_EC_MASK) >> ESR_EC_SHIFT) {
85 case ESR_EC_DA_CURRENT_EL:
86 /* Data abort. */
87 switch ((esr_el1 & ESR_IDFSC_MASK) >> ESR_IDFSC_SHIFT) {
88 case ESR_IDA_IDFSC_TF0:
89 case ESR_IDA_IDFSC_TF1:
90 case ESR_IDA_IDFSC_TF2:
91 case ESR_IDA_IDFSC_TF3:
92 /* Translation fault. */
93 access = (esr_el1 & ESR_DA_WNR_FLAG) ? PF_ACCESS_WRITE :
94 PF_ACCESS_READ;
95 as_page_fault(far_el1, access, istate);
96 return;
97 }
98 }
99
100 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
101 "SP_SELx, Synch, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
102 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
103}
104
105static void current_el_sp_selx_irq_exception(unsigned int exc_no,
106 istate_t *istate)
107{
108 machine_irq_exception(exc_no, istate);
109}
110
111static void current_el_sp_selx_fiq_exception(unsigned int exc_no,
112 istate_t *istate)
113{
114 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
115 "SP_SELx, FIQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
116 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
117}
118
119static void current_el_sp_selx_serror_exception(unsigned int exc_no,
120 istate_t *istate)
121{
122 panic_badtrap(istate, exc_no, "Unhandled exception from Current EL, "
123 "SP_SELx, SError, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64
124 ".", (uint32_t) ESR_EL1_read(), FAR_EL1_read());
125}
126
127static void lower_el_aarch64_synch_exception(unsigned int exc_no,
128 istate_t *istate)
129{
130 uint64_t esr_el1 = ESR_EL1_read();
131 uint64_t far_el1 = FAR_EL1_read();
132 pf_access_t access;
133 bool exec = false;
134
135 switch ((esr_el1 & ESR_EC_MASK) >> ESR_EC_SHIFT) {
136 case ESR_EC_FP:
137 /* Access to Advanced SIMD or floating-point functionality. */
138#ifdef CONFIG_FPU_LAZY
139 scheduler_fpu_lazy_request();
140#else
141 fault_from_uspace(istate, "AdvSIMD/FP fault.");
142#endif
143 return;
144 case ESR_EC_SVC:
145 /* SVC instruction. */
146 interrupts_enable();
147 istate->x0 = syscall_handler(istate->x0, istate->x1, istate->x2,
148 istate->x3, istate->x4, istate->x5, istate->x6);
149 interrupts_disable();
150 return;
151 case ESR_EC_IA_LOWER_EL:
152 /* Instruction abort. */
153 exec = true;
154 /* Fallthrough */
155 case ESR_EC_DA_LOWER_EL:
156 /* Data abort. */
157 switch ((esr_el1 & ESR_IDFSC_MASK) >> ESR_IDFSC_SHIFT) {
158 case ESR_IDA_IDFSC_TF0:
159 case ESR_IDA_IDFSC_TF1:
160 case ESR_IDA_IDFSC_TF2:
161 case ESR_IDA_IDFSC_TF3:
162 /* Translation fault. */
163 if (exec)
164 access = PF_ACCESS_EXEC;
165 else
166 access = (esr_el1 & ESR_DA_WNR_FLAG) ?
167 PF_ACCESS_WRITE : PF_ACCESS_READ;
168 as_page_fault(far_el1, access, istate);
169 return;
170 }
171 }
172
173 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch64, "
174 "Synch, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
175 (uint32_t) esr_el1, far_el1);
176}
177
178static void lower_el_aarch64_irq_exception(unsigned int exc_no,
179 istate_t *istate)
180{
181 machine_irq_exception(exc_no, istate);
182}
183
184static void lower_el_aarch64_fiq_exception(unsigned int exc_no,
185 istate_t *istate)
186{
187 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch64, "
188 "FIQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
189 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
190}
191
192static void lower_el_aarch64_serror_exception(unsigned int exc_no,
193 istate_t *istate)
194{
195 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch64, "
196 "SError, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
197 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
198}
199
200static void lower_el_aarch32_synch_exception(unsigned int exc_no,
201 istate_t *istate)
202{
203 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch32, "
204 "Synch, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
205 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
206}
207
208static void lower_el_aarch32_irq_exception(unsigned int exc_no,
209 istate_t *istate)
210{
211 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch32, "
212 "IRQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
213 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
214}
215
216static void lower_el_aarch32_fiq_exception(unsigned int exc_no,
217 istate_t *istate)
218{
219 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch32, "
220 "FIQ, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
221 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
222}
223
224static void lower_el_aarch32_serror_exception(unsigned int exc_no,
225 istate_t *istate)
226{
227 fault_from_uspace(istate, "Unhandled exception from Lower EL, AArch32, "
228 "SError, ESR_EL1=%0#10" PRIx32 ", FAR_EL1=%0#18" PRIx64 ".",
229 (uint32_t) ESR_EL1_read(), FAR_EL1_read());
230}
231
232/** Initializes exception handling.
233 *
234 * Installs low-level exception handlers and then registers exceptions and their
235 * handlers to kernel exception dispatcher.
236 */
237void exception_init(void)
238{
239 exc_register(EXC_CURRENT_EL_SP_SEL0_SYNCH,
240 "current EL, SP_SEL0, Synchronous", true,
241 (iroutine_t) current_el_sp_sel0_synch_exception);
242 exc_register(EXC_CURRENT_EL_SP_SEL0_IRQ,
243 "current EL, SP_SEL0, IRQ", true,
244 (iroutine_t) current_el_sp_sel0_irq_exception);
245 exc_register(EXC_CURRENT_EL_SP_SEL0_FIQ,
246 "current EL, SP_SEL0, FIQ", true,
247 (iroutine_t) current_el_sp_sel0_fiq_exception);
248 exc_register(EXC_CURRENT_EL_SP_SEL0_SERROR,
249 "current EL, SP_SEL0, SError", true,
250 (iroutine_t) current_el_sp_sel0_serror_exception);
251 exc_register(EXC_CURRENT_EL_SP_SELX_SYNCH,
252 "current EL, SP_SELx, Synchronous", true,
253 (iroutine_t) current_el_sp_selx_synch_exception);
254 exc_register(EXC_CURRENT_EL_SP_SELX_IRQ,
255 "current EL, SP_SELx, IRQ", true,
256 (iroutine_t) current_el_sp_selx_irq_exception);
257 exc_register(EXC_CURRENT_EL_SP_SELX_FIQ,
258 "current EL, SP_SELx, FIQ", true,
259 (iroutine_t) current_el_sp_selx_fiq_exception);
260 exc_register(EXC_CURRENT_EL_SP_SELX_SERROR,
261 "current EL, SP_SELx, SError", true,
262 (iroutine_t) current_el_sp_selx_serror_exception);
263 exc_register(EXC_LOWER_EL_AARCH64_SYNCH,
264 "lower EL, AArch64, Synchronous", true,
265 (iroutine_t) lower_el_aarch64_synch_exception);
266 exc_register(EXC_LOWER_EL_AARCH64_IRQ,
267 "lower EL, AArch64, IRQ", true,
268 (iroutine_t) lower_el_aarch64_irq_exception);
269 exc_register(EXC_LOWER_EL_AARCH64_FIQ,
270 "lower EL, AArch64, FIQ", true,
271 (iroutine_t) lower_el_aarch64_fiq_exception);
272 exc_register(EXC_LOWER_EL_AARCH64_SERROR,
273 "lower EL, AArch64, SError", true,
274 (iroutine_t) lower_el_aarch64_serror_exception);
275 exc_register(EXC_LOWER_EL_AARCH32_SYNCH,
276 "lower EL, AArch32, Synchronous", true,
277 (iroutine_t) lower_el_aarch32_synch_exception);
278 exc_register(EXC_LOWER_EL_AARCH32_IRQ,
279 "lower EL, AArch32, IRQ", true,
280 (iroutine_t) lower_el_aarch32_irq_exception);
281 exc_register(EXC_LOWER_EL_AARCH32_FIQ,
282 "lower EL, AArch32, FIQ", true,
283 (iroutine_t) lower_el_aarch32_fiq_exception);
284 exc_register(EXC_LOWER_EL_AARCH32_SERROR,
285 "lower EL, AArch32, SError", true,
286 (iroutine_t) lower_el_aarch32_serror_exception);
287
288 VBAR_EL1_write(((uint64_t) &exc_vector));
289}
290
291/** Print #istate_t structure content.
292 *
293 * @param istate Structure to be printed.
294 */
295void istate_decode(istate_t *istate)
296{
297 printf("x0 =%0#18" PRIx64 "\tx1 =%0#18" PRIx64 "\t"
298 "x2 =%0#18" PRIx64 "\n", istate->x0, istate->x1, istate->x2);
299 printf("x3 =%0#18" PRIx64 "\tx4 =%0#18" PRIx64 "\t"
300 "x5 =%0#18" PRIx64 "\n", istate->x3, istate->x4, istate->x5);
301 printf("x6 =%0#18" PRIx64 "\tx7 =%0#18" PRIx64 "\t"
302 "x8 =%0#18" PRIx64 "\n", istate->x6, istate->x7, istate->x8);
303 printf("x9 =%0#18" PRIx64 "\tx10=%0#18" PRIx64 "\t"
304 "x11=%0#18" PRIx64 "\n", istate->x9, istate->x10, istate->x11);
305 printf("x12=%0#18" PRIx64 "\tx13=%0#18" PRIx64 "\t"
306 "x14=%0#18" PRIx64 "\n", istate->x12, istate->x13, istate->x14);
307 printf("x15=%0#18" PRIx64 "\tx16=%0#18" PRIx64 "\t"
308 "x17=%0#18" PRIx64 "\n", istate->x15, istate->x16, istate->x17);
309 printf("x18=%0#18" PRIx64 "\tx19=%0#18" PRIx64 "\t"
310 "x20=%0#18" PRIx64 "\n", istate->x18, istate->x19, istate->x20);
311 printf("x21=%0#18" PRIx64 "\tx22=%0#18" PRIx64 "\t"
312 "x23=%0#18" PRIx64 "\n", istate->x21, istate->x22, istate->x23);
313 printf("x24=%0#18" PRIx64 "\tx25=%0#18" PRIx64 "\t"
314 "x26=%0#18" PRIx64 "\n", istate->x24, istate->x25, istate->x26);
315 printf("x27=%0#18" PRIx64 "\tx28=%0#18" PRIx64 "\t"
316 "x29=%0#18" PRIx64 "\n", istate->x27, istate->x28, istate->x29);
317 printf("x30=%0#18" PRIx64 "\tsp =%0#18" PRIx64 "\t"
318 "pc =%0#18" PRIx64 "\n", istate->x30, istate->sp, istate->pc);
319 printf("spsr=%0#18" PRIx64 "\ttpidr=%0#18" PRIx64 "\n", istate->spsr,
320 istate->tpidr);
321}
322
323/** @}
324 */
Note: See TracBrowser for help on using the repository browser.