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