Annotation of sys/arch/sparc64/sparc64/emul.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: emul.c,v 1.12 2003/11/03 07:01:33 david Exp $ */
! 2: /* $NetBSD: emul.c,v 1.8 2001/06/29 23:58:40 eeh Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1997, 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Christos Zoulas.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42: #include <sys/proc.h>
! 43: #include <sys/signalvar.h>
! 44: #include <sys/malloc.h>
! 45: #include <machine/reg.h>
! 46: #include <machine/instr.h>
! 47: #include <machine/cpu.h>
! 48: #include <machine/psl.h>
! 49: #include <sparc64/sparc64/cpuvar.h>
! 50: #include <uvm/uvm_extern.h>
! 51:
! 52: #ifdef DEBUG_EMUL
! 53: # define DPRINTF(a) printf a
! 54: #else
! 55: # define DPRINTF(a)
! 56: #endif
! 57:
! 58: #define GPR(tf, i) ((int32_t *)(u_long)&tf->tf_global)[i]
! 59: #define IPR(tf, i) ((int32_t *)(u_long)tf->tf_out[6])[i - 16]
! 60: #define FPR(p, i) ((int32_t) p->p_md.md_fpstate->fs_regs[i])
! 61:
! 62: static __inline int readgpreg(struct trapframe64 *, int, void *);
! 63: static __inline int readfpreg(struct proc *, int, void *);
! 64: static __inline int writegpreg(struct trapframe64 *, int, const void *);
! 65: static __inline int writefpreg(struct proc *, int, const void *);
! 66: static __inline int decodeaddr(struct trapframe64 *, union instr *, void *);
! 67: static int muldiv(struct trapframe64 *, union instr *, int32_t *, int32_t *,
! 68: int32_t *);
! 69: void swap_quad(int64_t *);
! 70:
! 71: #define REGNAME(i) "goli"[i >> 3], i & 7
! 72:
! 73:
! 74: static __inline int
! 75: readgpreg(tf, i, val)
! 76: struct trapframe64 *tf;
! 77: int i;
! 78: void *val;
! 79: {
! 80: int error = 0;
! 81: if (i == 0)
! 82: *(int32_t *) val = 0;
! 83: else if (i < 16)
! 84: *(int32_t *) val = GPR(tf, i);
! 85: else
! 86: error = copyin(&IPR(tf, i), val, sizeof(int32_t));
! 87:
! 88: return error;
! 89: }
! 90:
! 91:
! 92: static __inline int
! 93: writegpreg(tf, i, val)
! 94: struct trapframe64 *tf;
! 95: int i;
! 96: const void *val;
! 97: {
! 98: int error = 0;
! 99:
! 100: if (i == 0)
! 101: return error;
! 102: else if (i < 16)
! 103: GPR(tf, i) = *(int32_t *) val;
! 104: else
! 105: /* XXX: Fix copyout prototype */
! 106: error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t));
! 107:
! 108: return error;
! 109: }
! 110:
! 111:
! 112: static __inline int
! 113: readfpreg(p, i, val)
! 114: struct proc *p;
! 115: int i;
! 116: void *val;
! 117: {
! 118: *(int32_t *) val = FPR(p, i);
! 119: return 0;
! 120: }
! 121:
! 122:
! 123: static __inline int
! 124: writefpreg(p, i, val)
! 125: struct proc *p;
! 126: int i;
! 127: const void *val;
! 128: {
! 129: FPR(p, i) = *(const int32_t *) val;
! 130: return 0;
! 131: }
! 132:
! 133: static __inline int
! 134: decodeaddr(tf, code, val)
! 135: struct trapframe64 *tf;
! 136: union instr *code;
! 137: void *val;
! 138: {
! 139: if (code->i_simm13.i_i)
! 140: *((int32_t *) val) = code->i_simm13.i_simm13;
! 141: else {
! 142: int error;
! 143:
! 144: if (code->i_asi.i_asi)
! 145: return EINVAL;
! 146: if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0)
! 147: return error;
! 148: }
! 149: return 0;
! 150: }
! 151:
! 152:
! 153: static int
! 154: muldiv(tf, code, rd, rs1, rs2)
! 155: struct trapframe64 *tf;
! 156: union instr *code;
! 157: int32_t *rd, *rs1, *rs2;
! 158: {
! 159: /*
! 160: * We check for {S,U}{MUL,DIV}{,cc}
! 161: *
! 162: * [c = condition code, s = sign]
! 163: * Mul = 0c101s
! 164: * Div = 0c111s
! 165: */
! 166: union {
! 167: struct {
! 168: unsigned unused:26; /* padding */
! 169: unsigned zero:1; /* zero by opcode */
! 170: unsigned cc:1; /* one to send condition code */
! 171: unsigned one1:1; /* one by opcode */
! 172: unsigned div:1; /* one if divide */
! 173: unsigned one2:1; /* one by opcode */
! 174: unsigned sgn:1; /* sign bit */
! 175: } bits;
! 176: int num;
! 177: } op;
! 178:
! 179: op.num = code->i_op3.i_op3;
! 180:
! 181: #ifdef DEBUG_EMUL
! 182: printf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int,
! 183: "us"[op.bits.sgn], op.bits.div ? "div" : "mul",
! 184: op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd),
! 185: REGNAME(code->i_op3.i_rs1));
! 186: if (code->i_loadstore.i_i)
! 187: printf("0x%x\n", *rs2);
! 188: else
! 189: printf("%c%d\n", REGNAME(code->i_asi.i_rs2));
! 190: #endif
! 191:
! 192: if (op.bits.div) {
! 193: if (*rs2 == 0) {
! 194: /*
! 195: * XXX: to be 100% correct here, on sunos we need to
! 196: * ignore the error and return *rd = *rs1.
! 197: * It should be easy to fix by passing struct
! 198: * proc in here.
! 199: */
! 200: DPRINTF(("muldiv: avoid zerodivide\n"));
! 201: return EINVAL;
! 202: }
! 203: *rd = *rs1 / *rs2;
! 204: DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd));
! 205: }
! 206: else {
! 207: *rd = *rs1 * *rs2;
! 208: DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd));
! 209: }
! 210:
! 211: if (op.bits.cc) {
! 212: /* Set condition codes */
! 213: tf->tf_tstate &= ~(TSTATE_CCR);
! 214:
! 215: if (*rd == 0)
! 216: tf->tf_tstate |= (u_int64_t)(ICC_Z|XCC_Z) << TSTATE_CCR_SHIFT;
! 217: else {
! 218: if (op.bits.sgn && *rd < 0)
! 219: tf->tf_tstate |= (u_int64_t)(ICC_N|XCC_N) << TSTATE_CCR_SHIFT;
! 220: if (op.bits.div) {
! 221: if (*rd * *rs2 != *rs1)
! 222: tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
! 223: }
! 224: else {
! 225: if (*rd / *rs2 != *rs1)
! 226: tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
! 227: }
! 228: }
! 229: }
! 230:
! 231: return 0;
! 232: }
! 233:
! 234: /*
! 235: * Code to handle alignment faults on the sparc. This is enabled by sending
! 236: * a fixalign trap. Such code is generated by compiling with cc -misalign
! 237: * on SunOS, but we don't have such a feature yet on our gcc.
! 238: */
! 239:
! 240: int
! 241: fixalign(p, tf)
! 242: struct proc *p;
! 243: struct trapframe64 *tf;
! 244: {
! 245: static u_char sizedef[] = { 0x4, 0xff, 0x2, 0x8 };
! 246:
! 247: /*
! 248: * This is particular to load and store instructions
! 249: */
! 250: union {
! 251: struct {
! 252: unsigned unused:26; /* 26 padding */
! 253: unsigned fl:1; /* 1 bit float flag */
! 254: unsigned op:1; /* 1 bit opcode */
! 255: unsigned sgn:1; /* 1 bit sign */
! 256: unsigned st:1; /* 1 bit load/store */
! 257: unsigned sz:2; /* 2 bit size register */
! 258: } bits;
! 259: int num;
! 260: } op;
! 261:
! 262: union {
! 263: double d;
! 264: int32_t i[2];
! 265: int16_t s[4];
! 266: int8_t c[8];
! 267: } data;
! 268:
! 269: union instr code;
! 270: size_t size;
! 271: int64_t rs1, rs2;
! 272: int error;
! 273:
! 274: /* fetch and check the instruction that caused the fault */
! 275: error = copyin((caddr_t)(u_long)tf->tf_pc, &code.i_int, sizeof(code.i_int));
! 276: if (error != 0) {
! 277: DPRINTF(("fixalign: Bad instruction fetch\n"));
! 278: return EINVAL;
! 279: }
! 280:
! 281: /* Only support format 3 */
! 282: if (code.i_any.i_op != 3) {
! 283: DPRINTF(("fixalign: Not a load or store\n"));
! 284: return EINVAL;
! 285: }
! 286:
! 287: op.num = code.i_loadstore.i_op3;
! 288:
! 289: /* Check operand size */
! 290: if ((size = sizedef[op.bits.sz]) == 0xff) {
! 291: DPRINTF(("fixalign: Bad operand size\n"));
! 292: return EINVAL;
! 293: }
! 294:
! 295: write_user_windows();
! 296:
! 297: if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
! 298: DPRINTF(("fixalign: read rs1 %d\n", error));
! 299: return error;
! 300: }
! 301:
! 302: if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
! 303: DPRINTF(("fixalign: decode addr %d\n", error));
! 304: return error;
! 305: }
! 306:
! 307:
! 308: rs1 += rs2;
! 309:
! 310: #ifdef DEBUG_EMUL
! 311: printf("memalign 0x%x: %s%c%c %c%d, %c%d, ", code.i_int,
! 312: op.bits.st ? "st" : "ld", "us"[op.bits.sgn],
! 313: "w*hd"[op.bits.sz], op.bits.fl ? 'f' : REGNAME(code.i_op3.i_rd),
! 314: REGNAME(code.i_op3.i_rs1));
! 315: if (code.i_loadstore.i_i)
! 316: printf("0x%llx\n", (unsigned long long)rs2);
! 317: else
! 318: printf("%c%d\n", REGNAME(code.i_asi.i_rs2));
! 319: #endif
! 320: #ifdef DIAGNOSTIC
! 321: if (op.bits.fl && p != fpproc)
! 322: panic("fp align without being the FP owning process");
! 323: #endif
! 324:
! 325: if (op.bits.st) {
! 326: if (op.bits.fl) {
! 327: if (p == fpproc) {
! 328: savefpstate(p->p_md.md_fpstate);
! 329: fpproc = NULL;
! 330: }
! 331:
! 332: error = readfpreg(p, code.i_op3.i_rd, &data.i[0]);
! 333: if (error)
! 334: return error;
! 335: if (size == 8) {
! 336: error = readfpreg(p, code.i_op3.i_rd + 1,
! 337: &data.i[1]);
! 338: if (error)
! 339: return error;
! 340: }
! 341: }
! 342: else {
! 343: error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]);
! 344: if (error)
! 345: return error;
! 346: if (size == 8) {
! 347: error = readgpreg(tf, code.i_op3.i_rd + 1,
! 348: &data.i[1]);
! 349: if (error)
! 350: return error;
! 351: }
! 352: }
! 353:
! 354: if (size == 2)
! 355: return copyout(&data.s[1], (caddr_t)(u_long)rs1, size);
! 356: else
! 357: return copyout(&data.d, (caddr_t)(u_long)rs1, size);
! 358: }
! 359: else { /* load */
! 360: if (size == 2) {
! 361: error = copyin((caddr_t)(u_long)rs1, &data.s[1], size);
! 362: if (error)
! 363: return error;
! 364:
! 365: /* Sign extend if necessary */
! 366: if (op.bits.sgn && (data.s[1] & 0x8000) != 0)
! 367: data.s[0] = ~0;
! 368: else
! 369: data.s[0] = 0;
! 370: }
! 371: else
! 372: error = copyin((caddr_t)(u_long)rs1, &data.d, size);
! 373:
! 374: if (error)
! 375: return error;
! 376:
! 377: if (op.bits.fl) {
! 378: error = writefpreg(p, code.i_op3.i_rd, &data.i[0]);
! 379: if (error)
! 380: return error;
! 381: if (size == 8) {
! 382: error = writefpreg(p, code.i_op3.i_rd + 1,
! 383: &data.i[1]);
! 384: if (error)
! 385: return error;
! 386: }
! 387: loadfpstate(p->p_md.md_fpstate);
! 388: fpproc = p;
! 389: }
! 390: else {
! 391: error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]);
! 392: if (error)
! 393: return error;
! 394: if (size == 8)
! 395: error = writegpreg(tf, code.i_op3.i_rd + 1,
! 396: &data.i[1]);
! 397: }
! 398: }
! 399: return error;
! 400: }
! 401:
! 402: /*
! 403: * Emulate unimplemented instructions on earlier sparc chips.
! 404: */
! 405: int
! 406: emulinstr(pc, tf)
! 407: vaddr_t pc;
! 408: struct trapframe64 *tf;
! 409: {
! 410: union instr code;
! 411: int32_t rs1, rs2, rd;
! 412: int error;
! 413:
! 414: /* fetch and check the instruction that caused the fault */
! 415: error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int));
! 416: if (error != 0) {
! 417: DPRINTF(("emulinstr: Bad instruction fetch\n"));
! 418: return (SIGILL);
! 419: }
! 420:
! 421: /* Only support format 2 */
! 422: if (code.i_any.i_op != 2) {
! 423: DPRINTF(("emulinstr: Not a format 2 instruction\n"));
! 424: return (SIGILL);
! 425: }
! 426:
! 427: write_user_windows();
! 428:
! 429: if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
! 430: DPRINTF(("emulinstr: read rs1 %d\n", error));
! 431: return (SIGILL);
! 432: }
! 433:
! 434: if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
! 435: DPRINTF(("emulinstr: decode addr %d\n", error));
! 436: return (SIGILL);
! 437: }
! 438:
! 439: switch (code.i_op3.i_op3) {
! 440: case IOP3_FLUSH:
! 441: /* cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); XXX */
! 442: return (0);
! 443:
! 444: default:
! 445: if ((code.i_op3.i_op3 & 0x2a) != 0xa) {
! 446: DPRINTF(("emulinstr: Unsupported op3 0x%x\n",
! 447: code.i_op3.i_op3));
! 448: return (SIGILL);
! 449: }
! 450: else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0)
! 451: return (SIGFPE);
! 452: }
! 453:
! 454: if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) {
! 455: DPRINTF(("muldiv: write rd %d\n", error));
! 456: return (SIGILL);
! 457: }
! 458:
! 459: return (0);
! 460: }
! 461:
! 462: #define SIGN_EXT13(v) (((int64_t)(v) << 51) >> 51)
! 463:
! 464: void
! 465: swap_quad(int64_t *p)
! 466: {
! 467: int64_t t;
! 468:
! 469: t = htole64(p[0]);
! 470: p[0] = htole64(p[1]);
! 471: p[1] = t;
! 472: }
! 473:
! 474: /*
! 475: * emulate STQF, STQFA, LDQF, and LDQFA
! 476: */
! 477: int
! 478: emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
! 479: {
! 480: extern struct fpstate64 initfpstate;
! 481: struct fpstate64 *fs = p->p_md.md_fpstate;
! 482: int64_t addr, buf[2];
! 483: union instr ins;
! 484: int freg, isload, err;
! 485: u_int8_t asi;
! 486:
! 487: ins.i_int = insv;
! 488: freg = ins.i_op3.i_rd & ~1;
! 489: freg |= (ins.i_op3.i_rd & 1) << 5;
! 490:
! 491: if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA)
! 492: isload = 1;
! 493: else
! 494: isload = 0;
! 495:
! 496: if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF)
! 497: asi = ASI_PRIMARY;
! 498: else if (ins.i_loadstore.i_i)
! 499: asi = (tf->tf_tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT;
! 500: else
! 501: asi = ins.i_asi.i_asi;
! 502:
! 503: addr = tf->tf_global[ins.i_asi.i_rs1];
! 504: if (ins.i_loadstore.i_i)
! 505: addr += SIGN_EXT13(ins.i_simm13.i_simm13);
! 506: else
! 507: addr += tf->tf_global[ins.i_asi.i_rs2];
! 508:
! 509: if (asi < ASI_PRIMARY) {
! 510: /* privileged asi */
! 511: trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
! 512: return (0);
! 513: }
! 514: if (asi > ASI_SECONDARY_NOFAULT_LITTLE ||
! 515: (asi > ASI_SECONDARY_NOFAULT && asi < ASI_PRIMARY_LITTLE)) {
! 516: /* architecturally undefined user ASI's */
! 517: goto segv;
! 518: }
! 519:
! 520: if ((freg & 3) != 0) {
! 521: /* only valid for %fN where N % 4 = 0 */
! 522: trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
! 523: return (0);
! 524: }
! 525:
! 526: if ((p->p_md.md_flags & MDP_FIXALIGN) == 0 && (addr & 3) != 0) {
! 527: /*
! 528: * If process doesn't want us to fix alignment and the
! 529: * request isn't aligned, kill it.
! 530: */
! 531: trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
! 532: return (0);
! 533: }
! 534:
! 535: fs = p->p_md.md_fpstate;
! 536: if (fs == NULL) {
! 537: /* don't currently have an fpu context, get one */
! 538: fs = malloc(sizeof(*fs), M_SUBPROC, M_WAITOK);
! 539: *fs = initfpstate;
! 540: fs->fs_qsize = 0;
! 541: p->p_md.md_fpstate = fs;
! 542: }
! 543: if (fpproc != p) {
! 544: /* make this process the current holder of the fpu */
! 545: if (fpproc != NULL)
! 546: savefpstate(fpproc->p_md.md_fpstate);
! 547: fpproc = p;
! 548: }
! 549: tf->tf_tstate |= TSTATE_PEF;
! 550:
! 551: /* Ok, try to do the actual operation (finally) */
! 552: if (isload) {
! 553: err = copyin((caddr_t)addr, buf, sizeof(buf));
! 554: if (err != 0 && (asi & 2) == 0)
! 555: goto segv;
! 556: if (err == 0) {
! 557: savefpstate(fs);
! 558: if (asi & 8)
! 559: swap_quad(buf);
! 560: bcopy(buf, &fs->fs_regs[freg], sizeof(buf));
! 561: loadfpstate(fs);
! 562: }
! 563: } else {
! 564: bcopy(&fs->fs_regs[freg], buf, sizeof(buf));
! 565: if (asi & 8)
! 566: swap_quad(buf);
! 567: if (copyout(buf, (caddr_t)addr, sizeof(buf)) && (asi & 2) == 0)
! 568: goto segv;
! 569: }
! 570:
! 571: return (1);
! 572:
! 573: segv:
! 574: trapsignal(p, SIGSEGV, isload ? VM_PROT_READ : VM_PROT_WRITE,
! 575: SEGV_MAPERR, sv);
! 576: return (0);
! 577: }
! 578:
! 579: int
! 580: emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
! 581: {
! 582: u_int64_t val, ret = 0;
! 583: union instr ins;
! 584:
! 585: ins.i_int = insv;
! 586: if (ins.i_simm13.i_i == 0)
! 587: val = tf->tf_global[ins.i_asi.i_rs2];
! 588: else
! 589: val = SIGN_EXT13(ins.i_simm13.i_simm13);
! 590:
! 591: for (; val != 0; val >>= 1)
! 592: ret += val & 1;
! 593:
! 594: tf->tf_global[ins.i_asi.i_rd] = ret;
! 595: return (1);
! 596: }
CVSweb