xref: /openbsd-src/sys/arch/mips64/mips64/context.S (revision bb00e81153b2ff3fcf42c8955e50b70f573a8323)
1/*	$OpenBSD: context.S,v 1.66 2023/10/24 13:20:10 claudio 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#include <sys/errno.h>
29#include <sys/syscall.h>
30
31#include <machine/param.h>
32#include <machine/asm.h>
33#include <machine/cpu.h>
34#include <machine/pte.h>
35#include <machine/regnum.h>
36#include <mips64/mips_cpu.h>
37#include <machine/cpustate.h>
38#ifdef CPU_LOONGSON2
39#include <machine/loongson2.h>
40#endif
41
42#include "assym.h"
43
44	.set	mips3
45	.set	noreorder		# Noreorder is default style!
46
47/*
48 * Save registers and state used by reboot to take snapshot.
49 */
50LEAF(savectx, 0)
51	REG_S	s0, PCB_CONTEXT+0*REGSZ(a0)
52	REG_S	s1, PCB_CONTEXT+1*REGSZ(a0)
53	REG_S	s2, PCB_CONTEXT+2*REGSZ(a0)
54	REG_S	s3, PCB_CONTEXT+3*REGSZ(a0)
55	MFC0	v0, COP_0_STATUS_REG
56	MFC0_HAZARD
57	REG_S	s4, PCB_CONTEXT+4*REGSZ(a0)
58	REG_S	s5, PCB_CONTEXT+5*REGSZ(a0)
59	REG_S	s6, PCB_CONTEXT+6*REGSZ(a0)
60	REG_S	s7, PCB_CONTEXT+7*REGSZ(a0)
61	REG_S	sp, PCB_CONTEXT+8*REGSZ(a0)
62	REG_S	s8, PCB_CONTEXT+9*REGSZ(a0)
63	REG_S	ra, PCB_CONTEXT+10*REGSZ(a0)
64	REG_S	v0, PCB_CONTEXT+11*REGSZ(a0)
65	j	ra
66	 move	v0, zero
67END(savectx)
68
69LEAF(cpu_idle_cycle_nop, 0)
70	j	ra
71	 NOP
72END(cpu_idle_cycle_nop)
73
74LEAF(cpu_idle_cycle_wait, 0)
75	wait
76	j	ra
77	 NOP
78END(cpu_idle_cycle_wait)
79
80/*
81 * cpu_switchto_asm(struct proc *oldproc, struct proc *newproc)
82 */
83NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ), ra)
84	GET_CPU_INFO(t1, t3)
85	PTR_L	t3, CI_CURPROCPADDR(t1)
86	REG_S	sp, PCB_CONTEXT+8*REGSZ(t3)	# save old sp
87
88	PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
89	REG_S	ra, CF_RA_OFFS(sp)
90	.mask	0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
91
92	beqz	a0, 1f
93	 MFC0	v0, COP_0_STATUS_REG
94
95	REG_S	s0, PCB_CONTEXT+0*REGSZ(t3)	# do a 'savectx()'
96	REG_S	s1, PCB_CONTEXT+1*REGSZ(t3)
97	REG_S	s2, PCB_CONTEXT+2*REGSZ(t3)
98	REG_S	s3, PCB_CONTEXT+3*REGSZ(t3)
99	REG_S	s4, PCB_CONTEXT+4*REGSZ(t3)
100	REG_S	s5, PCB_CONTEXT+5*REGSZ(t3)
101	REG_S	s6, PCB_CONTEXT+6*REGSZ(t3)
102	REG_S	s7, PCB_CONTEXT+7*REGSZ(t3)
103	REG_S	s8, PCB_CONTEXT+9*REGSZ(t3)
104	REG_S	ra, PCB_CONTEXT+10*REGSZ(t3)
105	REG_S	v0, PCB_CONTEXT+11*REGSZ(t3)
106
1071:
108	/*
109	 * Switch to new context
110	 */
111	move	s0, a1				# save p
112	move	s1, v0				# save status register
113	jal	pmap_activate
114	 move	a0, s0
115
116	/*
117	 * Disable interrupts
118	 */
119	ori	s1, SR_INT_ENAB
120	xori	s1, SR_INT_ENAB
121	MTC0	s1, COP_0_STATUS_REG
122	MTC0_SR_IE_HAZARD
123
124	PTR_L	t3, P_ADDR(s0)			# get uarea pointer.
125	GET_CPU_INFO(t1, t0)
126	PTR_S	s0, CI_CURPROC(t1)		# set curproc
127	PTR_S	t3, CI_CURPROCPADDR(t1)
128
129#ifdef MULTIPROCESSOR
130	PTR_S	t1, P_CPU(s0)
131#endif
132	li	t1, SONPROC
133	sb	t1, P_STAT(s0)			# set to onproc.
134
135	/* get process ASID */
136	PTR_L	t0, P_VMSPACE(s0)		# p->p_vmspace
137	PTR_L	t1, VMSPACE_PMAP(t0)		# ->vm_map.pmap
138#ifdef MULTIPROCESSOR
139	GET_CPU_INFO(v0, t2)
140	PTR_L	v0, CI_CPUID(v0)
141	PTR_SLL	v0, v0, 0x3			# size of pmap_asid_info
142	PTR_ADDU t1, t1, v0
143#endif
144	lw	v0, PM_ASID(t1)			# ->pm_asid[cpuid].pma_asid
145
146#if UPAGES > 1	/* { */
147	or	v0, t3
148	dmtc0	v0, COP_0_TLB_HI		# init high entry (tlbid)
149
150	/*
151	 * We need to wire the process kernel stack mapping so there
152	 * will be no tlb misses in exception handlers. This is done
153	 * by invalidating any tlb entries mapping the U-area and
154	 * put valid mappings in tlb entries 0 and 1.
155	 */
156
157	LA	t1, CKSEG0_BASE
158	PTR_SUBU t2, t3, t1
159	bgez	t2, ctx3			# in CKSEG0
160	LA	t1, VM_MIN_KERNEL_ADDRESS	# (safe if expands to > 1 insn)
161	PTR_SUBU t2, t3, t1
162	bltz	t2, ctx3			# not mapped.
163	PTR_SRL	t2, PGSHIFT+1
164	PTR_L	t1, Sysmap
165	TLB_HAZARD
166	tlbp
167	TLB_HAZARD			# necessary?
168	PTR_SLL	t2, PTE_LOG + 1
169	PTR_ADDU t1, t2				# t1 now points at ptes.
170	mfc0	t0, COP_0_TLB_INDEX
171	nop
172	bltz	t0, ctx1			# not in tlb
173	LA	t2, CKSEG0_BASE			# safe if expands to > 1 insn
174
175	dmtc0	t2, COP_0_TLB_HI		# invalidate it.
176	dmtc0	zero, COP_0_TLB_LO0
177	dmtc0	zero, COP_0_TLB_LO1
178	TLB_HAZARD
179	tlbwi
180	TLB_HAZARD
181
182ctx1:
183	mtc0	zero, COP_0_TLB_INDEX
184	dmtc0	v0, COP_0_TLB_HI
185	PTE_LOAD ta0, 0(t1)
186	PTE_LOAD ta1, PTE_OFFS(t1)
187	PTE_CLEAR_SWBITS(ta0)
188	PTE_CLEAR_SWBITS(ta1)
189	dmtc0	ta0, COP_0_TLB_LO0
190	dmtc0	ta1, COP_0_TLB_LO1
191	PTR_ADDU v0, 2*PAGE_SIZE
192	TLB_HAZARD
193	tlbwi
194	TLB_HAZARD
195
196#if UPAGES > 2	/* { */
197	dmtc0	v0, COP_0_TLB_HI		# init high entry (tlbid)
198	PTE_LOAD ta0, (2*PTE_OFFS)(t1)
199	PTE_LOAD ta1, (3*PTE_OFFS)(t1)
200	PTE_CLEAR_SWBITS(ta0)
201	TLB_HAZARD
202	tlbp
203	TLB_HAZARD			# necessary?
204	PTE_CLEAR_SWBITS(ta1)
205	mfc0	t0, COP_0_TLB_INDEX
206	nop
207	bltz	t0, ctx2			# not in tlb
208	li	t2, 1
209
210	dmtc0	t2, COP_0_TLB_HI		# invalidate it.
211	dmtc0	zero, COP_0_TLB_LO0
212	dmtc0	zero, COP_0_TLB_LO1
213	TLB_HAZARD
214	tlbwi
215	TLB_HAZARD
216
217ctx2:
218	mtc0	t2, COP_0_TLB_INDEX
219	dmtc0	v0, COP_0_TLB_HI
220	dmtc0	ta0, COP_0_TLB_LO0
221	dmtc0	ta1, COP_0_TLB_LO1
222	TLB_HAZARD
223	tlbwi
224	TLB_HAZARD
225#endif	/* } UPAGES > 2 */
226ctx3:
227#else	/* } UPAGES > 1 { */
228#if PG_ASID_SHIFT != 0
229	dsll	v0, PG_ASID_SHIFT
230#endif
231	DMTC0	v0, COP_0_TLB_HI		# init high entry (tlbid)
232	MTC0_HAZARD
233#endif	/* } UPAGES > 1 */
234
235#ifdef CPU_LOONGSON2
236	li	v0, COP_0_DIAG_ITLB_CLEAR | COP_0_DIAG_BTB_CLEAR | COP_0_DIAG_RAS_DISABLE
237	dmtc0	v0, COP_0_DIAG
238#endif
239
240#ifdef CPU_MIPS64R2
241	/*
242	 * Restore UserLocal register.
243	 */
244	lw	t1, cpu_has_userlocal
245	beq	t1, zero, 1f
246	 nop
247	.set	push
248	.set	mips64r2
249	ld	t0, P_TCB(s0)
250	dmtc0	t0, COP_0_USERLOCAL
251	.set	pop
2521:
253#endif /* CPU_MIPS64R2 */
254
255	/*
256	 * Restore registers and return.
257	 */
258
259	REG_L	s0, PCB_CONTEXT+0*REGSZ(t3)
260	REG_L	s1, PCB_CONTEXT+1*REGSZ(t3)
261	REG_L	s2, PCB_CONTEXT+2*REGSZ(t3)
262	REG_L	s3, PCB_CONTEXT+3*REGSZ(t3)
263	REG_L	s4, PCB_CONTEXT+4*REGSZ(t3)
264	REG_L	s5, PCB_CONTEXT+5*REGSZ(t3)
265	REG_L	s6, PCB_CONTEXT+6*REGSZ(t3)
266	REG_L	s7, PCB_CONTEXT+7*REGSZ(t3)
267	REG_L	sp, PCB_CONTEXT+8*REGSZ(t3)
268	REG_L	s8, PCB_CONTEXT+9*REGSZ(t3)
269	REG_L	ra, PCB_CONTEXT+10*REGSZ(t3)
270	REG_L	v0, PCB_CONTEXT+11*REGSZ(t3)
271	ori	v0, v0, SR_INT_ENAB
272	MTC0	v0, COP_0_STATUS_REG
273	MTC0_SR_IE_HAZARD
274	j	ra
275	 NOP
276END(cpu_switchto_asm)
277
278/*-------------------------------------------------------------- proc_trampoline
279 *	Setup for and return to user.
280 */
281LEAF(proc_trampoline, 0)
282#ifdef DDB
283	move	zero, ra
284#endif
285	jal	proc_trampoline_mi
286	 NOP
287	jal	updateimask		# Make sure SR imask is updated
288	 xor	a0, a0			# and interrupts enabled
289
290	jal	s0
291	 move	a0,s1			# invoke callback.
292
293	MFC0	t0, COP_0_STATUS_REG
294	MFC0_HAZARD
295	LI	t1, ~SR_INT_ENAB
296	and	t0, t0, t1
297	MTC0	t0, COP_0_STATUS_REG
298	MTC0_SR_IE_HAZARD
299
300	ori	t0, SR_EXL		# restoring to user mode.
301	MTC0	t0, COP_0_STATUS_REG	# must set exception level bit.
302	MTC0_SR_IE_HAZARD
303
304	.set	noat
305	GET_CPU_INFO(k1, k0)
306	PTR_L	k0, CI_CURPROCPADDR(k1)
307	RESTORE_CPU_SREG(k0, 0)
308	RESTORE_REG(a0, PC, k0, 0)
309	RESTORE_CPU(k0, 0)
310	RESTORE_REG(sp, SP, k0, 0)
311	LI	k0, 0
312	LI	k1, 0
313	ERET
314	.set	at
315END(proc_trampoline)
316