1 /* $NetBSD: emul.c,v 1.5 1998/10/01 21:26:55 christos 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 * 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 <sparc/sparc/cpuvar.h> 47 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 *) &tf->tf_global)[i] 55 #define IPR(tf, i) ((int32_t *) 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 trapframe *, int, void *)); 59 static __inline int readfpreg __P((struct proc *, int, void *)); 60 static __inline int writegpreg __P((struct trapframe *, int, const void *)); 61 static __inline int writefpreg __P((struct proc *, int, const void *)); 62 static __inline int decodeaddr __P((struct trapframe *, union instr *, void *)); 63 static int muldiv __P((struct trapframe *, 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 trapframe *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 trapframe *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 trapframe *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 trapframe *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_psr &= ~PSR_ICC; 209 210 if (*rd == 0) 211 tf->tf_psr |= PSR_Z << 20; 212 else { 213 if (op.bits.sgn && *rd < 0) 214 tf->tf_psr |= PSR_N << 20; 215 if (op.bits.div) { 216 if (*rd * *rs2 != *rs1) 217 tf->tf_psr |= PSR_O << 20; 218 } 219 else { 220 if (*rd / *rs2 != *rs1) 221 tf->tf_psr |= PSR_O << 20; 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 trapframe *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 int32_t rs1, rs2; 267 int error; 268 269 /* fetch and check the instruction that caused the fault */ 270 error = copyin((caddr_t) 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%x\n", 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 != cpuinfo.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 savefpstate(p->p_md.md_fpstate); 323 324 error = readfpreg(p, code.i_op3.i_rd, &data.i[0]); 325 if (error) 326 return error; 327 if (size == 8) { 328 error = readfpreg(p, code.i_op3.i_rd + 1, 329 &data.i[1]); 330 if (error) 331 return error; 332 } 333 } 334 else { 335 error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]); 336 if (error) 337 return error; 338 if (size == 8) { 339 error = readgpreg(tf, code.i_op3.i_rd + 1, 340 &data.i[1]); 341 if (error) 342 return error; 343 } 344 } 345 346 if (size == 2) 347 return copyout(&data.s[1], (caddr_t) rs1, size); 348 else 349 return copyout(&data.d, (caddr_t) rs1, size); 350 } 351 else { /* load */ 352 if (size == 2) { 353 error = copyin((caddr_t) rs1, &data.s[1], size); 354 if (error) 355 return error; 356 357 /* Sign extend if necessary */ 358 if (op.bits.sgn && (data.s[1] & 0x8000) != 0) 359 data.s[0] = ~0; 360 else 361 data.s[0] = 0; 362 } 363 else 364 error = copyin((caddr_t) rs1, &data.d, size); 365 366 if (error) 367 return error; 368 369 if (op.bits.fl) { 370 error = writefpreg(p, code.i_op3.i_rd, &data.i[0]); 371 if (error) 372 return error; 373 if (size == 8) { 374 error = writefpreg(p, code.i_op3.i_rd + 1, 375 &data.i[1]); 376 if (error) 377 return error; 378 } 379 loadfpstate(p->p_md.md_fpstate); 380 } 381 else { 382 error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]); 383 if (error) 384 return error; 385 if (size == 8) 386 error = writegpreg(tf, code.i_op3.i_rd + 1, 387 &data.i[1]); 388 } 389 } 390 return error; 391 } 392 393 /* 394 * Emulate unimplemented instructions on earlier sparc chips. 395 */ 396 int 397 emulinstr(pc, tf) 398 int pc; 399 struct trapframe *tf; 400 { 401 union instr code; 402 int32_t rs1, rs2, rd; 403 int error; 404 405 /* fetch and check the instruction that caused the fault */ 406 error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int)); 407 if (error != 0) { 408 DPRINTF(("emulinstr: Bad instruction fetch\n")); 409 return SIGILL; 410 } 411 412 /* Only support format 2 */ 413 if (code.i_any.i_op != 2) { 414 DPRINTF(("emulinstr: Not a format 2 instruction\n")); 415 return SIGILL; 416 } 417 418 write_user_windows(); 419 420 if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) { 421 DPRINTF(("emulinstr: read rs1 %d\n", error)); 422 return SIGILL; 423 } 424 425 if ((error = decodeaddr(tf, &code, &rs2)) != 0) { 426 DPRINTF(("emulinstr: decode addr %d\n", error)); 427 return SIGILL; 428 } 429 430 switch (code.i_op3.i_op3) { 431 case IOP3_FLUSH: 432 cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); /*XXX*/ 433 return 0; 434 435 default: 436 if ((code.i_op3.i_op3 & 0x2a) != 0xa) { 437 DPRINTF(("emulinstr: Unsupported op3 0x%x\n", 438 code.i_op3.i_op3)); 439 return SIGILL; 440 } 441 else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0) 442 return SIGFPE; 443 } 444 445 if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) { 446 DPRINTF(("muldiv: write rd %d\n", error)); 447 return SIGILL; 448 } 449 450 return 0; 451 } 452