summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/shared/exceptions/ppc_exc.S
blob: 9ffb2ccca748efa1086b2a68900dcff610047ed9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 * (c) 1999, Eric Valette valette@crf.canon.fr
 *
 * Modified and partially rewritten by Till Straumann, 2007
 *
 * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>, 2008.
 *
 * Low-level assembly code for PPC exceptions.
 *
 * This file was written with the goal to eliminate
 * ALL #ifdef <cpu_flavor> conditionals -- please do not
 * reintroduce such statements.
 */

/* Load macro definitions */
#include <rtems/asm.h>
#include <rtems/score/percpu.h>

/*
 * This code uses the small-data area which is not available in the 64-bit
 * PowerPC ELFv2 ABI.
 */
#ifndef __powerpc64__

#include "ppc_exc_asm_macros.h"

/******************************************************/
/*  PROLOGUES                                         */
/******************************************************/

	/*
	 * Expand prologue snippets for classic, ppc405-critical, bookE-critical
	 * and E500 machine-check, synchronous and asynchronous exceptions
	 */
	PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_std        _VEC=0 _PRI=std  _FLVR=std
	PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_p405_crit  _VEC=0 _PRI=crit _FLVR=p405_crit
	PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit
	PPC_EXC_MIN_PROLOG_SYNC _NAME=tmpl_e500_mchk  _VEC=0 _PRI=mchk _FLVR=e500_mchk

	PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_std        _VEC=0 _PRI=std  _FLVR=std
	PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_p405_crit  _VEC=0 _PRI=crit _FLVR=p405_crit
	PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit
	PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_e500_mchk  _VEC=0 _PRI=mchk _FLVR=e500_mchk

	.global ppc_exc_min_prolog_size
ppc_exc_min_prolog_size      = 4 * 4

/* Special prologue for 603e-style CPUs.
 *
 * 603e shadows GPR0..GPR3 for certain exceptions. We must switch
 * that off before we can use the stack pointer. Note that this is
 * ONLY safe if the shadowing is actually active -- otherwise, r1
 * is destroyed. We deliberately use r1 so problems become obvious
 * if this is misused!
 */
	.global ppc_exc_tgpr_clr_prolog
ppc_exc_tgpr_clr_prolog:
	mfmsr   r1
	rlwinm  r1,r1,0,15,13
	mtmsr   r1
	isync
	/* FALL THRU TO 'auto' PROLOG */

/* Determine vector dynamically/automatically
 *
 * BUT: - only standard exceptions (no critical ones)
 *      - vector offset must be on 256 Byte boundary.
 */
	.global ppc_exc_min_prolog_auto
ppc_exc_min_prolog_auto:
	stwu	r1, -EXCEPTION_FRAME_END(r1)
	stw	VECTOR_REGISTER, VECTOR_OFFSET(r1)
	mflr	VECTOR_REGISTER

	/*
	 * We store the absolute branch target address here.  It will be used
	 * to generate the branch operation in ppc_exc_make_prologue().
	 *
	 * We add one to request the link in the generated branch instruction.
	 */
	.int	ppc_exc_wrap_auto + 1

	.global ppc_exc_tgpr_clr_prolog_size
ppc_exc_tgpr_clr_prolog_size = . - ppc_exc_tgpr_clr_prolog

/*
 * Automatic vector, asynchronous exception; however,
 * automatic vector calculation is less efficient than
 * using an explicit vector in a minimal prolog snippet.
 * The latter method is preferable since there usually
 * are few asynchronous exceptions.
 *
 * For generic exceptions (which are the bulk) using
 * the 'auto' prologue is OK since performance is not
 * really an issue.
 */
	.global ppc_exc_min_prolog_auto_async
ppc_exc_min_prolog_auto_async:
	stw	r1, ppc_exc_lock_std@sdarel(r13)
	stw	VECTOR_REGISTER, ppc_exc_vector_register_std@sdarel(r13)
	mflr	VECTOR_REGISTER

	/*
	 * We store the absolute branch target address here.  It will be used
	 * to generate the branch operation in ppc_exc_make_prologue().
	 *
	 * We add one to request the link in the generated branch instruction.
	 */
	.int	ppc_exc_wrap_auto_async + 1

/******************************************************/
/*  WRAPPERS                                          */
/******************************************************/

	/* Tag start and end of the wrappers.
	 * If exceptions are installed farther removed
	 * from the text area than 32M then the wrappers
	 * must be moved to an area that is reachable
	 * from where the prologues reside. Branches into
	 * C-code are far.
	 */

	.global	__ppc_exc_wrappers_start
__ppc_exc_wrappers_start = .

	/* Expand wrappers for different exception flavors */

	/* Standard/classic powerpc */
	WRAP	_FLVR=std _PRI=std _SRR0=srr0 _SRR1=srr1 _RFI=rfi

	/* ppc405 has a critical exception using srr2/srr3 */
	WRAP	_FLVR=p405_crit _PRI=crit _SRR0=srr2 _SRR1=srr3 _RFI=rfci

	/* bookE has critical exception using csrr0 cssr1 */
	WRAP	_FLVR=bookE_crit _PRI=crit _SRR0=csrr0 _SRR1=csrr1 _RFI=rfci

	/* e500 has machine-check exception using mcsrr0 mcssr1 */
	WRAP	_FLVR=e500_mchk _PRI=mchk _SRR0=mcsrr0 _SRR1=mcsrr1 _RFI=rfmci

	/* LR holds vector, VECTOR_REGISTER holds orig. LR */
        .global ppc_exc_wrap_auto
ppc_exc_wrap_auto:
	stw	FRAME_REGISTER, FRAME_OFFSET(r1)

	/* Find address where we jumped from */
	mflr	FRAME_REGISTER

	/* Restore LR */
	mtlr	VECTOR_REGISTER

	/* Compute vector into R3 */
	rlwinm	VECTOR_REGISTER, FRAME_REGISTER, 24, 26, 31

	/*
	 * We're now in almost the same state as if called by
	 * min_prolog_std but we must skip saving FRAME_REGISTER
	 * since that's done already
	 */
	b	wrap_no_save_frame_register_std

        .global ppc_exc_wrap_auto_async
ppc_exc_wrap_auto_async:
	stwu	r1, -EXCEPTION_FRAME_END(r1)
	stw	FRAME_REGISTER, FRAME_OFFSET(r1)
	/* find address where we jumped from */
	mflr	FRAME_REGISTER
	/* restore LR     */
	mtlr	VECTOR_REGISTER
	/* set upper bits to indicate that non-volatile
	 * registers should not be saved/restored.
	 */
	li	VECTOR_REGISTER, 0xffff8000
	/* compute vector into R3 */
	rlwimi	VECTOR_REGISTER, FRAME_REGISTER, 24, 26, 31
	/* we're now in almost the same state as if called by
	 * min_prolog_std but we must skip saving FRAME_REGISTER
	 * since that's done already
	 */
	b	wrap_no_save_frame_register_std

	.global	__ppc_exc_wrappers_end
__ppc_exc_wrappers_end = .

#endif /* !__powerpc64__ */