xref: /openbsd/sys/arch/sparc64/sparc64/emul.c (revision b5125ced)
1 /*	$OpenBSD: emul.c,v 1.28 2024/03/29 21:14:31 miod 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  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/signalvar.h>
37 #include <sys/malloc.h>
38 #include <machine/reg.h>
39 #include <machine/instr.h>
40 #include <machine/cpu.h>
41 #include <machine/psl.h>
42 #include <uvm/uvm_extern.h>
43 
44 #ifdef DEBUG_EMUL
45 # define DPRINTF(a) printf a
46 #else
47 # define DPRINTF(a)
48 #endif
49 
50 void swap_quad(int64_t *);
51 
52 #define	SIGN_EXT13(v)	(((int64_t)(v) << 51) >> 51)
53 
54 void
swap_quad(int64_t * p)55 swap_quad(int64_t *p)
56 {
57 	int64_t t;
58 
59 	t = htole64(p[0]);
60 	p[0] = htole64(p[1]);
61 	p[1] = t;
62 }
63 
64 /*
65  * emulate STQF, STQFA, LDQF, and LDQFA
66  */
67 int
emul_qf(int32_t insv,struct proc * p,union sigval sv,struct trapframe * tf)68 emul_qf(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
69 {
70 	extern const struct fpstate initfpstate;
71 	struct fpstate *fs = p->p_md.md_fpstate;
72 	int64_t addr, buf[2];
73 	union instr ins;
74 	int freg, isload, err;
75 	u_int8_t asi;
76 
77 	ins.i_int = insv;
78 	freg = ins.i_op3.i_rd & ~1;
79 	freg |= (ins.i_op3.i_rd & 1) << 5;
80 
81 	if (ins.i_op3.i_op3 == IOP3_LDQF || ins.i_op3.i_op3 == IOP3_LDQFA)
82 		isload = 1;
83 	else
84 		isload = 0;
85 
86 	if (ins.i_op3.i_op3 == IOP3_STQF || ins.i_op3.i_op3 == IOP3_LDQF)
87 		asi = ASI_PRIMARY;
88 	else if (ins.i_loadstore.i_i)
89 		asi = (tf->tf_tstate & TSTATE_ASI) >> TSTATE_ASI_SHIFT;
90 	else
91 		asi = ins.i_asi.i_asi;
92 
93 	addr = tf->tf_global[ins.i_asi.i_rs1];
94 	if (ins.i_loadstore.i_i)
95 		addr += SIGN_EXT13(ins.i_simm13.i_simm13);
96 	else
97 		addr += tf->tf_global[ins.i_asi.i_rs2];
98 
99 	if (asi < ASI_PRIMARY) {
100 		/* privileged asi */
101 		trapsignal(p, SIGILL, 0, ILL_PRVOPC, sv);
102 		return (0);
103 	}
104 	if (asi > ASI_SECONDARY_NOFAULT_LITTLE ||
105 	    (asi > ASI_SECONDARY_NOFAULT && asi < ASI_PRIMARY_LITTLE)) {
106 		/* architecturally undefined user ASI's */
107 		goto segv;
108 	}
109 
110 	if ((freg & 3) != 0) {
111 		/* only valid for %fN where N % 4 = 0 */
112 		trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
113 		return (0);
114 	}
115 
116 	if ((addr & 3) != 0) {
117 		/* request is not aligned */
118 		trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
119 		return (0);
120 	}
121 
122 	fs = p->p_md.md_fpstate;
123 	if (fs == NULL) {
124 		KERNEL_LOCK();
125 		/* don't currently have an fpu context, get one */
126 		fs = malloc(sizeof(*fs), M_SUBPROC, M_WAITOK);
127 		*fs = initfpstate;
128 		p->p_md.md_fpstate = fs;
129 		KERNEL_UNLOCK();
130 	} else
131 		fpusave_proc(p, 1);
132 
133 	/* Ok, try to do the actual operation (finally) */
134 	if (isload) {
135 		err = copyin((caddr_t)addr, buf, sizeof(buf));
136 		if (err != 0 && (asi & 2) == 0)
137 			goto segv;
138 		if (err == 0) {
139 			if (asi & 8)
140 				swap_quad(buf);
141 			bcopy(buf, &fs->fs_regs[freg], sizeof(buf));
142 		}
143 	} else {
144 		bcopy(&fs->fs_regs[freg], buf, sizeof(buf));
145 		if (asi & 8)
146 			swap_quad(buf);
147 		if (copyout(buf, (caddr_t)addr, sizeof(buf)) && (asi & 2) == 0)
148 			goto segv;
149 	}
150 
151 	return (1);
152 
153 segv:
154 	trapsignal(p, SIGSEGV, isload ? PROT_READ : PROT_WRITE,
155 	    SEGV_MAPERR, sv);
156 	return (0);
157 }
158 
159 int
emul_popc(int32_t insv,struct proc * p,union sigval sv,struct trapframe * tf)160 emul_popc(int32_t insv, struct proc *p, union sigval sv, struct trapframe *tf)
161 {
162 	u_int64_t val, ret = 0;
163 	union instr ins;
164 
165 	ins.i_int = insv;
166 	if (ins.i_simm13.i_i == 0)
167 		val = tf->tf_global[ins.i_asi.i_rs2];
168 	else
169 		val = SIGN_EXT13(ins.i_simm13.i_simm13);
170 
171 	for (; val != 0; val >>= 1)
172 		ret += val & 1;
173 
174 	tf->tf_global[ins.i_asi.i_rd] = ret;
175 	return (1);
176 }
177