headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / arch / ppc / arch_exceptions.S
blob85e532dd1e4f3f73d24db4fc59f2a52ecd9854e9
1 /*
2  * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  *
5  * Copyright 2003, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 #include <asm_defs.h>
10 /*      General exception handling concept:
12         The PPC architecture specifies entry point offsets for the various
13         exceptions in the first two physical pages. We put a short piece of code
14         (VEC_ENTRY()) into each exception vector. It calls exception_vector_common,
15         which is defined in the unused space at the beginning of the first physical
16         page. It re-enables address translation and calls ppc_exception_tail which
17         lies in the kernel. It dumps an iframe and invokes ppc_exception_entry()
18         (arch_int.cpp), which handles the exception and returns eventually.
19         The registers are restored from the iframe and we return from the
20         interrupt.
22         algorithm overview:
24         * VEC_ENTRY
25         * exception_vector_common
26         * ppc_exception_tail
27                 - dump iframe
28                 - ppc_exception_entry()
29                 - restore registers and return from interrupt
31         Here we use the following SPRG registers, which are at the disposal of the
32         operating system:
33         * SPRG0: Physical address pointer to a struct cpu_exception_context
34                          for the current CPU. The structure contains helpful pointers
35                          as well as some scratch memory for temporarily saving registers.
36         * SPRG1: Scratch.
38         struct cpu_exception_context (defined in arch_int.h):
39         offset 0:  virtual address of the exception handler routine in the kernel
40         offset 4:  virtual address of the exception context
41         offset 8:  kernel stack for the current thread
42         offset 12: start of scratch memory for saving registers etc.
44         algorithm in detail:
46         * VEC_ENTRY
47                 - save r1 in SPRG1 and load cpu_exception_context into r1
48                 - save r0, save LR in r0
49         * exception_vector_common
50                 - params:
51                         . r0: old LR
52                         . r1: exception context (physical address)
53                         . SPRG1: original r1
54                 - save r0-3
55                 - load virtual exception context address to r1
56                 - turn on BAT for exception vector code
57                 - turn on address translation
58                 - get exception vector offset from LR
59         * ppc_exception_tail
60                 - params:
61                         . r1: exception context (virtual address)
62                         . r3: exception vector offset
63                         . SPRG1: original r1
64                 - turn off BAT
65                 - get kernel stack pointer
66                 - dump iframe
67                 - ppc_exception_entry()
68                 - restore registers and return from interrupt
69  */
72 /* exception vector definitions */
74 /* code in each exception vector */
75 #define VEC_ENTRY() \
76         mtsprg1 %r1                                     ; /* temporarily save r1 in SPRG1 */            \
77         mfsprg0 %r1                                     ; /* ppc_cpu_exception_context* -> r1 */        \
78         stw             %r0, 16(%r1)            ; /* save r0 */                                                         \
79         mflr    %r0                                     ; /* save LR in r0 */                                           \
80         bl              exception_vector_common ; /* continue with the common part */
82 /* defines an exception vector */
83 #define DEFINE_VECTOR(offset, name)     \
84 .skip   offset - (. - __irqvec_start);  \
85 FUNCTION(name):                                                 \
86         VEC_ENTRY()
89 .global __irqvec_start
90 __irqvec_start:
91         .long   0
93 /* Called by the exception vector code.
94  * LR:    Points to the end of the exception vector code we're coming from.
95  * r0:    original LR
96  * r1:    ppc_cpu_exception_context* (physical address)
97  * SPRG1: original r1
98  */
99 exception_vector_common:
100         stw             %r0, 20(%r1)                    /* save original LR */
101         stw             %r2, 24(%r1)                    /* save r2 */
102         stw             %r3, 28(%r1)                    /* save r3 */
104         /* load the virtual address of the ppc_cpu_exception_context for this CPU */
105         lwz             %r1, 4(%r1)
107         /* Address translation is turned off. We map this code via BAT, turn on
108            address translation, and continue in the kernel proper. */
109         li              %r0, 0x10|0x2                   /* BATL_MC | BATL_PP_RW */
110         mtibatl 0, %r0                                  /* load lower word of the instruction BAT */
111         li              %r0, 0x2                                /* BEPI = 0, BL = 0 (128 KB), BATU_VS */
112         mtibatu 0, %r0                                  /* load upper word of the instruction BAT */
113         isync
114         sync
116         /* turn on address translation */
117         mfsrr1  %r0                                             /* load saved msr */
118         rlwinm  %r0, %r0, 28, 30, 31    /* extract mmu bits */
119         mfmsr   %r3                                             /* load the current msr */
120         rlwimi  %r3, %r0, 4, 26, 27             /* merge the mmu bits with the current msr */
121         li              %r0, 1
122         rlwimi  %r3, %r0, 13, 18, 18    /* turn on FPU, too */
123         mtmsr   %r3                                             /* load new msr (turning the mmu back on) */
124         isync
126         /* Get LR -- it points to the end of the exception vector code. We adjust it
127            to point to the beginning and can use it to identify the vector later. */
128         mflr    %r3
129         subi    %r3, %r3, 20            /* 5 instructions */
131         /* jump to kernel code (ppc_exception_tail) */
132         lwz             %r2, 0(%r1)
133         mtlr    %r2
134         blr
137 DEFINE_VECTOR(0x100, system_reset_exception)
138 DEFINE_VECTOR(0x200, machine_check_exception)
139 DEFINE_VECTOR(0x300, DSI_exception)
140 DEFINE_VECTOR(0x400, ISI_exception)
141 DEFINE_VECTOR(0x500, external_interrupt_exception)
142 DEFINE_VECTOR(0x600, alignment_exception)
143 DEFINE_VECTOR(0x700, program_exception)
144 DEFINE_VECTOR(0x800, FP_unavailable_exception)
145 DEFINE_VECTOR(0x900, decrementer_exception)
146 DEFINE_VECTOR(0xc00, system_call_exception)
147 DEFINE_VECTOR(0xd00, trace_exception)
148 DEFINE_VECTOR(0xe00, FP_assist_exception)
149 DEFINE_VECTOR(0xf00, perf_monitor_exception)
150 DEFINE_VECTOR(0xf20, altivec_unavailable_exception)
151 DEFINE_VECTOR(0x1000, ITLB_miss_exception)
152 DEFINE_VECTOR(0x1100, DTLB_miss_on_load_exception)
153 DEFINE_VECTOR(0x1200, DTLB_miss_on_store_exception)
154 DEFINE_VECTOR(0x1300, instruction_address_breakpoint_exception)
155 DEFINE_VECTOR(0x1400, system_management_exception)
156 DEFINE_VECTOR(0x1600, altivec_assist_exception)
157 DEFINE_VECTOR(0x1700, thermal_management_exception)
159 .global __irqvec_end
160 __irqvec_end:
163 /* This is where exception_vector_common continues. We're in the kernel here.
164    r1:    ppc_cpu_exception_context* (virtual address)
165    r3:    exception vector offset
166    SPRG1: original r1
167  */
168 FUNCTION(ppc_exception_tail):
169         /* turn off BAT */
170         li              %r2, 0
171         mtibatu 0, %r2
172         mtibatl 0, %r2
173         isync
174         sync
176         /* save CR */
177         mfcr    %r0
179         mfsrr1  %r2                                     /* load saved msr */
180         andi.   %r2, %r2, (1 << 14)     /* see if it was in kernel mode */
181         beq             .kernel                         /* yep */
183         /* We come from userland. Load the kernel stack top address for the current
184            userland thread. */
185         mr              %r2, %r1
186         lwz             %r1, 8(%r1)
187         b               .restore_stack_end
189 .kernel:
190         mr              %r2, %r1
191         mfsprg1 %r1
193 .restore_stack_end:
194         /* now r2 points to the ppc_cpu_exception_context, r1 to the kernel stack */
195         /* restore the CR, it was messed up in the previous compare */
196         mtcrf   0xff, %r0
198         /* align r1 to 8 bytes, so the iframe will be aligned too */
199         rlwinm  %r1, %r1, 0, 0, 28
201         /* save the registers */
202         bl              __save_regs
204         /* iframe pointer to r4 and a backup to r20 */
205         mr              %r4, %r1
206         mr              %r20, %r1
208         /* adjust the stack pointer for ABI compatibility */
209         subi    %r1, %r1, 8                             /* make sure there's space for the previous
210                                                                            frame pointer and the return address */
211         rlwinm  %r1, %r1, 0, 0, 27              /* 16 byte align the stack pointer */
212         li              %r0, 0
213         stw             %r0, 0(%r1)                             /* previous frame pointer: NULL */
214                 /* 4(%r1) is room for the return address to be filled in by the
215                    called function. */
217         /* r3: exception vector offset
218            r4: iframe pointer */
219         bl              ppc_exception_entry
221         /* move the iframe to r1 */
222         mr              %r1, %r20
224         b               __restore_regs_and_rfi
227 /* called by ppc_exception_tail
228  * register expectations:
229  *  r1:        stack
230  *  r2:        ppc_cpu_exception_context*
231  *  SPRG1:     original r1
232  *  r0,r3, LR: scrambled, but saved in scratch memory
233  * all other regs should have been unmodified by the exception handler,
234  * and ready to be saved
235  */
236 __save_regs:
237         /* Note: The iframe must be 8 byte aligned. The stack pointer we are passed
238            in r1 is aligned. So we store the floating point registers first and
239            need to take care that an even number of 4 byte registers is stored,
240            or insert padding respectively. */
242         /* push f0-f31 */
243         stfdu   %f0, -8(%r1)
244         stfdu   %f1, -8(%r1)
245         stfdu   %f2, -8(%r1)
246         stfdu   %f3, -8(%r1)
247         stfdu   %f4, -8(%r1)
248         stfdu   %f5, -8(%r1)
249         stfdu   %f6, -8(%r1)
250         stfdu   %f7, -8(%r1)
251         stfdu   %f8, -8(%r1)
252         stfdu   %f9, -8(%r1)
253         stfdu   %f10, -8(%r1)
254         stfdu   %f11, -8(%r1)
255         stfdu   %f12, -8(%r1)
256         stfdu   %f13, -8(%r1)
257         stfdu   %f14, -8(%r1)
258         stfdu   %f15, -8(%r1)
259         stfdu   %f16, -8(%r1)
260         stfdu   %f17, -8(%r1)
261         stfdu   %f18, -8(%r1)
262         stfdu   %f19, -8(%r1)
263         stfdu   %f20, -8(%r1)
264         stfdu   %f21, -8(%r1)
265         stfdu   %f22, -8(%r1)
266         stfdu   %f23, -8(%r1)
267         stfdu   %f24, -8(%r1)
268         stfdu   %f25, -8(%r1)
269         stfdu   %f26, -8(%r1)
270         stfdu   %f27, -8(%r1)
271         stfdu   %f28, -8(%r1)
272         stfdu   %f29, -8(%r1)
273         stfdu   %f30, -8(%r1)
274         stfdu   %f31, -8(%r1)
276         /* push r0-r3 */
277         lwz             %r0, 16(%r2)            /* original r0 */
278         stwu    %r0, -4(%r1)            /* push r0 */
279         mfsprg1 %r0                                     /* original r1 */
280         stwu    %r0, -4(%r1)            /* push r1 */
281         lwz             %r0, 24(%r2)            /* original r2 */
282         stwu    %r0, -4(%r1)            /* push r2 */
283         lwz             %r0, 28(%r2)            /* original r3 */
284         stwu    %r0, -4(%r1)            /* push r3 */
286         /* push r4-r31 */
287         stwu    %r4, -4(%r1)            
288         stwu    %r5, -4(%r1)
289         stwu    %r6, -4(%r1)
290         stwu    %r7, -4(%r1)
291         stwu    %r8, -4(%r1)
292         stwu    %r9, -4(%r1)
293         stwu    %r10, -4(%r1)
294         stwu    %r11, -4(%r1)
295         stwu    %r12, -4(%r1)
296         stwu    %r13, -4(%r1)
297         stwu    %r14, -4(%r1)
298         stwu    %r15, -4(%r1)
299         stwu    %r16, -4(%r1)
300         stwu    %r17, -4(%r1)
301         stwu    %r18, -4(%r1)
302         stwu    %r19, -4(%r1)
303         stwu    %r20, -4(%r1)
304         stwu    %r21, -4(%r1)
305         stwu    %r22, -4(%r1)
306         stwu    %r23, -4(%r1)
307         stwu    %r24, -4(%r1)
308         stwu    %r25, -4(%r1)
309         stwu    %r26, -4(%r1)
310         stwu    %r27, -4(%r1)
311         stwu    %r28, -4(%r1)
312         stwu    %r29, -4(%r1)
313         stwu    %r30, -4(%r1)
314         stwu    %r31, -4(%r1)
316         /* save some of the other regs */
317         mffs    %f0
318         stfsu   %f0, -4(%r1)            /* push FPSCR */
319         mfctr   %r0
320         stwu    %r0, -4(%r1)            /* push CTR */
321         mfxer   %r0
322         stwu    %r0, -4(%r1)            /* push XER */
323         mfcr    %r0
324         stwu    %r0, -4(%r1)            /* push CR */
325         lwz             %r0, 20(%r2)            /* original LR */
326         stwu    %r0, -4(%r1)            /* push LR */
327         mfspr   %r0, %dsisr
328         stwu    %r0, -4(%r1)            /* push DSISR */
329         mfspr   %r0, %dar
330         stwu    %r0, -4(%r1)            /* push DAR */
331         mfspr   %r0, %srr1
332         stwu    %r0, -4(%r1)            /* push SRR1 */
333         mfspr   %r0, %srr0
334         stwu    %r0, -4(%r1)            /* push SRR0 */
336         stwu    %r3, -4(%r1)            /* exception vector offset */
338         blr
341 /* called at the tail end of each of the exceptions
342  * r1: iframe pointer
343  */
344 __restore_regs_and_rfi:
345         lwzu    %r0, 4(%r1)             /* SRR0 (skip vector offset) */
346         mtspr   %srr0, %r0
347         lwzu    %r0, 4(%r1)             /* SRR1 */
348         mtspr   %srr1, %r0
349         lwzu    %r0, 4(%r1)             /* DAR */
350         mtspr   %dar, %r0
351         lwzu    %r0, 4(%r1)             /* DSISR */
352         mtspr   %dsisr, %r0
353         lwzu    %r0, 4(%r1)             /* LR */
354         mtlr    %r0
355         lwzu    %r0, 4(%r1)             /* CR */
356         mtcr    %r0
357         lwzu    %r0, 4(%r1)             /* XER */
358         mtxer   %r0
359         lwzu    %r0, 4(%r1)             /* CTR */
360         mtctr   %r0
361         lfsu    %f0, 4(%r1)             /* FPSCR */
362         mtfsf   0xff, %f0
364         lwzu    %r31, 4(%r1)
365         lwzu    %r30, 4(%r1)
366         lwzu    %r29, 4(%r1)
367         lwzu    %r28, 4(%r1)
368         lwzu    %r27, 4(%r1)
369         lwzu    %r26, 4(%r1)
370         lwzu    %r25, 4(%r1)
371         lwzu    %r24, 4(%r1)
372         lwzu    %r23, 4(%r1)
373         lwzu    %r22, 4(%r1)
374         lwzu    %r21, 4(%r1)
375         lwzu    %r20, 4(%r1)
376         lwzu    %r19, 4(%r1)
377         lwzu    %r18, 4(%r1)
378         lwzu    %r17, 4(%r1)
379         lwzu    %r16, 4(%r1)
380         lwzu    %r15, 4(%r1)
381         lwzu    %r14, 4(%r1)
382         lwzu    %r13, 4(%r1)
383         lwzu    %r12, 4(%r1)
384         lwzu    %r11, 4(%r1)
385         lwzu    %r10, 4(%r1)
386         lwzu    %r9, 4(%r1)
387         lwzu    %r8, 4(%r1)
388         lwzu    %r7, 4(%r1)
389         lwzu    %r6, 4(%r1)
390         lwzu    %r5, 4(%r1)
391         lwzu    %r4, 4(%r1)
392         lwzu    %r3, 4(%r1)
393         
394         /* Stop here, before we overwrite r1, and continue with the floating point
395            registers first. */
396         addi    %r2, %r1, 16            /* skip r3-r0 */
398         /* f31-f0 */
399         lfd             %f31, 0(%r2)
400         lfdu    %f30, 8(%r2)
401         lfdu    %f29, 8(%r2)
402         lfdu    %f28, 8(%r2)
403         lfdu    %f27, 8(%r2)
404         lfdu    %f26, 8(%r2)
405         lfdu    %f25, 8(%r2)
406         lfdu    %f24, 8(%r2)
407         lfdu    %f23, 8(%r2)
408         lfdu    %f22, 8(%r2)
409         lfdu    %f21, 8(%r2)
410         lfdu    %f20, 8(%r2)
411         lfdu    %f19, 8(%r2)
412         lfdu    %f18, 8(%r2)
413         lfdu    %f17, 8(%r2)
414         lfdu    %f16, 8(%r2)
415         lfdu    %f15, 8(%r2)
416         lfdu    %f14, 8(%r2)
417         lfdu    %f13, 8(%r2)
418         lfdu    %f12, 8(%r2)
419         lfdu    %f11, 8(%r2)
420         lfdu    %f10, 8(%r2)
421         lfdu    %f9, 8(%r2)
422         lfdu    %f8, 8(%r2)
423         lfdu    %f7, 8(%r2)
424         lfdu    %f6, 8(%r2)
425         lfdu    %f5, 8(%r2)
426         lfdu    %f4, 8(%r2)
427         lfdu    %f3, 8(%r2)
428         lfdu    %f2, 8(%r2)
429         lfdu    %f1, 8(%r2)
430         lfd             %f0, 8(%r2)
432         /* r2-r0 */
433         lwzu    %r2, 4(%r1)
434         lwz             %r0, 8(%r1)
435         lwz             %r1, 4(%r1)
437         /* return from interrupt */
438         rfi