xref: /netbsd/sys/arch/sparc64/sparc64/emul.c (revision bf9ec67e)
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