1 /* $NetBSD: emul.c,v 1.9 2002/04/18 16:37:26 eeh 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 47 #define DEBUG_EMUL 48 #ifdef DEBUG_EMUL 49 # define DPRINTF(a) uprintf a 50 #else 51 # define DPRINTF(a) 52 #endif 53 54 #define GPR(tf, i) ((int32_t *)(u_long)&tf->tf_global)[i] 55 #define IPR(tf, i) ((int32_t *)(u_long)tf->tf_out[6])[i - 16] 56 #define FPR(p, i) ((int32_t) p->p_md.md_fpstate->fs_regs[i]) 57 58 static __inline int readgpreg __P((struct trapframe64 *, int, void *)); 59 static __inline int readfpreg __P((struct proc *, int, void *)); 60 static __inline int writegpreg __P((struct trapframe64 *, int, const void *)); 61 static __inline int writefpreg __P((struct proc *, int, const void *)); 62 static __inline int decodeaddr __P((struct trapframe64 *, union instr *, void *)); 63 static int muldiv __P((struct trapframe64 *, union instr *, int32_t *, int32_t *, 64 int32_t *)); 65 66 #define REGNAME(i) "goli"[i >> 3], i & 7 67 68 69 static __inline int 70 readgpreg(tf, i, val) 71 struct trapframe64 *tf; 72 int i; 73 void *val; 74 { 75 int error = 0; 76 if (i == 0) 77 *(int32_t *) val = 0; 78 else if (i < 16) 79 *(int32_t *) val = GPR(tf, i); 80 else 81 error = copyin(&IPR(tf, i), val, sizeof(int32_t)); 82 83 return error; 84 } 85 86 87 static __inline int 88 writegpreg(tf, i, val) 89 struct trapframe64 *tf; 90 int i; 91 const void *val; 92 { 93 int error = 0; 94 95 if (i == 0) 96 return error; 97 else if (i < 16) 98 GPR(tf, i) = *(int32_t *) val; 99 else 100 /* XXX: Fix copyout prototype */ 101 error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t)); 102 103 return error; 104 } 105 106 107 static __inline int 108 readfpreg(p, i, val) 109 struct proc *p; 110 int i; 111 void *val; 112 { 113 *(int32_t *) val = FPR(p, i); 114 return 0; 115 } 116 117 118 static __inline int 119 writefpreg(p, i, val) 120 struct proc *p; 121 int i; 122 const void *val; 123 { 124 FPR(p, i) = *(const int32_t *) val; 125 return 0; 126 } 127 128 static __inline int 129 decodeaddr(tf, code, val) 130 struct trapframe64 *tf; 131 union instr *code; 132 void *val; 133 { 134 if (code->i_simm13.i_i) 135 *((int32_t *) val) = code->i_simm13.i_simm13; 136 else { 137 int error; 138 139 if (code->i_asi.i_asi) 140 return EINVAL; 141 if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0) 142 return error; 143 } 144 return 0; 145 } 146 147 148 static int 149 muldiv(tf, code, rd, rs1, rs2) 150 struct trapframe64 *tf; 151 union instr *code; 152 int32_t *rd, *rs1, *rs2; 153 { 154 /* 155 * We check for {S,U}{MUL,DIV}{,cc} 156 * 157 * [c = condition code, s = sign] 158 * Mul = 0c101s 159 * Div = 0c111s 160 */ 161 union { 162 struct { 163 unsigned unused:26; /* padding */ 164 unsigned zero:1; /* zero by opcode */ 165 unsigned cc:1; /* one to send condition code */ 166 unsigned one1:1; /* one by opcode */ 167 unsigned div:1; /* one if divide */ 168 unsigned one2:1; /* one by opcode */ 169 unsigned sgn:1; /* sign bit */ 170 } bits; 171 int num; 172 } op; 173 174 op.num = code->i_op3.i_op3; 175 176 #ifdef DEBUG_EMUL 177 uprintf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int, 178 "us"[op.bits.sgn], op.bits.div ? "div" : "mul", 179 op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd), 180 REGNAME(code->i_op3.i_rs1)); 181 if (code->i_loadstore.i_i) 182 uprintf("0x%x\n", *rs2); 183 else 184 uprintf("%c%d\n", REGNAME(code->i_asi.i_rs2)); 185 #endif 186 187 if (op.bits.div) { 188 if (*rs2 == 0) { 189 /* 190 * XXX: to be 100% correct here, on sunos we need to 191 * ignore the error and return *rd = *rs1. 192 * It should be easy to fix by passing struct 193 * proc in here. 194 */ 195 DPRINTF(("emulinstr: avoid zerodivide\n")); 196 return EINVAL; 197 } 198 *rd = *rs1 / *rs2; 199 DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd)); 200 } 201 else { 202 *rd = *rs1 * *rs2; 203 DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd)); 204 } 205 206 if (op.bits.cc) { 207 /* Set condition codes */ 208 tf->tf_tstate &= ~(TSTATE_CCR); 209 210 if (*rd == 0) 211 tf->tf_tstate |= (u_int64_t)(ICC_Z|XCC_Z) << TSTATE_CCR_SHIFT; 212 else { 213 if (op.bits.sgn && *rd < 0) 214 tf->tf_tstate |= (u_int64_t)(ICC_N|XCC_N) << TSTATE_CCR_SHIFT; 215 if (op.bits.div) { 216 if (*rd * *rs2 != *rs1) 217 tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT; 218 } 219 else { 220 if (*rd / *rs2 != *rs1) 221 tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT; 222 } 223 } 224 } 225 226 return 0; 227 } 228 229 /* 230 * Code to handle alignment faults on the sparc. This is enabled by sending 231 * a fixalign trap. Such code is generated by compiling with cc -misalign 232 * on SunOS, but we don't have such a feature yet on our gcc. 233 */ 234 235 int 236 fixalign(p, tf) 237 struct proc *p; 238 struct trapframe64 *tf; 239 { 240 static u_char sizedef[] = { 0x4, 0xff, 0x2, 0x8 }; 241 242 /* 243 * This is particular to load and store instructions 244 */ 245 union { 246 struct { 247 unsigned unused:26; /* 26 padding */ 248 unsigned fl:1; /* 1 bit float flag */ 249 unsigned op:1; /* 1 bit opcode */ 250 unsigned sgn:1; /* 1 bit sign */ 251 unsigned st:1; /* 1 bit load/store */ 252 unsigned sz:2; /* 2 bit size register */ 253 } bits; 254 int num; 255 } op; 256 257 union { 258 double d; 259 int32_t i[2]; 260 int16_t s[4]; 261 int8_t c[8]; 262 } data; 263 264 union instr code; 265 size_t size; 266 int64_t rs1, rs2; 267 int error; 268 269 /* fetch and check the instruction that caused the fault */ 270 error = copyin((caddr_t)(u_long)tf->tf_pc, &code.i_int, sizeof(code.i_int)); 271 if (error != 0) { 272 DPRINTF(("fixalign: Bad instruction fetch\n")); 273 return EINVAL; 274 } 275 276 /* Only support format 3 */ 277 if (code.i_any.i_op != 3) { 278 DPRINTF(("fixalign: Not a load or store\n")); 279 return EINVAL; 280 } 281 282 op.num = code.i_loadstore.i_op3; 283 284 /* Check operand size */ 285 if ((size = sizedef[op.bits.sz]) == 0xff) { 286 DPRINTF(("fixalign: Bad operand size\n")); 287 return EINVAL; 288 } 289 290 write_user_windows(); 291 292 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 293 DPRINTF(("emulinstr: read rs1 %d\n", error)); 294 return error; 295 } 296 297 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 298 DPRINTF(("emulinstr: decode addr %d\n", error)); 299 return error; 300 } 301 302 303 rs1 += rs2; 304 305 #ifdef DEBUG_EMUL 306 uprintf("memalign 0x%x: %s%c%c %c%d, %c%d, ", code.i_int, 307 op.bits.st ? "st" : "ld", "us"[op.bits.sgn], 308 "w*hd"[op.bits.sz], op.bits.fl ? 'f' : REGNAME(code.i_op3.i_rd), 309 REGNAME(code.i_op3.i_rs1)); 310 if (code.i_loadstore.i_i) 311 uprintf("0x%llx\n", (unsigned long long)rs2); 312 else 313 uprintf("%c%d\n", REGNAME(code.i_asi.i_rs2)); 314 #endif 315 #ifdef DIAGNOSTIC 316 if (op.bits.fl && p != fpproc) 317 panic("fp align without being the FP owning process"); 318 #endif 319 320 if (op.bits.st) { 321 if (op.bits.fl) { 322 if (p == fpproc) { 323 savefpstate(p->p_md.md_fpstate); 324 fpproc = NULL; 325 } 326 327 error = readfpreg(p, code.i_op3.i_rd, &data.i[0]); 328 if (error) 329 return error; 330 if (size == 8) { 331 error = readfpreg(p, code.i_op3.i_rd + 1, 332 &data.i[1]); 333 if (error) 334 return error; 335 } 336 } 337 else { 338 error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]); 339 if (error) 340 return error; 341 if (size == 8) { 342 error = readgpreg(tf, code.i_op3.i_rd + 1, 343 &data.i[1]); 344 if (error) 345 return error; 346 } 347 } 348 349 if (size == 2) 350 return copyout(&data.s[1], (caddr_t)(u_long)rs1, size); 351 else 352 return copyout(&data.d, (caddr_t)(u_long)rs1, size); 353 } 354 else { /* load */ 355 if (size == 2) { 356 error = copyin((caddr_t)(u_long)rs1, &data.s[1], size); 357 if (error) 358 return error; 359 360 /* Sign extend if necessary */ 361 if (op.bits.sgn && (data.s[1] & 0x8000) != 0) 362 data.s[0] = ~0; 363 else 364 data.s[0] = 0; 365 } 366 else 367 error = copyin((caddr_t)(u_long)rs1, &data.d, size); 368 369 if (error) 370 return error; 371 372 if (op.bits.fl) { 373 error = writefpreg(p, code.i_op3.i_rd, &data.i[0]); 374 if (error) 375 return error; 376 if (size == 8) { 377 error = writefpreg(p, code.i_op3.i_rd + 1, 378 &data.i[1]); 379 if (error) 380 return error; 381 } 382 loadfpstate(p->p_md.md_fpstate); 383 fpproc = p; 384 } 385 else { 386 error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]); 387 if (error) 388 return error; 389 if (size == 8) 390 error = writegpreg(tf, code.i_op3.i_rd + 1, 391 &data.i[1]); 392 } 393 } 394 return error; 395 } 396 397 /* 398 * Emulate unimplemented instructions on earlier sparc chips. 399 */ 400 int 401 emulinstr(pc, tf) 402 vaddr_t pc; 403 struct trapframe64 *tf; 404 { 405 union instr code; 406 int32_t rs1, rs2, rd; 407 int error; 408 409 /* fetch and check the instruction that caused the fault */ 410 error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int)); 411 if (error != 0) { 412 DPRINTF(("emulinstr: Bad instruction fetch\n")); 413 return SIGILL; 414 } 415 416 /* Only support format 2 */ 417 if (code.i_any.i_op != 2) { 418 DPRINTF(("emulinstr: Not a format 2 instruction\n")); 419 return SIGILL; 420 } 421 422 write_user_windows(); 423 424 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 425 DPRINTF(("emulinstr: read rs1 %d\n", error)); 426 return SIGILL; 427 } 428 429 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 430 DPRINTF(("emulinstr: decode addr %d\n", error)); 431 return SIGILL; 432 } 433 434 switch (code.i_op3.i_op3) { 435 case IOP3_FLUSH: 436 printf("emulinstr: we can't execute a cache flush???"); 437 /* cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); XXX */ 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