1 /* $NetBSD: emul.c,v 1.19 2016/08/15 08:43:19 maxv Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: emul.c,v 1.19 2016/08/15 08:43:19 maxv Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/lwp.h> 38 #include <machine/reg.h> 39 #include <machine/instr.h> 40 #include <machine/cpu.h> 41 #include <machine/psl.h> 42 #include <sparc/sparc/cpuvar.h> 43 44 #ifdef DEBUG_EMUL 45 # define DPRINTF(a) uprintf a 46 #else 47 # define DPRINTF(a) 48 #endif 49 50 #define GPR(tf, i) ((int32_t *) &tf->tf_global)[i] 51 #define IPR(tf, i) ((int32_t *) tf->tf_out[6])[i - 16] 52 #define FPR(l, i) ((int32_t) l->l_md.md_fpstate->fs_regs[i]) 53 #define FPRSET(l, i, v) (l->l_md.md_fpstate->fs_regs[i] = (int32_t)(v)) 54 55 static inline int readgpreg(struct trapframe *, int, void *); 56 static inline int readfpreg(struct lwp *, int, void *); 57 static inline int writegpreg(struct trapframe *, int, const void *); 58 static inline int writefpreg(struct lwp *, int, const void *); 59 static inline int decodeaddr(struct trapframe *, union instr *, void *); 60 static int muldiv(struct trapframe *, union instr *, int32_t *, int32_t *, 61 int32_t *); 62 63 #define REGNAME(i) "goli"[i >> 3], i & 7 64 65 66 static inline int 67 readgpreg(struct trapframe *tf, int i, void *val) 68 { 69 int error = 0; 70 if (i == 0) 71 *(int32_t *) val = 0; 72 else if (i < 16) 73 *(int32_t *) val = GPR(tf, i); 74 else 75 error = copyin(&IPR(tf, i), val, sizeof(int32_t)); 76 77 return error; 78 } 79 80 81 static inline int 82 writegpreg(struct trapframe *tf, int i, const void *val) 83 { 84 int error = 0; 85 86 if (i == 0) 87 return 0; 88 else if (i < 16) 89 GPR(tf, i) = *(const int32_t *) val; 90 else 91 error = copyout(val, &IPR(tf, i), sizeof(int32_t)); 92 93 return error; 94 } 95 96 97 static inline int 98 readfpreg(struct lwp *l, int i, void *val) 99 { 100 101 *(int32_t *) val = FPR(l, i); 102 return 0; 103 } 104 105 106 static inline int 107 writefpreg(struct lwp *l, int i, const void *val) 108 { 109 110 FPRSET(l, i, *(const int32_t *) val); 111 return 0; 112 } 113 114 static inline int 115 decodeaddr(struct trapframe *tf, union instr *code, void *val) 116 { 117 118 if (code->i_simm13.i_i) 119 *((int32_t *) val) = code->i_simm13.i_simm13; 120 else { 121 int error; 122 123 if (code->i_asi.i_asi) 124 return EINVAL; 125 if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0) 126 return error; 127 } 128 return 0; 129 } 130 131 132 static int 133 muldiv(struct trapframe *tf, 134 union instr *code, int32_t *rd, int32_t *rs1, int32_t *rs2) 135 { 136 /* 137 * We check for {S,U}{MUL,DIV}{,cc} 138 * 139 * [c = condition code, s = sign] 140 * Mul = 0c101s 141 * Div = 0c111s 142 */ 143 union { 144 struct { 145 unsigned unused:26; /* padding */ 146 unsigned zero:1; /* zero by opcode */ 147 unsigned cc:1; /* one to send condition code */ 148 unsigned one1:1; /* one by opcode */ 149 unsigned div:1; /* one if divide */ 150 unsigned one2:1; /* one by opcode */ 151 unsigned sgn:1; /* sign bit */ 152 } bits; 153 int num; 154 } op; 155 156 op.num = code->i_op3.i_op3; 157 158 #ifdef DEBUG_EMUL 159 uprintf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int, 160 "us"[op.bits.sgn], op.bits.div ? "div" : "mul", 161 op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd), 162 REGNAME(code->i_op3.i_rs1)); 163 if (code->i_loadstore.i_i) 164 uprintf("0x%x\n", *rs2); 165 else 166 uprintf("%c%d\n", REGNAME(code->i_asi.i_rs2)); 167 #endif 168 169 if (op.bits.div) { 170 if (*rs2 == 0) { 171 /* 172 * XXX: to be 100% correct here, on sunos we need to 173 * ignore the error and return *rd = *rs1. 174 * It should be easy to fix by passing struct 175 * proc in here. 176 */ 177 DPRINTF(("emulinstr: avoid zerodivide\n")); 178 return EINVAL; 179 } 180 *rd = *rs1 / *rs2; 181 DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd)); 182 } 183 else { 184 *rd = *rs1 * *rs2; 185 DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd)); 186 } 187 188 if (op.bits.cc) { 189 /* Set condition codes */ 190 tf->tf_psr &= ~PSR_ICC; 191 192 if (*rd == 0) 193 tf->tf_psr |= PSR_Z; 194 else { 195 if (op.bits.sgn && *rd < 0) 196 tf->tf_psr |= PSR_N; 197 if (op.bits.div) { 198 if (*rd * *rs2 != *rs1) 199 tf->tf_psr |= PSR_O; 200 } 201 else { 202 if (*rd / *rs2 != *rs1) 203 tf->tf_psr |= PSR_O; 204 } 205 } 206 } 207 208 return 0; 209 } 210 211 /* 212 * Code to handle alignment faults on the sparc. This is enabled by sending 213 * a fixalign trap. Such code is generated by compiling with cc -misalign 214 * on SunOS, but we don't have such a feature yet on our gcc. 215 * If data_address is passed, do not emulate the instruction but just report 216 * back the VA (this is used for signal delivery). 217 */ 218 219 int 220 fixalign(struct lwp *l, struct trapframe *tf, void **data_address) 221 { 222 static u_char sizedef[] = { 0x4, 0xff, 0x2, 0x8 }; 223 224 /* 225 * This is particular to load and store instructions 226 */ 227 union { 228 struct { 229 unsigned unused:26; /* 26 padding */ 230 unsigned fl:1; /* 1 bit float flag */ 231 unsigned op:1; /* 1 bit opcode */ 232 unsigned sgn:1; /* 1 bit sign */ 233 unsigned st:1; /* 1 bit load/store */ 234 unsigned sz:2; /* 2 bit size register */ 235 } bits; 236 int num; 237 } op; 238 239 union { 240 double d; 241 int32_t i[2]; 242 int16_t s[4]; 243 int8_t c[8]; 244 } data; 245 246 union instr code; 247 size_t size; 248 int32_t rs1, rs2; 249 int error; 250 251 /* fetch and check the instruction that caused the fault */ 252 error = copyin((void *) tf->tf_pc, &code.i_int, sizeof(code.i_int)); 253 if (error != 0) { 254 DPRINTF(("fixalign: Bad instruction fetch\n")); 255 return EINVAL; 256 } 257 258 /* Only support format 3 */ 259 if (code.i_any.i_op != 3) { 260 DPRINTF(("fixalign: Not a load or store\n")); 261 return EINVAL; 262 } 263 264 op.num = code.i_loadstore.i_op3; 265 266 /* Check operand size */ 267 if ((size = sizedef[op.bits.sz]) == 0xff) { 268 DPRINTF(("fixalign: Bad operand size\n")); 269 return EINVAL; 270 } 271 272 write_user_windows(); 273 274 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 275 DPRINTF(("emulinstr: read rs1 %d\n", error)); 276 return error; 277 } 278 279 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 280 DPRINTF(("emulinstr: decode addr %d\n", error)); 281 return error; 282 } 283 284 285 rs1 += rs2; 286 287 /* Only querying faulting data address? */ 288 if (data_address) { 289 *data_address = (void*)rs1; 290 return 0; 291 } 292 293 #ifdef DEBUG_EMUL 294 uprintf("memalign 0x%x: %s%c%c %c%d, %c%d, ", code.i_int, 295 op.bits.st ? "st" : "ld", "us"[op.bits.sgn], 296 "w*hd"[op.bits.sz], op.bits.fl ? 'f' : REGNAME(code.i_op3.i_rd), 297 REGNAME(code.i_op3.i_rs1)); 298 if (code.i_loadstore.i_i) 299 uprintf("0x%x\n", rs2); 300 else 301 uprintf("%c%d\n", REGNAME(code.i_asi.i_rs2)); 302 #endif 303 #ifdef DIAGNOSTIC 304 if (op.bits.fl && l != cpuinfo.fplwp) 305 panic("fp align without being the FP owning process"); 306 #endif 307 308 if (op.bits.st) { 309 if (op.bits.fl) { 310 savefpstate(l->l_md.md_fpstate); 311 312 error = readfpreg(l, code.i_op3.i_rd, &data.i[0]); 313 if (error) 314 return error; 315 if (size == 8) { 316 error = readfpreg(l, code.i_op3.i_rd + 1, 317 &data.i[1]); 318 if (error) 319 return error; 320 } 321 } 322 else { 323 error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]); 324 if (error) 325 return error; 326 if (size == 8) { 327 error = readgpreg(tf, code.i_op3.i_rd + 1, 328 &data.i[1]); 329 if (error) 330 return error; 331 } 332 } 333 334 if (size == 2) 335 return copyout(&data.s[1], (void *) rs1, size); 336 else 337 return copyout(&data.d, (void *) rs1, size); 338 } 339 else { /* load */ 340 if (size == 2) { 341 error = copyin((void *) rs1, &data.s[1], size); 342 if (error) 343 return error; 344 345 /* Sign extend if necessary */ 346 if (op.bits.sgn && (data.s[1] & 0x8000) != 0) 347 data.s[0] = ~0; 348 else 349 data.s[0] = 0; 350 } 351 else 352 error = copyin((void *) rs1, &data.d, size); 353 354 if (error) 355 return error; 356 357 if (op.bits.fl) { 358 error = writefpreg(l, code.i_op3.i_rd, &data.i[0]); 359 if (error) 360 return error; 361 if (size == 8) { 362 error = writefpreg(l, code.i_op3.i_rd + 1, 363 &data.i[1]); 364 if (error) 365 return error; 366 } 367 loadfpstate(l->l_md.md_fpstate); 368 } 369 else { 370 error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]); 371 if (error) 372 return error; 373 if (size == 8) 374 error = writegpreg(tf, code.i_op3.i_rd + 1, 375 &data.i[1]); 376 } 377 } 378 return error; 379 } 380 381 /* 382 * Emulate unimplemented instructions on earlier sparc chips. 383 */ 384 int 385 emulinstr(int pc, struct trapframe *tf) 386 { 387 union instr code; 388 int32_t rs1, rs2, rd; 389 int error; 390 391 /* fetch and check the instruction that caused the fault */ 392 error = copyin((void *) pc, &code.i_int, sizeof(code.i_int)); 393 if (error != 0) { 394 DPRINTF(("emulinstr: Bad instruction fetch\n")); 395 return SIGILL; 396 } 397 398 /* Only support format 2 */ 399 if (code.i_any.i_op != 2) { 400 DPRINTF(("emulinstr: Not a format 2 instruction\n")); 401 return SIGILL; 402 } 403 404 write_user_windows(); 405 406 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 407 DPRINTF(("emulinstr: read rs1 %d\n", error)); 408 return SIGILL; 409 } 410 411 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 412 DPRINTF(("emulinstr: decode addr %d\n", error)); 413 return SIGILL; 414 } 415 416 switch (code.i_op3.i_op3) { 417 case IOP3_FLUSH: 418 /* 419 * A FLUSH instruction causing a T_ILLINST! 420 * Turn it into a NOP. 421 */ 422 return 0; 423 424 default: 425 if ((code.i_op3.i_op3 & 0x2a) != 0xa) { 426 DPRINTF(("emulinstr: Unsupported op3 0x%x\n", 427 code.i_op3.i_op3)); 428 return SIGILL; 429 } 430 else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0) 431 return SIGFPE; 432 } 433 434 if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) { 435 DPRINTF(("muldiv: write rd %d\n", error)); 436 return SIGILL; 437 } 438 439 return 0; 440 } 441