xref: /openbsd-src/sys/arch/mips64/mips64/exception.S (revision bfc185c1fc344eead3f54156b93fe14638b67e0e)
1/*	$OpenBSD: exception.S,v 1.43 2021/05/01 16:11:11 visa Exp $ */
2
3/*
4 * Copyright (c) 2002-2003 Opsycon AB  (www.opsycon.se / www.opsycon.com)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29/*
30 *  This code handles exceptions and dispatches to the
31 *  correct handler depending on the exception type.
32 *
33 *  Exceptions are directed to the following addresses:
34 *      0xffffffffbfc00000  Reset, NMI etc. Not handled by the kernel.
35 *	0xffffffff80000000  TLB refill, not in exception.
36 *	0xffffffff80000080  XTLB refill, not in exception.
37 *	0xffffffffa0000100  Cache errors.
38 *	0xffffffff80000180  Interrupts. Same as next.
39 *	0xffffffff80000180  Everything else...
40 */
41
42#include <machine/param.h>
43#include <machine/asm.h>
44#include <machine/cpu.h>
45#include <mips64/mips_cpu.h>
46#include <machine/regnum.h>
47#include <machine/cpustate.h>
48#ifdef CPU_LOONGSON2
49#include <machine/loongson2.h>
50#endif
51
52#include "assym.h"
53
54	.set	mips3
55
56	.text
57
58k_exception_table:
59	PTR_VAL	k_intr			/* T_INT */
60	PTR_VAL	k_general		/* T_TLB_MOD */
61	PTR_VAL	k_tlb_inv		/* T_TLB_LD_MISS */
62	PTR_VAL	k_tlb_inv		/* T_TLB_ST_MISS */
63	PTR_VAL	k_general		/* T_ADDR_ERR_LD */
64	PTR_VAL	k_general		/* T_ADDR_ERR_ST */
65	PTR_VAL	k_general		/* T_BUS_ERR_IFETCH */
66	PTR_VAL	k_general		/* T_BUS_ERR_LD_ST */
67	PTR_VAL	k_general		/* T_SYSCALL */
68	PTR_VAL	k_general		/* T_BREAK */
69	PTR_VAL	k_general		/* T_RES_INST */
70	PTR_VAL	k_general		/* T_COP_UNUSABLE */
71	PTR_VAL	k_general		/* T_OVFLOW */
72	PTR_VAL	k_general		/* T_TRAP */
73	PTR_VAL	k_general		/* T_VCEI */
74	PTR_VAL	k_general		/* T_FPE */
75	PTR_VAL	k_general		/* T_IWATCH */
76	PTR_VAL	k_general
77	PTR_VAL	k_general		/* T_C2E */
78	PTR_VAL	k_general
79	PTR_VAL	k_general
80	PTR_VAL	k_general
81	PTR_VAL	k_general		/* T_MDMX */
82	PTR_VAL	k_general		/* T_DWATCH */
83	PTR_VAL	k_general		/* T_MCHECK */
84	PTR_VAL	k_general
85	PTR_VAL	k_general
86	PTR_VAL	k_general
87	PTR_VAL	k_general
88	PTR_VAL	k_general
89	PTR_VAL	k_general		/* T_CACHEERR */
90	PTR_VAL	k_general		/* T_VCED */
91
92u_exception_table:
93	PTR_VAL	u_intr			/* T_INT */
94	PTR_VAL	u_general		/* T_TLB_MOD */
95	PTR_VAL	u_general		/* T_TLB_LD_MISS */
96	PTR_VAL	u_general		/* T_TLB_ST_MISS */
97	PTR_VAL	u_general		/* T_ADDR_ERR_LD */
98	PTR_VAL	u_general		/* T_ADDR_ERR_ST */
99	PTR_VAL	u_general		/* T_BUS_ERR_IFETCH */
100	PTR_VAL	u_general		/* T_BUS_ERR_LD_ST */
101	PTR_VAL	u_general		/* T_SYSCALL */
102	PTR_VAL	u_general		/* T_BREAK */
103	PTR_VAL	u_general		/* T_RES_INST */
104	PTR_VAL	u_general		/* T_COP_UNUSABLE */
105	PTR_VAL	u_general		/* T_OVFLOW */
106	PTR_VAL	u_general		/* T_TRAP */
107	PTR_VAL	u_general		/* T_VCEI */
108	PTR_VAL	u_general		/* T_FPE */
109	PTR_VAL	u_general		/* T_IWATCH */
110	PTR_VAL	u_general
111	PTR_VAL	u_general		/* T_C2E */
112	PTR_VAL	u_general
113	PTR_VAL	u_general
114	PTR_VAL	u_general
115	PTR_VAL	u_general		/* T_MDMX */
116	PTR_VAL	u_general		/* T_DWATCH */
117	PTR_VAL	u_general		/* T_MCHECK */
118	PTR_VAL	u_general
119	PTR_VAL	u_general
120	PTR_VAL	u_general
121	PTR_VAL	u_general
122	PTR_VAL	u_general
123	PTR_VAL	u_general		/* T_CACHEERR */
124	PTR_VAL	u_general		/* T_VCED */
125
126	.set	noreorder		# Noreorder is default style!
127
128/*---------------------------------------------------------------- exception
129 *	General exception handler dispatcher. This code is copied
130 *	to the vector area and must thus be PIC and less than 128
131 *	bytes long to fit. Only k0 and k1 may be used at this time.
132 */
133	.globl	exception
134exception:
135	.set	noat
136#ifdef CPU_LOONGSON2
137	/*
138	 * To work around a branch prediction issue on earlier LS2F
139	 * chips, it is necessary to clear the BTB upon
140	 * userland->kernel boundaries.
141	 */
142	li	k0, COP_0_DIAG_BTB_CLEAR | COP_0_DIAG_RAS_DISABLE
143	dmtc0	k0, COP_0_DIAG
144#endif
145	MFC0	k0, COP_0_STATUS_REG
146	MFC0	k1, COP_0_CAUSE_REG
147	and	k0, k0, SR_KSU_USER
148	beqz	k0, k_exception		# Kernel mode mode
149	and	k1, k1, CR_EXC_CODE
150
151	LA	k0, u_exception_table
152	PTR_ADDU k0, k0, k1
153	PTR_ADDU k0, k0, k1		# yes, twice...
154	PTR_L	k0, 0(k0)
155	j	k0
156	nop
157
158k_exception:
159	LA	k0, k_exception_table
160	PTR_ADDU k0, k0, k1
161	PTR_ADDU k0, k0, k1		# yes, twice...
162	PTR_L	k0, 0(k0)
163	j	k0
164	nop
165	.set	at
166	.globl	e_exception
167e_exception:
168
169
170/*---------------------------------------------------------------- k_intr
171 *	Handle an interrupt in kernel mode. This is easy since we
172 *	just need to save away the 'save' registers and state.
173 *	State is saved on kernel stack.
174 */
175
176NNON_LEAF(k_intr, FRAMESZ(KERN_EXC_FRAME_SIZE), ra)
177	.set	noat
178	.mask	0x80000000, (CF_RA_OFFS - FRAMESZ(KERN_EXC_FRAME_SIZE))
179	PTR_SUB	k0, sp, FRAMESZ(KERN_EXC_FRAME_SIZE)
180	SAVE_CPU(k0, CF_RA_OFFS)
181	.set	at
182	move	sp, k0			# Already on kernel stack
183	and	t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK)
184	MTC0	t0, COP_0_STATUS_REG
185	MTC0_SR_IE_HAZARD
186	PTR_S	a0, 0(sp)
187	jal	interrupt
188	PTR_S	a3, CF_RA_OFFS + KERN_REG_SIZE(sp)
189
190	PTR_L	a0, CF_RA_OFFS + KERN_REG_SIZE(sp)
191	.set	noat
192	RESTORE_CPU(sp, CF_RA_OFFS)
193	PTR_ADDU sp, sp, FRAMESZ(KERN_EXC_FRAME_SIZE)
194	ERET
195	.set	at
196END(k_intr)
197
198/*---------------------------------------------------------------- u_intr
199 *	Handle an interrupt in user mode. Save the relevant user
200 *	registers into the u.u_pcb struct. This will allow us
201 *	to preempt the interrupted process. Full save is held
202 *	off though until a switch() really is required.
203 */
204NNON_LEAF(u_intr, FRAMESZ(CF_SZ), ra)
205	.set	noat
206	.mask	0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
207	GET_CPU_INFO(k1, k0)
208	PTR_L	k0, CI_CURPROCPADDR(k1)
209	SAVE_CPU(k0, 0)
210	PTR_ADDU sp, k0, USPACE-FRAMESZ(CF_SZ)
211	.set	at
212	and	t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK)
213	MTC0	t0, COP_0_STATUS_REG
214	MTC0_SR_IE_HAZARD
215	PTR_S	a0, 0(sp)
216	jal	interrupt
217	PTR_S	a3, CF_RA_OFFS(sp)	# for debugging
218
219	GET_CPU_INFO(t1, t0)
2200:
221	MFC0	t0, COP_0_STATUS_REG	# disable interrupts for checking AST
222	LI	v0, ~SR_INT_ENAB
223	and	t0, t0, v0
224	MTC0	t0, COP_0_STATUS_REG
225	MTC0_SR_IE_HAZARD
226
227	PTR_L	v1, CI_CURPROC(t1)
228	lw	v0, P_ASTPENDING(v1)	# any pending AST?
229	beq	v0, zero, 4f
230	nop
231
232	ori	t0, SR_INT_ENAB		# enable interrupts for handling AST
233	MTC0	t0, COP_0_STATUS_REG
234	MTC0_SR_IE_HAZARD
235
236	PTR_L	t0, CI_CURPROCPADDR(t1)	# curprocpaddr
237	SAVE_CPU_SREG(t0, 0)
238
239	jal	ast
240	nop
241
242/*
243 * Restore user registers and return. NOTE: interrupts are enabled.
244 */
245	GET_CPU_INFO(t1, t0)
246	PTR_L	t0, CI_CURPROCPADDR(t1)
247	RESTORE_CPU_SREG(t0, 0)
248
249	b	0b
250	nop
251
2524:
253	# t0 is status register from earlier
254	ori	t0, SR_EXL		# restoring to user mode.
255	MTC0	t0, COP_0_STATUS_REG	# must set exception level bit.
256	MTC0_SR_IE_HAZARD
257
258	# t1 is curcpu() from earlier
259	move	k1, t1
260	PTR_L	k0, CI_CURPROCPADDR(k1)
261	RESTORE_REG(a3, CPL, k0, 0)
262	sw	a3, CI_IPL(k1)
263	.set	noat
264	RESTORE_REG(a0, PC, k0, 0)
265	RESTORE_CPU(k0, 0)
266	RESTORE_REG(sp, SP, k0, 0)
267	LI	k0, 0
268	LI	k1, 0
269	ERET
270	.set	at
271END(u_intr)
272
273/*---------------------------------------------------------------- k_general
274 *	Handle a kernel general trap. This is very much like
275 *	k_intr except that we call ktrap instead of interrupt.
276 */
277
278NNON_LEAF(k_general, FRAMESZ(KERN_EXC_FRAME_SIZE), ra)
279	.set	noat
280	.mask	0x80000000, (CF_RA_OFFS - FRAMESZ(KERN_EXC_FRAME_SIZE))
281	PTR_SUB	k0, sp, FRAMESZ(KERN_EXC_FRAME_SIZE)
282	SAVE_CPU(k0, CF_RA_OFFS)
283#if defined(DDB)
284	SAVE_CPU_SREG(k0, CF_RA_OFFS)
285#endif
286	.set	at
287	move	sp, k0			# Already on kernel stack
288	and	t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK)
289	MTC0	t0, COP_0_STATUS_REG
290	MTC0_SR_IE_HAZARD
291	PTR_S	a0, 0(sp)
292	jal	trap
293	PTR_S	a3, CF_RA_OFFS + KERN_REG_SIZE(sp)
294
295	MFC0	t0, COP_0_STATUS_REG	# disable interrupts
296	LI	t1, ~SR_INT_ENAB
297	and	t0, t0, t1
298	MTC0	t0, COP_0_STATUS_REG
299	MTC0_SR_IE_HAZARD
300
301	.set	noat
302	RESTORE_REG(a0, PC, sp, CF_RA_OFFS)
303	RESTORE_CPU(sp, CF_RA_OFFS)
304	PTR_ADDU sp, sp, FRAMESZ(KERN_EXC_FRAME_SIZE)
305	ERET
306	.set	at
307END(k_general)
308
309/*---------------------------------------------------------------- u_general
310 *	Handle a user general trap.
311 */
312NNON_LEAF(u_general, FRAMESZ(CF_SZ), ra)
313	.set	noat
314	.mask	0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
315
316	GET_CPU_INFO(k1, k0)
317	PTR_L	k0, CI_CURPROCPADDR(k1)
318	SAVE_CPU(k0, 0)
319	SAVE_CPU_SREG(k0, 0)
320	PTR_ADDU sp, k0, USPACE-FRAMESZ(CF_SZ)
321	.set	at
322	and	t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK)
323	MTC0	t0, COP_0_STATUS_REG
324	MTC0_SR_IE_HAZARD
325
326	jal	trap
327	PTR_S	a3, CF_RA_OFFS(sp)		# for debugging
328
3290:
330	MFC0	t0, COP_0_STATUS_REG	# disable interrupts for checking AST
331	LI	t1, ~SR_INT_ENAB
332	and	t0, t0, t1
333	MTC0	t0, COP_0_STATUS_REG
334	MTC0_SR_IE_HAZARD
335
336	GET_CPU_INFO(t1, v0)
337	PTR_L	v1, CI_CURPROC(t1)
338	lw	v0, P_ASTPENDING(v1)	# any pending AST?
339	beq	v0, zero, 4f
340	nop
341
342	ori	t0, SR_INT_ENAB		# enable interrupts for handling AST
343	MTC0	t0, COP_0_STATUS_REG
344	MTC0_SR_IE_HAZARD
345
346	jal	ast
347	nop
348
349	b	0b
350	nop
351
3524:
353	# t0 is status register from earlier
354	ori	t0, SR_EXL		# restoring to user mode.
355	MTC0	t0, COP_0_STATUS_REG	# must set exception level bit.
356	MTC0_SR_IE_HAZARD
357
358	# t1 is curcpu() from earlier
359	move	k1, t1
360	PTR_L	k0, CI_CURPROCPADDR(k1)
361	RESTORE_REG(a3, CPL, k0, 0)
362	sw	a3, CI_IPL(k1)
363	.set	noat
364	RESTORE_CPU_SREG(k0, 0)
365	RESTORE_REG(a0, PC, k0, 0)
366	RESTORE_CPU(k0, 0)
367	RESTORE_REG(sp, SP, k0, 0)
368	LI	k0, 0
369	LI	k1, 0
370	ERET
371	.set	at
372END(u_general)
373