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