1/* $NetBSD: support.S,v 1.10 2020/06/30 16:20:01 maxv Exp $ */ 2 3/*- 4 * Copyright (c) 1998 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31/*- 32 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. 33 * All rights reserved. 34 * 35 * Author: Chris G. Demetriou 36 * 37 * Permission to use, copy, modify and distribute this software and 38 * its documentation is hereby granted, provided that both the copyright 39 * notice and this permission notice appear in all copies of the 40 * software, derivative works or modified versions, and any portions 41 * thereof, and that both notices appear in supporting documentation. 42 * 43 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 44 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 45 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 46 * 47 * Carnegie Mellon requests users of this software to return to 48 * 49 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 50 * School of Computer Science 51 * Carnegie Mellon University 52 * Pittsburgh PA 15213-3890 53 * 54 * any improvements or extensions that they make and grant Carnegie the 55 * rights to redistribute these changes. 56 */ 57 58#include <machine/asm.h> 59 60#include "assym.h" 61 62.text 63 64/* 65 * ia64_change_mode: change mode to/from physical mode 66 * 67 * Arguments: 68 * r14 psr for desired mode 69 * 70 * Modifies: 71 * r15-r19 scratch 72 * ar.bsp tranlated to new mode 73 */ 74ENTRY_NOPROFILE(ia64_change_mode, 0) 75 rsm psr.i | psr.ic 76 mov r19=ar.rsc // save rsc while we change mode 77 tbit.nz p6,p7=r14,17 // physical or virtual ? 78 ;; 79 mov ar.rsc=0 // turn off RSE 80(p6) mov r15=7 // RR base for virtual addresses 81(p7) mov r15=0 // RR base for physical addresses 82 flushrs // no dirty registers please 83 srlz.i 84 ;; 85 mov r16=ar.bsp 86 mov r17=rp 87 mov r18=ar.rnat 88 ;; 89 dep r16=r15,r16,61,3 // new address of ar.bsp 90 dep r17=r15,r17,61,3 // new address of rp 91 dep sp=r15,sp,61,3 // new address of sp 92 ;; 93 mov ar.bspstore=r16 94 mov rp=r17 95 ;; 961: mov r16=ip 97 mov ar.rnat=r18 98 mov cr.ipsr=r14 // psr for new mode 99 ;; 100 add r16=2f-1b,r16 // address to rfi to 101 ;; 102 dep r16=r15,r16,61,3 // new mode address for rfi 103 ;; 104 mov cr.iip=r16 // setup for rfi 105 mov cr.ifs=r0 106 ;; 107 rfi 108 1092: mov ar.rsc=r19 // restore ar.rsc 110 br.ret.sptk.few rp // now in new mode 111END(ia64_change_mode) 112 113/* 114 * ia64_physical_mode: change mode to physical mode 115 * 116 * Return: 117 * ret0 psr to restore 118 * 119 * Modifies: 120 * r15-r18 scratch 121 * ar.bsp tranlated to physical mode 122 * psr.i cleared 123 */ 124ENTRY(ia64_physical_mode, 0) 125 mov r14=psr 126 mov ret0=psr 127 movl r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH) 128 movl r16=IA64_PSR_BN 129 ;; 130 andcm r14=r14,r15 // clear various xT bits 131 ;; 132 or r14=r14,r16 // make sure BN=1 133 or ret0=ret0,r16 // make sure BN=1 134 135 br.cond.sptk.many ia64_change_mode 136END(ia64_physical_mode) 137 138/* 139 * ia64_call_efi_physical: call an EFI procedure in physical mode 140 * 141 * Arguments: 142 * in0 Address of EFI procedure descriptor 143 * in1-in5 Arguments to EFI procedure 144 * 145 * Return: 146 * ret0-ret3 return values from EFI 147 * 148 */ 149ENTRY(ia64_call_efi_physical, 6) 150 .prologue 151 .regstk 6,4,5,0 152 .save ar.pfs,loc0 153 alloc loc0=ar.pfs,6,4,5,0 154 ;; 155 .save rp,loc1 156 mov loc1=rp 157 ;; 158 .body 159 br.call.sptk.many rp=ia64_physical_mode 160 ;; 161 mov loc2=r8 // psr to restore mode 162 mov loc3=gp // save kernel gp 163 ld8 r14=[in0],8 // function address 164 ;; 165 mov out0=in1 166 mov out1=in2 167 mov out2=in3 168 mov out3=in4 169 mov out4=in5 170 ld8 gp=[in0] // function gp value 171 ;; 172 mov b6=r14 173 ;; 174 br.call.sptk.many rp=b6 // call EFI procedure 175 mov gp=loc3 // restore kernel gp 176 ;; 177 mov r14=loc2 // psr to restore mode 178 br.call.sptk.many rp=ia64_change_mode 179 ;; 180 mov rp=loc1 181 mov ar.pfs=loc0 182 ;; 183 br.ret.sptk.many rp 184END(ia64_call_efi_physical) 185 186/**************************************************************************/ 187 188ENTRY(fusufault, 0) 189{ .mib 190 st8.rel [r15]=r0 // Clear onfault. 191 add ret0=-1,r0 192 br.ret.sptk rp 193 ;; 194} 195END(fusufault) 196 197/* 198 * casuptr(intptr_t *p, intptr_t old, intptr_t new) 199 * Perform a compare-exchange in user space. 200 */ 201ENTRY(casuptr, 3) 202{ .mlx 203 add r15=PC_CURLWP,r13 204 movl r14=VM_MAX_ADDRESS 205 ;; 206} 207{ .mib 208 ld8 r15=[r15] // r15 = curthread 209 cmp.geu p6,p0=in0,r14 210(p6) br.dpnt.few 1f 211 ;; 212} 213{ .mlx 214 add r15=L_PCB,r15 215 movl r14=fusufault 216 ;; 217} 218{ .mmi 219 ld8 r15=[r15] // r15 = PCB 220 ;; 221 mov ar.ccv=in1 222 add r15=PCB_ONFAULT,r15 223 ;; 224} 225{ .mmi 226 st8 [r15]=r14 // Set onfault 227 ;; 228 cmpxchg8.rel ret0=[in0],in2,ar.ccv 229 nop 0 230 ;; 231} 232{ .mfb 233 st8.rel [r15]=r0 // Clear onfault 234 nop 0 235 br.ret.sptk rp 236 ;; 237} 2381: 239{ .mfb 240 add ret0=-1,r0 241 nop 0 242 br.ret.sptk rp 243 ;; 244} 245END(casuptr) 246 247/**************************************************************************/ 248 249ENTRY(ufetchstore_fault, 0) 250{ .mfb 251 st8.rel [r15]=r0 /* curpcb->pcb_onfault = NULL */ 252 nop 0 /* ret0 already has error */ 253 br.ret.sptk rp 254 ;; 255} 256END(ufetchstore_fault) 257 258#define UFETCH(load_insn, store_insn) \ 259{ .mlx ;\ 260 add r15=PC_CURLWP,r13 ;\ 261 movl r14=VM_MAX_ADDRESS ;;\ 262} ;\ 263{ .mib ;\ 264 ld8 r15=[r15] /* r15 = curlwp */ ;\ 265 cmp.geu p6,p0=in0,r14 ;\ 266(p6) br.dpnt.few 1f ;;\ 267} ;\ 268{ .mlx ;\ 269 add r15=L_PCB,r15 ;\ 270 movl r14=ufetchstore_fault ;;\ 271} ;\ 272{ .mmi ;\ 273 ld8 r15=[r15] /*r15 = curlwp->l_pcb */ ;;\ 274 nop 0 ;\ 275 add r15=PCB_ONFAULT,r15 ;;\ 276} ;\ 277{ .mmi ;\ 278 st8 [r15]=r14 /* curpcb->pcb_onfault = */ ;;\ 279 /* ufetchstore_fault */ \ 280 mf ;\ 281 nop 0 ;;\ 282} ;\ 283{ .mmi ;\ 284 load_insn r14=[in0] /* r14 = *uaddr */ ;;\ 285 st8.rel [r15]=r0 /* curpcb->pcb_onfault = NULL */ ;\ 286 nop 0 ;;\ 287} ;\ 288{ .mib ;\ 289 store_insn [in1]=r14 /* *valp = r14 */ ;\ 290 mov ret0=r0 /* ret0 = 0 (success!) */ ;\ 291 br.ret.sptk rp ;;\ 292} ;\ 2931: \ 294{ .mfb ;\ 295 mov ret0=EFAULT /* return EFAULT */ ;\ 296 nop 0 ;\ 297 br.ret.sptk rp ;;\ 298} 299 300/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */ 301ENTRY(_ufetch_8, 2) 302 UFETCH(ld1, st1) 303END(_ufetch_8) 304 305/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */ 306ENTRY(_ufetch_16, 2) 307 UFETCH(ld2, st2) 308END(_ufetch_16) 309 310/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */ 311ENTRY(_ufetch_32, 2) 312 UFETCH(ld4, st4) 313END(_ufetch_32) 314 315/* LINTSTUB: int _ufetch_64(const uint64_t *uaddr, uint64_t *valp); */ 316ENTRY(_ufetch_64, 2) 317 UFETCH(ld8, st8) 318END(_ufetch_64) 319 320#define USTORE(store_insn) \ 321{ .mlx ;\ 322 add r15=PC_CURLWP,r13 ;\ 323 movl r14=VM_MAX_ADDRESS ;;\ 324} ;\ 325{ .mib ;\ 326 ld8 r15=[r15] /* r15 = curlwp */ ;\ 327 cmp.geu p6,p0=in0,r14 ;\ 328(p6) br.dpnt.few 1f ;;\ 329} ;\ 330{ .mlx ;\ 331 add r15=L_PCB,r15 ;\ 332 movl r14=ufetchstore_fault ;;\ 333} ;\ 334{ .mmi ;\ 335 ld8 r15=[r15] /*r15 = curlwp->l_pcb */ ;;\ 336 nop 0 ;\ 337 add r15=PCB_ONFAULT,r15 ;;\ 338} ;\ 339{ .mmi ;\ 340 st8 [r15]=r14 /* curpcb->pcb_onfault = */ ;;\ 341 /* ufetchstore_fault */ \ 342 store_insn [in0]=in1 /* *uaddr = val */ ;\ 343 nop 0 ;;\ 344} ;\ 345{ .mib ;\ 346 st8.rel [r15]=r0 /* curpcb->pcb_onfault = NULL */ ;\ 347 mov ret0=r0 /* ret0 = 0 (success!) */ ;\ 348 br.ret.sptk rp ;;\ 349} ;\ 3501: \ 351{ .mfb ;\ 352 mov ret0=EFAULT /* return EFAULT */ ;\ 353 nop 0 ;\ 354 br.ret.sptk rp ;;\ 355} 356 357/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */ 358ENTRY(_ustore_8, 2) 359 USTORE(st1.rel) 360END(_ustore_8) 361 362/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */ 363ENTRY(_ustore_16, 2) 364 USTORE(st2.rel) 365END(_ustore_16) 366 367/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */ 368ENTRY(_ustore_32, 2) 369 USTORE(st4.rel) 370END(_ustore_32) 371 372/* LINTSTUB: int _ustore_64(uint64_t *uaddr, uint64_t val); */ 373ENTRY(_ustore_64, 2) 374 USTORE(st8.rel) 375END(_ustore_64) 376 377/**************************************************************************/ 378 379/* 380 * XXX XXX XXX: Should be removed? 381 */ 382ENTRY(ia64_copystr, 4) 383 mov r14=in2 // r14 = i = len 384 cmp.eq p6,p0=r0,in2 385(p6) br.cond.spnt.few 2f // if (len == 0), bail out 386 3871: ld1 r15=[in0],1 // read one byte 388 ;; 389 st1 [in1]=r15,1 // write that byte 390 add in2=-1,in2 // len-- 391 ;; 392 cmp.eq p6,p0=r0,r15 393 cmp.ne p7,p0=r0,in2 394 ;; 395(p6) br.cond.spnt.few 2f // if (*from == 0), bail out 396(p7) br.cond.sptk.few 1b // if (len != 0) copy more 397 3982: cmp.eq p6,p0=r0,in3 399(p6) br.cond.dpnt.few 3f // if (lenp != NULL) 400 sub r14=r14,in2 // *lenp = (i - len) 401 ;; 402 st8 [in3]=r14 403 4043: cmp.eq p6,p0=r0,r15 405(p6) br.cond.spnt.few 4f // *from == '\0'; leave quietly 406 407 mov ret0=ENAMETOOLONG // *from != '\0'; error. 408 br.ret.sptk.few rp 409 4104: mov ret0=0 // return 0. 411 br.ret.sptk.few rp 412END(ia64_copystr) 413 414ENTRY(copyinstr, 4) 415 .prologue 416 .regstk 4, 3, 4, 0 417 .save ar.pfs,loc0 418 alloc loc0=ar.pfs,4,3,4,0 419 .save rp,loc1 420 mov loc1=rp 421 .body 422 423 movl loc2=VM_MAX_ADDRESS // make sure that src addr 424 ;; 425 cmp.geu p6,p0=in0,loc2 // is in user space. 426 ;; 427(p6) br.cond.spnt.few copyefault // if it's not, error out. 428 movl r14=copyerr // set up fault handler. 429 add r15=PC_CURLWP,r13 // find curthread 430 ;; 431 ld8 r15=[r15] 432 ;; 433 add r15=L_PCB,r15 // find pcb 434 ;; 435 ld8 r15=[r15] 436 ;; 437 add loc2=PCB_ONFAULT,r15 438 ;; 439 st8 [loc2]=r14 440 ;; 441 mov out0=in0 442 mov out1=in1 443 mov out2=in2 444 mov out3=in3 445 ;; 446 br.call.sptk.few rp=ia64_copystr // do the copy. 447 st8 [loc2]=r0 // kill the fault handler. 448 mov ar.pfs=loc0 // restore ar.pfs 449 mov rp=loc1 // restore ra. 450 br.ret.sptk.few rp // ret0 left over from copystr 451END(copyinstr) 452 453ENTRY(copyoutstr, 4) 454 .prologue 455 .regstk 4, 3, 4, 0 456 .save ar.pfs,loc0 457 alloc loc0=ar.pfs,4,3,4,0 458 .save rp,loc1 459 mov loc1=rp 460 .body 461 462 movl loc2=VM_MAX_ADDRESS // make sure that dest addr 463 ;; 464 cmp.geu p6,p0=in1,loc2 // is in user space. 465 ;; 466(p6) br.cond.spnt.few copyefault // if it's not, error out. 467 movl r14=copyerr // set up fault handler. 468 add r15=PC_CURLWP,r13 // find curthread 469 ;; 470 ld8 r15=[r15] 471 ;; 472 add r15=L_PCB,r15 // find pcb 473 ;; 474 ld8 r15=[r15] 475 ;; 476 add loc2=PCB_ONFAULT,r15 477 ;; 478 st8 [loc2]=r14 479 ;; 480 mov out0=in0 481 mov out1=in1 482 mov out2=in2 483 mov out3=in3 484 ;; 485 br.call.sptk.few rp=ia64_copystr // do the copy. 486 st8 [loc2]=r0 // kill the fault handler. 487 mov ar.pfs=loc0 // restore ar.pfs 488 mov rp=loc1 // restore ra. 489 br.ret.sptk.few rp // ret0 left over from copystr 490END(copyoutstr) 491 492/* 493 * int kcopy(const void *from, void *to, size_t len); 494 * Copy len bytes, abort on fault. 495 */ 496 497ENTRY(kcopy, 3) 498 .prologue 499 .regstk 3, 3, 3, 0 500 .save ar.pfs,loc0 501 alloc loc0=ar.pfs,3,3,3,0 502 .save rp,loc1 503 mov loc1=rp 504 .body 505 506 movl r14=copyerr // set up fault handler. 507 add r15=PC_CURLWP,r13 // find curthread 508 ;; 509 ld8 r15=[r15] 510 ;; 511 add r15=L_PCB,r15 // find pcb 512 ;; 513 ld8 r15=[r15] 514 ;; 515 add loc2=PCB_ONFAULT,r15 516 ;; 517 st8 [loc2]=r14 518 ;; 519 mov out0=in0 520 mov out1=in1 521 mov out2=in2 522 mov ret0=r0 // XXX netbsd kcopy same as freebsd? 523 ;; 524 br.call.sptk.few rp=bcopy // do the copy. 525 st8 [loc2]=r0 // kill the fault handler. 526 mov ar.pfs=loc0 // restore ar.pfs 527 mov rp=loc1 // restore ra. 528 br.ret.sptk.few rp 529END(kcopy) 530 531ENTRY(copyin, 3) 532 .prologue 533 .regstk 3, 3, 3, 0 534 .save ar.pfs,loc0 535 alloc loc0=ar.pfs,3,3,3,0 536 .save rp,loc1 537 mov loc1=rp 538 .body 539 540 movl loc2=VM_MAX_ADDRESS // make sure that src addr 541 ;; 542 cmp.geu p6,p0=in0,loc2 // is in user space. 543 ;; 544(p6) br.cond.spnt.few copyefault // if it's not, error out. 545 movl r14=copyerr // set up fault handler. 546 add r15=PC_CURLWP,r13 // find curthread 547 ;; 548 ld8 r15=[r15] 549 ;; 550 add r15=L_PCB,r15 // find pcb 551 ;; 552 ld8 r15=[r15] 553 ;; 554 add loc2=PCB_ONFAULT,r15 555 ;; 556 st8 [loc2]=r14 557 ;; 558 mov out0=in0 559 mov out1=in1 560 mov out2=in2 561 mov ret0=r0 // return zero for copy{in,out} 562 ;; 563 br.call.sptk.few rp=bcopy // do the copy. 564 st8 [loc2]=r0 // kill the fault handler. 565 mov ar.pfs=loc0 // restore ar.pfs 566 mov rp=loc1 // restore ra. 567 br.ret.sptk.few rp 568END(copyin) 569 570ENTRY(copyout, 3) 571 .prologue 572 .regstk 3, 3, 3, 0 573 .save ar.pfs,loc0 574 alloc loc0=ar.pfs,3,3,3,0 575 .save rp,loc1 576 mov loc1=rp 577 .body 578 579 movl loc2=VM_MAX_ADDRESS // make sure that dest addr 580 ;; 581 cmp.geu p6,p0=in1,loc2 // is in user space. 582 ;; 583(p6) br.cond.spnt.few copyefault // if it's not, error out. 584 movl r14=copyerr // set up fault handler. 585 add r15=PC_CURLWP,r13 // find curthread 586 ;; 587 ld8 r15=[r15] 588 ;; 589 add r15=L_PCB,r15 // find pcb 590 ;; 591 ld8 r15=[r15] 592 ;; 593 add loc2=PCB_ONFAULT,r15 594 ;; 595 st8 [loc2]=r14 596 ;; 597 mov out0=in0 598 mov out1=in1 599 mov out2=in2 600 mov ret0=r0 // return zero for copy{in,out} 601 ;; 602 br.call.sptk.few rp=bcopy // do the copy. 603 st8 [loc2]=r0 // kill the fault handler. 604 mov ar.pfs=loc0 // restore ar.pfs 605 mov rp=loc1 // restore ra. 606 br.ret.sptk.few rp 607END(copyout) 608 609ENTRY(copyerr, 0) 610 add r14=PC_CURLWP,r13 ;; // find curthread 611 ld8 r14=[r14] ;; 612 add r14=L_PCB,r14 ;; // curthread->td_addr 613 ld8 r14=[r14] ;; 614 add r14=PCB_ONFAULT,r14 ;; // &curthread->td_pcb->pcb_onfault 615 st8 [r14]=r0 // reset fault handler 616 617 br.ret.sptk.few rp 618END(copyerr) 619 620ENTRY(copyefault, 0) 621 add r14=PC_CURLWP,r13 ;; // find curthread 622 ld8 r14=[r14] ;; 623 add r14=L_PCB,r14 ;; // curthread->td_addr 624 ld8 r14=[r14] ;; 625 add r14=PCB_ONFAULT,r14 ;; // &curthread->td_pcb->pcb_onfault 626 st8 [r14]=r0 // reset fault handler 627 628 mov ret0=EFAULT // return EFAULT 629 br.ret.sptk.few rp 630END(copyefault) 631 632#if defined(GPROF) 633/* 634 * Important registers: 635 * r8 structure return address 636 * rp our return address 637 * in0 caller's ar.pfs 638 * in1 caller's gp 639 * in2 caller's rp 640 * in3 GOT entry 641 * ar.pfs our pfs 642 */ 643ENTRY_NOPROFILE(_mcount, 4) 644 alloc loc0 = ar.pfs, 4, 3, 2, 0 645 mov loc1 = r8 646 mov loc2 = rp 647 ;; 648 mov out0 = in2 649 mov out1 = rp 650 br.call.sptk rp = __mcount 651 ;; 6521: 653 mov gp = in1 654 mov r14 = ip 655 mov b7 = loc2 656 ;; 657 add r14 = 2f - 1b, r14 658 mov ar.pfs = loc0 659 mov rp = in2 660 ;; 661 mov b7 = r14 662 mov b6 = loc2 663 mov r8 = loc1 664 mov r14 = in0 665 br.ret.sptk b7 666 ;; 6672: 668 mov ar.pfs = r14 669 br.sptk b6 670 ;; 671END(_mcount) 672#endif 673