1 /* $NetBSD: mips_emul.c,v 1.2 2002/07/21 05:47:51 gmcgarry Exp $ */ 2 3 /* 4 * Copyright (c) 1999 Shuichiro URATA. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/proc.h> 32 #include <sys/user.h> 33 34 #include <mips/locore.h> 35 #include <mips/mips_opcode.h> 36 37 #include <machine/cpu.h> 38 #include <mips/reg.h> 39 #include <mips/regnum.h> /* symbolic register indices */ 40 #include <mips/vmparam.h> /* for VM_MAX_ADDRESS */ 41 #include <mips/trap.h> 42 43 extern void MachEmulateFP(u_int32_t, struct frame *, u_int32_t); 44 45 static __inline void send_sigsegv(u_int32_t, u_int32_t, struct frame *, 46 u_int32_t); 47 static __inline void update_pc(struct frame *, u_int32_t); 48 49 vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int); 50 void MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *); 51 52 void MachEmulateLWC0(u_int32_t inst, struct frame *, u_int32_t); 53 void MachEmulateSWC0(u_int32_t inst, struct frame *, u_int32_t); 54 void MachEmulateSpecial(u_int32_t inst, struct frame *, u_int32_t); 55 void MachEmulateLWC1(u_int32_t inst, struct frame *, u_int32_t); 56 void MachEmulateLDC1(u_int32_t inst, struct frame *, u_int32_t); 57 void MachEmulateSWC1(u_int32_t inst, struct frame *, u_int32_t); 58 void MachEmulateSDC1(u_int32_t inst, struct frame *, u_int32_t); 59 60 void bcemul_lb(u_int32_t inst, struct frame *, u_int32_t); 61 void bcemul_lbu(u_int32_t inst, struct frame *, u_int32_t); 62 void bcemul_lh(u_int32_t inst, struct frame *, u_int32_t); 63 void bcemul_lhu(u_int32_t inst, struct frame *, u_int32_t); 64 void bcemul_lw(u_int32_t inst, struct frame *, u_int32_t); 65 void bcemul_lwl(u_int32_t inst, struct frame *, u_int32_t); 66 void bcemul_lwr(u_int32_t inst, struct frame *, u_int32_t); 67 void bcemul_sb(u_int32_t inst, struct frame *, u_int32_t); 68 void bcemul_sh(u_int32_t inst, struct frame *, u_int32_t); 69 void bcemul_sw(u_int32_t inst, struct frame *, u_int32_t); 70 void bcemul_swl(u_int32_t inst, struct frame *, u_int32_t); 71 void bcemul_swr(u_int32_t inst, struct frame *f, u_int32_t); 72 73 /* 74 * MIPS2 LL instruction emulation state 75 */ 76 struct { 77 struct proc *proc; 78 vaddr_t addr; 79 u_int32_t value; 80 } llstate; 81 82 /* 83 * Analyse 'next' PC address taking account of branch/jump instructions 84 */ 85 vaddr_t 86 MachEmulateBranch(f, instpc, fpuCSR, allowNonBranch) 87 struct frame *f; 88 vaddr_t instpc; 89 unsigned fpuCSR; 90 int allowNonBranch; 91 { 92 #define BRANCHTARGET(p) (4 + (p) + ((short)((InstFmt *)(p))->IType.imm << 2)) 93 InstFmt inst; 94 vaddr_t nextpc; 95 96 if (instpc < MIPS_KSEG0_START) 97 inst.word = fuiword((void *)instpc); 98 else 99 inst.word = *(unsigned *)instpc; 100 101 switch ((int)inst.JType.op) { 102 case OP_SPECIAL: 103 if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR) 104 nextpc = f->f_regs[inst.RType.rs]; 105 else if (allowNonBranch) 106 nextpc = instpc + 4; 107 else 108 panic("MachEmulateBranch: Non-branch"); 109 break; 110 111 case OP_BCOND: 112 switch ((int)inst.IType.rt) { 113 case OP_BLTZ: 114 case OP_BLTZAL: 115 case OP_BLTZL: /* squashed */ 116 case OP_BLTZALL: /* squashed */ 117 if ((int)(f->f_regs[inst.RType.rs]) < 0) 118 nextpc = BRANCHTARGET(instpc); 119 else 120 nextpc = instpc + 8; 121 break; 122 123 case OP_BGEZ: 124 case OP_BGEZAL: 125 case OP_BGEZL: /* squashed */ 126 case OP_BGEZALL: /* squashed */ 127 if ((int)(f->f_regs[inst.RType.rs]) >= 0) 128 nextpc = BRANCHTARGET(instpc); 129 else 130 nextpc = instpc + 8; 131 break; 132 133 default: 134 panic("MachEmulateBranch: Bad branch cond"); 135 } 136 break; 137 138 case OP_J: 139 case OP_JAL: 140 nextpc = (inst.JType.target << 2) | 141 ((unsigned)instpc & 0xF0000000); 142 break; 143 144 case OP_BEQ: 145 case OP_BEQL: /* squashed */ 146 if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt]) 147 nextpc = BRANCHTARGET(instpc); 148 else 149 nextpc = instpc + 8; 150 break; 151 152 case OP_BNE: 153 case OP_BNEL: /* squashed */ 154 if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt]) 155 nextpc = BRANCHTARGET(instpc); 156 else 157 nextpc = instpc + 8; 158 break; 159 160 case OP_BLEZ: 161 case OP_BLEZL: /* squashed */ 162 if ((int)(f->f_regs[inst.RType.rs]) <= 0) 163 nextpc = BRANCHTARGET(instpc); 164 else 165 nextpc = instpc + 8; 166 break; 167 168 case OP_BGTZ: 169 case OP_BGTZL: /* squashed */ 170 if ((int)(f->f_regs[inst.RType.rs]) > 0) 171 nextpc = BRANCHTARGET(instpc); 172 else 173 nextpc = instpc + 8; 174 break; 175 176 case OP_COP1: 177 if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) { 178 int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0; 179 if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE) 180 condition = !condition; 181 if (condition) 182 nextpc = BRANCHTARGET(instpc); 183 else 184 nextpc = instpc + 8; 185 } 186 else if (allowNonBranch) 187 nextpc = instpc + 4; 188 else 189 panic("MachEmulateBranch: Bad COP1 branch instruction"); 190 break; 191 192 default: 193 if (!allowNonBranch) 194 panic("MachEmulateBranch: Non-branch instruction"); 195 nextpc = instpc + 4; 196 } 197 return nextpc; 198 #undef BRANCHTARGET 199 } 200 201 /* 202 * Emulate instructions (including floating-point instructions) 203 */ 204 void 205 MachEmulateInst(status, cause, opc, frame) 206 u_int32_t status; 207 u_int32_t cause; 208 u_int32_t opc; 209 struct frame *frame; 210 { 211 u_int32_t inst; 212 213 /* 214 * Fetch the instruction. 215 */ 216 if (cause & MIPS_CR_BR_DELAY) 217 inst = fuword((u_int32_t *)opc+1); 218 else 219 inst = fuword((u_int32_t *)opc); 220 221 switch (((InstFmt)inst).FRType.op) { 222 case OP_LWC0: 223 MachEmulateLWC0(inst, frame, cause); 224 break; 225 case OP_SWC0: 226 MachEmulateSWC0(inst, frame, cause); 227 break; 228 case OP_SPECIAL: 229 MachEmulateSpecial(inst, frame, cause); 230 break; 231 case OP_COP1: 232 MachEmulateFP(inst, frame, cause); 233 break; 234 #if defined(SOFTFLOAT) 235 case OP_LWC1: 236 MachEmulateLWC1(inst, frame, cause); 237 break; 238 case OP_LDC1: 239 MachEmulateLDC1(inst, frame, cause); 240 break; 241 case OP_SWC1: 242 MachEmulateSWC1(inst, frame, cause); 243 break; 244 case OP_SDC1: 245 MachEmulateSDC1(inst, frame, cause); 246 break; 247 #endif 248 default: 249 frame->f_regs[CAUSE] = cause; 250 frame->f_regs[BADVADDR] = opc; 251 trapsignal(curproc, SIGSEGV, opc); 252 } 253 } 254 255 static __inline void 256 send_sigsegv(u_int32_t vaddr, u_int32_t exccode, struct frame *frame, 257 u_int32_t cause) 258 { 259 260 cause = (cause & 0xFFFFFF00) | (exccode << MIPS_CR_EXC_CODE_SHIFT); 261 262 frame->f_regs[CAUSE] = cause; 263 frame->f_regs[BADVADDR] = vaddr; 264 trapsignal(curproc, SIGSEGV, vaddr); 265 } 266 267 static __inline void 268 update_pc(struct frame *frame, u_int32_t cause) 269 { 270 271 if (cause & MIPS_CR_BR_DELAY) 272 frame->f_regs[PC] = MachEmulateBranch(frame, frame->f_regs[PC], 273 PCB_FSR(curpcb), 0); 274 else 275 frame->f_regs[PC] += 4; 276 } 277 278 /* 279 * MIPS2 LL instruction 280 */ 281 void 282 MachEmulateLWC0(u_int32_t inst, struct frame *frame, u_int32_t cause) 283 { 284 u_int32_t vaddr; 285 int16_t offset; 286 void *t; 287 288 offset = inst & 0xFFFF; 289 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 290 291 /* segment and alignment check */ 292 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 293 frame->f_regs[CAUSE] = cause; 294 frame->f_regs[BADVADDR] = vaddr; 295 trapsignal(curproc, SIGBUS, vaddr); 296 return; 297 } 298 299 t = &(frame->f_regs[(inst>>16)&0x1F]); 300 301 if (copyin((void *)vaddr, t, 4) != 0) { 302 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 303 return; 304 } 305 306 llstate.proc = curproc; 307 llstate.addr = vaddr; 308 llstate.value = *((u_int32_t *)t); 309 310 update_pc(frame, cause); 311 } 312 313 /* 314 * MIPS2 SC instruction 315 */ 316 void 317 MachEmulateSWC0(u_int32_t inst, struct frame *frame, u_int32_t cause) 318 { 319 u_int32_t vaddr, value; 320 int16_t offset; 321 mips_reg_t *t; 322 323 offset = inst & 0xFFFF; 324 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 325 326 /* segment and alignment check */ 327 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 328 frame->f_regs[CAUSE] = cause; 329 frame->f_regs[BADVADDR] = vaddr; 330 trapsignal(curproc, SIGBUS, vaddr); 331 return; 332 } 333 334 t = (mips_reg_t *)&(frame->f_regs[(inst>>16)&0x1F]); 335 336 /* 337 * Check that the process and address match the last 338 * LL instruction. 339 */ 340 if (curproc == llstate.proc && vaddr == llstate.addr) { 341 llstate.proc = NULL; 342 /* 343 * Check that the data at the address hasn't changed 344 * since the LL instruction. 345 */ 346 if (copyin((void *)vaddr, &value, 4) != 0) { 347 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 348 return; 349 } 350 if (value == llstate.value) { 351 /* SC successful */ 352 if (copyout(t, (void *)vaddr, 4) != 0) { 353 send_sigsegv(vaddr, T_TLB_ST_MISS, 354 frame, cause); 355 return; 356 } 357 *t = 1; 358 update_pc(frame, cause); 359 return; 360 } 361 } 362 363 /* SC failed */ 364 *t = 0; 365 update_pc(frame, cause); 366 } 367 368 void 369 MachEmulateSpecial(u_int32_t inst, struct frame *frame, u_int32_t cause) 370 { 371 switch (((InstFmt)inst).RType.func) { 372 case OP_SYNC: 373 /* nothing */ 374 break; 375 default: 376 frame->f_regs[CAUSE] = cause; 377 frame->f_regs[BADVADDR] = frame->f_regs[PC]; 378 trapsignal(curproc, SIGSEGV, frame->f_regs[PC]); 379 } 380 381 update_pc(frame, cause); 382 } 383 384 #if defined(SOFTFLOAT) 385 386 #define LWSWC1_MAXLOOP 12 387 388 void 389 MachEmulateLWC1(u_int32_t inst, struct frame *frame, u_int32_t cause) 390 { 391 u_int32_t vaddr; 392 int16_t offset; 393 void *t; 394 mips_reg_t pc; 395 int i; 396 397 offset = inst & 0xFFFF; 398 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 399 400 /* segment and alignment check */ 401 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 402 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 403 return; 404 } 405 406 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 407 408 if (copyin((void *)vaddr, t, 4) != 0) { 409 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 410 return; 411 } 412 413 pc = frame->f_regs[PC]; 414 update_pc(frame, cause); 415 416 if (cause & MIPS_CR_BR_DELAY) 417 return; 418 419 for (i = 1; i < LWSWC1_MAXLOOP; i++) { 420 if (mips_btop(frame->f_regs[PC]) != mips_btop(pc)) 421 return; 422 423 vaddr = frame->f_regs[PC]; /* XXX truncates to 32 bits */ 424 inst = fuiword((u_int32_t *)vaddr); 425 if (((InstFmt)inst).FRType.op != OP_LWC1) 426 return; 427 428 offset = inst & 0xFFFF; 429 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 430 431 /* segment and alignment check */ 432 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 433 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 434 return; 435 } 436 437 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 438 439 if (copyin((void *)vaddr, t, 4) != 0) { 440 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 441 return; 442 } 443 444 pc = frame->f_regs[PC]; 445 update_pc(frame, cause); 446 } 447 } 448 449 void 450 MachEmulateLDC1(u_int32_t inst, struct frame *frame, u_int32_t cause) 451 { 452 u_int32_t vaddr; 453 int16_t offset; 454 void *t; 455 456 offset = inst & 0xFFFF; 457 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 458 459 /* segment and alignment check */ 460 if (vaddr & 0x80000007) { 461 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 462 return; 463 } 464 465 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); 466 467 if (copyin((void *)vaddr, t, 8) != 0) { 468 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 469 return; 470 } 471 472 update_pc(frame, cause); 473 } 474 475 void 476 MachEmulateSWC1(u_int32_t inst, struct frame *frame, u_int32_t cause) 477 { 478 u_int32_t vaddr; 479 int16_t offset; 480 void *t; 481 mips_reg_t pc; 482 int i; 483 484 offset = inst & 0xFFFF; 485 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 486 487 /* segment and alignment check */ 488 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 489 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 490 return; 491 } 492 493 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 494 495 if (copyout(t, (void *)vaddr, 4) != 0) { 496 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 497 return; 498 } 499 500 pc = frame->f_regs[PC]; 501 update_pc(frame, cause); 502 503 if (cause & MIPS_CR_BR_DELAY) 504 return; 505 506 for (i = 1; i < LWSWC1_MAXLOOP; i++) { 507 if (mips_btop(frame->f_regs[PC]) != mips_btop(pc)) 508 return; 509 510 vaddr = frame->f_regs[PC]; /* XXX truncates to 32 bits */ 511 inst = fuiword((u_int32_t *)vaddr); 512 if (((InstFmt)inst).FRType.op != OP_SWC1) 513 return; 514 515 offset = inst & 0xFFFF; 516 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 517 518 /* segment and alignment check */ 519 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 520 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 521 return; 522 } 523 524 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 525 526 if (copyout(t, (void *)vaddr, 4) != 0) { 527 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 528 return; 529 } 530 531 pc = frame->f_regs[PC]; 532 update_pc(frame, cause); 533 } 534 } 535 536 void 537 MachEmulateSDC1(u_int32_t inst, struct frame *frame, u_int32_t cause) 538 { 539 u_int32_t vaddr; 540 int16_t offset; 541 void *t; 542 543 offset = inst & 0xFFFF; 544 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 545 546 /* segment and alignment check */ 547 if (vaddr & 0x80000007) { 548 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 549 return; 550 } 551 552 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); 553 554 if (copyout(t, (void *)vaddr, 8) != 0) { 555 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 556 return; 557 } 558 559 update_pc(frame, cause); 560 } 561 562 void 563 bcemul_lb(u_int32_t inst, struct frame *frame, u_int32_t cause) 564 { 565 u_int32_t vaddr; 566 int16_t offset; 567 int8_t x; 568 569 offset = inst & 0xFFFF; 570 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 571 572 /* segment check */ 573 if (vaddr & 0x80000000) { 574 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 575 return; 576 } 577 578 if (copyin((void *)vaddr, &x, 1) != 0) { 579 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 580 return; 581 } 582 583 frame->f_regs[(inst>>16)&0x1F] = (int32_t)x; 584 585 update_pc(frame, cause); 586 } 587 588 void 589 bcemul_lbu(u_int32_t inst, struct frame *frame, u_int32_t cause) 590 { 591 u_int32_t vaddr; 592 int16_t offset; 593 u_int8_t x; 594 595 offset = inst & 0xFFFF; 596 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 597 598 /* segment check */ 599 if (vaddr & 0x80000000) { 600 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 601 return; 602 } 603 604 if (copyin((void *)vaddr, &x, 1) != 0) { 605 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 606 return; 607 } 608 609 frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x; 610 611 update_pc(frame, cause); 612 } 613 614 void 615 bcemul_lh(u_int32_t inst, struct frame *frame, u_int32_t cause) 616 { 617 u_int32_t vaddr; 618 int16_t offset; 619 int16_t x; 620 621 offset = inst & 0xFFFF; 622 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 623 624 /* segment and alignment check */ 625 if (vaddr & 0x80000001) { 626 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 627 return; 628 } 629 630 if (copyin((void *)vaddr, &x, 2) != 0) { 631 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 632 return; 633 } 634 635 frame->f_regs[(inst>>16)&0x1F] = (int32_t)x; 636 637 update_pc(frame, cause); 638 } 639 640 void 641 bcemul_lhu(u_int32_t inst, struct frame *frame, u_int32_t cause) 642 { 643 u_int32_t vaddr; 644 int16_t offset; 645 u_int16_t x; 646 647 offset = inst & 0xFFFF; 648 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 649 650 /* segment and alignment check */ 651 if (vaddr & 0x80000001) { 652 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 653 return; 654 } 655 656 if (copyin((void *)vaddr, &x, 2) != 0) { 657 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 658 return; 659 } 660 661 frame->f_regs[(inst>>16)&0x1F] = (u_int32_t)x; 662 663 update_pc(frame, cause); 664 } 665 666 void 667 bcemul_lw(u_int32_t inst, struct frame *frame, u_int32_t cause) 668 { 669 u_int32_t vaddr; 670 int16_t offset; 671 672 offset = inst & 0xFFFF; 673 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 674 675 /* segment and alignment check */ 676 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 677 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 678 return; 679 } 680 681 if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 4) != 0) { 682 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 683 return; 684 } 685 686 update_pc(frame, cause); 687 } 688 689 void 690 bcemul_lwl(u_int32_t inst, struct frame *frame, u_int32_t cause) 691 { 692 u_int32_t vaddr, a, x, shift; 693 int16_t offset; 694 695 offset = inst & 0xFFFF; 696 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 697 698 /* segment check */ 699 if (vaddr & 0x80000000) { 700 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 701 return; 702 } 703 704 if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { 705 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 706 return; 707 } 708 709 x = frame->f_regs[(inst>>16)&0x1F]; 710 711 shift = (3 - (vaddr & 0x00000003)) * 8; 712 a <<= shift; 713 x &= ~(0xFFFFFFFFUL << shift); 714 x |= a; 715 716 frame->f_regs[(inst>>16)&0x1F] = x; 717 718 update_pc(frame, cause); 719 } 720 721 void 722 bcemul_lwr(u_int32_t inst, struct frame *frame, u_int32_t cause) 723 { 724 u_int32_t vaddr, a, x, shift; 725 int16_t offset; 726 727 offset = inst & 0xFFFF; 728 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 729 730 /* segment check */ 731 if (vaddr & 0x80000000) { 732 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 733 return; 734 } 735 736 if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { 737 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 738 return; 739 } 740 741 x = frame->f_regs[(inst>>16)&0x1F]; 742 743 shift = (vaddr & 0x00000003) * 8; 744 a >>= shift; 745 x &= ~(0xFFFFFFFFUL >> shift); 746 x |= a; 747 748 frame->f_regs[(inst>>16)&0x1F] = x; 749 750 update_pc(frame, cause); 751 } 752 753 void 754 bcemul_sb(u_int32_t inst, struct frame *frame, u_int32_t cause) 755 { 756 u_int32_t vaddr; 757 int16_t offset; 758 759 offset = inst & 0xFFFF; 760 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 761 762 /* segment check */ 763 if (vaddr & 0x80000000) { 764 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 765 return; 766 } 767 768 if (subyte((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 769 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 770 return; 771 } 772 773 update_pc(frame, cause); 774 } 775 776 void 777 bcemul_sh(u_int32_t inst, struct frame *frame, u_int32_t cause) 778 { 779 u_int32_t vaddr; 780 int16_t offset; 781 782 offset = inst & 0xFFFF; 783 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 784 785 /* segment and alignment check */ 786 if (vaddr & 0x80000001) { 787 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 788 return; 789 } 790 791 if (susword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 792 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 793 return; 794 } 795 796 update_pc(frame, cause); 797 } 798 799 void 800 bcemul_sw(u_int32_t inst, struct frame *frame, u_int32_t cause) 801 { 802 u_int32_t vaddr; 803 int16_t offset; 804 805 offset = inst & 0xFFFF; 806 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 807 808 /* segment and alignment check */ 809 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) { 810 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 811 return; 812 } 813 814 if (suword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 815 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 816 return; 817 } 818 819 update_pc(frame, cause); 820 } 821 822 void 823 bcemul_swl(u_int32_t inst, struct frame *frame, u_int32_t cause) 824 { 825 u_int32_t vaddr, a, x, shift; 826 int16_t offset; 827 828 offset = inst & 0xFFFF; 829 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 830 831 /* segment check */ 832 if (vaddr & 0x80000000) { 833 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 834 return; 835 } 836 837 if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { 838 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 839 return; 840 } 841 842 x = frame->f_regs[(inst>>16)&0x1F]; 843 844 shift = (3 - (vaddr & 0x00000003)) * 8; 845 x >>= shift; 846 a &= ~(0xFFFFFFFFUL >> shift); 847 a |= x; 848 849 if (suword((void *)vaddr, a) < 0) { 850 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 851 return; 852 } 853 854 update_pc(frame, cause); 855 } 856 857 void 858 bcemul_swr(u_int32_t inst, struct frame *frame, u_int32_t cause) 859 { 860 u_int32_t vaddr, a, x, shift; 861 int16_t offset; 862 863 offset = inst & 0xFFFF; 864 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 865 866 /* segment check */ 867 if (vaddr & 0x80000000) { 868 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 869 return; 870 } 871 872 if (copyin((void *)(vaddr & ~0x3), &a, 4) != 0) { 873 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 874 return; 875 } 876 877 x = frame->f_regs[(inst>>16)&0x1F]; 878 879 shift = (vaddr & 0x00000003) * 8; 880 x <<= shift; 881 a &= ~(0xFFFFFFFFUL << shift); 882 a |= x; 883 884 if (suword((void *)vaddr, a) < 0) { 885 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 886 return; 887 } 888 889 update_pc(frame, cause); 890 } 891 #endif /* defined(SOFTFLOAT) */ 892