1 /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Digital Equipment Corporation and Ralph Campbell.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
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.
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)
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
54 * Contains code that is the first executed at boot time plus
55 * assembly language support routines.
59 #include <sys/errno.h>
60 #include <machine/asm.h>
61 #include <machine/cpu.h>
62 #include <machine/regnum.h>
66 .set noreorder # Noreorder is default style!
73 * This table is indexed by u.u_pcb.pcb_onfault in trap().
74 * The reason for using this table rather than storing an address in
75 * u.u_pcb.pcb_onfault is simply to make the code faster.
81 .word 0 # invalid index number
90 #if defined(DDB) || defined(DEBUG)
100 * See if access to addr with a len type instruction causes a machine check.
101 * len is length of access (1=byte, 2=short, 4=long)
112 sw v0, U_PCB_ONFAULT(v1)
123 sw zero, U_PCB_ONFAULT(v1)
125 move v0, zero # made it w/o errors
128 li v0, 1 # trap sends us here
132 * int copystr(void *kfaddr, void *kdaddr, size_t maxlen, size_t *lencopied)
133 * Copy a NIL-terminated string, at most maxlen characters long. Return the
134 * number of characters copied (including the NIL) in *lencopied. If the
135 * string is too long, return ENAMETOOLONG; else return 0.
144 sb v0, 0(a1) # each byte until NIL
146 bne a2, zero, 1b # less than maxlen
149 li v0, ENAMETOOLONG # run out of space
151 beq a3, zero, 3f # return num. of copied bytes
152 subu a2, t0, a2 # if the 4th arg was non-NULL
155 j ra # v0 is 0 or ENAMETOOLONG
161 * fillw(pat, addr, count)
175 * Optimized memory zero code.
176 * mem_zero_page(addr);
190 * Block I/O routines mainly used by I/O drivers.
193 * a1 = memory address
255 bne v0, zero, 3f # arghh, unaligned.
281 bne v0, zero, 3f # arghh, unaligned.
303 * Copy a null terminated string from the user address space into
304 * the kernel address space.
306 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
312 NON_LEAF(copyinstr, STAND_FRAME_SIZE, ra)
313 subu sp, sp, STAND_FRAME_SIZE
314 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
315 sw ra, STAND_RA_OFFSET(sp)
316 blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space
320 jal _C_LABEL(copystr)
321 sw v0, U_PCB_ONFAULT(v1)
322 lw ra, STAND_RA_OFFSET(sp)
325 sw zero, U_PCB_ONFAULT(v1)
327 addu sp, sp, STAND_FRAME_SIZE
331 * Copy a null terminated string from the kernel address space into
332 * the user address space.
334 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
340 NON_LEAF(copyoutstr, STAND_FRAME_SIZE, ra)
341 subu sp, sp, STAND_FRAME_SIZE
342 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
343 sw ra, STAND_RA_OFFSET(sp)
344 blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space
348 jal _C_LABEL(copystr)
349 sw v0, U_PCB_ONFAULT(v1)
350 lw ra, STAND_RA_OFFSET(sp)
353 sw zero, U_PCB_ONFAULT(v1)
355 addu sp, sp, STAND_FRAME_SIZE
359 * Copy specified amount of data from user space into the kernel
360 * copyin(from, to, len)
361 * caddr_t *from; (user source address)
362 * caddr_t *to; (kernel destination address)
365 NON_LEAF(copyin, STAND_FRAME_SIZE, ra)
366 subu sp, sp, STAND_FRAME_SIZE
367 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
368 sw ra, STAND_RA_OFFSET(sp)
369 blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space
374 sw v0, U_PCB_ONFAULT(v1)
375 lw ra, STAND_RA_OFFSET(sp)
377 lw v1, PC_CURPCB(v1) # bcopy modified v1, so reload
378 sw zero, U_PCB_ONFAULT(v1)
379 addu sp, sp, STAND_FRAME_SIZE
385 * Copy specified amount of data from kernel to the user space
386 * copyout(from, to, len)
387 * caddr_t *from; (kernel source address)
388 * caddr_t *to; (user destination address)
391 NON_LEAF(copyout, STAND_FRAME_SIZE, ra)
392 subu sp, sp, STAND_FRAME_SIZE
393 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
394 sw ra, STAND_RA_OFFSET(sp)
395 blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space
400 sw v0, U_PCB_ONFAULT(v1)
401 lw ra, STAND_RA_OFFSET(sp)
403 lw v1, PC_CURPCB(v1) # bcopy modified v1, so reload
404 sw zero, U_PCB_ONFAULT(v1)
405 addu sp, sp, STAND_FRAME_SIZE
411 lw ra, STAND_RA_OFFSET(sp)
414 sw zero, U_PCB_ONFAULT(v1)
415 addu sp, sp, STAND_FRAME_SIZE
417 li v0, EFAULT # return error
421 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
423 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
429 blt a0, zero, fswberr # make sure address is in user space
433 sw v0, U_PCB_ONFAULT(v1)
434 lw v0, 0(a0) # fetch word
436 sw zero, U_PCB_ONFAULT(v1)
441 blt a0, zero, fswberr # make sure address is in user space
445 sw v0, U_PCB_ONFAULT(v1)
446 lhu v0, 0(a0) # fetch short
448 sw zero, U_PCB_ONFAULT(v1)
453 blt a0, zero, fswberr # make sure address is in user space
457 sw v0, U_PCB_ONFAULT(v1)
458 lbu v0, 0(a0) # fetch byte
460 sw zero, U_PCB_ONFAULT(v1)
465 blt a0, zero, fswberr # make sure address is in user space
469 sw v0, U_PCB_ONFAULT(v1)
470 sw a1, 0(a0) # store word
471 sw zero, U_PCB_ONFAULT(v1)
478 * <v0>u_long casuword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long newval)
489 * <v0>uint32_t casuword(<a0>uint32_t *p, <a1>uint32_t oldval,
490 * <a2>uint32_t newval)
500 /* unused in FreeBSD */
502 * Have to flush instruction cache afterwards.
505 blt a0, zero, fswberr # make sure address is in user space
509 sw v0, U_PCB_ONFAULT(v1)
510 sw a1, 0(a0) # store word
511 sw zero, U_PCB_ONFAULT(v1)
512 j _C_LABEL(Mips_SyncICache) # FlushICache sets v0 = 0. (Ugly)
513 li a1, 4 # size of word
518 * Will have to flush the instruction cache if byte merging is done in hardware.
522 blt a0, zero, fswberr # make sure address is in user space
526 sw v0, U_PCB_ONFAULT(v1)
527 sh a1, 0(a0) # store short
528 sw zero, U_PCB_ONFAULT(v1)
535 blt a0, zero, fswberr # make sure address is in user space
539 sw v0, U_PCB_ONFAULT(v1)
540 sb a1, 0(a0) # store byte
541 sw zero, U_PCB_ONFAULT(v1)
552 * fuswintr and suswintr are just like fusword and susword except that if
553 * the page is not in memory or would cause a trap, then we return an error.
554 * The important thing is to prevent sleep() and switch().
557 blt a0, zero, fswintrberr # make sure address is in user space
561 sw v0, U_PCB_ONFAULT(v1)
562 lhu v0, 0(a0) # fetch short
564 sw zero, U_PCB_ONFAULT(v1)
568 blt a0, zero, fswintrberr # make sure address is in user space
572 sw v0, U_PCB_ONFAULT(v1)
573 sh a1, 0(a0) # store short
574 sw zero, U_PCB_ONFAULT(v1)
585 * Insert 'p' after 'q'.
590 lw v0, 0(a1) # v0 = q->next
591 sw a1, 4(a0) # p->prev = q
592 sw v0, 0(a0) # p->next = q->next
593 sw a0, 4(v0) # q->next->prev = p
595 sw a0, 0(a1) # q->next = p
599 * Remove item 'p' from queue.
604 lw v0, 0(a0) # v0 = p->next
605 lw v1, 4(a0) # v1 = p->prev
607 sw v0, 0(v1) # p->prev->next = p->next
609 sw v1, 4(v0) # p->next->prev = p->prev
612 /*--------------------------------------------------------------------------
619 * Returns the current COUNT reg.
624 *--------------------------------------------------------------------------
634 /*--------------------------------------------------------------------------
641 * Sets a new value to the COMPARE register.
644 * The COMPARE equal interrupt is acknowledged.
646 *--------------------------------------------------------------------------
648 LEAF(Mips_SetCOMPARE)
649 mtc0 a0, COP_0_COMPARE
654 LEAF(Mips_GetCOMPARE)
655 mfc0 v0, COP_0_COMPARE
661 * u_int32_t mips_cp0_status_read(void)
663 * Return the current value of the CP0 Status register.
665 LEAF(mips_cp0_status_read)
666 mfc0 v0, COP_0_STATUS_REG
669 END(mips_cp0_status_read)
672 * void mips_cp0_status_write(u_int32_t)
674 * Set the value of the CP0 Status register.
676 * Note: This is almost certainly not the way you want to write a
677 * "permanent" value to to the CP0 Status register, since it gets
678 * saved in trap frames and restores.
680 LEAF(mips_cp0_status_write)
681 mtc0 a0, COP_0_STATUS_REG
686 END(mips_cp0_status_write)
690 * memcpy(to, from, len)
691 * {ov}bcopy(from, to, len)
695 move v0, a0 # swap from and to
701 addu t0, a0, a2 # t0 = end of s1 region
704 and t1, t1, t2 # t1 = true if from < to < (from+len)
705 beq t1, zero, forward # non overlapping, do forward copy
706 slt t2, a2, 12 # check for small copy
709 addu t1, a1, a2 # t1 = end of to region
711 lb v1, -1(t0) # copy bytes backwards,
712 subu t0, t0, 1 # doesnt happen often so do slow way
720 bne t2, zero, smallcpy # do a small bcopy
721 xor v1, a0, a1 # compare low two bits of addresses
723 subu a3, zero, a1 # compute # bytes to word align address
724 beq v1, zero, aligned # addresses can be word aligned
728 subu a2, a2, a3 # subtract from remaining count
729 LWHI v1, 0(a0) # get next 4 bytes (unaligned)
732 SWHI v1, 0(a1) # store 1, 2, or 3 bytes to align a1
735 and v1, a2, 3 # compute number of words left
738 addu a3, a3, a0 # compute ending address
740 LWHI v1, 0(a0) # copy words a0 unaligned, a1 aligned
746 nop # We have to do this mmu-bug.
751 subu a2, a2, a3 # subtract from remaining count
752 LWHI v1, 0(a0) # copy 1, 2, or 3 bytes to align
757 and v1, a2, 3 # compute number of whole words left
760 addu a3, a3, a0 # compute ending address
762 lw v1, 0(a0) # copy words
769 addu a3, a2, a0 # compute ending address
771 lbu v1, 0(a0) # copy bytes
775 addu a1, a1, 1 # MMU BUG ? can not do -1(a1) at 0x80000000!!
782 * memset(void *s1, int c, int len)
783 * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp
787 blt a2, 12, memsetsmallclr # small amount to clear?
788 move v0, a0 # save s1 for result
790 sll t1, a1, 8 # compute c << 8 in t1
791 or t1, t1, a1 # compute c << 8 | c in 11
792 sll t2, t1, 16 # shift that left 16
793 or t1, t2, t1 # or together
795 subu t0, zero, a0 # compute # bytes to word align address
797 beq t0, zero, 1f # skip if word aligned
798 subu a2, a2, t0 # subtract from remaining count
799 SWHI t1, 0(a0) # store 1, 2, or 3 bytes to align
802 and v1, a2, 3 # compute number of whole words left
805 addu t0, t0, a0 # compute ending address
807 addu a0, a0, 4 # clear words
814 bne a0, t0, 2b # unrolling loop does not help
815 sw t1, -4(a0) # since we are limited by memory speed
819 addu t0, a2, a0 # compute ending address
821 addu a0, a0, 1 # clear bytes
842 blt a1, 12, smallclr # small amount to clear?
843 subu a3, zero, a0 # compute # bytes to word align address
845 beq a3, zero, 1f # skip if word aligned
846 subu a1, a1, a3 # subtract from remaining count
847 SWHI zero, 0(a0) # clear 1, 2, or 3 bytes to align
850 and v0, a1, 3 # compute number of words left
853 addu a3, a3, a0 # compute ending address
855 addu a0, a0, 4 # clear words
856 bne a0, a3, 2b # unrolling loop does not help
857 sw zero, -4(a0) # since we are limited by memory speed
860 addu a3, a1, a0 # compute ending address
862 addu a0, a0, 1 # clear bytes
876 blt a2, 16, smallcmp # is it worth any trouble?
877 xor v0, a0, a1 # compare low two bits of addresses
879 subu a3, zero, a1 # compute # bytes to word align address
880 bne v0, zero, unalignedcmp # not possible to align addresses
884 subu a2, a2, a3 # subtract from remaining count
885 move v0, v1 # init v0,v1 so unmodified bytes match
886 LWHI v0, 0(a0) # read 1, 2, or 3 bytes
892 and a3, a2, ~3 # compute number of whole words left
893 subu a2, a2, a3 # which has to be >= (16-3) & ~3
894 addu a3, a3, a0 # compute ending address
896 lw v0, 0(a0) # compare words
903 b smallcmp # finish remainder
907 subu a2, a2, a3 # subtract from remaining count
908 addu a3, a3, a0 # compute ending address
910 lbu v0, 0(a0) # compare bytes until a1 word aligned
918 and a3, a2, ~3 # compute number of whole words left
919 subu a2, a2, a3 # which has to be >= (16-3) & ~3
920 addu a3, a3, a0 # compute ending address
922 LWHI v0, 0(a0) # compare words a0 unaligned, a1 aligned
932 addu a3, a2, a0 # compute ending address
958 and v1, a0, 1 # bit set?
960 beq v1, zero, 1b # no, continue
986 * u_int32_t atomic_cmpset_32(u_int32_t *p, u_int32_t cmpval, u_int32_t newval)
987 * Atomically compare the value stored at p with cmpval
988 * and if the two values are equal, update value *p with
989 * newval. Return zero if compare failed, non-zero otherwise
993 LEAF(atomic_cmpset_32)
1006 END(atomic_cmpset_32)
1010 * atomic_readandclear_32(u_int32_t *a)
1017 LEAF(atomic_readandclear_32)
1028 END(atomic_readandclear_32)
1032 * atomic_set_32(u_int32_t *a, u_int32_t b)
1051 * atomic_add_32(uint32_t *a, uint32_t b)
1058 srl a0, a0, 2 # round down address to be 32-bit aligned
1072 * atomic_clear_32(u_int32_t *a, u_int32_t b)
1077 LEAF(atomic_clear_32)
1079 srl a0, a0, 2 # round down address to be 32-bit aligned
1084 and t0, t0, a1 # t1 has the new lower 16 bits
1090 END(atomic_clear_32)
1094 * atomic_subtract_32(uint16_t *a, uint16_t b)
1099 LEAF(atomic_subtract_32)
1101 srl a0, a0, 2 # round down address to be 32-bit aligned
1111 END(atomic_subtract_32)
1117 * atomic_set_16(u_int16_t *a, u_int16_t b)
1124 srl a0, a0, 2 # round down address to be 32-bit aligned
1139 * atomic_clear_16(u_int16_t *a, u_int16_t b)
1144 LEAF(atomic_clear_16)
1146 srl a0, a0, 2 # round down address to be 32-bit aligned
1152 andi t1, t1, 0xffff # t1 has the original lower 16 bits
1153 and t1, t1, a1 # t1 has the new lower 16 bits
1154 srl t0, t0, 16 # preserve original top 16 bits
1162 END(atomic_clear_16)
1167 * atomic_subtract_16(uint16_t *a, uint16_t b)
1172 LEAF(atomic_subtract_16)
1174 srl a0, a0, 2 # round down address to be 32-bit aligned
1179 andi t1, t1, 0xffff # t1 has the original lower 16 bits
1181 andi t1, t1, 0xffff # t1 has the new lower 16 bits
1182 srl t0, t0, 16 # preserve original top 16 bits
1190 END(atomic_subtract_16)
1194 * atomic_add_16(uint16_t *a, uint16_t b)
1201 srl a0, a0, 2 # round down address to be 32-bit aligned
1206 andi t1, t1, 0xffff # t1 has the original lower 16 bits
1208 andi t1, t1, 0xffff # t1 has the new lower 16 bits
1209 srl t0, t0, 16 # preserve original top 16 bits
1221 * atomic_add_8(uint8_t *a, uint8_t b)
1228 srl a0, a0, 2 # round down address to be 32-bit aligned
1233 andi t1, t1, 0xff # t1 has the original lower 8 bits
1235 andi t1, t1, 0xff # t1 has the new lower 8 bits
1236 srl t0, t0, 8 # preserve original top 24 bits
1249 * atomic_subtract_8(uint8_t *a, uint8_t b)
1254 LEAF(atomic_subtract_8)
1256 srl a0, a0, 2 # round down address to be 32-bit aligned
1261 andi t1, t1, 0xff # t1 has the original lower 8 bits
1263 andi t1, t1, 0xff # t1 has the new lower 8 bits
1264 srl t0, t0, 8 # preserve original top 24 bits
1272 END(atomic_subtract_8)
1275 * atomic 64-bit register read/write assembly language support routines.
1278 .set noreorder # Noreorder is default style!
1279 #ifndef _MIPS_ARCH_XLR
1283 LEAF(atomic_readandclear_64)
1292 END(atomic_readandclear_64)
1294 LEAF(atomic_store_64)
1295 mfc0 t1, COP_0_STATUS_REG
1296 and t2, t1, ~SR_INT_ENAB
1297 mtc0 t2, COP_0_STATUS_REG
1308 mtc0 t1,COP_0_STATUS_REG
1315 END(atomic_store_64)
1317 LEAF(atomic_load_64)
1318 mfc0 t1, COP_0_STATUS_REG
1319 and t2, t1, ~SR_INT_ENAB
1320 mtc0 t2, COP_0_STATUS_REG
1331 mtc0 t1,COP_0_STATUS_REG
1340 #if defined(DDB) || defined(DEBUG)
1344 and v0, a0, 3 # unaligned ?
1346 lw t1, PC_CURPCB(t1)
1348 sw v1, U_PCB_ONFAULT(t1)
1352 sw zero, U_PCB_ONFAULT(t1)
1358 sw zero, U_PCB_ONFAULT(t1)
1368 and v0, a0, 3 # unaligned ?
1370 lw t1, PC_CURPCB(t1)
1372 sw v1, U_PCB_ONFAULT(t1)
1376 sw zero, U_PCB_ONFAULT(t1)
1382 sw zero, U_PCB_ONFAULT(t1)
1389 #ifndef _MIPS_ARCH_XLR
1393 #endif /* DDB || DEBUG */
1396 #define STORE sw /* 32 bit mode regsave instruction */
1397 #define LOAD lw /* 32 bit mode regload instruction */
1398 #define RSIZE 4 /* 32 bit mode register size */
1400 #define STORE sd /* 64 bit mode regsave instruction */
1401 #define LOAD ld /* 64 bit mode regload instruction */
1402 #define RSIZE 8 /* 64 bit mode register size */
1405 #define ITLBNOPFIX nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
1409 break BREAK_SOVER_VAL
1415 mfc0 v0, COP_0_STATUS_REG # Later the "real" spl value!
1416 STORE s0, (RSIZE * PREG_S0)(a0)
1417 STORE s1, (RSIZE * PREG_S1)(a0)
1418 STORE s2, (RSIZE * PREG_S2)(a0)
1419 STORE s3, (RSIZE * PREG_S3)(a0)
1420 STORE s4, (RSIZE * PREG_S4)(a0)
1421 STORE s5, (RSIZE * PREG_S5)(a0)
1422 STORE s6, (RSIZE * PREG_S6)(a0)
1423 STORE s7, (RSIZE * PREG_S7)(a0)
1424 STORE s8, (RSIZE * PREG_SP)(a0)
1425 STORE sp, (RSIZE * PREG_S8)(a0)
1426 STORE ra, (RSIZE * PREG_RA)(a0)
1427 STORE v0, (RSIZE * PREG_SR)(a0)
1429 li v0, 0 # setjmp return
1433 LOAD v0, (RSIZE * PREG_SR)(a0)
1434 LOAD ra, (RSIZE * PREG_RA)(a0)
1435 LOAD s0, (RSIZE * PREG_S0)(a0)
1436 LOAD s1, (RSIZE * PREG_S1)(a0)
1437 LOAD s2, (RSIZE * PREG_S2)(a0)
1438 LOAD s3, (RSIZE * PREG_S3)(a0)
1439 LOAD s4, (RSIZE * PREG_S4)(a0)
1440 LOAD s5, (RSIZE * PREG_S5)(a0)
1441 LOAD s6, (RSIZE * PREG_S6)(a0)
1442 LOAD s7, (RSIZE * PREG_S7)(a0)
1443 LOAD s8, (RSIZE * PREG_S8)(a0)
1444 LOAD sp, (RSIZE * PREG_SP)(a0)
1445 mtc0 v0, COP_0_STATUS_REG # Later the "real" spl value!
1448 li v0, 1 # longjmp return
1453 lw t0, PC_CURTHREAD(t0)
1455 sw zero, U_PCB_ONFAULT(t0)
1460 /* Define a new md function 'casuptr'. This atomically compares and sets
1461 a pointer that is in user space. It will be used as the basic primitive
1462 for a kernel supported user space lock implementation. */
1465 li t0, VM_MAXUSER_ADDRESS /* verify address validity */
1466 blt a0, t0, fusufault /* trap faults */
1470 lw t1, PC_CURTHREAD(t1)
1474 sw t2, U_PCB_ONFAULT(t1)
1476 ll v0, 0(a0) /* try to load the old value */
1477 beq v0, a1, 2f /* compare */
1478 move t0, a2 /* setup value to write */
1479 sc t0, 0(a0) /* write if address still locked */
1480 beq t0, zero, 1b /* if it failed, spin */
1482 sw zero, U_PCB_ONFAULT(t1) /* clean up */
1487 #ifdef TARGET_OCTEON
1489 * void octeon_enable_shadow(void)
1490 * turns on access to CC and CCRes
1492 LEAF(octeon_enable_shadow)
1497 END(octeon_enable_shadow)
1500 LEAF(octeon_get_shadow)
1504 END(octeon_get_shadow)
1507 * octeon_set_control(addr, uint32_t val)
1509 LEAF(octeon_set_control)
1521 END(octeon_set_control)
1524 * octeon_get_control(addr)
1526 LEAF(octeon_get_control)
1528 /* dmfc0 a1, 9, 7 */
1534 END(octeon_get_control)