summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/mpc5xx/vectors/vectors.S
blob: 35d2f23a30721ccb52e08fb865d70a78f924705e (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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/*
 * vectors.S
 *
 *  This file contains the assembly code for the PowerPC exception veneers
 *  for RTEMS.
 *
 *
 *  MPC5xx port sponsored by Defence Research and Development Canada - Suffield
 *  Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
 *
 *  Derived from libbsp/powerpc/mbx8xx/vectors/vectors.S,
 *
 *  (c) 1999, Eric Valette valette@crf.canon.fr
 */

#include <rtems/asm.h>
#include <rtems/score/cpu.h>
#include <libcpu/vectors.h>

#define SYNC \
	sync; \
	isync


/*
 * Hardware exception vector table.
 *
 * The MPC555 can be configured to use a compressed vector table with 8
 * bytes per entry, rather than the usual 0x100 bytes of other PowerPC
 * devices.  The following macro uses this feature to save the better part
 * of 8 kbytes of flash ROM.
 *
 * Each vector table entry has room for only a simple branch instruction
 * which branches to a prologue specific to that exception.  This
 * exception-specific prologue begins the context save, loads the exception
 * number into a register, and jumps to a common exception prologue, below.
 */

	.macro	vectors	num=0, total=NUM_EXCEPTIONS  /* create vector table */

/* vector table entry */
	.section .vectors, "ax"

	ba	specific_prologue\@		/* run specific prologue */
	.long	0				/* each entry is 8 bytes */

/* exception-specific prologue */
	.text

specific_prologue\@:
	stwu    r1, -EXCEPTION_FRAME_END(r1)	/* open stack frame */
	stw	r4, GPR4_OFFSET(r1)		/* preserve register */
	li	r4, \num			/* get exception number */
	b	common_prologue			/* run common prologue */

/* invoke macro recursively to create remainder of table */
	.if	\total - (\num + 1)
	vectors	"(\num + 1)", \total
	.endif

	.endm


/* invoke macro to create entire vector table */
	vectors


/*
 * Common exception prologue.
 *
 * Because the MPC555 vector table is in flash ROM, it's not possible to
 * change the exception handlers by overwriting them at run-time, so this
 * common exception prologue uses a table of exception handler pointers to
 * provide equivalent flexibility.
 *
 * When the actual exception handler is run, R1 points to the base of a new
 * exception stack frame, in which R3, R4 and LR have been saved.  R4 holds
 * the exception number.
 */
	.text

common_prologue:
	stw	r3, GPR3_OFFSET(r1)		/* preserve registers */
	mflr	r3
	stw	r3, EXC_LR_OFFSET(r1)

	slwi	r3, r4, 2				/* make table offset */
	addis	r3, r3, exception_handler_table@ha	/* point to entry */
	addi	r3, r3, exception_handler_table@l
	lwz	r3, 0(r3)				/* get entry */
	mtlr	r3					/* run it */
	blr


/*
 * Default exception handler.
 *
 * The function initialize_exceptions() initializes all of the entries in
 * the exception handler table with pointers to this routine, which saves
 * the remainder of the interrupted code's state, then calls
 * C_default_exception_handler() to dump registers.
 *
 * On entry, R1 points to a new exception stack frame in which R3, R4, and
 * LR have been saved.  R4 holds the exception number.
 */
	.text

PUBLIC_VAR(default_exception_handler)
SYM (default_exception_handler):
	/*
	 * Save the interrupted code's program counter and MSR.  Beyond this
	 * point, all exceptions are recoverable.  Use an RCPU-specific SPR
	 * to set the RI bit in the MSR to indicate the recoverable state.
	 */
	mfsrr0  r3
	stw	r3, SRR0_FRAME_OFFSET(r1)
	mfsrr1  r3
	stw	r3, SRR1_FRAME_OFFSET(r1)

	mtspr	eid, r3			/* set MSR[RI], clear MSR[EE] */
	SYNC

	/*
	 * Save the remainder of the general-purpose registers.
	 *
	 * Compute the value of R1 at exception entry before storing it in
	 * the frame.
	 *
	 * Note that R2 should never change (it's the EABI pointer to
	 * .sdata2), but we save it just in case.
	 *
	 * Recall that R3 and R4 were saved by the specific- and
	 * common-exception handlers before entry to this routine.
	 */
	stw	r0, GPR0_OFFSET(r1)
        addi    r0, r1, EXCEPTION_FRAME_END
        stw     r0, GPR1_OFFSET(r1)
	stw	r2, GPR2_OFFSET(r1)
	stmw	r5, GPR5_OFFSET(r1)		/* save R5 to R31 */

	/*
	 * Save the remainder of the UISA special-purpose registers.  Recall
	 * that LR was saved before entry.
	 */
	mfcr	r0
	stw	r0,  EXC_CR_OFFSET(r1)
	mfctr	r0
	stw	r0,  EXC_CTR_OFFSET(r1)
	mfxer	r0
	stw	r0,  EXC_XER_OFFSET(r1)

	/*
	 * Call C-language portion of the default exception handler, passing
	 * in the address of the frame.
	 *
	 * To simplify things a bit, we assume that the target routine is
	 * within +/- 32 Mbyte from here, which is a reasonable assumption
	 * on the MPC555.
	 */
	stw	r4, EXCEPTION_NUMBER_OFFSET(r1)	/* save exception number */
	addi	r3, r1, 0x8			/* get frame address */
	bl	C_default_exception_handler	/* call handler */

	/*
	 * Restore UISA special-purpose registers.
	 */
	lwz	r0,  EXC_XER_OFFSET(r1)
	mtxer	r0
	lwz	r0,  EXC_CTR_OFFSET(r1)
	mtctr	r0
	lwz	r0,  EXC_CR_OFFSET(r1)
	mtcr	r0
	lwz	r0,  EXC_LR_OFFSET(r1)
	mtlr	r0

	/*
	 * Restore most general-purpose registers.
	 */
	lmw	r2, GPR2_OFFSET(r1)

	/*
	 * Restore the interrupted code's program counter and MSR, but first
	 * use an RCPU-specific special-purpose register to clear the RI
	 * bit, indicating that exceptions are temporarily non-recoverable.
	 */
	mtspr	nri, r0			/* clear MSR[RI] */
	SYNC

	lwz	r0, SRR1_FRAME_OFFSET(r1)
	mtsrr1	r0
	lwz	r0, SRR0_FRAME_OFFSET(r1)
	mtsrr0	r0

	/*
	 * Restore the final GPR, close the stack frame, and return to the
	 * interrupted code.
	 */
	lwz	r0, GPR0_OFFSET(r1)
	addi 	r1, r1, EXCEPTION_FRAME_END
	SYNC
	rfi