support.S revision 327195
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/11/sys/mips/mips/support.S 327195 2017-12-26 10:07:17Z 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.s"
98
99	.set	noreorder		# Noreorder is default style!
100
101/*
102 * Primitives
103 */
104
105	.text
106
107/*
108 * See if access to addr with a len type instruction causes a machine check.
109 * len is length of access (1=byte, 2=short, 4=int)
110 *
111 * badaddr(addr, len)
112 *	char *addr;
113 *	int len;
114 */
115LEAF(badaddr)
116	PTR_LA	v0, baderr
117	GET_CPU_PCPU(v1)
118	PTR_L	v1, PC_CURPCB(v1)
119	bne	a1, 1, 2f
120	PTR_S	v0, U_PCB_ONFAULT(v1)
121	b	5f
122	lbu	v0, (a0)
1232:
124	bne	a1, 2, 4f
125	nop
126	b	5f
127	lhu	v0, (a0)
1284:
129	lw	v0, (a0)
1305:
131	PTR_S	zero, U_PCB_ONFAULT(v1)
132	j	ra
133	move	v0, zero		# made it w/o errors
134baderr:
135	j	ra
136	li	v0, 1			# trap sends us here
137END(badaddr)
138
139/*
140 * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied)
141 * Copy a NIL-terminated string, at most maxlen characters long.  Return the
142 * number of characters copied (including the NIL) in *lencopied.  If the
143 * string is too long, return ENAMETOOLONG; else return 0.
144 */
145LEAF(copystr)
146	move		t0, a2
147	beq		a2, zero, 4f
1481:
149	lbu		v0, 0(a0)
150	PTR_SUBU	a2, a2, 1
151	beq		v0, zero, 2f
152	sb		v0, 0(a1)		# each byte until NIL
153	PTR_ADDU	a0, a0, 1
154	bne		a2, zero, 1b		# less than maxlen
155	PTR_ADDU	a1, a1, 1
1564:
157	li		v0, ENAMETOOLONG	# run out of space
1582:
159	beq		a3, zero, 3f		# return num. of copied bytes
160	PTR_SUBU	a2, t0, a2		# if the 4th arg was non-NULL
161	PTR_S		a2, 0(a3)
1623:
163	j		ra			# v0 is 0 or ENAMETOOLONG
164	nop
165END(copystr)
166
167
168/*
169 * Copy a null terminated string from the user address space into
170 * the kernel address space.
171 *
172 *	copyinstr(fromaddr, toaddr, maxlength, &lencopied)
173 *		caddr_t fromaddr;
174 *		caddr_t toaddr;
175 *		u_int maxlength;
176 *		u_int *lencopied;
177 */
178NESTED(copyinstr, CALLFRAME_SIZ, ra)
179	PTR_SUBU	sp, sp, CALLFRAME_SIZ
180	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
181	PTR_LA	v0, copyerr
182	blt	a0, zero, _C_LABEL(copyerr)  # make sure address is in user space
183	REG_S	ra, CALLFRAME_RA(sp)
184	GET_CPU_PCPU(v1)
185	PTR_L	v1, PC_CURPCB(v1)
186	jal	_C_LABEL(copystr)
187	PTR_S	v0, U_PCB_ONFAULT(v1)
188	REG_L	ra, CALLFRAME_RA(sp)
189	GET_CPU_PCPU(v1)
190	PTR_L	v1, PC_CURPCB(v1)
191	PTR_S	zero, U_PCB_ONFAULT(v1)
192	j	ra
193	PTR_ADDU	sp, sp, CALLFRAME_SIZ
194END(copyinstr)
195
196/*
197 * Copy a null terminated string from the kernel address space into
198 * the user address space.
199 *
200 *	copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
201 *		caddr_t fromaddr;
202 *		caddr_t toaddr;
203 *		u_int maxlength;
204 *		u_int *lencopied;
205 */
206NESTED(copyoutstr, CALLFRAME_SIZ, ra)
207	PTR_SUBU	sp, sp, CALLFRAME_SIZ
208	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
209	PTR_LA	v0, copyerr
210	blt	a1, zero, _C_LABEL(copyerr)  # make sure address is in user space
211	REG_S	ra, CALLFRAME_RA(sp)
212	GET_CPU_PCPU(v1)
213	PTR_L	v1, PC_CURPCB(v1)
214	jal	_C_LABEL(copystr)
215	PTR_S	v0, U_PCB_ONFAULT(v1)
216	REG_L	ra, CALLFRAME_RA(sp)
217	GET_CPU_PCPU(v1)
218	PTR_L	v1, PC_CURPCB(v1)
219	PTR_S	zero, U_PCB_ONFAULT(v1)
220	j	ra
221	PTR_ADDU	sp, sp, CALLFRAME_SIZ
222END(copyoutstr)
223
224/*
225 * Copy specified amount of data from user space into the kernel
226 *	copyin(from, to, len)
227 *		caddr_t *from;	(user source address)
228 *		caddr_t *to;	(kernel destination address)
229 *		unsigned len;
230 */
231NESTED(copyin, CALLFRAME_SIZ, ra)
232	PTR_SUBU	sp, sp, CALLFRAME_SIZ
233	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
234	PTR_LA	v0, copyerr
235	blt	a0, zero, _C_LABEL(copyerr)  # make sure address is in user space
236	REG_S	ra, CALLFRAME_RA(sp)
237	GET_CPU_PCPU(v1)
238	PTR_L	v1, PC_CURPCB(v1)
239	jal	_C_LABEL(bcopy)
240	PTR_S	v0, U_PCB_ONFAULT(v1)
241	REG_L	ra, CALLFRAME_RA(sp)
242	GET_CPU_PCPU(v1)
243	PTR_L	v1, PC_CURPCB(v1)	 	# bcopy modified v1, so reload
244	PTR_S	zero, U_PCB_ONFAULT(v1)
245	PTR_ADDU	sp, sp, CALLFRAME_SIZ
246	j	ra
247	move	v0, zero
248END(copyin)
249
250/*
251 * Copy specified amount of data from kernel to the user space
252 *	copyout(from, to, len)
253 *		caddr_t *from;	(kernel source address)
254 *		caddr_t *to;	(user destination address)
255 *		unsigned len;
256 */
257NESTED(copyout, CALLFRAME_SIZ, ra)
258	PTR_SUBU	sp, sp, CALLFRAME_SIZ
259	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
260	PTR_LA	v0, copyerr
261	blt	a1, zero, _C_LABEL(copyerr) # make sure address is in user space
262	REG_S	ra, CALLFRAME_RA(sp)
263	GET_CPU_PCPU(v1)
264	PTR_L	v1, PC_CURPCB(v1)
265	jal	_C_LABEL(bcopy)
266	PTR_S	v0, U_PCB_ONFAULT(v1)
267	REG_L	ra, CALLFRAME_RA(sp)
268	GET_CPU_PCPU(v1)
269	PTR_L	v1, PC_CURPCB(v1)	 	# bcopy modified v1, so reload
270	PTR_S	zero, U_PCB_ONFAULT(v1)
271	PTR_ADDU	sp, sp, CALLFRAME_SIZ
272	j	ra
273	move	v0, zero
274END(copyout)
275
276LEAF(copyerr)
277	REG_L	ra, CALLFRAME_RA(sp)
278	PTR_ADDU	sp, sp, CALLFRAME_SIZ
279	j	ra
280	li	v0, EFAULT			# return error
281END(copyerr)
282
283/*
284 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
285 * user text space.
286 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
287 * user data space.
288 */
289#ifdef __mips_n64
290LEAF(fuword64)
291XLEAF(fuword)
292	PTR_LA	v0, fswberr
293	blt	a0, zero, fswberr	# make sure address is in user space
294	nop
295	GET_CPU_PCPU(v1)
296	PTR_L	v1, PC_CURPCB(v1)
297	PTR_S	v0, U_PCB_ONFAULT(v1)
298	ld	v0, 0(a0)		# fetch word
299	j	ra
300	PTR_S	zero, U_PCB_ONFAULT(v1)
301END(fuword64)
302#endif
303
304LEAF(fuword32)
305#ifndef __mips_n64
306XLEAF(fuword)
307#endif
308	PTR_LA	v0, fswberr
309	blt	a0, zero, fswberr	# make sure address is in user space
310	nop
311	GET_CPU_PCPU(v1)
312	PTR_L	v1, PC_CURPCB(v1)
313	PTR_S	v0, U_PCB_ONFAULT(v1)
314	lw	v0, 0(a0)		# fetch word
315	j	ra
316	PTR_S	zero, U_PCB_ONFAULT(v1)
317END(fuword32)
318
319LEAF(fusword)
320	PTR_LA	v0, fswberr
321	blt	a0, zero, fswberr	# make sure address is in user space
322	nop
323	GET_CPU_PCPU(v1)
324	PTR_L	v1, PC_CURPCB(v1)
325	PTR_S	v0, U_PCB_ONFAULT(v1)
326	lhu	v0, 0(a0)		# fetch short
327	j	ra
328	PTR_S	zero, U_PCB_ONFAULT(v1)
329END(fusword)
330
331LEAF(fubyte)
332	PTR_LA	v0, fswberr
333	blt	a0, zero, fswberr	# make sure address is in user space
334	nop
335	GET_CPU_PCPU(v1)
336	PTR_L	v1, PC_CURPCB(v1)
337	PTR_S	v0, U_PCB_ONFAULT(v1)
338	lbu	v0, 0(a0)		# fetch byte
339	j	ra
340	PTR_S	zero, U_PCB_ONFAULT(v1)
341END(fubyte)
342
343LEAF(suword32)
344#ifndef __mips_n64
345XLEAF(suword)
346#endif
347	PTR_LA	v0, fswberr
348	blt	a0, zero, fswberr	# make sure address is in user space
349	nop
350	GET_CPU_PCPU(v1)
351	PTR_L	v1, PC_CURPCB(v1)
352	PTR_S	v0, U_PCB_ONFAULT(v1)
353	sw	a1, 0(a0)		# store word
354	PTR_S	zero, U_PCB_ONFAULT(v1)
355	j	ra
356	move	v0, zero
357END(suword32)
358
359#ifdef __mips_n64
360LEAF(suword64)
361XLEAF(suword)
362	PTR_LA	v0, fswberr
363	blt	a0, zero, fswberr	# make sure address is in user space
364	nop
365	GET_CPU_PCPU(v1)
366	PTR_L	v1, PC_CURPCB(v1)
367	PTR_S	v0, U_PCB_ONFAULT(v1)
368	sd	a1, 0(a0)		# store word
369	PTR_S	zero, U_PCB_ONFAULT(v1)
370	j	ra
371	move	v0, zero
372END(suword64)
373#endif
374
375/*
376 * casuword(9)
377 * <v0>u_long casuword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long newval)
378 */
379/*
380 * casuword32(9)
381 * <v0>uint32_t casuword(<a0>uint32_t *p, <a1>uint32_t oldval,
382 *							<a2>uint32_t newval)
383 */
384LEAF(casuword32)
385#ifndef __mips_n64
386XLEAF(casuword)
387#endif
388	PTR_LA	v0, fswberr
389	blt	a0, zero, fswberr	# make sure address is in user space
390	nop
391	GET_CPU_PCPU(v1)
392	PTR_L	v1, PC_CURPCB(v1)
393	PTR_S	v0, U_PCB_ONFAULT(v1)
3941:
395	move	t0, a2
396	ll	v0, 0(a0)
397	bne	a1, v0, 2f
398	nop
399	sc	t0, 0(a0)		# store word
400	beqz	t0, 1b
401	nop
402	j	3f
403	nop
4042:
405	li	v0, -1
4063:
407	PTR_S	zero, U_PCB_ONFAULT(v1)
408	jr	ra
409	nop
410END(casuword32)
411
412#ifdef __mips_n64
413LEAF(casuword64)
414XLEAF(casuword)
415	PTR_LA	v0, fswberr
416	blt	a0, zero, fswberr	# make sure address is in user space
417	nop
418	GET_CPU_PCPU(v1)
419	PTR_L	v1, PC_CURPCB(v1)
420	PTR_S	v0, U_PCB_ONFAULT(v1)
4211:
422	move	t0, a2
423	lld	v0, 0(a0)
424	bne	a1, v0, 2f
425	nop
426	scd	t0, 0(a0)		# store double word
427	beqz	t0, 1b
428	nop
429	j	3f
430	nop
4312:
432	li	v0, -1
4333:
434	PTR_S	zero, U_PCB_ONFAULT(v1)
435	jr	ra
436	nop
437END(casuword64)
438#endif
439
440/*
441 * Will have to flush the instruction cache if byte merging is done in hardware.
442 */
443LEAF(susword)
444	PTR_LA	v0, fswberr
445	blt	a0, zero, fswberr	# make sure address is in user space
446	nop
447	GET_CPU_PCPU(v1)
448	PTR_L	v1, PC_CURPCB(v1)
449	PTR_S	v0, U_PCB_ONFAULT(v1)
450	sh	a1, 0(a0)		# store short
451	PTR_S	zero, U_PCB_ONFAULT(v1)
452	j	ra
453	move	v0, zero
454END(susword)
455
456LEAF(subyte)
457	PTR_LA	v0, fswberr
458	blt	a0, zero, fswberr	# make sure address is in user space
459	nop
460	GET_CPU_PCPU(v1)
461	PTR_L	v1, PC_CURPCB(v1)
462	PTR_S	v0, U_PCB_ONFAULT(v1)
463	sb	a1, 0(a0)		# store byte
464	PTR_S	zero, U_PCB_ONFAULT(v1)
465	j	ra
466	move	v0, zero
467END(subyte)
468
469LEAF(fswberr)
470	j	ra
471	li	v0, -1
472END(fswberr)
473
474/*
475 * fuswintr and suswintr are just like fusword and susword except that if
476 * the page is not in memory or would cause a trap, then we return an error.
477 * The important thing is to prevent sleep() and switch().
478 */
479LEAF(fuswintr)
480	PTR_LA	v0, fswintrberr
481	blt	a0, zero, fswintrberr	# make sure address is in user space
482	nop
483	GET_CPU_PCPU(v1)
484	PTR_L	v1, PC_CURPCB(v1)
485	PTR_S	v0, U_PCB_ONFAULT(v1)
486	lhu	v0, 0(a0)		# fetch short
487	j	ra
488	PTR_S	zero, U_PCB_ONFAULT(v1)
489END(fuswintr)
490
491LEAF(suswintr)
492	PTR_LA	v0, fswintrberr
493	blt	a0, zero, fswintrberr	# make sure address is in user space
494	nop
495	GET_CPU_PCPU(v1)
496	PTR_L	v1, PC_CURPCB(v1)
497	PTR_S	v0, U_PCB_ONFAULT(v1)
498	sh	a1, 0(a0)		# store short
499	PTR_S	zero, U_PCB_ONFAULT(v1)
500	j	ra
501	move	v0, zero
502END(suswintr)
503
504LEAF(fswintrberr)
505	j	ra
506	li	v0, -1
507END(fswintrberr)
508
509/*
510 * memset(void *s1, int c, int len)
511 * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp
512 */
513LEAF(memset)
514	.set noreorder
515	blt	a2, 12, memsetsmallclr	# small amount to clear?
516	move	v0, a0			# save s1 for result
517
518	sll	t1, a1, 8		# compute  c << 8 in t1
519	or	t1, t1, a1		# compute c << 8 | c in 11
520	sll	t2, t1, 16		# shift that left 16
521	or	t1, t2, t1		# or together
522
523	PTR_SUBU	t0, zero, a0		# compute # bytes to word align address
524	and	t0, t0, 3
525	beq	t0, zero, 1f		# skip if word aligned
526	PTR_SUBU	a2, a2, t0		# subtract from remaining count
527	SWHI	t1, 0(a0)		# store 1, 2, or 3 bytes to align
528	PTR_ADDU	a0, a0, t0
5291:
530	and	v1, a2, 3		# compute number of whole words left
531	PTR_SUBU	t0, a2, v1
532	PTR_SUBU	a2, a2, t0
533	PTR_ADDU	t0, t0, a0		# compute ending address
5342:
535	PTR_ADDU	a0, a0, 4		# clear words
536	bne	a0, t0, 2b		#  unrolling loop does not help
537	sw	t1, -4(a0)		#  since we are limited by memory speed
538
539memsetsmallclr:
540	ble	a2, zero, 2f
541	PTR_ADDU	t0, a2, a0		# compute ending address
5421:
543	PTR_ADDU	a0, a0, 1		# clear bytes
544	bne	a0, t0, 1b
545	sb	a1, -1(a0)
5462:
547	j	ra
548	nop
549	.set reorder
550END(memset)
551
552/*
553 * bzero(s1, n)
554 */
555LEAF(bzero)
556XLEAF(blkclr)
557	.set	noreorder
558	blt	a1, 12, smallclr	# small amount to clear?
559	PTR_SUBU	a3, zero, a0		# compute # bytes to word align address
560	and	a3, a3, 3
561	beq	a3, zero, 1f		# skip if word aligned
562	PTR_SUBU	a1, a1, a3		# subtract from remaining count
563	SWHI	zero, 0(a0)		# clear 1, 2, or 3 bytes to align
564	PTR_ADDU	a0, a0, a3
5651:
566	and	v0, a1, 3		# compute number of words left
567	PTR_SUBU	a3, a1, v0
568	move	a1, v0
569	PTR_ADDU	a3, a3, a0		# compute ending address
5702:
571	PTR_ADDU	a0, a0, 4		# clear words
572	bne	a0, a3, 2b		#  unrolling loop does not help
573	sw	zero, -4(a0)		#  since we are limited by memory speed
574smallclr:
575	ble	a1, zero, 2f
576	PTR_ADDU	a3, a1, a0		# compute ending address
5771:
578	PTR_ADDU	a0, a0, 1		# clear bytes
579	bne	a0, a3, 1b
580	sb	zero, -1(a0)
5812:
582	j	ra
583	nop
584END(bzero)
585
586
587/*
588 * bcmp(s1, s2, n)
589 */
590LEAF(bcmp)
591	.set	noreorder
592	blt	a2, 16, smallcmp	# is it worth any trouble?
593	xor	v0, a0, a1		# compare low two bits of addresses
594	and	v0, v0, 3
595	PTR_SUBU	a3, zero, a1		# compute # bytes to word align address
596	bne	v0, zero, unalignedcmp	# not possible to align addresses
597	and	a3, a3, 3
598
599	beq	a3, zero, 1f
600	PTR_SUBU	a2, a2, a3		# subtract from remaining count
601	move	v0, v1			# init v0,v1 so unmodified bytes match
602	LWHI	v0, 0(a0)		# read 1, 2, or 3 bytes
603	LWHI	v1, 0(a1)
604	PTR_ADDU	a1, a1, a3
605	bne	v0, v1, nomatch
606	PTR_ADDU	a0, a0, a3
6071:
608	and	a3, a2, ~3		# compute number of whole words left
609	PTR_SUBU	a2, a2, a3		#   which has to be >= (16-3) & ~3
610	PTR_ADDU	a3, a3, a0		# compute ending address
6112:
612	lw	v0, 0(a0)		# compare words
613	lw	v1, 0(a1)
614	PTR_ADDU	a0, a0, 4
615	bne	v0, v1, nomatch
616	PTR_ADDU	a1, a1, 4
617	bne	a0, a3, 2b
618	nop
619	b	smallcmp		# finish remainder
620	nop
621unalignedcmp:
622	beq	a3, zero, 2f
623	PTR_SUBU	a2, a2, a3		# subtract from remaining count
624	PTR_ADDU	a3, a3, a0		# compute ending address
6251:
626	lbu	v0, 0(a0)		# compare bytes until a1 word aligned
627	lbu	v1, 0(a1)
628	PTR_ADDU	a0, a0, 1
629	bne	v0, v1, nomatch
630	PTR_ADDU	a1, a1, 1
631	bne	a0, a3, 1b
632	nop
6332:
634	and	a3, a2, ~3		# compute number of whole words left
635	PTR_SUBU	a2, a2, a3		#   which has to be >= (16-3) & ~3
636	PTR_ADDU	a3, a3, a0		# compute ending address
6373:
638	LWHI	v0, 0(a0)		# compare words a0 unaligned, a1 aligned
639	LWLO	v0, 3(a0)
640	lw	v1, 0(a1)
641	PTR_ADDU	a0, a0, 4
642	bne	v0, v1, nomatch
643	PTR_ADDU	a1, a1, 4
644	bne	a0, a3, 3b
645	nop
646smallcmp:
647	ble	a2, zero, match
648	PTR_ADDU	a3, a2, a0		# compute ending address
6491:
650	lbu	v0, 0(a0)
651	lbu	v1, 0(a1)
652	PTR_ADDU	a0, a0, 1
653	bne	v0, v1, nomatch
654	PTR_ADDU	a1, a1, 1
655	bne	a0, a3, 1b
656	nop
657match:
658	j	ra
659	 move	v0, zero
660nomatch:
661	j	ra
662	li	v0, 1
663END(bcmp)
664
665
666/*
667 * bit = ffs(value)
668 */
669LEAF(ffs)
670	.set	noreorder
671	beq	a0, zero, 2f
672	move	v0, zero
6731:
674	and	v1, a0, 1		# bit set?
675	addu	v0, v0, 1
676	beq	v1, zero, 1b		# no, continue
677	srl	a0, a0, 1
6782:
679	j	ra
680	nop
681END(ffs)
682
683/**
684 * void
685 * atomic_set_16(u_int16_t *a, u_int16_t b)
686 * {
687 *	*a |= b;
688 * }
689 */
690LEAF(atomic_set_16)
691	.set	noreorder
692	srl	a0, a0, 2	# round down address to be 32-bit aligned
693	sll	a0, a0, 2
694	andi	a1, a1, 0xffff
6951:
696	ll	t0, 0(a0)
697	or	t0, t0, a1
698	sc	t0, 0(a0)
699	beq	t0, zero, 1b
700	nop
701	j	ra
702	nop
703END(atomic_set_16)
704
705/**
706 * void
707 * atomic_clear_16(u_int16_t *a, u_int16_t b)
708 * {
709 *	*a &= ~b;
710 * }
711 */
712LEAF(atomic_clear_16)
713	.set	noreorder
714	srl	a0, a0, 2	# round down address to be 32-bit aligned
715	sll	a0, a0, 2
716	nor	a1, zero, a1
7171:
718	ll	t0, 0(a0)
719	move	t1, t0
720	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
721	and	t1, t1, a1	# t1 has the new lower 16 bits
722	srl	t0, t0, 16	# preserve original top 16 bits
723	sll	t0, t0, 16
724	or	t0, t0, t1
725	sc	t0, 0(a0)
726	beq	t0, zero, 1b
727	nop
728	j	ra
729	nop
730END(atomic_clear_16)
731
732
733/**
734 * void
735 * atomic_subtract_16(uint16_t *a, uint16_t b)
736 * {
737 *	*a -= b;
738 * }
739 */
740LEAF(atomic_subtract_16)
741	.set	noreorder
742	srl	a0, a0, 2	# round down address to be 32-bit aligned
743	sll	a0, a0, 2
7441:
745	ll	t0, 0(a0)
746	move	t1, t0
747	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
748	subu	t1, t1, a1
749	andi	t1, t1, 0xffff	# t1 has the new lower 16 bits
750	srl	t0, t0, 16	# preserve original top 16 bits
751	sll	t0, t0, 16
752	or	t0, t0, t1
753	sc	t0, 0(a0)
754	beq	t0, zero, 1b
755	nop
756	j	ra
757	nop
758END(atomic_subtract_16)
759
760/**
761 * void
762 * atomic_add_16(uint16_t *a, uint16_t b)
763 * {
764 *	*a += b;
765 * }
766 */
767LEAF(atomic_add_16)
768	.set	noreorder
769	srl	a0, a0, 2	# round down address to be 32-bit aligned
770	sll	a0, a0, 2
7711:
772	ll	t0, 0(a0)
773	move	t1, t0
774	andi	t1, t1, 0xffff	# t1 has the original lower 16 bits
775	addu	t1, t1, a1
776	andi	t1, t1, 0xffff	# t1 has the new lower 16 bits
777	srl	t0, t0, 16	# preserve original top 16 bits
778	sll	t0, t0, 16
779	or	t0, t0, t1
780	sc	t0, 0(a0)
781	beq	t0, zero, 1b
782	nop
783	j	ra
784	nop
785END(atomic_add_16)
786
787/**
788 * void
789 * atomic_add_8(uint8_t *a, uint8_t b)
790 * {
791 *	*a += b;
792 * }
793 */
794LEAF(atomic_add_8)
795	.set	noreorder
796	srl	a0, a0, 2	# round down address to be 32-bit aligned
797	sll	a0, a0, 2
7981:
799	ll	t0, 0(a0)
800	move	t1, t0
801	andi	t1, t1, 0xff	# t1 has the original lower 8 bits
802	addu	t1, t1, a1
803	andi	t1, t1, 0xff	# t1 has the new lower 8 bits
804	srl	t0, t0, 8	# preserve original top 24 bits
805	sll	t0, t0, 8
806	or	t0, t0, t1
807	sc	t0, 0(a0)
808	beq	t0, zero, 1b
809	nop
810	j	ra
811	nop
812END(atomic_add_8)
813
814
815/**
816 * void
817 * atomic_subtract_8(uint8_t *a, uint8_t b)
818 * {
819 *	*a += b;
820 * }
821 */
822LEAF(atomic_subtract_8)
823	.set	noreorder
824	srl	a0, a0, 2	# round down address to be 32-bit aligned
825	sll	a0, a0, 2
8261:
827	ll	t0, 0(a0)
828	move	t1, t0
829	andi	t1, t1, 0xff	# t1 has the original lower 8 bits
830	subu	t1, t1, a1
831	andi	t1, t1, 0xff	# t1 has the new lower 8 bits
832	srl	t0, t0, 8	# preserve original top 24 bits
833	sll	t0, t0, 8
834	or	t0, t0, t1
835	sc	t0, 0(a0)
836	beq	t0, zero, 1b
837	nop
838	j	ra
839	nop
840END(atomic_subtract_8)
841
842	.set	noreorder		# Noreorder is default style!
843
844#if defined(DDB) || defined(DEBUG)
845
846LEAF(kdbpeek)
847	PTR_LA	v1, ddberr
848	and	v0, a0, 3			# unaligned ?
849	GET_CPU_PCPU(t1)
850	PTR_L	t1, PC_CURPCB(t1)
851	bne	v0, zero, 1f
852	PTR_S	v1, U_PCB_ONFAULT(t1)
853
854	lw	v0, (a0)
855	jr	ra
856	PTR_S	zero, U_PCB_ONFAULT(t1)
857
8581:
859	LWHI	v0, 0(a0)
860	LWLO	v0, 3(a0)
861	jr	ra
862	PTR_S	zero, U_PCB_ONFAULT(t1)
863END(kdbpeek)
864
865LEAF(kdbpeekd)
866	PTR_LA	v1, ddberr
867	and	v0, a0, 3			# unaligned ?
868	GET_CPU_PCPU(t1)
869	PTR_L	t1, PC_CURPCB(t1)
870	bne	v0, zero, 1f
871	PTR_S	v1, U_PCB_ONFAULT(t1)
872
873	ld	v0, (a0)
874	jr	ra
875	PTR_S	zero, U_PCB_ONFAULT(t1)
876
8771:
878	REG_LHI	v0, 0(a0)
879	REG_LLO	v0, 7(a0)
880	jr	ra
881	PTR_S	zero, U_PCB_ONFAULT(t1)
882END(kdbpeekd)
883
884ddberr:
885	jr	ra
886	nop
887
888#if defined(DDB)
889LEAF(kdbpoke)
890	PTR_LA	v1, ddberr
891	and	v0, a0, 3			# unaligned ?
892	GET_CPU_PCPU(t1)
893	PTR_L	t1, PC_CURPCB(t1)
894	bne	v0, zero, 1f
895	PTR_S	v1, U_PCB_ONFAULT(t1)
896
897	sw	a1, (a0)
898	jr	ra
899	PTR_S	zero, U_PCB_ONFAULT(t1)
900
9011:
902	SWHI	a1, 0(a0)
903	SWLO	a1, 3(a0)
904	jr	ra
905	PTR_S	zero, U_PCB_ONFAULT(t1)
906END(kdbpoke)
907
908	.data
909	.globl	esym
910esym:	.word	0
911
912#endif /* DDB */
913#endif /* DDB || DEBUG */
914
915	.text
916LEAF(breakpoint)
917	break	MIPS_BREAK_SOVER_VAL
918	jr	ra
919	nop
920END(breakpoint)
921
922LEAF(setjmp)
923	mfc0	v0, MIPS_COP_0_STATUS	# Later the "real" spl value!
924	REG_S	s0, (SZREG * PCB_REG_S0)(a0)
925	REG_S	s1, (SZREG * PCB_REG_S1)(a0)
926	REG_S	s2, (SZREG * PCB_REG_S2)(a0)
927	REG_S	s3, (SZREG * PCB_REG_S3)(a0)
928	REG_S	s4, (SZREG * PCB_REG_S4)(a0)
929	REG_S	s5, (SZREG * PCB_REG_S5)(a0)
930	REG_S	s6, (SZREG * PCB_REG_S6)(a0)
931	REG_S	s7, (SZREG * PCB_REG_S7)(a0)
932	REG_S	s8, (SZREG * PCB_REG_S8)(a0)
933	REG_S	sp, (SZREG * PCB_REG_SP)(a0)
934	REG_S	ra, (SZREG * PCB_REG_RA)(a0)
935	REG_S	v0, (SZREG * PCB_REG_SR)(a0)
936	jr	ra
937	li	v0, 0			# setjmp return
938END(setjmp)
939
940LEAF(longjmp)
941	REG_L	v0, (SZREG * PCB_REG_SR)(a0)
942	REG_L	ra, (SZREG * PCB_REG_RA)(a0)
943	REG_L	s0, (SZREG * PCB_REG_S0)(a0)
944	REG_L	s1, (SZREG * PCB_REG_S1)(a0)
945	REG_L	s2, (SZREG * PCB_REG_S2)(a0)
946	REG_L	s3, (SZREG * PCB_REG_S3)(a0)
947	REG_L	s4, (SZREG * PCB_REG_S4)(a0)
948	REG_L	s5, (SZREG * PCB_REG_S5)(a0)
949	REG_L	s6, (SZREG * PCB_REG_S6)(a0)
950	REG_L	s7, (SZREG * PCB_REG_S7)(a0)
951	REG_L	s8, (SZREG * PCB_REG_S8)(a0)
952	REG_L	sp, (SZREG * PCB_REG_SP)(a0)
953	mtc0	v0, MIPS_COP_0_STATUS	# Later the "real" spl value!
954	ITLBNOPFIX
955	jr	ra
956	li	v0, 1			# longjmp return
957END(longjmp)
958
959LEAF(mips3_ld)
960	.set push
961	.set noreorder
962	.set mips64
963#if defined(__mips_o32)
964	mfc0	t0, MIPS_COP_0_STATUS		# turn off interrupts
965	and	t1, t0, ~(MIPS_SR_INT_IE)
966	mtc0	t1, MIPS_COP_0_STATUS
967	COP0_SYNC
968	nop
969	nop
970	nop
971
972	ld	v0, 0(a0)
973#if _BYTE_ORDER == _BIG_ENDIAN
974	dsll	v1, v0, 32
975	dsra	v1, v1, 32			# low word in v1
976	dsra	v0, v0, 32			# high word in v0
977#else
978	dsra	v1, v0, 32			# high word in v1
979	dsll	v0, v0, 32
980	dsra	v0, v0, 32			# low word in v0
981#endif
982
983	mtc0	t0, MIPS_COP_0_STATUS		# restore intr status.
984	COP0_SYNC
985	nop
986#else /* !__mips_o32 */
987	ld	v0, 0(a0)
988#endif /* !__mips_o32 */
989
990	jr	ra
991	nop
992	.set pop
993END(mips3_ld)
994
995LEAF(mips3_sd)
996	.set push
997	.set mips64
998	.set noreorder
999#if defined(__mips_o32)
1000	mfc0	t0, MIPS_COP_0_STATUS		# turn off interrupts
1001	and	t1, t0, ~(MIPS_SR_INT_IE)
1002	mtc0	t1, MIPS_COP_0_STATUS
1003	COP0_SYNC
1004	nop
1005	nop
1006	nop
1007
1008	# NOTE: a1 is padding!
1009
1010#if _BYTE_ORDER == _BIG_ENDIAN
1011	dsll	a2, a2, 32			# high word in a2
1012	dsll	a3, a3, 32			# low word in a3
1013	dsrl	a3, a3, 32
1014#else
1015	dsll	a2, a2, 32			# low word in a2
1016	dsrl	a2, a2, 32
1017	dsll	a3, a3, 32			# high word in a3
1018#endif
1019	or	a1, a2, a3
1020	sd	a1, 0(a0)
1021
1022	mtc0	t0, MIPS_COP_0_STATUS		# restore intr status.
1023	COP0_SYNC
1024	nop
1025#else /* !__mips_o32 */
1026	sd	a1, 0(a0)
1027#endif /* !__mips_o32 */
1028
1029	jr	ra
1030	nop
1031	.set pop
1032END(mips3_sd)
1033