1/*	$OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $	*/
2/*-
3 * Copyright (c) 1992, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Digital Equipment Corporation and Ralph Campbell.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Copyright (C) 1989 Digital Equipment Corporation.
34 * Permission to use, copy, modify, and distribute this software and
35 * its documentation for any purpose and without fee is hereby granted,
36 * provided that the above copyright notice appears in all copies.
37 * Digital Equipment Corporation makes no representations about the
38 * suitability of this software for any purpose.  It is provided "as is"
39 * without express or implied warranty.
40 *
41 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
42 *	v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
43 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
44 *	v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
45 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
46 *	v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
47 *
48 *	from: @(#)locore.s	8.5 (Berkeley) 1/4/94
49 *	JNPR: support.S,v 1.5.2.2 2007/08/29 10:03:49 girish
50 * $FreeBSD: stable/12/sys/mips/mips/support.S 351789 2019-09-03 20:04:44Z kib $
51 */
52
53/*
54 * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author)
55 * All rights reserved.
56 *
57 * Redistribution and use in source and binary forms, with or without
58 * modification, are permitted provided that the following conditions
59 * are met:
60 * 1. Redistributions of source code must retain the above copyright
61 *    notice, this list of conditions and the following disclaimer.
62 * 2. Redistributions in binary form must reproduce the above copyright
63 *    notice, this list of conditions and the following disclaimer in the
64 *    documentation and/or other materials provided with the distribution.
65 * 3. All advertising materials mentioning features or use of this software
66 *    must display the following acknowledgement:
67 *      This product includes software developed by Jonathan R. Stone for
68 *      the NetBSD Project.
69 * 4. The name of the author may not be used to endorse or promote products
70 *    derived from this software without specific prior written permission.
71 *
72 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
73 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
74 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
76 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
77 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
78 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
79 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
80 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
81 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
82 * SUCH DAMAGE.
83 */
84
85/*
86 *	Contains assembly language support routines.
87 */
88
89#include "opt_ddb.h"
90#include <sys/errno.h>
91#include <machine/asm.h>
92#include <machine/cpu.h>
93#include <machine/regnum.h>
94#include <machine/cpuregs.h>
95#include <machine/pcb.h>
96
97#include "assym.inc"
98
99	.set	noreorder		# Noreorder is default style!
100
101/*
102 * Primitives
103 */
104
105	.text
106
107/*
108 * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied)
109 * Copy a NIL-terminated string, at most maxlen characters long.  Return the
110 * number of characters copied (including the NIL) in *lencopied.  If the
111 * string is too long, return ENAMETOOLONG; else return 0.
112 */
113LEAF(copystr)
114	move		t0, a2
115	beq		a2, zero, 4f
1161:
117	lbu		v0, 0(a0)
118	PTR_SUBU	a2, a2, 1
119	beq		v0, zero, 2f
120	sb		v0, 0(a1)		# each byte until NIL
121	PTR_ADDU	a0, a0, 1
122	bne		a2, zero, 1b		# less than maxlen
123	PTR_ADDU	a1, a1, 1
1244:
125	li		v0, ENAMETOOLONG	# run out of space
1262:
127	beq		a3, zero, 3f		# return num. of copied bytes
128	PTR_SUBU	a2, t0, a2		# if the 4th arg was non-NULL
129	PTR_S		a2, 0(a3)
1303:
131	j		ra			# v0 is 0 or ENAMETOOLONG
132	nop
133END(copystr)
134
135
136/*
137 * Copy a null terminated string from the user address space into
138 * the kernel address space.
139 *
140 *	copyinstr(fromaddr, toaddr, maxlength, &lencopied)
141 *		caddr_t fromaddr;
142 *		caddr_t toaddr;
143 *		u_int maxlength;
144 *		u_int *lencopied;
145 */
146NESTED(copyinstr, CALLFRAME_SIZ, ra)
147	PTR_SUBU	sp, sp, CALLFRAME_SIZ
148	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
149	PTR_LA	v0, copyerr
150	blt	a0, zero, _C_LABEL(copyerr)  # make sure address is in user space
151	REG_S	ra, CALLFRAME_RA(sp)
152	GET_CPU_PCPU(v1)
153	PTR_L	v1, PC_CURPCB(v1)
154	jal	_C_LABEL(copystr)
155	PTR_S	v0, U_PCB_ONFAULT(v1)
156	REG_L	ra, CALLFRAME_RA(sp)
157	GET_CPU_PCPU(v1)
158	PTR_L	v1, PC_CURPCB(v1)
159	PTR_S	zero, U_PCB_ONFAULT(v1)
160	j	ra
161	PTR_ADDU	sp, sp, CALLFRAME_SIZ
162END(copyinstr)
163
164/*
165 * Copy specified amount of data from user space into the kernel
166 *	copyin(from, to, len)
167 *		caddr_t *from;	(user source address)
168 *		caddr_t *to;	(kernel destination address)
169 *		unsigned len;
170 */
171NESTED(copyin, CALLFRAME_SIZ, ra)
172	PTR_SUBU	sp, sp, CALLFRAME_SIZ
173	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
174	PTR_LA	v0, copyerr
175	blt	a0, zero, _C_LABEL(copyerr)  # make sure address is in user space
176	REG_S	ra, CALLFRAME_RA(sp)
177	GET_CPU_PCPU(v1)
178	PTR_L	v1, PC_CURPCB(v1)
179	jal	_C_LABEL(bcopy)
180	PTR_S	v0, U_PCB_ONFAULT(v1)
181	REG_L	ra, CALLFRAME_RA(sp)
182	GET_CPU_PCPU(v1)
183	PTR_L	v1, PC_CURPCB(v1)	 	# bcopy modified v1, so reload
184	PTR_S	zero, U_PCB_ONFAULT(v1)
185	PTR_ADDU	sp, sp, CALLFRAME_SIZ
186	j	ra
187	move	v0, zero
188END(copyin)
189
190/*
191 * Copy specified amount of data from kernel to the user space
192 *	copyout(from, to, len)
193 *		caddr_t *from;	(kernel source address)
194 *		caddr_t *to;	(user destination address)
195 *		unsigned len;
196 */
197NESTED(copyout, CALLFRAME_SIZ, ra)
198	PTR_SUBU	sp, sp, CALLFRAME_SIZ
199	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
200	PTR_LA	v0, copyerr
201	blt	a1, zero, _C_LABEL(copyerr) # make sure address is in user space
202	REG_S	ra, CALLFRAME_RA(sp)
203	GET_CPU_PCPU(v1)
204	PTR_L	v1, PC_CURPCB(v1)
205	jal	_C_LABEL(bcopy)
206	PTR_S	v0, U_PCB_ONFAULT(v1)
207	REG_L	ra, CALLFRAME_RA(sp)
208	GET_CPU_PCPU(v1)
209	PTR_L	v1, PC_CURPCB(v1)	 	# bcopy modified v1, so reload
210	PTR_S	zero, U_PCB_ONFAULT(v1)
211	PTR_ADDU	sp, sp, CALLFRAME_SIZ
212	j	ra
213	move	v0, zero
214END(copyout)
215
216LEAF(copyerr)
217	REG_L	ra, CALLFRAME_RA(sp)
218	PTR_ADDU	sp, sp, CALLFRAME_SIZ
219	j	ra
220	li	v0, EFAULT			# return error
221END(copyerr)
222
223/*
224 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
225 * user-space.
226 */
227#ifdef __mips_n64
228LEAF(fueword64)
229XLEAF(fueword)
230	PTR_LA	v0, fswberr
231	blt	a0, zero, fswberr	# make sure address is in user space
232	nop
233	GET_CPU_PCPU(v1)
234	PTR_L	v1, PC_CURPCB(v1)
235	PTR_S	v0, U_PCB_ONFAULT(v1)
236	ld	v0, 0(a0)		# fetch word
237	PTR_S	zero, U_PCB_ONFAULT(v1)
238	sd	v0, 0(a1)		# store word
239	j	ra
240	li	v0, 0
241END(fueword64)
242#endif
243
244LEAF(fueword32)
245#ifndef __mips_n64
246XLEAF(fueword)
247#endif
248	PTR_LA	v0, fswberr
249	blt	a0, zero, fswberr	# make sure address is in user space
250	nop
251	GET_CPU_PCPU(v1)
252	PTR_L	v1, PC_CURPCB(v1)
253	PTR_S	v0, U_PCB_ONFAULT(v1)
254	lw	v0, 0(a0)		# fetch word
255	PTR_S	zero, U_PCB_ONFAULT(v1)
256	sw	v0, 0(a1)		# store word
257	j	ra
258	li	v0, 0
259END(fueword32)
260
261LEAF(fuesword)
262	PTR_LA	v0, fswberr
263	blt	a0, zero, fswberr	# make sure address is in user space
264	nop
265	GET_CPU_PCPU(v1)
266	PTR_L	v1, PC_CURPCB(v1)
267	PTR_S	v0, U_PCB_ONFAULT(v1)
268	lhu	v0, 0(a0)		# fetch short
269	PTR_S	zero, U_PCB_ONFAULT(v1)
270	sh	v0, 0(a1)		# store short
271	j	ra
272	li	v0, 0
273END(fuesword)
274
275LEAF(fubyte)
276	PTR_LA	v0, fswberr
277	blt	a0, zero, fswberr	# make sure address is in user space
278	nop
279	GET_CPU_PCPU(v1)
280	PTR_L	v1, PC_CURPCB(v1)
281	PTR_S	v0, U_PCB_ONFAULT(v1)
282	lbu	v0, 0(a0)		# fetch byte
283	j	ra
284	PTR_S	zero, U_PCB_ONFAULT(v1)
285END(fubyte)
286
287LEAF(suword32)
288#ifndef __mips_n64
289XLEAF(suword)
290#endif
291	PTR_LA	v0, fswberr
292	blt	a0, zero, fswberr	# make sure address is in user space
293	nop
294	GET_CPU_PCPU(v1)
295	PTR_L	v1, PC_CURPCB(v1)
296	PTR_S	v0, U_PCB_ONFAULT(v1)
297	sw	a1, 0(a0)		# store word
298	PTR_S	zero, U_PCB_ONFAULT(v1)
299	j	ra
300	move	v0, zero
301END(suword32)
302
303#ifdef __mips_n64
304LEAF(suword64)
305XLEAF(suword)
306	PTR_LA	v0, fswberr
307	blt	a0, zero, fswberr	# make sure address is in user space
308	nop
309	GET_CPU_PCPU(v1)
310	PTR_L	v1, PC_CURPCB(v1)
311	PTR_S	v0, U_PCB_ONFAULT(v1)
312	sd	a1, 0(a0)		# store word
313	PTR_S	zero, U_PCB_ONFAULT(v1)
314	j	ra
315	move	v0, zero
316END(suword64)
317#endif
318
319/*
320 * casueword(9)
321 * <v0>u_long casueword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long *oldval_p,
322 *		       <a3>u_long newval)
323 */
324/*
325 * casueword32(9)
326 * <v0>uint32_t casueword(<a0>uint32_t *p, <a1>uint32_t oldval,
327 *			 <a2>uint32_t newval)
328 */
329LEAF(casueword32)
330#ifndef __mips_n64
331XLEAF(casueword)
332#endif
333	PTR_LA	v0, fswberr
334	blt	a0, zero, fswberr	# make sure address is in user space
335	nop
336	GET_CPU_PCPU(v1)
337	PTR_L	v1, PC_CURPCB(v1)
338	PTR_S	v0, U_PCB_ONFAULT(v1)
339
340	li	v0, 1
341	move	t0, a3
342	ll	t1, 0(a0)
343	bne	a1, t1, 1f
344	nop
345	sc	t0, 0(a0)		# store word
346	xori	v0, t0, 1
3471:
348	PTR_S	zero, U_PCB_ONFAULT(v1)
349	jr	ra
350	sw	t1, 0(a2)		# unconditionally store old word
351END(casueword32)
352
353#ifdef __mips_n64
354LEAF(casueword64)
355XLEAF(casueword)
356	PTR_LA	v0, fswberr
357	blt	a0, zero, fswberr	# make sure address is in user space
358	nop
359	GET_CPU_PCPU(v1)
360	PTR_L	v1, PC_CURPCB(v1)
361	PTR_S	v0, U_PCB_ONFAULT(v1)
362
363	li	v0, 1
364	move	t0, a3
365	lld	t1, 0(a0)
366	bne	a1, t1, 1f
367	nop
368	scd	t0, 0(a0)		# store double word
369	xori	v0, t0, 1
3701:
371	PTR_S	zero, U_PCB_ONFAULT(v1)
372	jr	ra
373	sd	t1, 0(a2)		# unconditionally store old word
374END(casueword64)
375#endif
376
377/*
378 * Will have to flush the instruction cache if byte merging is done in hardware.
379 */
380LEAF(susword)
381	PTR_LA	v0, fswberr
382	blt	a0, zero, fswberr	# make sure address is in user space
383	nop
384	GET_CPU_PCPU(v1)
385	PTR_L	v1, PC_CURPCB(v1)
386	PTR_S	v0, U_PCB_ONFAULT(v1)
387	sh	a1, 0(a0)		# store short
388	PTR_S	zero, U_PCB_ONFAULT(v1)
389	j	ra
390	move	v0, zero
391END(susword)
392
393LEAF(subyte)
394	PTR_LA	v0, fswberr
395	blt	a0, zero, fswberr	# make sure address is in user space
396	nop
397	GET_CPU_PCPU(v1)
398	PTR_L	v1, PC_CURPCB(v1)
399	PTR_S	v0, U_PCB_ONFAULT(v1)
400	sb	a1, 0(a0)		# store byte
401	PTR_S	zero, U_PCB_ONFAULT(v1)
402	j	ra
403	move	v0, zero
404END(subyte)
405
406LEAF(fswberr)
407	j	ra
408	li	v0, -1
409END(fswberr)
410
411/*
412 * memset(void *s1, int c, int len)
413 * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp
414 */
415LEAF(memset)
416	.set noreorder
417	blt	a2, 12, memsetsmallclr	# small amount to clear?
418	move	v0, a0			# save s1 for result
419
420	sll	t1, a1, 8		# compute  c << 8 in t1
421	or	t1, t1, a1		# compute c << 8 | c in 11
422	sll	t2, t1, 16		# shift that left 16
423	or	t1, t2, t1		# or together
424
425	PTR_SUBU	t0, zero, a0		# compute # bytes to word align address
426	and	t0, t0, 3
427	beq	t0, zero, 1f		# skip if word aligned
428	PTR_SUBU	a2, a2, t0		# subtract from remaining count
429	SWHI	t1, 0(a0)		# store 1, 2, or 3 bytes to align
430	PTR_ADDU	a0, a0, t0
4311:
432	and	v1, a2, 3		# compute number of whole words left
433	PTR_SUBU	t0, a2, v1
434	PTR_SUBU	a2, a2, t0
435	PTR_ADDU	t0, t0, a0		# compute ending address
4362:
437	PTR_ADDU	a0, a0, 4		# clear words
438	bne	a0, t0, 2b		#  unrolling loop does not help
439	sw	t1, -4(a0)		#  since we are limited by memory speed
440
441memsetsmallclr:
442	ble	a2, zero, 2f
443	PTR_ADDU	t0, a2, a0		# compute ending address
4441:
445	PTR_ADDU	a0, a0, 1		# clear bytes
446	bne	a0, t0, 1b
447	sb	a1, -1(a0)
4482:
449	j	ra
450	nop
451	.set reorder
452END(memset)
453
454/*
455 * bzero(s1, n)
456 */
457LEAF(bzero)
458XLEAF(blkclr)
459	.set	noreorder
460	blt	a1, 12, smallclr	# small amount to clear?
461	PTR_SUBU	a3, zero, a0		# compute # bytes to word align address
462	and	a3, a3, 3
463	beq	a3, zero, 1f		# skip if word aligned
464	PTR_SUBU	a1, a1, a3		# subtract from remaining count
465	SWHI	zero, 0(a0)		# clear 1, 2, or 3 bytes to align
466	PTR_ADDU	a0, a0, a3
4671:
468	and	v0, a1, 3		# compute number of words left
469	PTR_SUBU	a3, a1, v0
470	move	a1, v0
471	PTR_ADDU	a3, a3, a0		# compute ending address
4722:
473	PTR_ADDU	a0, a0, 4		# clear words
474	bne	a0, a3, 2b		#  unrolling loop does not help
475	sw	zero, -4(a0)		#  since we are limited by memory speed
476smallclr:
477	ble	a1, zero, 2f
478	PTR_ADDU	a3, a1, a0		# compute ending address
4791:
480	PTR_ADDU	a0, a0, 1		# clear bytes
481	bne	a0, a3, 1b
482	sb	zero, -1(a0)
4832:
484	j	ra
485	nop
486END(bzero)
487
488
489/*
490 * bcmp(s1, s2, n)
491 */
492LEAF(bcmp)
493	.set	noreorder
494	blt	a2, 16, smallcmp	# is it worth any trouble?
495	xor	v0, a0, a1		# compare low two bits of addresses
496	and	v0, v0, 3
497	PTR_SUBU	a3, zero, a1		# compute # bytes to word align address
498	bne	v0, zero, unalignedcmp	# not possible to align addresses
499	and	a3, a3, 3
500
501	beq	a3, zero, 1f
502	PTR_SUBU	a2, a2, a3		# subtract from remaining count
503	move	v0, v1			# init v0,v1 so unmodified bytes match
504	LWHI	v0, 0(a0)		# read 1, 2, or 3 bytes
505	LWHI	v1, 0(a1)
506	PTR_ADDU	a1, a1, a3
507	bne	v0, v1, nomatch
508	PTR_ADDU	a0, a0, a3
5091:
510	and	a3, a2, ~3		# compute number of whole words left
511	PTR_SUBU	a2, a2, a3		#   which has to be >= (16-3) & ~3
512	PTR_ADDU	a3, a3, a0		# compute ending address
5132:
514	lw	v0, 0(a0)		# compare words
515	lw	v1, 0(a1)
516	PTR_ADDU	a0, a0, 4
517	bne	v0, v1, nomatch
518	PTR_ADDU	a1, a1, 4
519	bne	a0, a3, 2b
520	nop
521	b	smallcmp		# finish remainder
522	nop
523unalignedcmp:
524	beq	a3, zero, 2f
525	PTR_SUBU	a2, a2, a3		# subtract from remaining count
526	PTR_ADDU	a3, a3, a0		# compute ending address
5271:
528	lbu	v0, 0(a0)		# compare bytes until a1 word aligned
529	lbu	v1, 0(a1)
530	PTR_ADDU	a0, a0, 1
531	bne	v0, v1, nomatch
532	PTR_ADDU	a1, a1, 1
533	bne	a0, a3, 1b
534	nop
5352:
536	and	a3, a2, ~3		# compute number of whole words left
537	PTR_SUBU	a2, a2, a3		#   which has to be >= (16-3) & ~3
538	PTR_ADDU	a3, a3, a0		# compute ending address
5393:
540	LWHI	v0, 0(a0)		# compare words a0 unaligned, a1 aligned
541	LWLO	v0, 3(a0)
542	lw	v1, 0(a1)
543	PTR_ADDU	a0, a0, 4
544	bne	v0, v1, nomatch
545	PTR_ADDU	a1, a1, 4
546	bne	a0, a3, 3b
547	nop
548smallcmp:
549	ble	a2, zero, match
550	PTR_ADDU	a3, a2, a0		# compute ending address
5511:
552	lbu	v0, 0(a0)
553	lbu	v1, 0(a1)
554	PTR_ADDU	a0, a0, 1
555	bne	v0, v1, nomatch
556	PTR_ADDU	a1, a1, 1
557	bne	a0, a3, 1b
558	nop
559match:
560	j	ra
561	 move	v0, zero
562nomatch:
563	j	ra
564	li	v0, 1
565END(bcmp)
566
567
568/*
569 * bit = ffs(value)
570 */
571LEAF(ffs)
572	.set	noreorder
573	beq	a0, zero, 2f
574	move	v0, zero
5751:
576	and	v1, a0, 1		# bit set?
577	addu	v0, v0, 1
578	beq	v1, zero, 1b		# no, continue
579	srl	a0, a0, 1
5802:
581	j	ra
582	nop
583END(ffs)
584
585/**
586 * void
587 * atomic_set_16(u_int16_t *a, u_int16_t b)
588 * {
589 *	*a |= b;
590 * }
591 */
592LEAF(atomic_set_16)
593	.set	noreorder
594	srl	a0, a0, 2	# round down address to be 32-bit aligned
595	sll	a0, a0, 2
596	andi	a1, a1, 0xffff
5971:
598	ll	t0, 0(a0)
599	or	t0, t0, a1
600	sc	t0, 0(a0)
601	beq	t0, zero, 1b
602	nop
603	j	ra
604	nop
605END(atomic_set_16)
606
607/**
608 * void
609 * atomic_clear_16(u_int16_t *a, u_int16_t b)
610 * {
611 *	*a &= ~b;
612 * }
613 */
614LEAF(atomic_clear_16)
615	.set	noreorder
616	srl	a0, a0, 2	# round down address to be 32-bit aligned
617	sll	a0, a0, 2
618	nor	a1, zero, a1
6191:
620	ll	t0, 0(a0)
621	move	t1, t0
622	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
623	and	t1, t1, a1	# t1 has the new lower 16 bits
624	srl	t0, t0, 16	# preserve original top 16 bits
625	sll	t0, t0, 16
626	or	t0, t0, t1
627	sc	t0, 0(a0)
628	beq	t0, zero, 1b
629	nop
630	j	ra
631	nop
632END(atomic_clear_16)
633
634
635/**
636 * void
637 * atomic_subtract_16(uint16_t *a, uint16_t b)
638 * {
639 *	*a -= b;
640 * }
641 */
642LEAF(atomic_subtract_16)
643	.set	noreorder
644	srl	a0, a0, 2	# round down address to be 32-bit aligned
645	sll	a0, a0, 2
6461:
647	ll	t0, 0(a0)
648	move	t1, t0
649	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
650	subu	t1, t1, a1
651	andi	t1, t1, 0xffff	# t1 has the new lower 16 bits
652	srl	t0, t0, 16	# preserve original top 16 bits
653	sll	t0, t0, 16
654	or	t0, t0, t1
655	sc	t0, 0(a0)
656	beq	t0, zero, 1b
657	nop
658	j	ra
659	nop
660END(atomic_subtract_16)
661
662/**
663 * void
664 * atomic_add_16(uint16_t *a, uint16_t b)
665 * {
666 *	*a += b;
667 * }
668 */
669LEAF(atomic_add_16)
670	.set	noreorder
671	srl	a0, a0, 2	# round down address to be 32-bit aligned
672	sll	a0, a0, 2
6731:
674	ll	t0, 0(a0)
675	move	t1, t0
676	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
677	addu	t1, t1, a1
678	andi	t1, t1, 0xffff	# t1 has the new lower 16 bits
679	srl	t0, t0, 16	# preserve original top 16 bits
680	sll	t0, t0, 16
681	or	t0, t0, t1
682	sc	t0, 0(a0)
683	beq	t0, zero, 1b
684	nop
685	j	ra
686	nop
687END(atomic_add_16)
688
689/**
690 * void
691 * atomic_add_8(uint8_t *a, uint8_t b)
692 * {
693 *	*a += b;
694 * }
695 */
696LEAF(atomic_add_8)
697	.set	noreorder
698	srl	a0, a0, 2	# round down address to be 32-bit aligned
699	sll	a0, a0, 2
7001:
701	ll	t0, 0(a0)
702	move	t1, t0
703	andi	t1, t1, 0xff	# t1 has the original lower 8 bits
704	addu	t1, t1, a1
705	andi	t1, t1, 0xff	# t1 has the new lower 8 bits
706	srl	t0, t0, 8	# preserve original top 24 bits
707	sll	t0, t0, 8
708	or	t0, t0, t1
709	sc	t0, 0(a0)
710	beq	t0, zero, 1b
711	nop
712	j	ra
713	nop
714END(atomic_add_8)
715
716
717/**
718 * void
719 * atomic_subtract_8(uint8_t *a, uint8_t b)
720 * {
721 *	*a += b;
722 * }
723 */
724LEAF(atomic_subtract_8)
725	.set	noreorder
726	srl	a0, a0, 2	# round down address to be 32-bit aligned
727	sll	a0, a0, 2
7281:
729	ll	t0, 0(a0)
730	move	t1, t0
731	andi	t1, t1, 0xff	# t1 has the original lower 8 bits
732	subu	t1, t1, a1
733	andi	t1, t1, 0xff	# t1 has the new lower 8 bits
734	srl	t0, t0, 8	# preserve original top 24 bits
735	sll	t0, t0, 8
736	or	t0, t0, t1
737	sc	t0, 0(a0)
738	beq	t0, zero, 1b
739	nop
740	j	ra
741	nop
742END(atomic_subtract_8)
743
744	.set	noreorder		# Noreorder is default style!
745
746#if defined(DDB) || defined(DEBUG)
747
748LEAF(kdbpeek)
749	PTR_LA	v1, ddberr
750	and	v0, a0, 3			# unaligned ?
751	GET_CPU_PCPU(t1)
752	PTR_L	t1, PC_CURPCB(t1)
753	bne	v0, zero, 1f
754	PTR_S	v1, U_PCB_ONFAULT(t1)
755
756	lw	v0, (a0)
757	jr	ra
758	PTR_S	zero, U_PCB_ONFAULT(t1)
759
7601:
761	LWHI	v0, 0(a0)
762	LWLO	v0, 3(a0)
763	jr	ra
764	PTR_S	zero, U_PCB_ONFAULT(t1)
765END(kdbpeek)
766
767LEAF(kdbpeekd)
768	PTR_LA	v1, ddberr
769	and	v0, a0, 3			# unaligned ?
770	GET_CPU_PCPU(t1)
771	PTR_L	t1, PC_CURPCB(t1)
772	bne	v0, zero, 1f
773	PTR_S	v1, U_PCB_ONFAULT(t1)
774
775	ld	v0, (a0)
776	jr	ra
777	PTR_S	zero, U_PCB_ONFAULT(t1)
778
7791:
780	REG_LHI	v0, 0(a0)
781	REG_LLO	v0, 7(a0)
782	jr	ra
783	PTR_S	zero, U_PCB_ONFAULT(t1)
784END(kdbpeekd)
785
786ddberr:
787	jr	ra
788	nop
789
790#if defined(DDB)
791LEAF(kdbpoke)
792	PTR_LA	v1, ddberr
793	and	v0, a0, 3			# unaligned ?
794	GET_CPU_PCPU(t1)
795	PTR_L	t1, PC_CURPCB(t1)
796	bne	v0, zero, 1f
797	PTR_S	v1, U_PCB_ONFAULT(t1)
798
799	sw	a1, (a0)
800	jr	ra
801	PTR_S	zero, U_PCB_ONFAULT(t1)
802
8031:
804	SWHI	a1, 0(a0)
805	SWLO	a1, 3(a0)
806	jr	ra
807	PTR_S	zero, U_PCB_ONFAULT(t1)
808END(kdbpoke)
809
810	.data
811	.globl	esym
812esym:	.word	0
813
814#endif /* DDB */
815#endif /* DDB || DEBUG */
816
817	.text
818LEAF(breakpoint)
819	break	MIPS_BREAK_SOVER_VAL
820	jr	ra
821	nop
822END(breakpoint)
823
824LEAF(setjmp)
825	mfc0	v0, MIPS_COP_0_STATUS	# Later the "real" spl value!
826	REG_S	s0, (SZREG * PCB_REG_S0)(a0)
827	REG_S	s1, (SZREG * PCB_REG_S1)(a0)
828	REG_S	s2, (SZREG * PCB_REG_S2)(a0)
829	REG_S	s3, (SZREG * PCB_REG_S3)(a0)
830	REG_S	s4, (SZREG * PCB_REG_S4)(a0)
831	REG_S	s5, (SZREG * PCB_REG_S5)(a0)
832	REG_S	s6, (SZREG * PCB_REG_S6)(a0)
833	REG_S	s7, (SZREG * PCB_REG_S7)(a0)
834	REG_S	s8, (SZREG * PCB_REG_S8)(a0)
835	REG_S	sp, (SZREG * PCB_REG_SP)(a0)
836	REG_S	ra, (SZREG * PCB_REG_RA)(a0)
837	REG_S	v0, (SZREG * PCB_REG_SR)(a0)
838	jr	ra
839	li	v0, 0			# setjmp return
840END(setjmp)
841
842LEAF(longjmp)
843	REG_L	v0, (SZREG * PCB_REG_SR)(a0)
844	REG_L	ra, (SZREG * PCB_REG_RA)(a0)
845	REG_L	s0, (SZREG * PCB_REG_S0)(a0)
846	REG_L	s1, (SZREG * PCB_REG_S1)(a0)
847	REG_L	s2, (SZREG * PCB_REG_S2)(a0)
848	REG_L	s3, (SZREG * PCB_REG_S3)(a0)
849	REG_L	s4, (SZREG * PCB_REG_S4)(a0)
850	REG_L	s5, (SZREG * PCB_REG_S5)(a0)
851	REG_L	s6, (SZREG * PCB_REG_S6)(a0)
852	REG_L	s7, (SZREG * PCB_REG_S7)(a0)
853	REG_L	s8, (SZREG * PCB_REG_S8)(a0)
854	REG_L	sp, (SZREG * PCB_REG_SP)(a0)
855	mtc0	v0, MIPS_COP_0_STATUS	# Later the "real" spl value!
856	ITLBNOPFIX
857	jr	ra
858	li	v0, 1			# longjmp return
859END(longjmp)
860
861LEAF(mips3_ld)
862	.set push
863	.set noreorder
864	.set mips64
865#if defined(__mips_o32)
866	mfc0	t0, MIPS_COP_0_STATUS		# turn off interrupts
867	and	t1, t0, ~(MIPS_SR_INT_IE)
868	mtc0	t1, MIPS_COP_0_STATUS
869	COP0_SYNC
870	nop
871	nop
872	nop
873
874	ld	v0, 0(a0)
875#if _BYTE_ORDER == _BIG_ENDIAN
876	dsll	v1, v0, 32
877	dsra	v1, v1, 32			# low word in v1
878	dsra	v0, v0, 32			# high word in v0
879#else
880	dsra	v1, v0, 32			# high word in v1
881	dsll	v0, v0, 32
882	dsra	v0, v0, 32			# low word in v0
883#endif
884
885	mtc0	t0, MIPS_COP_0_STATUS		# restore intr status.
886	COP0_SYNC
887	nop
888#else /* !__mips_o32 */
889	ld	v0, 0(a0)
890#endif /* !__mips_o32 */
891
892	jr	ra
893	nop
894	.set pop
895END(mips3_ld)
896
897LEAF(mips3_sd)
898	.set push
899	.set mips64
900	.set noreorder
901#if defined(__mips_o32)
902	mfc0	t0, MIPS_COP_0_STATUS		# turn off interrupts
903	and	t1, t0, ~(MIPS_SR_INT_IE)
904	mtc0	t1, MIPS_COP_0_STATUS
905	COP0_SYNC
906	nop
907	nop
908	nop
909
910	# NOTE: a1 is padding!
911
912#if _BYTE_ORDER == _BIG_ENDIAN
913	dsll	a2, a2, 32			# high word in a2
914	dsll	a3, a3, 32			# low word in a3
915	dsrl	a3, a3, 32
916#else
917	dsll	a2, a2, 32			# low word in a2
918	dsrl	a2, a2, 32
919	dsll	a3, a3, 32			# high word in a3
920#endif
921	or	a1, a2, a3
922	sd	a1, 0(a0)
923
924	mtc0	t0, MIPS_COP_0_STATUS		# restore intr status.
925	COP0_SYNC
926	nop
927#else /* !__mips_o32 */
928	sd	a1, 0(a0)
929#endif /* !__mips_o32 */
930
931	jr	ra
932	nop
933	.set pop
934END(mips3_sd)
935