]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/mips/support.S
Remove reference to unimplemented fuiword, etc.
[FreeBSD/FreeBSD.git] / sys / mips / mips / support.S
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$
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  */
115 LEAF(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)
123 2:
124         bne     a1, 2, 4f
125         nop
126         b       5f
127         lhu     v0, (a0)
128 4:
129         lw      v0, (a0)
130 5:
131         PTR_S   zero, U_PCB_ONFAULT(v1)
132         j       ra
133         move    v0, zero                # made it w/o errors
134 baderr:
135         j       ra
136         li      v0, 1                   # trap sends us here
137 END(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  */
145 LEAF(copystr)
146         move            t0, a2
147         beq             a2, zero, 4f
148 1:
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
156 4:
157         li              v0, ENAMETOOLONG        # run out of space
158 2:
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)
162 3:
163         j               ra                      # v0 is 0 or ENAMETOOLONG
164         nop
165 END(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  */
178 NESTED(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
194 END(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  */
206 NESTED(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
222 END(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  */
231 NESTED(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
248 END(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  */
257 NESTED(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
274 END(copyout)
275
276 LEAF(copyerr)
277         REG_L   ra, CALLFRAME_RA(sp)
278         PTR_ADDU        sp, sp, CALLFRAME_SIZ
279         j       ra
280         li      v0, EFAULT                      # return error
281 END(copyerr)
282
283 /*
284  * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
285  * user-space.
286  */
287 #ifdef __mips_n64
288 LEAF(fuword64)
289 XLEAF(fuword)
290         PTR_LA  v0, fswberr
291         blt     a0, zero, fswberr       # make sure address is in user space
292         nop
293         GET_CPU_PCPU(v1)
294         PTR_L   v1, PC_CURPCB(v1)
295         PTR_S   v0, U_PCB_ONFAULT(v1)
296         ld      v0, 0(a0)               # fetch word
297         j       ra
298         PTR_S   zero, U_PCB_ONFAULT(v1)
299 END(fuword64)
300 #endif
301
302 LEAF(fuword32)
303 #ifndef __mips_n64
304 XLEAF(fuword)
305 #endif
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         lw      v0, 0(a0)               # fetch word
313         j       ra
314         PTR_S   zero, U_PCB_ONFAULT(v1)
315 END(fuword32)
316
317 LEAF(fusword)
318         PTR_LA  v0, fswberr
319         blt     a0, zero, fswberr       # make sure address is in user space
320         nop
321         GET_CPU_PCPU(v1)
322         PTR_L   v1, PC_CURPCB(v1)
323         PTR_S   v0, U_PCB_ONFAULT(v1)
324         lhu     v0, 0(a0)               # fetch short
325         j       ra
326         PTR_S   zero, U_PCB_ONFAULT(v1)
327 END(fusword)
328
329 LEAF(fubyte)
330         PTR_LA  v0, fswberr
331         blt     a0, zero, fswberr       # make sure address is in user space
332         nop
333         GET_CPU_PCPU(v1)
334         PTR_L   v1, PC_CURPCB(v1)
335         PTR_S   v0, U_PCB_ONFAULT(v1)
336         lbu     v0, 0(a0)               # fetch byte
337         j       ra
338         PTR_S   zero, U_PCB_ONFAULT(v1)
339 END(fubyte)
340
341 LEAF(suword32)
342 #ifndef __mips_n64
343 XLEAF(suword)
344 #endif
345         PTR_LA  v0, fswberr
346         blt     a0, zero, fswberr       # make sure address is in user space
347         nop
348         GET_CPU_PCPU(v1)
349         PTR_L   v1, PC_CURPCB(v1)
350         PTR_S   v0, U_PCB_ONFAULT(v1)
351         sw      a1, 0(a0)               # store word
352         PTR_S   zero, U_PCB_ONFAULT(v1)
353         j       ra
354         move    v0, zero
355 END(suword32)
356
357 #ifdef __mips_n64
358 LEAF(suword64)
359 XLEAF(suword)
360         PTR_LA  v0, fswberr
361         blt     a0, zero, fswberr       # make sure address is in user space
362         nop
363         GET_CPU_PCPU(v1)
364         PTR_L   v1, PC_CURPCB(v1)
365         PTR_S   v0, U_PCB_ONFAULT(v1)
366         sd      a1, 0(a0)               # store word
367         PTR_S   zero, U_PCB_ONFAULT(v1)
368         j       ra
369         move    v0, zero
370 END(suword64)
371 #endif
372
373 /*
374  * casuword(9)
375  * <v0>u_long casuword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long newval)
376  */
377 /*
378  * casuword32(9)
379  * <v0>uint32_t casuword(<a0>uint32_t *p, <a1>uint32_t oldval, 
380  *                                                      <a2>uint32_t newval)
381  */
382 LEAF(casuword32)
383 #ifndef __mips_n64
384 XLEAF(casuword)
385 #endif
386         PTR_LA  v0, fswberr
387         blt     a0, zero, fswberr       # make sure address is in user space
388         nop
389         GET_CPU_PCPU(v1)
390         PTR_L   v1, PC_CURPCB(v1)
391         PTR_S   v0, U_PCB_ONFAULT(v1)
392 1:
393         move    t0, a2
394         ll      v0, 0(a0)
395         bne     a1, v0, 2f
396         nop
397         sc      t0, 0(a0)               # store word
398         beqz    t0, 1b
399         nop
400         j       3f
401         nop
402 2:
403         li      v0, -1
404 3:
405         PTR_S   zero, U_PCB_ONFAULT(v1)
406         jr      ra
407         nop
408 END(casuword32)
409
410 #ifdef __mips_n64
411 LEAF(casuword64)
412 XLEAF(casuword)
413         PTR_LA  v0, fswberr
414         blt     a0, zero, fswberr       # make sure address is in user space
415         nop
416         GET_CPU_PCPU(v1)
417         PTR_L   v1, PC_CURPCB(v1)
418         PTR_S   v0, U_PCB_ONFAULT(v1)
419 1:
420         move    t0, a2
421         lld     v0, 0(a0)
422         bne     a1, v0, 2f
423         nop
424         scd     t0, 0(a0)               # store double word
425         beqz    t0, 1b
426         nop
427         j       3f
428         nop
429 2:
430         li      v0, -1
431 3:
432         PTR_S   zero, U_PCB_ONFAULT(v1)
433         jr      ra
434         nop
435 END(casuword64)
436 #endif
437
438 /*
439  * Will have to flush the instruction cache if byte merging is done in hardware.
440  */
441 LEAF(susword)
442         PTR_LA  v0, fswberr
443         blt     a0, zero, fswberr       # make sure address is in user space
444         nop
445         GET_CPU_PCPU(v1)
446         PTR_L   v1, PC_CURPCB(v1)
447         PTR_S   v0, U_PCB_ONFAULT(v1)
448         sh      a1, 0(a0)               # store short
449         PTR_S   zero, U_PCB_ONFAULT(v1)
450         j       ra
451         move    v0, zero
452 END(susword)
453
454 LEAF(subyte)
455         PTR_LA  v0, fswberr
456         blt     a0, zero, fswberr       # make sure address is in user space
457         nop
458         GET_CPU_PCPU(v1)
459         PTR_L   v1, PC_CURPCB(v1)
460         PTR_S   v0, U_PCB_ONFAULT(v1)
461         sb      a1, 0(a0)               # store byte
462         PTR_S   zero, U_PCB_ONFAULT(v1)
463         j       ra
464         move    v0, zero
465 END(subyte)
466
467 LEAF(fswberr)
468         j       ra
469         li      v0, -1
470 END(fswberr)
471
472 /*
473  * fuswintr and suswintr are just like fusword and susword except that if
474  * the page is not in memory or would cause a trap, then we return an error.
475  * The important thing is to prevent sleep() and switch().
476  */
477 LEAF(fuswintr)
478         PTR_LA  v0, fswintrberr
479         blt     a0, zero, fswintrberr   # make sure address is in user space
480         nop
481         GET_CPU_PCPU(v1)
482         PTR_L   v1, PC_CURPCB(v1)
483         PTR_S   v0, U_PCB_ONFAULT(v1)
484         lhu     v0, 0(a0)               # fetch short
485         j       ra
486         PTR_S   zero, U_PCB_ONFAULT(v1)
487 END(fuswintr)
488
489 LEAF(suswintr)
490         PTR_LA  v0, fswintrberr
491         blt     a0, zero, fswintrberr   # make sure address is in user space
492         nop
493         GET_CPU_PCPU(v1)
494         PTR_L   v1, PC_CURPCB(v1)
495         PTR_S   v0, U_PCB_ONFAULT(v1)
496         sh      a1, 0(a0)               # store short
497         PTR_S   zero, U_PCB_ONFAULT(v1)
498         j       ra
499         move    v0, zero
500 END(suswintr)
501
502 LEAF(fswintrberr)
503         j       ra
504         li      v0, -1
505 END(fswintrberr)
506
507 /*
508  * memset(void *s1, int c, int len)
509  * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp
510  */
511 LEAF(memset)
512         .set noreorder
513         blt     a2, 12, memsetsmallclr  # small amount to clear?
514         move    v0, a0                  # save s1 for result
515
516         sll     t1, a1, 8               # compute  c << 8 in t1
517         or      t1, t1, a1              # compute c << 8 | c in 11
518         sll     t2, t1, 16              # shift that left 16
519         or      t1, t2, t1              # or together
520
521         PTR_SUBU        t0, zero, a0            # compute # bytes to word align address
522         and     t0, t0, 3
523         beq     t0, zero, 1f            # skip if word aligned
524         PTR_SUBU        a2, a2, t0              # subtract from remaining count
525         SWHI    t1, 0(a0)               # store 1, 2, or 3 bytes to align
526         PTR_ADDU        a0, a0, t0
527 1:
528         and     v1, a2, 3               # compute number of whole words left
529         PTR_SUBU        t0, a2, v1
530         PTR_SUBU        a2, a2, t0
531         PTR_ADDU        t0, t0, a0              # compute ending address
532 2:
533         PTR_ADDU        a0, a0, 4               # clear words
534         bne     a0, t0, 2b              #  unrolling loop does not help
535         sw      t1, -4(a0)              #  since we are limited by memory speed
536
537 memsetsmallclr:
538         ble     a2, zero, 2f
539         PTR_ADDU        t0, a2, a0              # compute ending address
540 1:
541         PTR_ADDU        a0, a0, 1               # clear bytes
542         bne     a0, t0, 1b
543         sb      a1, -1(a0)
544 2:
545         j       ra
546         nop
547         .set reorder
548 END(memset)
549
550 /*
551  * bzero(s1, n)
552  */
553 LEAF(bzero)
554 XLEAF(blkclr)
555         .set    noreorder
556         blt     a1, 12, smallclr        # small amount to clear?
557         PTR_SUBU        a3, zero, a0            # compute # bytes to word align address
558         and     a3, a3, 3
559         beq     a3, zero, 1f            # skip if word aligned
560         PTR_SUBU        a1, a1, a3              # subtract from remaining count
561         SWHI    zero, 0(a0)             # clear 1, 2, or 3 bytes to align
562         PTR_ADDU        a0, a0, a3
563 1:
564         and     v0, a1, 3               # compute number of words left
565         PTR_SUBU        a3, a1, v0
566         move    a1, v0
567         PTR_ADDU        a3, a3, a0              # compute ending address
568 2:
569         PTR_ADDU        a0, a0, 4               # clear words
570         bne     a0, a3, 2b              #  unrolling loop does not help
571         sw      zero, -4(a0)            #  since we are limited by memory speed
572 smallclr:
573         ble     a1, zero, 2f
574         PTR_ADDU        a3, a1, a0              # compute ending address
575 1:
576         PTR_ADDU        a0, a0, 1               # clear bytes
577         bne     a0, a3, 1b
578         sb      zero, -1(a0)
579 2:
580         j       ra
581         nop
582 END(bzero)
583
584
585 /*
586  * bcmp(s1, s2, n)
587  */
588 LEAF(bcmp)
589         .set    noreorder
590         blt     a2, 16, smallcmp        # is it worth any trouble?
591         xor     v0, a0, a1              # compare low two bits of addresses
592         and     v0, v0, 3
593         PTR_SUBU        a3, zero, a1            # compute # bytes to word align address
594         bne     v0, zero, unalignedcmp  # not possible to align addresses
595         and     a3, a3, 3
596
597         beq     a3, zero, 1f
598         PTR_SUBU        a2, a2, a3              # subtract from remaining count
599         move    v0, v1                  # init v0,v1 so unmodified bytes match
600         LWHI    v0, 0(a0)               # read 1, 2, or 3 bytes
601         LWHI    v1, 0(a1)
602         PTR_ADDU        a1, a1, a3
603         bne     v0, v1, nomatch
604         PTR_ADDU        a0, a0, a3
605 1:
606         and     a3, a2, ~3              # compute number of whole words left
607         PTR_SUBU        a2, a2, a3              #   which has to be >= (16-3) & ~3
608         PTR_ADDU        a3, a3, a0              # compute ending address
609 2:
610         lw      v0, 0(a0)               # compare words
611         lw      v1, 0(a1)
612         PTR_ADDU        a0, a0, 4
613         bne     v0, v1, nomatch
614         PTR_ADDU        a1, a1, 4
615         bne     a0, a3, 2b
616         nop
617         b       smallcmp                # finish remainder
618         nop
619 unalignedcmp:
620         beq     a3, zero, 2f
621         PTR_SUBU        a2, a2, a3              # subtract from remaining count
622         PTR_ADDU        a3, a3, a0              # compute ending address
623 1:
624         lbu     v0, 0(a0)               # compare bytes until a1 word aligned
625         lbu     v1, 0(a1)
626         PTR_ADDU        a0, a0, 1
627         bne     v0, v1, nomatch
628         PTR_ADDU        a1, a1, 1
629         bne     a0, a3, 1b
630         nop
631 2:
632         and     a3, a2, ~3              # compute number of whole words left
633         PTR_SUBU        a2, a2, a3              #   which has to be >= (16-3) & ~3
634         PTR_ADDU        a3, a3, a0              # compute ending address
635 3:
636         LWHI    v0, 0(a0)               # compare words a0 unaligned, a1 aligned
637         LWLO    v0, 3(a0)
638         lw      v1, 0(a1)
639         PTR_ADDU        a0, a0, 4
640         bne     v0, v1, nomatch
641         PTR_ADDU        a1, a1, 4
642         bne     a0, a3, 3b
643         nop
644 smallcmp:
645         ble     a2, zero, match
646         PTR_ADDU        a3, a2, a0              # compute ending address
647 1:
648         lbu     v0, 0(a0)
649         lbu     v1, 0(a1)
650         PTR_ADDU        a0, a0, 1
651         bne     v0, v1, nomatch
652         PTR_ADDU        a1, a1, 1
653         bne     a0, a3, 1b
654         nop
655 match:
656         j       ra
657          move   v0, zero
658 nomatch:
659         j       ra
660         li      v0, 1
661 END(bcmp)
662
663
664 /*
665  * bit = ffs(value)
666  */
667 LEAF(ffs)
668         .set    noreorder
669         beq     a0, zero, 2f
670         move    v0, zero
671 1:
672         and     v1, a0, 1               # bit set?
673         addu    v0, v0, 1
674         beq     v1, zero, 1b            # no, continue
675         srl     a0, a0, 1
676 2:
677         j       ra
678         nop
679 END(ffs)
680
681 /**
682  * void
683  * atomic_set_16(u_int16_t *a, u_int16_t b)
684  * {
685  *      *a |= b;
686  * }
687  */
688 LEAF(atomic_set_16)
689         .set    noreorder
690         srl     a0, a0, 2       # round down address to be 32-bit aligned
691         sll     a0, a0, 2
692         andi    a1, a1, 0xffff
693 1:
694         ll      t0, 0(a0)
695         or      t0, t0, a1
696         sc      t0, 0(a0)
697         beq     t0, zero, 1b
698         nop
699         j       ra
700         nop
701 END(atomic_set_16)
702
703 /**
704  * void
705  * atomic_clear_16(u_int16_t *a, u_int16_t b)
706  * {
707  *      *a &= ~b;
708  * }
709  */
710 LEAF(atomic_clear_16)
711         .set    noreorder
712         srl     a0, a0, 2       # round down address to be 32-bit aligned
713         sll     a0, a0, 2
714         nor     a1, zero, a1
715 1:
716         ll      t0, 0(a0)
717         move    t1, t0
718         andi    t1, t1, 0xffff  # t1 has the original lower 16 bits
719         and     t1, t1, a1      # t1 has the new lower 16 bits
720         srl     t0, t0, 16      # preserve original top 16 bits
721         sll     t0, t0, 16
722         or      t0, t0, t1
723         sc      t0, 0(a0)
724         beq     t0, zero, 1b
725         nop
726         j       ra
727         nop
728 END(atomic_clear_16)
729
730
731 /**
732  * void
733  * atomic_subtract_16(uint16_t *a, uint16_t b)
734  * {
735  *      *a -= b;
736  * }
737  */
738 LEAF(atomic_subtract_16)
739         .set    noreorder
740         srl     a0, a0, 2       # round down address to be 32-bit aligned
741         sll     a0, a0, 2
742 1:
743         ll      t0, 0(a0)
744         move    t1, t0
745         andi    t1, t1, 0xffff  # t1 has the original lower 16 bits
746         subu    t1, t1, a1
747         andi    t1, t1, 0xffff  # t1 has the new lower 16 bits
748         srl     t0, t0, 16      # preserve original top 16 bits
749         sll     t0, t0, 16
750         or      t0, t0, t1
751         sc      t0, 0(a0)
752         beq     t0, zero, 1b
753         nop
754         j       ra
755         nop
756 END(atomic_subtract_16)
757
758 /**
759  * void
760  * atomic_add_16(uint16_t *a, uint16_t b)
761  * {
762  *      *a += b;
763  * }
764  */
765 LEAF(atomic_add_16)
766         .set    noreorder
767         srl     a0, a0, 2       # round down address to be 32-bit aligned
768         sll     a0, a0, 2
769 1:
770         ll      t0, 0(a0)
771         move    t1, t0
772         andi    t1, t1, 0xffff  # t1 has the original lower 16 bits
773         addu    t1, t1, a1
774         andi    t1, t1, 0xffff  # t1 has the new lower 16 bits
775         srl     t0, t0, 16      # preserve original top 16 bits
776         sll     t0, t0, 16
777         or      t0, t0, t1
778         sc      t0, 0(a0)
779         beq     t0, zero, 1b
780         nop
781         j       ra
782         nop
783 END(atomic_add_16)
784
785 /**
786  * void
787  * atomic_add_8(uint8_t *a, uint8_t b)
788  * {
789  *      *a += b;
790  * }
791  */
792 LEAF(atomic_add_8)
793         .set    noreorder
794         srl     a0, a0, 2       # round down address to be 32-bit aligned
795         sll     a0, a0, 2
796 1:
797         ll      t0, 0(a0)
798         move    t1, t0
799         andi    t1, t1, 0xff    # t1 has the original lower 8 bits
800         addu    t1, t1, a1
801         andi    t1, t1, 0xff    # t1 has the new lower 8 bits
802         srl     t0, t0, 8       # preserve original top 24 bits
803         sll     t0, t0, 8
804         or      t0, t0, t1
805         sc      t0, 0(a0)
806         beq     t0, zero, 1b
807         nop
808         j       ra
809         nop
810 END(atomic_add_8)
811
812
813 /**
814  * void
815  * atomic_subtract_8(uint8_t *a, uint8_t b)
816  * {
817  *      *a += b;
818  * }
819  */
820 LEAF(atomic_subtract_8)
821         .set    noreorder
822         srl     a0, a0, 2       # round down address to be 32-bit aligned
823         sll     a0, a0, 2
824 1:
825         ll      t0, 0(a0)
826         move    t1, t0
827         andi    t1, t1, 0xff    # t1 has the original lower 8 bits
828         subu    t1, t1, a1
829         andi    t1, t1, 0xff    # t1 has the new lower 8 bits
830         srl     t0, t0, 8       # preserve original top 24 bits
831         sll     t0, t0, 8
832         or      t0, t0, t1
833         sc      t0, 0(a0)
834         beq     t0, zero, 1b
835         nop
836         j       ra
837         nop
838 END(atomic_subtract_8)
839
840         .set    noreorder               # Noreorder is default style!
841
842 #if defined(DDB) || defined(DEBUG)
843
844 LEAF(kdbpeek)
845         PTR_LA  v1, ddberr
846         and     v0, a0, 3                       # unaligned ?
847         GET_CPU_PCPU(t1)
848         PTR_L   t1, PC_CURPCB(t1)
849         bne     v0, zero, 1f
850         PTR_S   v1, U_PCB_ONFAULT(t1)
851
852         lw      v0, (a0)
853         jr      ra
854         PTR_S   zero, U_PCB_ONFAULT(t1)
855
856 1:
857         LWHI    v0, 0(a0)
858         LWLO    v0, 3(a0)
859         jr      ra
860         PTR_S   zero, U_PCB_ONFAULT(t1)
861 END(kdbpeek)
862
863 LEAF(kdbpeekd)
864         PTR_LA  v1, ddberr
865         and     v0, a0, 3                       # unaligned ?
866         GET_CPU_PCPU(t1)
867         PTR_L   t1, PC_CURPCB(t1)
868         bne     v0, zero, 1f
869         PTR_S   v1, U_PCB_ONFAULT(t1)
870
871         ld      v0, (a0)
872         jr      ra
873         PTR_S   zero, U_PCB_ONFAULT(t1)
874
875 1:
876         REG_LHI v0, 0(a0)
877         REG_LLO v0, 7(a0)
878         jr      ra
879         PTR_S   zero, U_PCB_ONFAULT(t1)
880 END(kdbpeekd)
881
882 ddberr:
883         jr      ra
884         nop
885
886 #if defined(DDB)
887 LEAF(kdbpoke)
888         PTR_LA  v1, ddberr
889         and     v0, a0, 3                       # unaligned ?
890         GET_CPU_PCPU(t1)
891         PTR_L   t1, PC_CURPCB(t1)
892         bne     v0, zero, 1f
893         PTR_S   v1, U_PCB_ONFAULT(t1)
894
895         sw      a1, (a0)
896         jr      ra
897         PTR_S   zero, U_PCB_ONFAULT(t1)
898
899 1:
900         SWHI    a1, 0(a0)
901         SWLO    a1, 3(a0)
902         jr      ra
903         PTR_S   zero, U_PCB_ONFAULT(t1)
904 END(kdbpoke)
905
906         .data
907         .globl  esym
908 esym:   .word   0
909
910 #endif /* DDB */
911 #endif /* DDB || DEBUG */
912
913         .text
914 LEAF(breakpoint)
915         break   MIPS_BREAK_SOVER_VAL
916         jr      ra
917         nop
918 END(breakpoint)
919
920 LEAF(setjmp)
921         mfc0    v0, MIPS_COP_0_STATUS   # Later the "real" spl value!
922         REG_S   s0, (SZREG * PCB_REG_S0)(a0)
923         REG_S   s1, (SZREG * PCB_REG_S1)(a0)
924         REG_S   s2, (SZREG * PCB_REG_S2)(a0)
925         REG_S   s3, (SZREG * PCB_REG_S3)(a0)
926         REG_S   s4, (SZREG * PCB_REG_S4)(a0)
927         REG_S   s5, (SZREG * PCB_REG_S5)(a0)
928         REG_S   s6, (SZREG * PCB_REG_S6)(a0)
929         REG_S   s7, (SZREG * PCB_REG_S7)(a0)
930         REG_S   s8, (SZREG * PCB_REG_S8)(a0)
931         REG_S   sp, (SZREG * PCB_REG_SP)(a0)
932         REG_S   ra, (SZREG * PCB_REG_RA)(a0)
933         REG_S   v0, (SZREG * PCB_REG_SR)(a0)
934         jr      ra
935         li      v0, 0                   # setjmp return
936 END(setjmp)
937
938 LEAF(longjmp)
939         REG_L   v0, (SZREG * PCB_REG_SR)(a0)
940         REG_L   ra, (SZREG * PCB_REG_RA)(a0)
941         REG_L   s0, (SZREG * PCB_REG_S0)(a0)
942         REG_L   s1, (SZREG * PCB_REG_S1)(a0)
943         REG_L   s2, (SZREG * PCB_REG_S2)(a0)
944         REG_L   s3, (SZREG * PCB_REG_S3)(a0)
945         REG_L   s4, (SZREG * PCB_REG_S4)(a0)
946         REG_L   s5, (SZREG * PCB_REG_S5)(a0)
947         REG_L   s6, (SZREG * PCB_REG_S6)(a0)
948         REG_L   s7, (SZREG * PCB_REG_S7)(a0)
949         REG_L   s8, (SZREG * PCB_REG_S8)(a0)
950         REG_L   sp, (SZREG * PCB_REG_SP)(a0)
951         mtc0    v0, MIPS_COP_0_STATUS   # Later the "real" spl value!
952         ITLBNOPFIX
953         jr      ra
954         li      v0, 1                   # longjmp return
955 END(longjmp)
956
957 LEAF(mips3_ld)
958         .set push
959         .set noreorder
960         .set mips64
961 #if defined(__mips_o32)
962         mfc0    t0, MIPS_COP_0_STATUS           # turn off interrupts
963         and     t1, t0, ~(MIPS_SR_INT_IE)
964         mtc0    t1, MIPS_COP_0_STATUS
965         COP0_SYNC
966         nop
967         nop
968         nop
969
970         ld      v0, 0(a0)
971 #if _BYTE_ORDER == _BIG_ENDIAN
972         dsll    v1, v0, 32
973         dsra    v1, v1, 32                      # low word in v1
974         dsra    v0, v0, 32                      # high word in v0
975 #else
976         dsra    v1, v0, 32                      # high word in v1
977         dsll    v0, v0, 32
978         dsra    v0, v0, 32                      # low word in v0
979 #endif
980
981         mtc0    t0, MIPS_COP_0_STATUS           # restore intr status.
982         COP0_SYNC
983         nop
984 #else /* !__mips_o32 */
985         ld      v0, 0(a0)
986 #endif /* !__mips_o32 */
987
988         jr      ra
989         nop
990         .set pop
991 END(mips3_ld)
992
993 LEAF(mips3_sd)
994         .set push
995         .set mips64
996         .set noreorder
997 #if defined(__mips_o32)
998         mfc0    t0, MIPS_COP_0_STATUS           # turn off interrupts
999         and     t1, t0, ~(MIPS_SR_INT_IE)
1000         mtc0    t1, MIPS_COP_0_STATUS
1001         COP0_SYNC
1002         nop
1003         nop
1004         nop
1005
1006         # NOTE: a1 is padding!
1007
1008 #if _BYTE_ORDER == _BIG_ENDIAN
1009         dsll    a2, a2, 32                      # high word in a2
1010         dsll    a3, a3, 32                      # low word in a3
1011         dsrl    a3, a3, 32
1012 #else
1013         dsll    a2, a2, 32                      # low word in a2
1014         dsrl    a2, a2, 32
1015         dsll    a3, a3, 32                      # high word in a3
1016 #endif
1017         or      a1, a2, a3
1018         sd      a1, 0(a0)
1019
1020         mtc0    t0, MIPS_COP_0_STATUS           # restore intr status.
1021         COP0_SYNC
1022         nop
1023 #else /* !__mips_o32 */
1024         sd      a1, 0(a0)
1025 #endif /* !__mips_o32 */
1026
1027         jr      ra
1028         nop
1029         .set pop
1030 END(mips3_sd)