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/endian.h> 94#include <machine/regnum.h> 95#include <machine/cpuregs.h> 96#include <machine/pcb.h> 97 98#include "assym.inc" 99 100 .set noreorder # Noreorder is default style! 101 102/* 103 * Primitives 104 */ 105 106 .text 107 108/* 109 * Copy a null terminated string from the user address space into 110 * the kernel address space. 111 * 112 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 113 * caddr_t fromaddr; 114 * caddr_t toaddr; 115 * u_int maxlength; 116 * u_int *lencopied; 117 */ 118LEAF(copyinstr) 119 PTR_LA v0, __copyinstr_err 120 blt a0, zero, __copyinstr_err # make sure address is in user space 121 GET_CPU_PCPU(v1) 122 PTR_L v1, PC_CURPCB(v1) 123 PTR_S v0, U_PCB_ONFAULT(v1) 124 125 move t0, a2 126 beq a2, zero, 4f 1271: 128 lbu v0, 0(a0) 129 PTR_SUBU a2, a2, 1 130 beq v0, zero, 2f 131 sb v0, 0(a1) # each byte until NIL 132 PTR_ADDU a0, a0, 1 133 bne a2, zero, 1b # less than maxlen 134 PTR_ADDU a1, a1, 1 1354: 136 li v0, ENAMETOOLONG # run out of space 1372: 138 beq a3, zero, 3f # return num. of copied bytes 139 PTR_SUBU a2, t0, a2 # if the 4th arg was non-NULL 140 PTR_S a2, 0(a3) 1413: 142 143 PTR_S zero, U_PCB_ONFAULT(v1) 144 j ra 145 nop 146 147__copyinstr_err: 148 j ra 149 li v0, EFAULT 150END(copyinstr) 151 152/* 153 * Copy specified amount of data from user space into the kernel 154 * copyin(from, to, len) 155 * caddr_t *from; (user source address) 156 * caddr_t *to; (kernel destination address) 157 * unsigned len; 158 */ 159NESTED(copyin, CALLFRAME_SIZ, ra) 160 PTR_SUBU sp, sp, CALLFRAME_SIZ 161 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 162 PTR_LA v0, copyerr 163 blt a0, zero, _C_LABEL(copyerr) # make sure address is in user space 164 REG_S ra, CALLFRAME_RA(sp) 165 GET_CPU_PCPU(v1) 166 PTR_L v1, PC_CURPCB(v1) 167 jal _C_LABEL(bcopy) 168 PTR_S v0, U_PCB_ONFAULT(v1) 169 REG_L ra, CALLFRAME_RA(sp) 170 GET_CPU_PCPU(v1) 171 PTR_L v1, PC_CURPCB(v1) # bcopy modified v1, so reload 172 PTR_S zero, U_PCB_ONFAULT(v1) 173 PTR_ADDU sp, sp, CALLFRAME_SIZ 174 j ra 175 move v0, zero 176END(copyin) 177 178/* 179 * Copy specified amount of data from kernel to the user space 180 * copyout(from, to, len) 181 * caddr_t *from; (kernel source address) 182 * caddr_t *to; (user destination address) 183 * unsigned len; 184 */ 185NESTED(copyout, CALLFRAME_SIZ, ra) 186 PTR_SUBU sp, sp, CALLFRAME_SIZ 187 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 188 PTR_LA v0, copyerr 189 blt a1, zero, _C_LABEL(copyerr) # make sure address is in user space 190 REG_S ra, CALLFRAME_RA(sp) 191 GET_CPU_PCPU(v1) 192 PTR_L v1, PC_CURPCB(v1) 193 jal _C_LABEL(bcopy) 194 PTR_S v0, U_PCB_ONFAULT(v1) 195 REG_L ra, CALLFRAME_RA(sp) 196 GET_CPU_PCPU(v1) 197 PTR_L v1, PC_CURPCB(v1) # bcopy modified v1, so reload 198 PTR_S zero, U_PCB_ONFAULT(v1) 199 PTR_ADDU sp, sp, CALLFRAME_SIZ 200 j ra 201 move v0, zero 202END(copyout) 203 204LEAF(copyerr) 205 REG_L ra, CALLFRAME_RA(sp) 206 PTR_ADDU sp, sp, CALLFRAME_SIZ 207 j ra 208 li v0, EFAULT # return error 209END(copyerr) 210 211/* 212 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to 213 * user-space. 214 */ 215#ifdef __mips_n64 216LEAF(fueword64) 217XLEAF(fueword) 218 PTR_LA v0, fswberr 219 blt a0, zero, fswberr # make sure address is in user space 220 nop 221 GET_CPU_PCPU(v1) 222 PTR_L v1, PC_CURPCB(v1) 223 PTR_S v0, U_PCB_ONFAULT(v1) 224 ld v0, 0(a0) # fetch word 225 PTR_S zero, U_PCB_ONFAULT(v1) 226 sd v0, 0(a1) # store word 227 j ra 228 li v0, 0 229END(fueword64) 230#endif 231 232LEAF(fueword32) 233#ifndef __mips_n64 234XLEAF(fueword) 235#endif 236 PTR_LA v0, fswberr 237 blt a0, zero, fswberr # make sure address is in user space 238 nop 239 GET_CPU_PCPU(v1) 240 PTR_L v1, PC_CURPCB(v1) 241 PTR_S v0, U_PCB_ONFAULT(v1) 242 lw v0, 0(a0) # fetch word 243 PTR_S zero, U_PCB_ONFAULT(v1) 244 sw v0, 0(a1) # store word 245 j ra 246 li v0, 0 247END(fueword32) 248 249LEAF(fuesword) 250 PTR_LA v0, fswberr 251 blt a0, zero, fswberr # make sure address is in user space 252 nop 253 GET_CPU_PCPU(v1) 254 PTR_L v1, PC_CURPCB(v1) 255 PTR_S v0, U_PCB_ONFAULT(v1) 256 lhu v0, 0(a0) # fetch short 257 PTR_S zero, U_PCB_ONFAULT(v1) 258 sh v0, 0(a1) # store short 259 j ra 260 li v0, 0 261END(fuesword) 262 263LEAF(fubyte) 264 PTR_LA v0, fswberr 265 blt a0, zero, fswberr # make sure address is in user space 266 nop 267 GET_CPU_PCPU(v1) 268 PTR_L v1, PC_CURPCB(v1) 269 PTR_S v0, U_PCB_ONFAULT(v1) 270 lbu v0, 0(a0) # fetch byte 271 j ra 272 PTR_S zero, U_PCB_ONFAULT(v1) 273END(fubyte) 274 275LEAF(suword32) 276#ifndef __mips_n64 277XLEAF(suword) 278#endif 279 PTR_LA v0, fswberr 280 blt a0, zero, fswberr # make sure address is in user space 281 nop 282 GET_CPU_PCPU(v1) 283 PTR_L v1, PC_CURPCB(v1) 284 PTR_S v0, U_PCB_ONFAULT(v1) 285 sw a1, 0(a0) # store word 286 PTR_S zero, U_PCB_ONFAULT(v1) 287 j ra 288 move v0, zero 289END(suword32) 290 291#ifdef __mips_n64 292LEAF(suword64) 293XLEAF(suword) 294 PTR_LA v0, fswberr 295 blt a0, zero, fswberr # make sure address is in user space 296 nop 297 GET_CPU_PCPU(v1) 298 PTR_L v1, PC_CURPCB(v1) 299 PTR_S v0, U_PCB_ONFAULT(v1) 300 sd a1, 0(a0) # store word 301 PTR_S zero, U_PCB_ONFAULT(v1) 302 j ra 303 move v0, zero 304END(suword64) 305#endif 306 307/* 308 * casueword(9) 309 * <v0>u_long casueword(<a0>u_long *p, <a1>u_long oldval, <a2>u_long *oldval_p, 310 * <a3>u_long newval) 311 */ 312/* 313 * casueword32(9) 314 * <v0>uint32_t casueword(<a0>uint32_t *p, <a1>uint32_t oldval, 315 * <a2>uint32_t newval) 316 */ 317LEAF(casueword32) 318#ifndef __mips_n64 319XLEAF(casueword) 320#endif 321 PTR_LA v0, fswberr 322 blt a0, zero, fswberr # make sure address is in user space 323 nop 324 GET_CPU_PCPU(v1) 325 PTR_L v1, PC_CURPCB(v1) 326 PTR_S v0, U_PCB_ONFAULT(v1) 327 328 li v0, 1 329 move t0, a3 330 ll t1, 0(a0) 331 bne a1, t1, 1f 332 nop 333 sc t0, 0(a0) # store word 334 xori v0, t0, 1 3351: 336 PTR_S zero, U_PCB_ONFAULT(v1) 337 jr ra 338 sw t1, 0(a2) # unconditionally store old word 339END(casueword32) 340 341#ifdef __mips_n64 342LEAF(casueword64) 343XLEAF(casueword) 344 PTR_LA v0, fswberr 345 blt a0, zero, fswberr # make sure address is in user space 346 nop 347 GET_CPU_PCPU(v1) 348 PTR_L v1, PC_CURPCB(v1) 349 PTR_S v0, U_PCB_ONFAULT(v1) 350 351 li v0, 1 352 move t0, a3 353 lld t1, 0(a0) 354 bne a1, t1, 1f 355 nop 356 scd t0, 0(a0) # store double word 357 xori v0, t0, 1 3581: 359 PTR_S zero, U_PCB_ONFAULT(v1) 360 jr ra 361 sd t1, 0(a2) # unconditionally store old word 362END(casueword64) 363#endif 364 365/* 366 * Will have to flush the instruction cache if byte merging is done in hardware. 367 */ 368LEAF(susword) 369 PTR_LA v0, fswberr 370 blt a0, zero, fswberr # make sure address is in user space 371 nop 372 GET_CPU_PCPU(v1) 373 PTR_L v1, PC_CURPCB(v1) 374 PTR_S v0, U_PCB_ONFAULT(v1) 375 sh a1, 0(a0) # store short 376 PTR_S zero, U_PCB_ONFAULT(v1) 377 j ra 378 move v0, zero 379END(susword) 380 381LEAF(subyte) 382 PTR_LA v0, fswberr 383 blt a0, zero, fswberr # make sure address is in user space 384 nop 385 GET_CPU_PCPU(v1) 386 PTR_L v1, PC_CURPCB(v1) 387 PTR_S v0, U_PCB_ONFAULT(v1) 388 sb a1, 0(a0) # store byte 389 PTR_S zero, U_PCB_ONFAULT(v1) 390 j ra 391 move v0, zero 392END(subyte) 393 394LEAF(fswberr) 395 j ra 396 li v0, -1 397END(fswberr) 398 399/* 400 * memset(void *s1, int c, int len) 401 * NetBSD: memset.S,v 1.3 2001/10/16 15:40:53 uch Exp 402 */ 403LEAF(memset) 404 .set noreorder 405 blt a2, 12, memsetsmallclr # small amount to clear? 406 move v0, a0 # save s1 for result 407 408 sll t1, a1, 8 # compute c << 8 in t1 409 or t1, t1, a1 # compute c << 8 | c in 11 410 sll t2, t1, 16 # shift that left 16 411 or t1, t2, t1 # or together 412 413 PTR_SUBU t0, zero, a0 # compute # bytes to word align address 414 and t0, t0, 3 415 beq t0, zero, 1f # skip if word aligned 416 PTR_SUBU a2, a2, t0 # subtract from remaining count 417 SWHI t1, 0(a0) # store 1, 2, or 3 bytes to align 418 PTR_ADDU a0, a0, t0 4191: 420 and v1, a2, 3 # compute number of whole words left 421 PTR_SUBU t0, a2, v1 422 PTR_SUBU a2, a2, t0 423 PTR_ADDU t0, t0, a0 # compute ending address 4242: 425 PTR_ADDU a0, a0, 4 # clear words 426 bne a0, t0, 2b # unrolling loop does not help 427 sw t1, -4(a0) # since we are limited by memory speed 428 429memsetsmallclr: 430 ble a2, zero, 2f 431 PTR_ADDU t0, a2, a0 # compute ending address 4321: 433 PTR_ADDU a0, a0, 1 # clear bytes 434 bne a0, t0, 1b 435 sb a1, -1(a0) 4362: 437 j ra 438 nop 439 .set reorder 440END(memset) 441 442/* 443 * bzero(s1, n) 444 */ 445LEAF(bzero) 446XLEAF(blkclr) 447 .set noreorder 448 blt a1, 12, smallclr # small amount to clear? 449 PTR_SUBU a3, zero, a0 # compute # bytes to word align address 450 and a3, a3, 3 451 beq a3, zero, 1f # skip if word aligned 452 PTR_SUBU a1, a1, a3 # subtract from remaining count 453 SWHI zero, 0(a0) # clear 1, 2, or 3 bytes to align 454 PTR_ADDU a0, a0, a3 4551: 456 and v0, a1, 3 # compute number of words left 457 PTR_SUBU a3, a1, v0 458 move a1, v0 459 PTR_ADDU a3, a3, a0 # compute ending address 4602: 461 PTR_ADDU a0, a0, 4 # clear words 462 bne a0, a3, 2b # unrolling loop does not help 463 sw zero, -4(a0) # since we are limited by memory speed 464smallclr: 465 ble a1, zero, 2f 466 PTR_ADDU a3, a1, a0 # compute ending address 4671: 468 PTR_ADDU a0, a0, 1 # clear bytes 469 bne a0, a3, 1b 470 sb zero, -1(a0) 4712: 472 j ra 473 nop 474END(bzero) 475 476 477/* 478 * bcmp(s1, s2, n) 479 */ 480LEAF(bcmp) 481 .set noreorder 482 blt a2, 16, smallcmp # is it worth any trouble? 483 xor v0, a0, a1 # compare low two bits of addresses 484 and v0, v0, 3 485 PTR_SUBU a3, zero, a1 # compute # bytes to word align address 486 bne v0, zero, unalignedcmp # not possible to align addresses 487 and a3, a3, 3 488 489 beq a3, zero, 1f 490 PTR_SUBU a2, a2, a3 # subtract from remaining count 491 move v0, v1 # init v0,v1 so unmodified bytes match 492 LWHI v0, 0(a0) # read 1, 2, or 3 bytes 493 LWHI v1, 0(a1) 494 PTR_ADDU a1, a1, a3 495 bne v0, v1, nomatch 496 PTR_ADDU a0, a0, a3 4971: 498 and a3, a2, ~3 # compute number of whole words left 499 PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3 500 PTR_ADDU a3, a3, a0 # compute ending address 5012: 502 lw v0, 0(a0) # compare words 503 lw v1, 0(a1) 504 PTR_ADDU a0, a0, 4 505 bne v0, v1, nomatch 506 PTR_ADDU a1, a1, 4 507 bne a0, a3, 2b 508 nop 509 b smallcmp # finish remainder 510 nop 511unalignedcmp: 512 beq a3, zero, 2f 513 PTR_SUBU a2, a2, a3 # subtract from remaining count 514 PTR_ADDU a3, a3, a0 # compute ending address 5151: 516 lbu v0, 0(a0) # compare bytes until a1 word aligned 517 lbu v1, 0(a1) 518 PTR_ADDU a0, a0, 1 519 bne v0, v1, nomatch 520 PTR_ADDU a1, a1, 1 521 bne a0, a3, 1b 522 nop 5232: 524 and a3, a2, ~3 # compute number of whole words left 525 PTR_SUBU a2, a2, a3 # which has to be >= (16-3) & ~3 526 PTR_ADDU a3, a3, a0 # compute ending address 5273: 528 LWHI v0, 0(a0) # compare words a0 unaligned, a1 aligned 529 LWLO v0, 3(a0) 530 lw v1, 0(a1) 531 PTR_ADDU a0, a0, 4 532 bne v0, v1, nomatch 533 PTR_ADDU a1, a1, 4 534 bne a0, a3, 3b 535 nop 536smallcmp: 537 ble a2, zero, match 538 PTR_ADDU a3, a2, a0 # compute ending address 5391: 540 lbu v0, 0(a0) 541 lbu v1, 0(a1) 542 PTR_ADDU a0, a0, 1 543 bne v0, v1, nomatch 544 PTR_ADDU a1, a1, 1 545 bne a0, a3, 1b 546 nop 547match: 548 j ra 549 move v0, zero 550nomatch: 551 j ra 552 li v0, 1 553END(bcmp) 554 555 556/* 557 * bit = ffs(value) 558 */ 559LEAF(ffs) 560 .set noreorder 561 beq a0, zero, 2f 562 move v0, zero 5631: 564 and v1, a0, 1 # bit set? 565 addu v0, v0, 1 566 beq v1, zero, 1b # no, continue 567 srl a0, a0, 1 5682: 569 j ra 570 nop 571END(ffs) 572 573/** 574 * void 575 * atomic_set_16(u_int16_t *a, u_int16_t b) 576 * { 577 * *a |= b; 578 * } 579 */ 580LEAF(atomic_set_16) 581 .set noreorder 582 /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ 583 andi t0, a0, 2 # get unaligned offset 584 xor a0, a0, t0 # align pointer 585#if _BYTE_ORDER == BIG_ENDIAN 586 xori t0, t0, 2 587#endif 588 sll t0, t0, 3 # convert byte offset to bit offset 589 sll a1, a1, t0 # put bits in the right half 5901: 591 ll t0, 0(a0) 592 or t0, t0, a1 593 sc t0, 0(a0) 594 beq t0, zero, 1b 595 nop 596 j ra 597 nop 598END(atomic_set_16) 599 600/** 601 * void 602 * atomic_clear_16(u_int16_t *a, u_int16_t b) 603 * { 604 * *a &= ~b; 605 * } 606 */ 607LEAF(atomic_clear_16) 608 .set noreorder 609 /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ 610 andi t0, a0, 2 # get unaligned offset 611 xor a0, a0, t0 # align pointer 612#if _BYTE_ORDER == BIG_ENDIAN 613 xori t0, t0, 2 614#endif 615 sll t0, t0, 3 # convert byte offset to bit offset 616 sll a1, a1, t0 # put bits in the right half 617 not a1, a1 6181: 619 ll t0, 0(a0) 620 and t0, t0, a1 621 sc t0, 0(a0) 622 beq t0, zero, 1b 623 nop 624 j ra 625 nop 626END(atomic_clear_16) 627 628 629/** 630 * void 631 * atomic_subtract_16(uint16_t *a, uint16_t b) 632 * { 633 * *a -= b; 634 * } 635 */ 636LEAF(atomic_subtract_16) 637 .set noreorder 638 /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ 639 andi t0, a0, 2 # get unaligned offset 640 xor a0, a0, t0 # align pointer 641#if _BYTE_ORDER == BIG_ENDIAN 642 xori t0, t0, 2 # flip order for big-endian 643#endif 644 sll t0, t0, 3 # convert byte offset to bit offset 645 sll a1, a1, t0 # put bits in the right half 646 li t2, 0xffff 647 sll t2, t2, t0 # compute mask 6481: 649 ll t0, 0(a0) 650 subu t1, t0, a1 651 /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ 652 xor t1, t0, t1 653 and t1, t1, t2 654 xor 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 /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ 672 andi t0, a0, 2 # get unaligned offset 673 xor a0, a0, t0 # align pointer 674#if _BYTE_ORDER == BIG_ENDIAN 675 xori t0, t0, 2 # flip order for big-endian 676#endif 677 sll t0, t0, 3 # convert byte offset to bit offset 678 sll a1, a1, t0 # put bits in the right half 679 li t2, 0xffff 680 sll t2, t2, t0 # compute mask 6811: 682 ll t0, 0(a0) 683 addu t1, t0, a1 684 /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ 685 xor t1, t0, t1 686 and t1, t1, t2 687 xor t0, t0, t1 688 sc t0, 0(a0) 689 beq t0, zero, 1b 690 nop 691 j ra 692 nop 693END(atomic_add_16) 694 695/** 696 * void 697 * atomic_add_8(uint8_t *a, uint8_t b) 698 * { 699 * *a += b; 700 * } 701 */ 702LEAF(atomic_add_8) 703 .set noreorder 704 andi t0, a0, 3 # get unaligned offset 705 xor a0, a0, t0 # align pointer 706#if _BYTE_ORDER == BIG_ENDIAN 707 xori t0, t0, 3 # flip order for big-endian 708#endif 709 sll t0, t0, 3 # convert byte offset to bit offset 710 sll a1, a1, t0 # put bits in the right quarter 711 li t2, 0xff 712 sll t2, t2, t0 # compute mask 7131: 714 ll t0, 0(a0) 715 addu t1, t0, a1 716 /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ 717 xor t1, t0, t1 718 and t1, t1, t2 719 xor t0, t0, t1 720 sc t0, 0(a0) 721 beq t0, zero, 1b 722 nop 723 j ra 724 nop 725END(atomic_add_8) 726 727 728/** 729 * void 730 * atomic_subtract_8(uint8_t *a, uint8_t b) 731 * { 732 * *a += b; 733 * } 734 */ 735LEAF(atomic_subtract_8) 736 .set noreorder 737 andi t0, a0, 3 # get unaligned offset 738 xor a0, a0, t0 # align pointer 739#if _BYTE_ORDER == BIG_ENDIAN 740 xori t0, t0, 3 # flip order for big-endian 741#endif 742 sll t0, t0, 3 # convert byte offset to bit offset 743 sll a1, a1, t0 # put bits in the right quarter 744 li t2, 0xff 745 sll t2, t2, t0 # compute mask 7461: 747 ll t0, 0(a0) 748 subu t1, t0, a1 749 /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ 750 xor t1, t0, t1 751 and t1, t1, t2 752 xor t0, t0, t1 753 sc t0, 0(a0) 754 beq t0, zero, 1b 755 nop 756 j ra 757 nop 758END(atomic_subtract_8) 759 760 .set noreorder # Noreorder is default style! 761 762#if defined(DDB) || defined(DEBUG) 763 764LEAF(kdbpeek) 765 PTR_LA v1, ddberr 766 and v0, a0, 3 # unaligned ? 767 GET_CPU_PCPU(t1) 768 PTR_L t1, PC_CURPCB(t1) 769 bne v0, zero, 1f 770 PTR_S v1, U_PCB_ONFAULT(t1) 771 772 lw v0, (a0) 773 jr ra 774 PTR_S zero, U_PCB_ONFAULT(t1) 775 7761: 777 LWHI v0, 0(a0) 778 LWLO v0, 3(a0) 779 jr ra 780 PTR_S zero, U_PCB_ONFAULT(t1) 781END(kdbpeek) 782 783LEAF(kdbpeekd) 784 PTR_LA v1, ddberr 785 and v0, a0, 3 # unaligned ? 786 GET_CPU_PCPU(t1) 787 PTR_L t1, PC_CURPCB(t1) 788 bne v0, zero, 1f 789 PTR_S v1, U_PCB_ONFAULT(t1) 790 791 ld v0, (a0) 792 jr ra 793 PTR_S zero, U_PCB_ONFAULT(t1) 794 7951: 796 REG_LHI v0, 0(a0) 797 REG_LLO v0, 7(a0) 798 jr ra 799 PTR_S zero, U_PCB_ONFAULT(t1) 800END(kdbpeekd) 801 802ddberr: 803 jr ra 804 nop 805 806#if defined(DDB) 807LEAF(kdbpoke) 808 PTR_LA v1, ddberr 809 and v0, a0, 3 # unaligned ? 810 GET_CPU_PCPU(t1) 811 PTR_L t1, PC_CURPCB(t1) 812 bne v0, zero, 1f 813 PTR_S v1, U_PCB_ONFAULT(t1) 814 815 sw a1, (a0) 816 jr ra 817 PTR_S zero, U_PCB_ONFAULT(t1) 818 8191: 820 SWHI a1, 0(a0) 821 SWLO a1, 3(a0) 822 jr ra 823 PTR_S zero, U_PCB_ONFAULT(t1) 824END(kdbpoke) 825 826 .data 827 .globl esym 828esym: .word 0 829 830#endif /* DDB */ 831#endif /* DDB || DEBUG */ 832 833 .text 834LEAF(breakpoint) 835 break MIPS_BREAK_SOVER_VAL 836 jr ra 837 nop 838END(breakpoint) 839 840LEAF(setjmp) 841 mfc0 v0, MIPS_COP_0_STATUS # Later the "real" spl value! 842 REG_S s0, (SZREG * PCB_REG_S0)(a0) 843 REG_S s1, (SZREG * PCB_REG_S1)(a0) 844 REG_S s2, (SZREG * PCB_REG_S2)(a0) 845 REG_S s3, (SZREG * PCB_REG_S3)(a0) 846 REG_S s4, (SZREG * PCB_REG_S4)(a0) 847 REG_S s5, (SZREG * PCB_REG_S5)(a0) 848 REG_S s6, (SZREG * PCB_REG_S6)(a0) 849 REG_S s7, (SZREG * PCB_REG_S7)(a0) 850 REG_S s8, (SZREG * PCB_REG_S8)(a0) 851 REG_S sp, (SZREG * PCB_REG_SP)(a0) 852 REG_S ra, (SZREG * PCB_REG_RA)(a0) 853 REG_S v0, (SZREG * PCB_REG_SR)(a0) 854 jr ra 855 li v0, 0 # setjmp return 856END(setjmp) 857 858LEAF(longjmp) 859 REG_L v0, (SZREG * PCB_REG_SR)(a0) 860 REG_L ra, (SZREG * PCB_REG_RA)(a0) 861 REG_L s0, (SZREG * PCB_REG_S0)(a0) 862 REG_L s1, (SZREG * PCB_REG_S1)(a0) 863 REG_L s2, (SZREG * PCB_REG_S2)(a0) 864 REG_L s3, (SZREG * PCB_REG_S3)(a0) 865 REG_L s4, (SZREG * PCB_REG_S4)(a0) 866 REG_L s5, (SZREG * PCB_REG_S5)(a0) 867 REG_L s6, (SZREG * PCB_REG_S6)(a0) 868 REG_L s7, (SZREG * PCB_REG_S7)(a0) 869 REG_L s8, (SZREG * PCB_REG_S8)(a0) 870 REG_L sp, (SZREG * PCB_REG_SP)(a0) 871 mtc0 v0, MIPS_COP_0_STATUS # Later the "real" spl value! 872 ITLBNOPFIX 873 jr ra 874 li v0, 1 # longjmp return 875END(longjmp) 876