Annotation of sys/arch/sparc64/sparc64/emul.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: emul.c,v 1.12 2003/11/03 07:01:33 david 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: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/proc.h>
43: #include <sys/signalvar.h>
44: #include <sys/malloc.h>
45: #include <machine/reg.h>
46: #include <machine/instr.h>
47: #include <machine/cpu.h>
48: #include <machine/psl.h>
49: #include <sparc64/sparc64/cpuvar.h>
50: #include <uvm/uvm_extern.h>
51:
52: #ifdef DEBUG_EMUL
53: # define DPRINTF(a) printf a
54: #else
55: # define DPRINTF(a)
56: #endif
57:
58: #define GPR(tf, i) ((int32_t *)(u_long)&tf->tf_global)[i]
59: #define IPR(tf, i) ((int32_t *)(u_long)tf->tf_out[6])[i - 16]
60: #define FPR(p, i) ((int32_t) p->p_md.md_fpstate->fs_regs[i])
61:
62: static __inline int readgpreg(struct trapframe64 *, int, void *);
63: static __inline int readfpreg(struct proc *, int, void *);
64: static __inline int writegpreg(struct trapframe64 *, int, const void *);
65: static __inline int writefpreg(struct proc *, int, const void *);
66: static __inline int decodeaddr(struct trapframe64 *, union instr *, void *);
67: static int muldiv(struct trapframe64 *, union instr *, int32_t *, int32_t *,
68: int32_t *);
69: void swap_quad(int64_t *);
70:
71: #define REGNAME(i) "goli"[i >> 3], i & 7
72:
73:
74: static __inline int
75: readgpreg(tf, i, val)
76: struct trapframe64 *tf;
77: int i;
78: void *val;
79: {
80: int error = 0;
81: if (i == 0)
82: *(int32_t *) val = 0;
83: else if (i < 16)
84: *(int32_t *) val = GPR(tf, i);
85: else
86: error = copyin(&IPR(tf, i), val, sizeof(int32_t));
87:
88: return error;
89: }
90:
91:
92: static __inline int
93: writegpreg(tf, i, val)
94: struct trapframe64 *tf;
95: int i;
96: const void *val;
97: {
98: int error = 0;
99:
100: if (i == 0)
101: return error;
102: else if (i < 16)
103: GPR(tf, i) = *(int32_t *) val;
104: else
105: /* XXX: Fix copyout prototype */
106: error = copyout((caddr_t) val, &IPR(tf, i), sizeof(int32_t));
107:
108: return error;
109: }
110:
111:
112: static __inline int
113: readfpreg(p, i, val)
114: struct proc *p;
115: int i;
116: void *val;
117: {
118: *(int32_t *) val = FPR(p, i);
119: return 0;
120: }
121:
122:
123: static __inline int
124: writefpreg(p, i, val)
125: struct proc *p;
126: int i;
127: const void *val;
128: {
129: FPR(p, i) = *(const int32_t *) val;
130: return 0;
131: }
132:
133: static __inline int
134: decodeaddr(tf, code, val)
135: struct trapframe64 *tf;
136: union instr *code;
137: void *val;
138: {
139: if (code->i_simm13.i_i)
140: *((int32_t *) val) = code->i_simm13.i_simm13;
141: else {
142: int error;
143:
144: if (code->i_asi.i_asi)
145: return EINVAL;
146: if ((error = readgpreg(tf, code->i_asi.i_rs2, val)) != 0)
147: return error;
148: }
149: return 0;
150: }
151:
152:
153: static int
154: muldiv(tf, code, rd, rs1, rs2)
155: struct trapframe64 *tf;
156: union instr *code;
157: int32_t *rd, *rs1, *rs2;
158: {
159: /*
160: * We check for {S,U}{MUL,DIV}{,cc}
161: *
162: * [c = condition code, s = sign]
163: * Mul = 0c101s
164: * Div = 0c111s
165: */
166: union {
167: struct {
168: unsigned unused:26; /* padding */
169: unsigned zero:1; /* zero by opcode */
170: unsigned cc:1; /* one to send condition code */
171: unsigned one1:1; /* one by opcode */
172: unsigned div:1; /* one if divide */
173: unsigned one2:1; /* one by opcode */
174: unsigned sgn:1; /* sign bit */
175: } bits;
176: int num;
177: } op;
178:
179: op.num = code->i_op3.i_op3;
180:
181: #ifdef DEBUG_EMUL
182: printf("muldiv 0x%x: %c%s%s %c%d, %c%d, ", code->i_int,
183: "us"[op.bits.sgn], op.bits.div ? "div" : "mul",
184: op.bits.cc ? "cc" : "", REGNAME(code->i_op3.i_rd),
185: REGNAME(code->i_op3.i_rs1));
186: if (code->i_loadstore.i_i)
187: printf("0x%x\n", *rs2);
188: else
189: printf("%c%d\n", REGNAME(code->i_asi.i_rs2));
190: #endif
191:
192: if (op.bits.div) {
193: if (*rs2 == 0) {
194: /*
195: * XXX: to be 100% correct here, on sunos we need to
196: * ignore the error and return *rd = *rs1.
197: * It should be easy to fix by passing struct
198: * proc in here.
199: */
200: DPRINTF(("muldiv: avoid zerodivide\n"));
201: return EINVAL;
202: }
203: *rd = *rs1 / *rs2;
204: DPRINTF(("muldiv: %d / %d = %d\n", *rs1, *rs2, *rd));
205: }
206: else {
207: *rd = *rs1 * *rs2;
208: DPRINTF(("muldiv: %d * %d = %d\n", *rs1, *rs2, *rd));
209: }
210:
211: if (op.bits.cc) {
212: /* Set condition codes */
213: tf->tf_tstate &= ~(TSTATE_CCR);
214:
215: if (*rd == 0)
216: tf->tf_tstate |= (u_int64_t)(ICC_Z|XCC_Z) << TSTATE_CCR_SHIFT;
217: else {
218: if (op.bits.sgn && *rd < 0)
219: tf->tf_tstate |= (u_int64_t)(ICC_N|XCC_N) << TSTATE_CCR_SHIFT;
220: if (op.bits.div) {
221: if (*rd * *rs2 != *rs1)
222: tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
223: }
224: else {
225: if (*rd / *rs2 != *rs1)
226: tf->tf_tstate |= (u_int64_t)(ICC_V|XCC_V) << TSTATE_CCR_SHIFT;
227: }
228: }
229: }
230:
231: return 0;
232: }
233:
234: /*
235: * Code to handle alignment faults on the sparc. This is enabled by sending
236: * a fixalign trap. Such code is generated by compiling with cc -misalign
237: * on SunOS, but we don't have such a feature yet on our gcc.
238: */
239:
240: int
241: fixalign(p, tf)
242: struct proc *p;
243: struct trapframe64 *tf;
244: {
245: static u_char sizedef[] = { 0x4, 0xff, 0x2, 0x8 };
246:
247: /*
248: * This is particular to load and store instructions
249: */
250: union {
251: struct {
252: unsigned unused:26; /* 26 padding */
253: unsigned fl:1; /* 1 bit float flag */
254: unsigned op:1; /* 1 bit opcode */
255: unsigned sgn:1; /* 1 bit sign */
256: unsigned st:1; /* 1 bit load/store */
257: unsigned sz:2; /* 2 bit size register */
258: } bits;
259: int num;
260: } op;
261:
262: union {
263: double d;
264: int32_t i[2];
265: int16_t s[4];
266: int8_t c[8];
267: } data;
268:
269: union instr code;
270: size_t size;
271: int64_t rs1, rs2;
272: int error;
273:
274: /* fetch and check the instruction that caused the fault */
275: error = copyin((caddr_t)(u_long)tf->tf_pc, &code.i_int, sizeof(code.i_int));
276: if (error != 0) {
277: DPRINTF(("fixalign: Bad instruction fetch\n"));
278: return EINVAL;
279: }
280:
281: /* Only support format 3 */
282: if (code.i_any.i_op != 3) {
283: DPRINTF(("fixalign: Not a load or store\n"));
284: return EINVAL;
285: }
286:
287: op.num = code.i_loadstore.i_op3;
288:
289: /* Check operand size */
290: if ((size = sizedef[op.bits.sz]) == 0xff) {
291: DPRINTF(("fixalign: Bad operand size\n"));
292: return EINVAL;
293: }
294:
295: write_user_windows();
296:
297: if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
298: DPRINTF(("fixalign: read rs1 %d\n", error));
299: return error;
300: }
301:
302: if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
303: DPRINTF(("fixalign: decode addr %d\n", error));
304: return error;
305: }
306:
307:
308: rs1 += rs2;
309:
310: #ifdef DEBUG_EMUL
311: printf("memalign 0x%x: %s%c%c %c%d, %c%d, ", code.i_int,
312: op.bits.st ? "st" : "ld", "us"[op.bits.sgn],
313: "w*hd"[op.bits.sz], op.bits.fl ? 'f' : REGNAME(code.i_op3.i_rd),
314: REGNAME(code.i_op3.i_rs1));
315: if (code.i_loadstore.i_i)
316: printf("0x%llx\n", (unsigned long long)rs2);
317: else
318: printf("%c%d\n", REGNAME(code.i_asi.i_rs2));
319: #endif
320: #ifdef DIAGNOSTIC
321: if (op.bits.fl && p != fpproc)
322: panic("fp align without being the FP owning process");
323: #endif
324:
325: if (op.bits.st) {
326: if (op.bits.fl) {
327: if (p == fpproc) {
328: savefpstate(p->p_md.md_fpstate);
329: fpproc = NULL;
330: }
331:
332: error = readfpreg(p, code.i_op3.i_rd, &data.i[0]);
333: if (error)
334: return error;
335: if (size == 8) {
336: error = readfpreg(p, code.i_op3.i_rd + 1,
337: &data.i[1]);
338: if (error)
339: return error;
340: }
341: }
342: else {
343: error = readgpreg(tf, code.i_op3.i_rd, &data.i[0]);
344: if (error)
345: return error;
346: if (size == 8) {
347: error = readgpreg(tf, code.i_op3.i_rd + 1,
348: &data.i[1]);
349: if (error)
350: return error;
351: }
352: }
353:
354: if (size == 2)
355: return copyout(&data.s[1], (caddr_t)(u_long)rs1, size);
356: else
357: return copyout(&data.d, (caddr_t)(u_long)rs1, size);
358: }
359: else { /* load */
360: if (size == 2) {
361: error = copyin((caddr_t)(u_long)rs1, &data.s[1], size);
362: if (error)
363: return error;
364:
365: /* Sign extend if necessary */
366: if (op.bits.sgn && (data.s[1] & 0x8000) != 0)
367: data.s[0] = ~0;
368: else
369: data.s[0] = 0;
370: }
371: else
372: error = copyin((caddr_t)(u_long)rs1, &data.d, size);
373:
374: if (error)
375: return error;
376:
377: if (op.bits.fl) {
378: error = writefpreg(p, code.i_op3.i_rd, &data.i[0]);
379: if (error)
380: return error;
381: if (size == 8) {
382: error = writefpreg(p, code.i_op3.i_rd + 1,
383: &data.i[1]);
384: if (error)
385: return error;
386: }
387: loadfpstate(p->p_md.md_fpstate);
388: fpproc = p;
389: }
390: else {
391: error = writegpreg(tf, code.i_op3.i_rd, &data.i[0]);
392: if (error)
393: return error;
394: if (size == 8)
395: error = writegpreg(tf, code.i_op3.i_rd + 1,
396: &data.i[1]);
397: }
398: }
399: return error;
400: }
401:
402: /*
403: * Emulate unimplemented instructions on earlier sparc chips.
404: */
405: int
406: emulinstr(pc, tf)
407: vaddr_t pc;
408: struct trapframe64 *tf;
409: {
410: union instr code;
411: int32_t rs1, rs2, rd;
412: int error;
413:
414: /* fetch and check the instruction that caused the fault */
415: error = copyin((caddr_t) pc, &code.i_int, sizeof(code.i_int));
416: if (error != 0) {
417: DPRINTF(("emulinstr: Bad instruction fetch\n"));
418: return (SIGILL);
419: }
420:
421: /* Only support format 2 */
422: if (code.i_any.i_op != 2) {
423: DPRINTF(("emulinstr: Not a format 2 instruction\n"));
424: return (SIGILL);
425: }
426:
427: write_user_windows();
428:
429: if ((error = readgpreg(tf, code.i_op3.i_rs1, &rs1)) != 0) {
430: DPRINTF(("emulinstr: read rs1 %d\n", error));
431: return (SIGILL);
432: }
433:
434: if ((error = decodeaddr(tf, &code, &rs2)) != 0) {
435: DPRINTF(("emulinstr: decode addr %d\n", error));
436: return (SIGILL);
437: }
438:
439: switch (code.i_op3.i_op3) {
440: case IOP3_FLUSH:
441: /* cpuinfo.cache_flush((caddr_t)(rs1 + rs2), 4); XXX */
442: return (0);
443:
444: default:
445: if ((code.i_op3.i_op3 & 0x2a) != 0xa) {
446: DPRINTF(("emulinstr: Unsupported op3 0x%x\n",
447: code.i_op3.i_op3));
448: return (SIGILL);
449: }
450: else if ((error = muldiv(tf, &code, &rd, &rs1, &rs2)) != 0)
451: return (SIGFPE);
452: }
453:
454: if ((error = writegpreg(tf, code.i_op3.i_rd, &rd)) != 0) {
455: DPRINTF(("muldiv: write rd %d\n", error));
456: return (SIGILL);
457: }
458:
459: return (0);
460: }
461:
462: #define SIGN_EXT13(v) (((int64_t)(v) << 51) >> 51)
463:
464: void
465: swap_quad(int64_t *p)
466: {
467: int64_t t;
468:
469: t = htole64(p[0]);
470: p[0] = htole64(p[1]);
471: p[1] = t;
472: }
473:
474: /*
475: * emulate STQF, STQFA, LDQF, and LDQFA
476: */
477: int
478: emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
479: {
480: extern struct fpstate64 initfpstate;
481: struct fpstate64 *fs = p->p_md.md_fpstate;
482: int64_t addr, buf[2];
483: union instr ins;
484: int freg, isload, err;
485: u_int8_t asi;
486:
487: ins.i_int = insv;
488: freg = ins.i_op3.i_rd & ~1;
489: freg |= (ins.i_op3.i_rd & 1) << 5;
490:
491: if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA)
492: isload = 1;
493: else
494: isload = 0;
495:
496: if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF)
497: asi = ASI_PRIMARY;
498: else if (ins.i_loadstore.i_i)
499: asi = (tf->tf_tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT;
500: else
501: asi = ins.i_asi.i_asi;
502:
503: addr = tf->tf_global[ins.i_asi.i_rs1];
504: if (ins.i_loadstore.i_i)
505: addr += SIGN_EXT13(ins.i_simm13.i_simm13);
506: else
507: addr += tf->tf_global[ins.i_asi.i_rs2];
508:
509: if (asi < ASI_PRIMARY) {
510: /* privileged asi */
511: trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
512: return (0);
513: }
514: if (asi > ASI_SECONDARY_NOFAULT_LITTLE ||
515: (asi > ASI_SECONDARY_NOFAULT && asi < ASI_PRIMARY_LITTLE)) {
516: /* architecturally undefined user ASI's */
517: goto segv;
518: }
519:
520: if ((freg & 3) != 0) {
521: /* only valid for %fN where N % 4 = 0 */
522: trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
523: return (0);
524: }
525:
526: if ((p->p_md.md_flags & MDP_FIXALIGN) == 0 && (addr & 3) != 0) {
527: /*
528: * If process doesn't want us to fix alignment and the
529: * request isn't aligned, kill it.
530: */
531: trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
532: return (0);
533: }
534:
535: fs = p->p_md.md_fpstate;
536: if (fs == NULL) {
537: /* don't currently have an fpu context, get one */
538: fs = malloc(sizeof(*fs), M_SUBPROC, M_WAITOK);
539: *fs = initfpstate;
540: fs->fs_qsize = 0;
541: p->p_md.md_fpstate = fs;
542: }
543: if (fpproc != p) {
544: /* make this process the current holder of the fpu */
545: if (fpproc != NULL)
546: savefpstate(fpproc->p_md.md_fpstate);
547: fpproc = p;
548: }
549: tf->tf_tstate |= TSTATE_PEF;
550:
551: /* Ok, try to do the actual operation (finally) */
552: if (isload) {
553: err = copyin((caddr_t)addr, buf, sizeof(buf));
554: if (err != 0 && (asi & 2) == 0)
555: goto segv;
556: if (err == 0) {
557: savefpstate(fs);
558: if (asi & 8)
559: swap_quad(buf);
560: bcopy(buf, &fs->fs_regs[freg], sizeof(buf));
561: loadfpstate(fs);
562: }
563: } else {
564: bcopy(&fs->fs_regs[freg], buf, sizeof(buf));
565: if (asi & 8)
566: swap_quad(buf);
567: if (copyout(buf, (caddr_t)addr, sizeof(buf)) && (asi & 2) == 0)
568: goto segv;
569: }
570:
571: return (1);
572:
573: segv:
574: trapsignal(p, SIGSEGV, isload ? VM_PROT_READ : VM_PROT_WRITE,
575: SEGV_MAPERR, sv);
576: return (0);
577: }
578:
579: int
580: emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
581: {
582: u_int64_t val, ret = 0;
583: union instr ins;
584:
585: ins.i_int = insv;
586: if (ins.i_simm13.i_i == 0)
587: val = tf->tf_global[ins.i_asi.i_rs2];
588: else
589: val = SIGN_EXT13(ins.i_simm13.i_simm13);
590:
591: for (; val != 0; val >>= 1)
592: ret += val & 1;
593:
594: tf->tf_global[ins.i_asi.i_rd] = ret;
595: return (1);
596: }
CVSweb