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