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