xref: /linux/arch/mips/kernel/genex.S (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License.  See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2001 MIPS Technologies, Inc.
9 * Copyright (C) 2002 Maciej W. Rozycki
10 */
11#include <linux/config.h>
12#include <linux/init.h>
13
14#include <asm/asm.h>
15#include <asm/asmmacro.h>
16#include <asm/cacheops.h>
17#include <asm/regdef.h>
18#include <asm/fpregdef.h>
19#include <asm/mipsregs.h>
20#include <asm/stackframe.h>
21#include <asm/war.h>
22
23#define PANIC_PIC(msg)					\
24		.set push;				\
25		.set	reorder;			\
26		PTR_LA	a0,8f;				\
27		.set	noat;				\
28		PTR_LA	AT, panic;			\
29		jr	AT;				\
309:		b	9b;				\
31		.set	pop;				\
32		TEXT(msg)
33
34	__INIT
35
36NESTED(except_vec0_generic, 0, sp)
37	PANIC_PIC("Exception vector 0 called")
38	END(except_vec0_generic)
39
40NESTED(except_vec1_generic, 0, sp)
41	PANIC_PIC("Exception vector 1 called")
42	END(except_vec1_generic)
43
44/*
45 * General exception vector for all other CPUs.
46 *
47 * Be careful when changing this, it has to be at most 128 bytes
48 * to fit into space reserved for the exception handler.
49 */
50NESTED(except_vec3_generic, 0, sp)
51	.set	push
52	.set	noat
53#if R5432_CP0_INTERRUPT_WAR
54	mfc0	k0, CP0_INDEX
55#endif
56	mfc0	k1, CP0_CAUSE
57	andi	k1, k1, 0x7c
58#ifdef CONFIG_64BIT
59	dsll	k1, k1, 1
60#endif
61	PTR_L	k0, exception_handlers(k1)
62	jr	k0
63	.set	pop
64	END(except_vec3_generic)
65
66/*
67 * General exception handler for CPUs with virtual coherency exception.
68 *
69 * Be careful when changing this, it has to be at most 256 (as a special
70 * exception) bytes to fit into space reserved for the exception handler.
71 */
72NESTED(except_vec3_r4000, 0, sp)
73	.set	push
74	.set	mips3
75	.set	noat
76	mfc0	k1, CP0_CAUSE
77	li	k0, 31<<2
78	andi	k1, k1, 0x7c
79	.set	push
80	.set	noreorder
81	.set	nomacro
82	beq	k1, k0, handle_vced
83	 li	k0, 14<<2
84	beq	k1, k0, handle_vcei
85#ifdef CONFIG_64BIT
86	 dsll	k1, k1, 1
87#endif
88	.set	pop
89	PTR_L	k0, exception_handlers(k1)
90	jr	k0
91
92	/*
93	 * Big shit, we now may have two dirty primary cache lines for the same
94	 * physical address.  We can safely invalidate the line pointed to by
95	 * c0_badvaddr because after return from this exception handler the
96	 * load / store will be re-executed.
97	 */
98handle_vced:
99	MFC0	k0, CP0_BADVADDR
100	li	k1, -4					# Is this ...
101	and	k0, k1					# ... really needed?
102	mtc0	zero, CP0_TAGLO
103	cache	Index_Store_Tag_D, (k0)
104	cache	Hit_Writeback_Inv_SD, (k0)
105#ifdef CONFIG_PROC_FS
106	PTR_LA	k0, vced_count
107	lw	k1, (k0)
108	addiu	k1, 1
109	sw	k1, (k0)
110#endif
111	eret
112
113handle_vcei:
114	MFC0	k0, CP0_BADVADDR
115	cache	Hit_Writeback_Inv_SD, (k0)		# also cleans pi
116#ifdef CONFIG_PROC_FS
117	PTR_LA	k0, vcei_count
118	lw	k1, (k0)
119	addiu	k1, 1
120	sw	k1, (k0)
121#endif
122	eret
123	.set	pop
124	END(except_vec3_r4000)
125
126	__FINIT
127
128	.align  5
129NESTED(handle_int, PT_SIZE, sp)
130	SAVE_ALL
131	CLI
132
133	PTR_LA	ra, ret_from_irq
134	move	a0, sp
135	j	plat_irq_dispatch
136	END(handle_int)
137
138	__INIT
139
140/*
141 * Special interrupt vector for MIPS64 ISA & embedded MIPS processors.
142 * This is a dedicated interrupt exception vector which reduces the
143 * interrupt processing overhead.  The jump instruction will be replaced
144 * at the initialization time.
145 *
146 * Be careful when changing this, it has to be at most 128 bytes
147 * to fit into space reserved for the exception handler.
148 */
149NESTED(except_vec4, 0, sp)
1501:	j	1b			/* Dummy, will be replaced */
151	END(except_vec4)
152
153/*
154 * EJTAG debug exception handler.
155 * The EJTAG debug exception entry point is 0xbfc00480, which
156 * normally is in the boot PROM, so the boot PROM must do a
157 * unconditional jump to this vector.
158 */
159NESTED(except_vec_ejtag_debug, 0, sp)
160	j	ejtag_debug_handler
161	END(except_vec_ejtag_debug)
162
163	__FINIT
164
165/*
166 * Vectored interrupt handler.
167 * This prototype is copied to ebase + n*IntCtl.VS and patched
168 * to invoke the handler
169 */
170NESTED(except_vec_vi, 0, sp)
171	SAVE_SOME
172	SAVE_AT
173	.set	push
174	.set	noreorder
175#ifdef CONFIG_MIPS_MT_SMTC
176	/*
177	 * To keep from blindly blocking *all* interrupts
178	 * during service by SMTC kernel, we also want to
179	 * pass the IM value to be cleared.
180	 */
181EXPORT(except_vec_vi_mori)
182	ori	a0, $0, 0
183#endif /* CONFIG_MIPS_MT_SMTC */
184EXPORT(except_vec_vi_lui)
185	lui	v0, 0		/* Patched */
186	j	except_vec_vi_handler
187EXPORT(except_vec_vi_ori)
188	 ori	v0, 0		/* Patched */
189	.set	pop
190	END(except_vec_vi)
191EXPORT(except_vec_vi_end)
192
193/*
194 * Common Vectored Interrupt code
195 * Complete the register saves and invoke the handler which is passed in $v0
196 */
197NESTED(except_vec_vi_handler, 0, sp)
198	SAVE_TEMP
199	SAVE_STATIC
200#ifdef CONFIG_MIPS_MT_SMTC
201	/*
202	 * SMTC has an interesting problem that interrupts are level-triggered,
203	 * and the CLI macro will clear EXL, potentially causing a duplicate
204	 * interrupt service invocation. So we need to clear the associated
205	 * IM bit of Status prior to doing CLI, and restore it after the
206	 * service routine has been invoked - we must assume that the
207	 * service routine will have cleared the state, and any active
208	 * level represents a new or otherwised unserviced event...
209	 */
210	mfc0	t1, CP0_STATUS
211	and	t0, a0, t1
212	mfc0	t2, CP0_TCCONTEXT
213	or	t0, t0, t2
214	mtc0	t0, CP0_TCCONTEXT
215	xor	t1, t1, t0
216	mtc0	t1, CP0_STATUS
217	ehb
218#endif /* CONFIG_MIPS_MT_SMTC */
219	CLI
220	move	a0, sp
221	jalr	v0
222	j	ret_from_irq
223	END(except_vec_vi_handler)
224
225/*
226 * EJTAG debug exception handler.
227 */
228NESTED(ejtag_debug_handler, PT_SIZE, sp)
229	.set	push
230	.set	noat
231	MTC0	k0, CP0_DESAVE
232	mfc0	k0, CP0_DEBUG
233
234	sll	k0, k0, 30	# Check for SDBBP.
235	bgez	k0, ejtag_return
236
237	PTR_LA	k0, ejtag_debug_buffer
238	LONG_S	k1, 0(k0)
239	SAVE_ALL
240	move	a0, sp
241	jal	ejtag_exception_handler
242	RESTORE_ALL
243	PTR_LA	k0, ejtag_debug_buffer
244	LONG_L	k1, 0(k0)
245
246ejtag_return:
247	MFC0	k0, CP0_DESAVE
248	.set	mips32
249	deret
250	.set pop
251	END(ejtag_debug_handler)
252
253/*
254 * This buffer is reserved for the use of the EJTAG debug
255 * handler.
256 */
257	.data
258EXPORT(ejtag_debug_buffer)
259	.fill	LONGSIZE
260	.previous
261
262	__INIT
263
264/*
265 * NMI debug exception handler for MIPS reference boards.
266 * The NMI debug exception entry point is 0xbfc00000, which
267 * normally is in the boot PROM, so the boot PROM must do a
268 * unconditional jump to this vector.
269 */
270NESTED(except_vec_nmi, 0, sp)
271	j	nmi_handler
272	END(except_vec_nmi)
273
274	__FINIT
275
276NESTED(nmi_handler, PT_SIZE, sp)
277	.set	push
278	.set	noat
279	SAVE_ALL
280 	move	a0, sp
281	jal	nmi_exception_handler
282	RESTORE_ALL
283	.set	mips3
284	eret
285	.set	pop
286	END(nmi_handler)
287
288	.macro	__build_clear_none
289	.endm
290
291	.macro	__build_clear_sti
292	STI
293	.endm
294
295	.macro	__build_clear_cli
296	CLI
297	.endm
298
299	.macro	__build_clear_fpe
300	cfc1	a1, fcr31
301	li	a2, ~(0x3f << 12)
302	and	a2, a1
303	ctc1	a2, fcr31
304	STI
305	.endm
306
307	.macro	__build_clear_ade
308	MFC0	t0, CP0_BADVADDR
309	PTR_S	t0, PT_BVADDR(sp)
310	KMODE
311	.endm
312
313	.macro	__BUILD_silent exception
314	.endm
315
316	/* Gas tries to parse the PRINT argument as a string containing
317	   string escapes and emits bogus warnings if it believes to
318	   recognize an unknown escape code.  So make the arguments
319	   start with an n and gas will believe \n is ok ...  */
320	.macro	__BUILD_verbose	nexception
321	LONG_L	a1, PT_EPC(sp)
322#ifdef CONFIG_32BIT
323	PRINT("Got \nexception at %08lx\012")
324#endif
325#ifdef CONFIG_64BIT
326	PRINT("Got \nexception at %016lx\012")
327#endif
328	.endm
329
330	.macro	__BUILD_count exception
331	LONG_L	t0,exception_count_\exception
332	LONG_ADDIU t0, 1
333	LONG_S	t0,exception_count_\exception
334	.comm	exception_count\exception, 8, 8
335	.endm
336
337	.macro	__BUILD_HANDLER exception handler clear verbose ext
338	.align	5
339	NESTED(handle_\exception, PT_SIZE, sp)
340	.set	noat
341	SAVE_ALL
342	FEXPORT(handle_\exception\ext)
343	__BUILD_clear_\clear
344	.set	at
345	__BUILD_\verbose \exception
346	move	a0, sp
347	jal	do_\handler
348	j	ret_from_exception
349	END(handle_\exception)
350	.endm
351
352	.macro	BUILD_HANDLER exception handler clear verbose
353	__BUILD_HANDLER	\exception \handler \clear \verbose _int
354	.endm
355
356	BUILD_HANDLER adel ade ade silent		/* #4  */
357	BUILD_HANDLER ades ade ade silent		/* #5  */
358	BUILD_HANDLER ibe be cli silent			/* #6  */
359	BUILD_HANDLER dbe be cli silent			/* #7  */
360	BUILD_HANDLER bp bp sti silent			/* #9  */
361	BUILD_HANDLER ri ri sti silent			/* #10 */
362	BUILD_HANDLER cpu cpu sti silent		/* #11 */
363	BUILD_HANDLER ov ov sti silent			/* #12 */
364	BUILD_HANDLER tr tr sti silent			/* #13 */
365	BUILD_HANDLER fpe fpe fpe silent		/* #15 */
366	BUILD_HANDLER mdmx mdmx sti silent		/* #22 */
367	BUILD_HANDLER watch watch sti verbose		/* #23 */
368	BUILD_HANDLER mcheck mcheck cli verbose		/* #24 */
369	BUILD_HANDLER mt mt sti verbose			/* #25 */
370	BUILD_HANDLER dsp dsp sti silent		/* #26 */
371	BUILD_HANDLER reserved reserved sti verbose	/* others */
372
373#ifdef CONFIG_64BIT
374/* A temporary overflow handler used by check_daddi(). */
375
376	__INIT
377
378	BUILD_HANDLER  daddi_ov daddi_ov none silent	/* #12 */
379#endif
380