1 /* $NetBSD: mips_emul.c,v 1.21 2011/02/01 06:46:46 matt 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/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: mips_emul.c,v 1.21 2011/02/01 06:46:46 matt Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/cpu.h> 35 #include <sys/proc.h> 36 37 #include <mips/locore.h> 38 #include <mips/mips_opcode.h> 39 40 #include <mips/reg.h> 41 #include <mips/regnum.h> /* symbolic register indices */ 42 #include <mips/pcb.h> 43 #include <mips/vmparam.h> /* for VM_MAX_ADDRESS */ 44 #include <mips/trap.h> 45 46 void MachEmulateFP(uint32_t, struct frame *, uint32_t); 47 48 static inline void send_sigsegv(intptr_t, uint32_t, struct frame *, 49 uint32_t); 50 static inline void update_pc(struct frame *, uint32_t); 51 52 vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int); 53 void MachEmulateInst(uint32_t, uint32_t, vaddr_t, struct frame *); 54 55 void MachEmulateLWC0(uint32_t, struct frame *, uint32_t); 56 void MachEmulateSWC0(uint32_t, struct frame *, uint32_t); 57 void MachEmulateSpecial(uint32_t, struct frame *, uint32_t); 58 void MachEmulateSpecial3(uint32_t, struct frame *, uint32_t); 59 void MachEmulateLWC1(uint32_t, struct frame *, uint32_t); 60 void MachEmulateLDC1(uint32_t, struct frame *, uint32_t); 61 void MachEmulateSWC1(uint32_t, struct frame *, uint32_t); 62 void MachEmulateSDC1(uint32_t, struct frame *, uint32_t); 63 64 void bcemul_lb(uint32_t, struct frame *, uint32_t); 65 void bcemul_lbu(uint32_t, struct frame *, uint32_t); 66 void bcemul_lh(uint32_t, struct frame *, uint32_t); 67 void bcemul_lhu(uint32_t, struct frame *, uint32_t); 68 void bcemul_lw(uint32_t, struct frame *, uint32_t); 69 void bcemul_lwl(uint32_t, struct frame *, uint32_t); 70 void bcemul_lwr(uint32_t, struct frame *, uint32_t); 71 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) 72 void bcemul_ld(uint32_t, struct frame *, uint32_t); 73 void bcemul_ldl(uint32_t, struct frame *, uint32_t); 74 void bcemul_ldr(uint32_t, struct frame *, uint32_t); 75 #endif 76 void bcemul_sb(uint32_t, struct frame *, uint32_t); 77 void bcemul_sh(uint32_t, struct frame *, uint32_t); 78 void bcemul_sw(uint32_t, struct frame *, uint32_t); 79 void bcemul_swl(uint32_t, struct frame *, uint32_t); 80 void bcemul_swr(uint32_t, struct frame *f, uint32_t); 81 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) 82 void bcemul_sd(uint32_t, struct frame *, uint32_t); 83 void bcemul_sdl(uint32_t, struct frame *, uint32_t); 84 void bcemul_sdr(uint32_t, struct frame *f, uint32_t); 85 #endif 86 87 /* 88 * MIPS2 LL instruction emulation state 89 */ 90 struct { 91 struct lwp *lwp; 92 vaddr_t addr; 93 uint32_t value; 94 } llstate; 95 96 /* 97 * Analyse 'next' PC address taking account of branch/jump instructions 98 */ 99 vaddr_t 100 MachEmulateBranch(struct frame *f, vaddr_t instpc, unsigned fpuCSR, 101 int allowNonBranch) 102 { 103 #define BRANCHTARGET(p, i) (4 + (p) + ((short)(i).IType.imm << 2)) 104 InstFmt inst; 105 vaddr_t nextpc; 106 107 if (instpc < MIPS_KSEG0_START) 108 inst.word = fuiword((void *)instpc); 109 else 110 inst.word = *(unsigned *)instpc; 111 112 switch ((int)inst.JType.op) { 113 case OP_SPECIAL: 114 if (inst.RType.func == OP_JR || inst.RType.func == OP_JALR) 115 nextpc = f->f_regs[inst.RType.rs]; 116 else if (allowNonBranch) 117 nextpc = instpc + 4; 118 else 119 panic("MachEmulateBranch: Non-branch instruction at " 120 "pc 0x%lx", (long)instpc); 121 break; 122 123 case OP_BCOND: 124 switch ((int)inst.IType.rt) { 125 case OP_BLTZ: 126 case OP_BLTZAL: 127 case OP_BLTZL: /* squashed */ 128 case OP_BLTZALL: /* squashed */ 129 if ((int)(f->f_regs[inst.RType.rs]) < 0) 130 nextpc = BRANCHTARGET(instpc, inst); 131 else 132 nextpc = instpc + 8; 133 break; 134 135 case OP_BGEZ: 136 case OP_BGEZAL: 137 case OP_BGEZL: /* squashed */ 138 case OP_BGEZALL: /* squashed */ 139 if ((int)(f->f_regs[inst.RType.rs]) >= 0) 140 nextpc = BRANCHTARGET(instpc, inst); 141 else 142 nextpc = instpc + 8; 143 break; 144 145 default: 146 panic("MachEmulateBranch: Bad branch cond"); 147 } 148 break; 149 150 case OP_J: 151 case OP_JAL: 152 nextpc = (inst.JType.target << 2) | 153 ((unsigned)instpc & 0xF0000000); 154 break; 155 156 case OP_BEQ: 157 case OP_BEQL: /* squashed */ 158 if (f->f_regs[inst.RType.rs] == f->f_regs[inst.RType.rt]) 159 nextpc = BRANCHTARGET(instpc, inst); 160 else 161 nextpc = instpc + 8; 162 break; 163 164 case OP_BNE: 165 case OP_BNEL: /* squashed */ 166 if (f->f_regs[inst.RType.rs] != f->f_regs[inst.RType.rt]) 167 nextpc = BRANCHTARGET(instpc, inst); 168 else 169 nextpc = instpc + 8; 170 break; 171 172 case OP_BLEZ: 173 case OP_BLEZL: /* squashed */ 174 if ((int)(f->f_regs[inst.RType.rs]) <= 0) 175 nextpc = BRANCHTARGET(instpc, inst); 176 else 177 nextpc = instpc + 8; 178 break; 179 180 case OP_BGTZ: 181 case OP_BGTZL: /* squashed */ 182 if ((int)(f->f_regs[inst.RType.rs]) > 0) 183 nextpc = BRANCHTARGET(instpc, inst); 184 else 185 nextpc = instpc + 8; 186 break; 187 188 case OP_COP1: 189 if (inst.RType.rs == OP_BCx || inst.RType.rs == OP_BCy) { 190 int condition = (fpuCSR & MIPS_FPU_COND_BIT) != 0; 191 if ((inst.RType.rt & COPz_BC_TF_MASK) != COPz_BC_TRUE) 192 condition = !condition; 193 if (condition) 194 nextpc = BRANCHTARGET(instpc, inst); 195 else 196 nextpc = instpc + 8; 197 } 198 else if (allowNonBranch) 199 nextpc = instpc + 4; 200 else 201 panic("MachEmulateBranch: Bad COP1 branch instruction"); 202 break; 203 204 default: 205 if (!allowNonBranch) 206 panic("MachEmulateBranch: Non-branch instruction at " 207 "pc 0x%lx", (long)instpc); 208 nextpc = instpc + 4; 209 } 210 return nextpc; 211 #undef BRANCHTARGET 212 } 213 214 /* 215 * Emulate instructions (including floating-point instructions) 216 */ 217 void 218 MachEmulateInst(uint32_t status, uint32_t cause, vaddr_t opc, 219 struct frame *frame) 220 { 221 uint32_t inst; 222 ksiginfo_t ksi; 223 224 /* 225 * Fetch the instruction. 226 */ 227 if (cause & MIPS_CR_BR_DELAY) 228 inst = ufetch_uint32((uint32_t *)opc+1); 229 else 230 inst = ufetch_uint32((uint32_t *)opc); 231 232 switch (((InstFmt)inst).FRType.op) { 233 case OP_LWC0: 234 MachEmulateLWC0(inst, frame, cause); 235 break; 236 case OP_SWC0: 237 MachEmulateSWC0(inst, frame, cause); 238 break; 239 case OP_SPECIAL: 240 MachEmulateSpecial(inst, frame, cause); 241 break; 242 case OP_SPECIAL3: 243 MachEmulateSpecial3(inst, frame, cause); 244 break; 245 case OP_COP1: 246 MachEmulateFP(inst, frame, cause); 247 break; 248 #if defined(SOFTFLOAT) 249 case OP_LWC1: 250 MachEmulateLWC1(inst, frame, cause); 251 break; 252 case OP_LDC1: 253 MachEmulateLDC1(inst, frame, cause); 254 break; 255 case OP_SWC1: 256 MachEmulateSWC1(inst, frame, cause); 257 break; 258 case OP_SDC1: 259 MachEmulateSDC1(inst, frame, cause); 260 break; 261 #endif 262 default: 263 #ifdef DEBUG 264 printf("pid %d(%s): trap: bad vaddr %#"PRIxVADDR" cause %#x insn %#x\n", curproc->p_pid, curproc->p_comm, opc, cause, inst); 265 #endif 266 frame->f_regs[_R_CAUSE] = cause; 267 frame->f_regs[_R_BADVADDR] = opc; 268 KSI_INIT_TRAP(&ksi); 269 ksi.ksi_signo = SIGSEGV; 270 ksi.ksi_trap = cause; /* XXX */ 271 ksi.ksi_code = SEGV_MAPERR; 272 ksi.ksi_addr = (void *)opc; 273 (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); 274 break; 275 } 276 } 277 278 static inline void 279 send_sigsegv(intptr_t vaddr, uint32_t exccode, struct frame *frame, 280 uint32_t cause) 281 { 282 ksiginfo_t ksi; 283 cause = (cause & 0xFFFFFF00) | (exccode << MIPS_CR_EXC_CODE_SHIFT); 284 frame->f_regs[_R_CAUSE] = cause; 285 frame->f_regs[_R_BADVADDR] = vaddr; 286 KSI_INIT_TRAP(&ksi); 287 ksi.ksi_signo = SIGSEGV; 288 ksi.ksi_trap = cause; 289 ksi.ksi_code = SEGV_MAPERR; 290 ksi.ksi_addr = (void *)vaddr; 291 (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); 292 } 293 294 static inline void 295 update_pc(struct frame *frame, uint32_t cause) 296 { 297 298 if (cause & MIPS_CR_BR_DELAY) 299 frame->f_regs[_R_PC] = 300 MachEmulateBranch(frame, frame->f_regs[_R_PC], 301 PCB_FSR(curpcb), 0); 302 else 303 frame->f_regs[_R_PC] += 4; 304 } 305 306 /* 307 * MIPS2 LL instruction 308 */ 309 void 310 MachEmulateLWC0(uint32_t inst, struct frame *frame, uint32_t cause) 311 { 312 intptr_t vaddr; 313 int16_t offset; 314 void *t; 315 316 offset = inst & 0xFFFF; 317 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 318 319 /* segment and alignment check */ 320 if (vaddr < 0 || (vaddr & 3)) { 321 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 322 return; 323 } 324 325 t = &(frame->f_regs[(inst>>16)&0x1F]); 326 327 if (copyin((void *)vaddr, t, 4) != 0) { 328 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 329 return; 330 } 331 332 llstate.lwp = curlwp; 333 llstate.addr = vaddr; 334 llstate.value = *((uint32_t *)t); 335 336 update_pc(frame, cause); 337 } 338 339 /* 340 * MIPS2 SC instruction 341 */ 342 void 343 MachEmulateSWC0(uint32_t inst, struct frame *frame, uint32_t cause) 344 { 345 intptr_t vaddr; 346 uint32_t value; 347 int16_t offset; 348 mips_reg_t *t; 349 350 offset = inst & 0xFFFF; 351 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 352 353 /* segment and alignment check */ 354 if (vaddr < 0 || (vaddr & 3)) { 355 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 356 return; 357 } 358 359 t = (mips_reg_t *)&(frame->f_regs[(inst>>16)&0x1F]); 360 361 /* 362 * Check that the process and address match the last 363 * LL instruction. 364 */ 365 if (curlwp == llstate.lwp && vaddr == llstate.addr) { 366 llstate.lwp = NULL; 367 /* 368 * Check that the data at the address hasn't changed 369 * since the LL instruction. 370 */ 371 if (copyin((void *)vaddr, &value, 4) != 0) { 372 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 373 return; 374 } 375 if (value == llstate.value) { 376 /* SC successful */ 377 if (copyout(t, (void *)vaddr, 4) != 0) { 378 send_sigsegv(vaddr, T_TLB_ST_MISS, 379 frame, cause); 380 return; 381 } 382 *t = 1; 383 update_pc(frame, cause); 384 return; 385 } 386 } 387 388 /* SC failed */ 389 *t = 0; 390 update_pc(frame, cause); 391 } 392 393 void 394 MachEmulateSpecial(uint32_t inst, struct frame *frame, uint32_t cause) 395 { 396 ksiginfo_t ksi; 397 398 switch (((InstFmt)inst).RType.func) { 399 case OP_SYNC: 400 /* nothing */ 401 break; 402 default: 403 frame->f_regs[_R_CAUSE] = cause; 404 frame->f_regs[_R_BADVADDR] = frame->f_regs[_R_PC]; 405 KSI_INIT_TRAP(&ksi); 406 ksi.ksi_signo = SIGSEGV; 407 ksi.ksi_trap = cause; 408 ksi.ksi_code = SEGV_MAPERR; 409 ksi.ksi_addr = (void *)(intptr_t)frame->f_regs[_R_PC]; 410 (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); 411 break; 412 } 413 414 update_pc(frame, cause); 415 } 416 417 void 418 MachEmulateSpecial3(uint32_t inst, struct frame *frame, uint32_t cause) 419 { 420 ksiginfo_t ksi; 421 InstFmt instfmt = (InstFmt)inst; 422 423 switch (instfmt.RType.func) { 424 case OP_RDHWR: 425 switch (instfmt.RType.rd) { 426 case 29: 427 frame->f_regs[instfmt.RType.rt] = 428 (mips_reg_t)(intptr_t)curlwp->l_private; 429 goto out; 430 } 431 /* FALLTHROUGH */ 432 default: 433 frame->f_regs[_R_CAUSE] = cause; 434 frame->f_regs[_R_BADVADDR] = frame->f_regs[_R_PC]; 435 KSI_INIT_TRAP(&ksi); 436 ksi.ksi_signo = SIGILL; 437 ksi.ksi_trap = cause; 438 ksi.ksi_code = ILL_ILLOPC; 439 ksi.ksi_addr = (void *)(intptr_t)frame->f_regs[_R_PC]; 440 (*curproc->p_emul->e_trapsignal)(curlwp, &ksi); 441 break; 442 } 443 444 out: 445 update_pc(frame, cause); 446 } 447 448 #if defined(SOFTFLOAT) 449 450 #define LWSWC1_MAXLOOP 12 451 452 void 453 MachEmulateLWC1(uint32_t inst, struct frame *frame, uint32_t cause) 454 { 455 intptr_t vaddr; 456 int16_t offset; 457 void *t; 458 mips_reg_t pc; 459 int i; 460 461 offset = inst & 0xFFFF; 462 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 463 464 /* segment and alignment check */ 465 if (vaddr < 0 || (vaddr & 3)) { 466 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 467 return; 468 } 469 470 /* NewABI FIXME */ 471 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 472 473 if (copyin((void *)vaddr, t, 4) != 0) { 474 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 475 return; 476 } 477 478 pc = frame->f_regs[_R_PC]; 479 update_pc(frame, cause); 480 481 if (cause & MIPS_CR_BR_DELAY) 482 return; 483 484 for (i = 1; i < LWSWC1_MAXLOOP; i++) { 485 if (mips_btop(frame->f_regs[_R_PC]) != mips_btop(pc)) 486 return; 487 488 vaddr = frame->f_regs[_R_PC]; /* XXX truncates to 32 bits */ 489 inst = fuiword((uint32_t *)vaddr); 490 if (((InstFmt)inst).FRType.op != OP_LWC1) 491 return; 492 493 offset = inst & 0xFFFF; 494 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 495 496 /* segment and alignment check */ 497 if (vaddr < 0 || (vaddr & 3)) { 498 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 499 return; 500 } 501 502 /* NewABI FIXME */ 503 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 504 505 if (copyin((void *)vaddr, t, 4) != 0) { 506 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 507 return; 508 } 509 510 pc = frame->f_regs[_R_PC]; 511 update_pc(frame, cause); 512 } 513 } 514 515 void 516 MachEmulateLDC1(uint32_t inst, struct frame *frame, uint32_t cause) 517 { 518 intptr_t vaddr; 519 int16_t offset; 520 void *t; 521 522 offset = inst & 0xFFFF; 523 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 524 525 /* segment and alignment check */ 526 if (vaddr < 0 || (vaddr & 7)) { 527 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 528 return; 529 } 530 531 /* NewABI FIXME */ 532 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); 533 534 if (copyin((void *)vaddr, t, 8) != 0) { 535 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 536 return; 537 } 538 539 update_pc(frame, cause); 540 } 541 542 void 543 MachEmulateSWC1(uint32_t inst, struct frame *frame, uint32_t cause) 544 { 545 intptr_t vaddr; 546 int16_t offset; 547 void *t; 548 mips_reg_t pc; 549 int i; 550 551 offset = inst & 0xFFFF; 552 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 553 554 /* segment and alignment check */ 555 if (vaddr < 0 || (vaddr & 3)) { 556 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 557 return; 558 } 559 560 /* NewABI FIXME */ 561 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 562 563 if (copyout(t, (void *)vaddr, 4) != 0) { 564 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 565 return; 566 } 567 568 pc = frame->f_regs[_R_PC]; 569 update_pc(frame, cause); 570 571 if (cause & MIPS_CR_BR_DELAY) 572 return; 573 574 for (i = 1; i < LWSWC1_MAXLOOP; i++) { 575 if (mips_btop(frame->f_regs[_R_PC]) != mips_btop(pc)) 576 return; 577 578 vaddr = frame->f_regs[_R_PC]; /* XXX truncates to 32 bits */ 579 inst = fuiword((uint32_t *)vaddr); 580 if (((InstFmt)inst).FRType.op != OP_SWC1) 581 return; 582 583 offset = inst & 0xFFFF; 584 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 585 586 /* segment and alignment check */ 587 if (vaddr < 0 || (vaddr & 3)) { 588 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 589 return; 590 } 591 592 /* NewABI FIXME */ 593 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1F]); 594 595 if (copyout(t, (void *)vaddr, 4) != 0) { 596 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 597 return; 598 } 599 600 pc = frame->f_regs[_R_PC]; 601 update_pc(frame, cause); 602 } 603 } 604 605 void 606 MachEmulateSDC1(uint32_t inst, struct frame *frame, uint32_t cause) 607 { 608 intptr_t vaddr; 609 int16_t offset; 610 void *t; 611 612 offset = inst & 0xFFFF; 613 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 614 615 /* segment and alignment check */ 616 if (vaddr < 0 || (vaddr & 7)) { 617 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 618 return; 619 } 620 621 /* NewABI FIXME */ 622 t = &(curpcb->pcb_fpregs.r_regs[(inst>>16)&0x1E]); 623 624 if (copyout(t, (void *)vaddr, 8) != 0) { 625 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 626 return; 627 } 628 629 update_pc(frame, cause); 630 } 631 632 void 633 bcemul_lb(uint32_t inst, struct frame *frame, uint32_t cause) 634 { 635 intptr_t vaddr; 636 int16_t offset; 637 int8_t x; 638 639 offset = inst & 0xFFFF; 640 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 641 642 /* segment check */ 643 if (vaddr < 0) { 644 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 645 return; 646 } 647 648 if (copyin((void *)vaddr, &x, 1) != 0) { 649 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 650 return; 651 } 652 653 frame->f_regs[(inst>>16)&0x1F] = (int32_t)x; 654 655 update_pc(frame, cause); 656 } 657 658 void 659 bcemul_lbu(uint32_t inst, struct frame *frame, uint32_t cause) 660 { 661 intptr_t vaddr; 662 int16_t offset; 663 uint8_t x; 664 665 offset = inst & 0xFFFF; 666 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 667 668 /* segment check */ 669 if (vaddr < 0) { 670 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 671 return; 672 } 673 674 if (copyin((void *)vaddr, &x, 1) != 0) { 675 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 676 return; 677 } 678 679 frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x; 680 681 update_pc(frame, cause); 682 } 683 684 void 685 bcemul_lh(uint32_t inst, struct frame *frame, uint32_t cause) 686 { 687 intptr_t vaddr; 688 int16_t offset; 689 int16_t x; 690 691 offset = inst & 0xFFFF; 692 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 693 694 /* segment and alignment check */ 695 if (vaddr < 0 || (vaddr & 1)) { 696 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 697 return; 698 } 699 700 if (copyin((void *)vaddr, &x, 2) != 0) { 701 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 702 return; 703 } 704 705 frame->f_regs[(inst>>16)&0x1F] = x; 706 707 update_pc(frame, cause); 708 } 709 710 void 711 bcemul_lhu(uint32_t inst, struct frame *frame, uint32_t cause) 712 { 713 intptr_t vaddr; 714 int16_t offset; 715 u_int16_t x; 716 717 offset = inst & 0xFFFF; 718 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 719 720 /* segment and alignment check */ 721 if (vaddr < 0 || (vaddr & 1)) { 722 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 723 return; 724 } 725 726 if (copyin((void *)vaddr, &x, 2) != 0) { 727 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 728 return; 729 } 730 731 frame->f_regs[(inst>>16)&0x1F] = (mips_ureg_t)x; 732 733 update_pc(frame, cause); 734 } 735 736 void 737 bcemul_lw(uint32_t inst, struct frame *frame, uint32_t cause) 738 { 739 intptr_t vaddr; 740 int16_t offset; 741 742 offset = inst & 0xFFFF; 743 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 744 745 /* segment and alignment check */ 746 if (vaddr < 0 || (vaddr & 3)) { 747 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 748 return; 749 } 750 751 if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 4) != 0) { 752 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 753 return; 754 } 755 756 update_pc(frame, cause); 757 } 758 759 void 760 bcemul_lwl(uint32_t inst, struct frame *frame, uint32_t cause) 761 { 762 intptr_t vaddr; 763 uint32_t a, x, shift; 764 int16_t offset; 765 766 offset = inst & 0xFFFF; 767 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 768 769 /* segment check */ 770 if (vaddr < 0) { 771 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 772 return; 773 } 774 775 if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { 776 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 777 return; 778 } 779 780 x = frame->f_regs[(inst>>16)&0x1F]; 781 782 shift = (3 - (vaddr & 0x00000003)) * 8; 783 a <<= shift; 784 x &= ~(0xFFFFFFFFUL << shift); 785 x |= a; 786 787 frame->f_regs[(inst>>16)&0x1F] = x; 788 789 update_pc(frame, cause); 790 } 791 792 void 793 bcemul_lwr(uint32_t inst, struct frame *frame, uint32_t cause) 794 { 795 intptr_t vaddr; 796 uint32_t a, x, shift; 797 int16_t offset; 798 799 offset = inst & 0xFFFF; 800 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 801 802 /* segment check */ 803 if (vaddr & 0x80000000) { 804 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 805 return; 806 } 807 808 if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { 809 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 810 return; 811 } 812 813 x = frame->f_regs[(inst>>16)&0x1F]; 814 815 shift = (vaddr & 0x00000003) * 8; 816 a >>= shift; 817 x &= ~(0xFFFFFFFFUL >> shift); 818 x |= a; 819 820 frame->f_regs[(inst>>16)&0x1F] = x; 821 822 update_pc(frame, cause); 823 } 824 825 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) 826 void 827 bcemul_ld(uint32_t inst, struct frame *frame, uint32_t cause) 828 { 829 intptr_t vaddr; 830 int16_t offset; 831 832 offset = inst & 0xFFFF; 833 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 834 835 /* segment and alignment check */ 836 if (vaddr > VM_MAX_ADDRESS || vaddr & 0x7) { 837 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 838 return; 839 } 840 841 if (copyin((void *)vaddr, &(frame->f_regs[(inst>>16)&0x1F]), 8) != 0) { 842 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 843 return; 844 } 845 846 update_pc(frame, cause); 847 } 848 849 void 850 bcemul_ldl(uint32_t inst, struct frame *frame, uint32_t cause) 851 { 852 intptr_t vaddr; 853 uint64_t a, x; 854 uint32_t shift; 855 int16_t offset; 856 857 offset = inst & 0xFFFF; 858 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 859 860 /* segment check */ 861 if (vaddr & 0x80000000) { 862 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 863 return; 864 } 865 866 if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { 867 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 868 return; 869 } 870 871 x = frame->f_regs[(inst>>16)&0x1F]; 872 873 shift = (7 - (vaddr & 0x7)) * 8; 874 a <<= shift; 875 x &= ~(~(uint64_t)0UL << shift); 876 x |= a; 877 878 frame->f_regs[(inst>>16)&0x1F] = x; 879 880 update_pc(frame, cause); 881 } 882 883 void 884 bcemul_ldr(uint32_t inst, struct frame *frame, uint32_t cause) 885 { 886 intptr_t vaddr; 887 uint64_t a, x; 888 uint32_t shift; 889 int16_t offset; 890 891 offset = inst & 0xFFFF; 892 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 893 894 /* segment check */ 895 if (vaddr < 0) { 896 send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause); 897 return; 898 } 899 900 if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { 901 send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause); 902 return; 903 } 904 905 x = frame->f_regs[(inst>>16)&0x1F]; 906 907 shift = (vaddr & 0x7) * 8; 908 a >>= shift; 909 x &= ~(~(uint64_t)0UL >> shift); 910 x |= a; 911 912 frame->f_regs[(inst>>16)&0x1F] = x; 913 914 update_pc(frame, cause); 915 } 916 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */ 917 918 void 919 bcemul_sb(uint32_t inst, struct frame *frame, uint32_t cause) 920 { 921 intptr_t vaddr; 922 int16_t offset; 923 924 offset = inst & 0xFFFF; 925 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 926 927 /* segment check */ 928 if (vaddr < 0) { 929 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 930 return; 931 } 932 933 if (subyte((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 934 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 935 return; 936 } 937 938 update_pc(frame, cause); 939 } 940 941 void 942 bcemul_sh(uint32_t inst, struct frame *frame, uint32_t cause) 943 { 944 intptr_t vaddr; 945 int16_t offset; 946 947 offset = inst & 0xFFFF; 948 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 949 950 /* segment and alignment check */ 951 if (vaddr < 0 || vaddr & 1) { 952 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 953 return; 954 } 955 956 if (susword((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 957 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 958 return; 959 } 960 961 update_pc(frame, cause); 962 } 963 964 void 965 bcemul_sw(uint32_t inst, struct frame *frame, uint32_t cause) 966 { 967 intptr_t vaddr; 968 int16_t offset; 969 970 offset = inst & 0xFFFF; 971 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 972 973 /* segment and alignment check */ 974 if (vaddr < 0 || (vaddr & 3)) { 975 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 976 return; 977 } 978 979 if (ustore_uint32((void *)vaddr, frame->f_regs[(inst>>16)&0x1F]) < 0) { 980 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 981 return; 982 } 983 984 update_pc(frame, cause); 985 } 986 987 void 988 bcemul_swl(uint32_t inst, struct frame *frame, uint32_t cause) 989 { 990 intptr_t vaddr; 991 uint32_t a, x, shift; 992 int16_t offset; 993 994 offset = inst & 0xFFFF; 995 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 996 997 /* segment check */ 998 if (vaddr < 0) { 999 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 1000 return; 1001 } 1002 1003 if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { 1004 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1005 return; 1006 } 1007 1008 x = frame->f_regs[(inst>>16)&0x1F]; 1009 1010 shift = (3 - (vaddr & 3)) * 8; 1011 x >>= shift; 1012 a &= ~(0xFFFFFFFFUL >> shift); 1013 a |= x; 1014 1015 if (ustore_uint32((void *)vaddr, a) < 0) { 1016 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1017 return; 1018 } 1019 1020 update_pc(frame, cause); 1021 } 1022 1023 void 1024 bcemul_swr(uint32_t inst, struct frame *frame, uint32_t cause) 1025 { 1026 intptr_t vaddr; 1027 uint32_t a, x, shift; 1028 int16_t offset; 1029 1030 offset = inst & 0xFFFF; 1031 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 1032 1033 /* segment check */ 1034 if (vaddr < 0) { 1035 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 1036 return; 1037 } 1038 1039 if (copyin((void *)(vaddr & ~3), &a, 4) != 0) { 1040 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1041 return; 1042 } 1043 1044 x = frame->f_regs[(inst>>16)&0x1F]; 1045 1046 shift = (vaddr & 3) * 8; 1047 x <<= shift; 1048 a &= ~(0xFFFFFFFFUL << shift); 1049 a |= x; 1050 1051 if (ustore_uint32((void *)vaddr, a) < 0) { 1052 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1053 return; 1054 } 1055 1056 update_pc(frame, cause); 1057 } 1058 1059 #if defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) 1060 void 1061 bcemul_sd(uint32_t inst, struct frame *frame, uint32_t cause) 1062 { 1063 intptr_t vaddr; 1064 int16_t offset; 1065 1066 offset = inst & 0xFFFF; 1067 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 1068 1069 /* segment and alignment check */ 1070 if (vaddr < 0 || vaddr & 0x7) { 1071 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 1072 return; 1073 } 1074 1075 if (copyout((void *)vaddr, &frame->f_regs[(inst>>16)&0x1F], 8) < 0) { 1076 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1077 return; 1078 } 1079 1080 update_pc(frame, cause); 1081 } 1082 1083 void 1084 bcemul_sdl(uint32_t inst, struct frame *frame, uint32_t cause) 1085 { 1086 intptr_t vaddr; 1087 uint64_t a, x; 1088 uint32_t shift; 1089 int16_t offset; 1090 1091 offset = inst & 0xFFFF; 1092 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 1093 1094 /* segment check */ 1095 if (vaddr < 0) { 1096 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 1097 return; 1098 } 1099 1100 if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { 1101 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1102 return; 1103 } 1104 1105 x = frame->f_regs[(inst>>16)&0x1F]; 1106 1107 shift = (7 - (vaddr & 7)) * 8; 1108 x >>= shift; 1109 a &= ~(~(uint64_t)0U >> shift); 1110 a |= x; 1111 1112 if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) { 1113 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1114 return; 1115 } 1116 1117 update_pc(frame, cause); 1118 } 1119 1120 void 1121 bcemul_sdr(uint32_t inst, struct frame *frame, uint32_t cause) 1122 { 1123 intptr_t vaddr; 1124 uint64_t a, x; 1125 uint32_t shift; 1126 int16_t offset; 1127 1128 offset = inst & 0xFFFF; 1129 vaddr = frame->f_regs[(inst>>21)&0x1F] + offset; 1130 1131 /* segment check */ 1132 if (vaddr < 0) { 1133 send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause); 1134 return; 1135 } 1136 1137 if (copyin((void *)(vaddr & ~0x7), &a, 8) != 0) { 1138 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1139 return; 1140 } 1141 1142 x = frame->f_regs[(inst>>16)&0x1F]; 1143 1144 shift = (vaddr & 7) * 8; 1145 x <<= shift; 1146 a &= ~(~(uint64_t)0U << shift); 1147 a |= x; 1148 1149 if (copyout((void *)(vaddr & ~0x7), &a, 8) != 0) { 1150 send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause); 1151 return; 1152 } 1153 1154 update_pc(frame, cause); 1155 } 1156 #endif /* defined(__mips_n32) || defined(__mips_n64) || defined(__mips_o64) */ 1157 #endif /* defined(SOFTFLOAT) */ 1158