1 /* $OpenBSD: emul.c,v 1.22 2011/07/11 15:40:47 guenther 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/proc.h> 36 #include <sys/signalvar.h> 37 #include <sys/malloc.h> 38 #include <machine/reg.h> 39 #include <machine/instr.h> 40 #include <machine/cpu.h> 41 #include <machine/psl.h> 42 #include <uvm/uvm_extern.h> 43 44 #ifdef DEBUG_EMUL 45 # define DPRINTF(a) printf a 46 #else 47 # define DPRINTF(a) 48 #endif 49 50 #define GPR(tf, i) ((int32_t *)(u_long)&tf->tf_global)[i] 51 #define IPR(tf, i) ((int32_t *)(u_long)tf->tf_out[6])[i - 16] 52 #define FPR(p, i) ((int32_t) p->p_md.md_fpstate->fs_regs[i]) 53 #define FPRSET(p, i, v) p->p_md.md_fpstate->fs_regs[i] = (v) 54 55 static __inline int readgpreg(struct trapframe64 *, int, void *); 56 static __inline int readfpreg(struct proc *, int, void *); 57 static __inline int writegpreg(struct trapframe64 *, int, const void *); 58 static __inline int writefpreg(struct proc *, int, const void *); 59 static __inline int decodeaddr(struct trapframe64 *, union instr *, void *); 60 static int muldiv(struct trapframe64 *, union instr *, int32_t *, int32_t *, 61 int32_t *); 62 void swap_quad(int64_t *); 63 64 #define REGNAME(i) "goli"[i >> 3], i & 7 65 66 67 static __inline int 68 readgpreg(tf, i, val) 69 struct trapframe64 *tf; 70 int i; 71 void *val; 72 { 73 int error = 0; 74 if (i == 0) 75 *(int32_t *) val = 0; 76 else if (i < 16) 77 *(int32_t *) val = GPR(tf, i); 78 else 79 error = copyin(&IPR(tf, i), val, sizeof(int32_t)); 80 81 return error; 82 } 83 84 85 static __inline int 86 writegpreg(tf, i, val) 87 struct trapframe64 *tf; 88 int i; 89 const void *val; 90 { 91 int error = 0; 92 93 if (i == 0) 94 return error; 95 else if (i < 16) 96 GPR(tf, i) = *(int32_t *) val; 97 else 98 /* XXX: Fix copyout prototype */ 99 error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t)); 100 101 return error; 102 } 103 104 105 static __inline int 106 readfpreg(p, i, val) 107 struct proc *p; 108 int i; 109 void *val; 110 { 111 *(int32_t *) val = FPR(p, i); 112 return 0; 113 } 114 115 116 static __inline int 117 writefpreg(p, i, val) 118 struct proc *p; 119 int i; 120 const void *val; 121 { 122 FPRSET(p, i, *(const int32_t *) val); 123 return 0; 124 } 125 126 static __inline int 127 decodeaddr(tf, code, val) 128 struct trapframe64 *tf; 129 union instr *code; 130 void *val; 131 { 132 if (code->i_simm13.i_i) 133 *((int32_t *) val) = code->i_simm13.i_simm13; 134 else { 135 int error; 136 137 if (code->i_asi.i_asi) 138 return EINVAL; 139 if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0) 140 return error; 141 } 142 return 0; 143 } 144 145 146 static int 147 muldiv(tf, code, rd, rs1, rs2) 148 struct trapframe64 *tf; 149 union instr *code; 150 int32_t *rd, *rs1, *rs2; 151 { 152 /* 153 * We check for {S,U}{MUL,DIV}{,cc} 154 * 155 * [c = condition code, s = sign] 156 * Mul = 0c101s 157 * Div = 0c111s 158 */ 159 union { 160 struct { 161 unsigned unused:26; /* padding */ 162 unsigned zero:1; /* zero by opcode */ 163 unsigned cc:1; /* one to send condition code */ 164 unsigned one1:1; /* one by opcode */ 165 unsigned div:1; /* one if divide */ 166 unsigned one2:1; /* one by opcode */ 167 unsigned sgn:1; /* sign bit */ 168 } bits; 169 int num; 170 } op; 171 172 op.num = code->i_op3.i_op3; 173 174 #ifdef DEBUG_EMUL 175 printf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int, 176 "us"[op.bits.sgn], op.bits.div ? "div" : "mul", 177 op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd), 178 REGNAME(code->i_op3.i_rs1)); 179 if (code->i_loadstore.i_i) 180 printf("0x%x\n", *rs2); 181 else 182 printf("%c%d\n", REGNAME(code->i_asi.i_rs2)); 183 #endif 184 185 if (op.bits.div) { 186 if (*rs2 == 0) { 187 /* 188 * XXX: to be 100% correct here, on sunos we need to 189 * ignore the error and return *rd = *rs1. 190 * It should be easy to fix by passing struct 191 * proc in here. 192 */ 193 DPRINTF(("muldiv: avoid zerodivide\n")); 194 return EINVAL; 195 } 196 *rd = *rs1 / *rs2; 197 DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd)); 198 } 199 else { 200 *rd = *rs1 * *rs2; 201 DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd)); 202 } 203 204 if (op.bits.cc) { 205 /* Set condition codes */ 206 tf->tf_tstate &= ~(TSTATE_CCR); 207 208 if (*rd == 0) 209 tf->tf_tstate |= (u_int64_t)(ICC_Z|XCC_Z) << TSTATE_CCR_SHIFT; 210 else { 211 if (op.bits.sgn && *rd < 0) 212 tf->tf_tstate |= (u_int64_t)(ICC_N|XCC_N) << TSTATE_CCR_SHIFT; 213 if (op.bits.div) { 214 if (*rd * *rs2 != *rs1) 215 tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT; 216 } 217 else { 218 if (*rd / *rs2 != *rs1) 219 tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT; 220 } 221 } 222 } 223 224 return 0; 225 } 226 227 /* 228 * Emulate unimplemented instructions on earlier sparc chips. 229 */ 230 int 231 emulinstr(pc, tf) 232 vaddr_t pc; 233 struct trapframe64 *tf; 234 { 235 union instr code; 236 int32_t rs1, rs2, rd; 237 int error; 238 239 /* fetch and check the instruction that caused the fault */ 240 error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int)); 241 if (error != 0) { 242 DPRINTF(("emulinstr: Bad instruction fetch\n")); 243 return (SIGILL); 244 } 245 246 /* Only support format 2 */ 247 if (code.i_any.i_op != 2) { 248 DPRINTF(("emulinstr: Not a format 2 instruction\n")); 249 return (SIGILL); 250 } 251 252 write_user_windows(); 253 254 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 255 DPRINTF(("emulinstr: read rs1 %d\n", error)); 256 return (SIGILL); 257 } 258 259 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 260 DPRINTF(("emulinstr: decode addr %d\n", error)); 261 return (SIGILL); 262 } 263 264 switch (code.i_op3.i_op3) { 265 case IOP3_FLUSH: 266 /* cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); XXX */ 267 return (0); 268 269 default: 270 if ((code.i_op3.i_op3 & 0x2a) != 0xa) { 271 DPRINTF(("emulinstr: Unsupported op3 0x%x\n", 272 code.i_op3.i_op3)); 273 return (SIGILL); 274 } 275 else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0) 276 return (SIGFPE); 277 } 278 279 if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) { 280 DPRINTF(("muldiv: write rd %d\n", error)); 281 return (SIGILL); 282 } 283 284 return (0); 285 } 286 287 #define SIGN_EXT13(v) (((int64_t)(v) << 51) >> 51) 288 289 void 290 swap_quad(int64_t *p) 291 { 292 int64_t t; 293 294 t = htole64(p[0]); 295 p[0] = htole64(p[1]); 296 p[1] = t; 297 } 298 299 /* 300 * emulate STQF, STQFA, LDQF, and LDQFA 301 */ 302 int 303 emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf) 304 { 305 extern struct fpstate64 initfpstate; 306 struct fpstate64 *fs = p->p_md.md_fpstate; 307 int64_t addr, buf[2]; 308 union instr ins; 309 int freg, isload, err; 310 u_int8_t asi; 311 312 ins.i_int = insv; 313 freg = ins.i_op3.i_rd & ~1; 314 freg |= (ins.i_op3.i_rd & 1) << 5; 315 316 if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA) 317 isload = 1; 318 else 319 isload = 0; 320 321 if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF) 322 asi = ASI_PRIMARY; 323 else if (ins.i_loadstore.i_i) 324 asi = (tf->tf_tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT; 325 else 326 asi = ins.i_asi.i_asi; 327 328 addr = tf->tf_global[ins.i_asi.i_rs1]; 329 if (ins.i_loadstore.i_i) 330 addr += SIGN_EXT13(ins.i_simm13.i_simm13); 331 else 332 addr += tf->tf_global[ins.i_asi.i_rs2]; 333 334 if (asi < ASI_PRIMARY) { 335 /* privileged asi */ 336 KERNEL_LOCK(); 337 trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv); 338 KERNEL_UNLOCK(); 339 return (0); 340 } 341 if (asi > ASI_SECONDARY_NOFAULT_LITTLE || 342 (asi > ASI_SECONDARY_NOFAULT && asi < ASI_PRIMARY_LITTLE)) { 343 /* architecturally undefined user ASI's */ 344 goto segv; 345 } 346 347 if ((freg & 3) != 0) { 348 /* only valid for %fN where N % 4 = 0 */ 349 KERNEL_LOCK(); 350 trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv); 351 KERNEL_UNLOCK(); 352 return (0); 353 } 354 355 if ((addr & 3) != 0) { 356 /* request is not aligned */ 357 KERNEL_LOCK(); 358 trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv); 359 KERNEL_UNLOCK(); 360 return (0); 361 } 362 363 fs = p->p_md.md_fpstate; 364 if (fs == NULL) { 365 KERNEL_LOCK(); 366 /* don't currently have an fpu context, get one */ 367 fs = malloc(sizeof(*fs), M_SUBPROC, M_WAITOK); 368 *fs = initfpstate; 369 fs->fs_qsize = 0; 370 p->p_md.md_fpstate = fs; 371 KERNEL_UNLOCK(); 372 } else 373 fpusave_proc(p, 1); 374 375 /* Ok, try to do the actual operation (finally) */ 376 if (isload) { 377 err = copyin((caddr_t)addr, buf, sizeof(buf)); 378 if (err != 0 && (asi & 2) == 0) 379 goto segv; 380 if (err == 0) { 381 if (asi & 8) 382 swap_quad(buf); 383 bcopy(buf, &fs->fs_regs[freg], sizeof(buf)); 384 } 385 } else { 386 bcopy(&fs->fs_regs[freg], buf, sizeof(buf)); 387 if (asi & 8) 388 swap_quad(buf); 389 if (copyout(buf, (caddr_t)addr, sizeof(buf)) && (asi & 2) == 0) 390 goto segv; 391 } 392 393 return (1); 394 395 segv: 396 KERNEL_LOCK(); 397 trapsignal(p, SIGSEGV, isload ? VM_PROT_READ : VM_PROT_WRITE, 398 SEGV_MAPERR, sv); 399 KERNEL_UNLOCK(); 400 return (0); 401 } 402 403 int 404 emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf) 405 { 406 u_int64_t val, ret = 0; 407 union instr ins; 408 409 ins.i_int = insv; 410 if (ins.i_simm13.i_i == 0) 411 val = tf->tf_global[ins.i_asi.i_rs2]; 412 else 413 val = SIGN_EXT13(ins.i_simm13.i_simm13); 414 415 for (; val != 0; val >>= 1) 416 ret += val & 1; 417 418 tf->tf_global[ins.i_asi.i_rd] = ret; 419 return (1); 420 } 421