2 * Copyright 2013, François Revol <revol@free.fr>.
3 * All rights reserved. Distributed under the terms of the MIT License.
5 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
6 * All rights reserved. Distributed under the terms of the MIT License.
8 * Copyright 2003, Travis Geiselbrecht. All rights reserved.
9 * Distributed under the terms of the NewOS License.
13 /* General exception handling concept:
15 The PPC architecture specifies entry point offsets for the various
16 exceptions in the first two physical pages. We put a short piece of code
17 (VEC_ENTRY()) into each exception vector. It calls exception_vector_common,
18 which is defined in the unused space at the beginning of the first physical
19 page. It re-enables address translation and calls ppc_exception_tail which
20 lies in the kernel. It dumps an iframe and invokes ppc_exception_entry()
21 (arch_int.cpp), which handles the exception and returns eventually.
22 The registers are restored from the iframe and we return from the
28 * ppc_440_exception_vector_common
29 * ppc_440_exception_tail
31 - ppc_exception_entry()
32 - restore registers and return from interrupt
34 Here we use the following SPRG registers, which are at the disposal of the
36 * SPRG0: Physical address pointer to a struct cpu_exception_context
37 for the current CPU. The structure contains helpful pointers
38 as well as some scratch memory for temporarily saving registers.
41 struct cpu_exception_context (defined in arch_int.h):
42 offset 0: virtual address of the exception handler routine in the kernel
43 offset 4: virtual address of the exception context
44 offset 8: kernel stack for the current thread
45 offset 12: start of scratch memory for saving registers etc.
50 - save r1 in SPRG1 and load cpu_exception_context into r1
51 - save r0, save LR in r0
52 * ppc_440_exception_vector_common
55 . r1: exception context (physical address)
58 - load virtual exception context address to r1
59 - turn on BAT for exception vector code
60 - turn on address translation
61 - get exception vector offset from LR
62 * ppc_440_exception_tail
64 . r1: exception context (virtual address)
65 . r3: exception vector offset
68 - get kernel stack pointer
70 - ppc_exception_entry()
71 - restore registers and return from interrupt
75 /* exception vector definitions */
77 /* code in each exception vector */
79 mtsprg1 %r1 ; /* temporarily save r1 in SPRG1 */ \
80 mfsprg0 %r1 ; /* ppc_cpu_exception_context* -> r1 */ \
81 stw %r0, 16(%r1) ; /* save r0 */ \
82 mflr %r0 ; /* save LR in r0 */ \
83 bl ppc_440_exception_vector_common ; /* continue with the common part */
85 /* defines an exception vector */
86 #define DEFINE_VECTOR(offset, name) \
87 .skip offset - (. - __440_irqvec_start); \
88 FUNCTION(ppc_440_##name): \
92 .global __440_irqvec_start
96 /* Called by the exception vector code.
97 * LR: Points to the end of the exception vector code we're coming from.
99 * r1: ppc_cpu_exception_context* (physical address)
102 ppc_440_exception_vector_common:
103 stw %r0, 20(%r1) /* save original LR */
104 stw %r2, 24(%r1) /* save r2 */
105 stw %r3, 28(%r1) /* save r3 */
107 /* load the virtual address of the ppc_cpu_exception_context for this CPU */
110 /* Address translation is turned off. We map this code via BAT, turn on
111 address translation, and continue in the kernel proper. */
112 li %r0, 0x10|0x2 /* BATL_MC | BATL_PP_RW */
113 mtibatl 0, %r0 /* load lower word of the instruction BAT */
114 li %r0, 0x2 /* BEPI = 0, BL = 0 (128 KB), BATU_VS */
115 mtibatu 0, %r0 /* load upper word of the instruction BAT */
119 /* turn on address translation */
120 mfsrr1 %r0 /* load saved msr */
121 rlwinm %r0, %r0, 28, 30, 31 /* extract mmu bits */
122 mfmsr %r3 /* load the current msr */
123 rlwimi %r3, %r0, 4, 26, 27 /* merge the mmu bits with the current msr */
125 rlwimi %r3, %r0, 13, 18, 18 /* turn on FPU, too */
126 mtmsr %r3 /* load new msr (turning the mmu back on) */
129 /* Get LR -- it points to the end of the exception vector code. We adjust it
130 to point to the beginning and can use it to identify the vector later. */
132 subi %r3, %r3, 20 /* 5 instructions */
134 /* jump to kernel code (ppc_exception_tail) */
140 DEFINE_VECTOR(0x100, system_reset_exception)
141 DEFINE_VECTOR(0x200, machine_check_exception)
142 DEFINE_VECTOR(0x300, DSI_exception)
143 DEFINE_VECTOR(0x400, ISI_exception)
144 DEFINE_VECTOR(0x500, external_interrupt_exception)
145 DEFINE_VECTOR(0x600, alignment_exception)
146 DEFINE_VECTOR(0x700, program_exception)
147 DEFINE_VECTOR(0x800, FP_unavailable_exception)
148 DEFINE_VECTOR(0x900, decrementer_exception)
149 DEFINE_VECTOR(0xc00, system_call_exception)
150 DEFINE_VECTOR(0xd00, trace_exception)
151 DEFINE_VECTOR(0xe00, FP_assist_exception)
152 DEFINE_VECTOR(0xf00, perf_monitor_exception)
153 DEFINE_VECTOR(0xf20, altivec_unavailable_exception)
154 DEFINE_VECTOR(0x1000, ITLB_miss_exception)
155 DEFINE_VECTOR(0x1100, DTLB_miss_on_load_exception)
156 DEFINE_VECTOR(0x1200, DTLB_miss_on_store_exception)
157 DEFINE_VECTOR(0x1300, instruction_address_breakpoint_exception)
158 DEFINE_VECTOR(0x1400, system_management_exception)
159 DEFINE_VECTOR(0x1600, altivec_assist_exception)
160 DEFINE_VECTOR(0x1700, thermal_management_exception)
162 .global __440_irqvec_end
166 /* This is where ppc_440_exception_vector_common continues. We're in the kernel here.
167 r1: ppc_cpu_exception_context* (virtual address)
168 r3: exception vector offset
171 FUNCTION(ppc_440_exception_tail):
182 mfsrr1 %r2 /* load saved msr */
183 andi. %r2, %r2, (1 << 14) /* see if it was in kernel mode */
184 beq .kernel /* yep */
186 /* We come from userland. Load the kernel stack top address for the current
197 /* now r2 points to the ppc_cpu_exception_context, r1 to the kernel stack */
198 /* restore the CR, it was messed up in the previous compare */
201 /* align r1 to 8 bytes, so the iframe will be aligned too */
202 rlwinm %r1, %r1, 0, 0, 28
204 /* save the registers */
207 /* iframe pointer to r4 and a backup to r20 */
211 /* adjust the stack pointer for ABI compatibility */
212 subi %r1, %r1, 8 /* make sure there's space for the previous
213 frame pointer and the return address */
214 rlwinm %r1, %r1, 0, 0, 27 /* 16 byte align the stack pointer */
216 stw %r0, 0(%r1) /* previous frame pointer: NULL */
217 /* 4(%r1) is room for the return address to be filled in by the
220 /* r3: exception vector offset
221 r4: iframe pointer */
222 bl ppc_exception_entry
224 /* move the iframe to r1 */
227 b __440_restore_regs_and_rfi
230 /* called by ppc_440_exception_tail
231 * register expectations:
233 * r2: ppc_cpu_exception_context*
235 * r0,r3, LR: scrambled, but saved in scratch memory
236 * all other regs should have been unmodified by the exception handler,
237 * and ready to be saved
240 /* Note: The iframe must be 8 byte aligned. The stack pointer we are passed
241 in r1 is aligned. So we store the floating point registers first and
242 need to take care that an even number of 4 byte registers is stored,
243 or insert padding respectively. */
280 lwz %r0, 16(%r2) /* original r0 */
281 stwu %r0, -4(%r1) /* push r0 */
282 mfsprg1 %r0 /* original r1 */
283 stwu %r0, -4(%r1) /* push r1 */
284 lwz %r0, 24(%r2) /* original r2 */
285 stwu %r0, -4(%r1) /* push r2 */
286 lwz %r0, 28(%r2) /* original r3 */
287 stwu %r0, -4(%r1) /* push r3 */
319 /* save some of the other regs */
321 stfsu %f0, -4(%r1) /* push FPSCR */
323 stwu %r0, -4(%r1) /* push CTR */
325 stwu %r0, -4(%r1) /* push XER */
327 stwu %r0, -4(%r1) /* push CR */
328 lwz %r0, 20(%r2) /* original LR */
329 stwu %r0, -4(%r1) /* push LR */
331 stwu %r0, -4(%r1) /* push DSISR */
333 stwu %r0, -4(%r1) /* push DAR */
335 stwu %r0, -4(%r1) /* push SRR1 */
337 stwu %r0, -4(%r1) /* push SRR0 */
339 stwu %r3, -4(%r1) /* exception vector offset */
344 /* called at the tail end of each of the exceptions
347 __440_restore_regs_and_rfi:
348 lwzu %r0, 4(%r1) /* SRR0 (skip vector offset) */
350 lwzu %r0, 4(%r1) /* SRR1 */
352 lwzu %r0, 4(%r1) /* DAR */
354 lwzu %r0, 4(%r1) /* DSISR */
356 lwzu %r0, 4(%r1) /* LR */
358 lwzu %r0, 4(%r1) /* CR */
360 lwzu %r0, 4(%r1) /* XER */
362 lwzu %r0, 4(%r1) /* CTR */
364 lfsu %f0, 4(%r1) /* FPSCR */
397 /* Stop here, before we overwrite r1, and continue with the floating point
399 addi %r2, %r1, 16 /* skip r3-r0 */
440 /* return from interrupt */