1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /* Read/write user memory procedures for Sparc9 FPU simulator. */
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/fpu/fpu_simulator.h>
34 #include <sys/fpu/globals.h>
35 #include <sys/systm.h>
36 #include <vm/seg.h>
37 #include <sys/privregs.h>
38 #include <sys/stack.h>
39 #include <sys/debug.h>
40 #include <sys/model.h>
41
42 /* read the user instruction */
43 enum ftt_type
_fp_read_inst(const uint32_t * address,uint32_t * pvalue,fp_simd_type * pfpsd)44 _fp_read_inst(
45 const uint32_t *address, /* FPU instruction address. */
46 uint32_t *pvalue, /* Place for instruction value. */
47 fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */
48 {
49 if (((uintptr_t)address & 0x3) != 0)
50 return (ftt_alignment); /* Must be word-aligned. */
51
52 if (get_udatamodel() == DATAMODEL_ILP32) {
53 /*
54 * If this is a 32-bit program, chop the address accordingly.
55 * The intermediate uintptr_t casts prevent warnings under a
56 * certain compiler, and the temporary 32 bit storage is
57 * intended to force proper code generation and break up what
58 * would otherwise be a quadruple cast.
59 */
60 caddr32_t address32 = (caddr32_t)(uintptr_t)address;
61 address = (uint32_t *)(uintptr_t)address32;
62 }
63
64 if (fuword32(address, pvalue) == -1) {
65 pfpsd->fp_trapaddr = (caddr_t)address;
66 pfpsd->fp_traprw = S_READ;
67 return (ftt_fault);
68 }
69 return (ftt_none);
70 }
71
72 enum ftt_type
_fp_read_extword(const uint64_t * address,uint64_t * pvalue,fp_simd_type * pfpsd)73 _fp_read_extword(
74 const uint64_t *address, /* FPU data address. */
75 uint64_t *pvalue, /* Place for extended word value. */
76 fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */
77 {
78 if (((uintptr_t)address & 0x7) != 0)
79 return (ftt_alignment); /* Must be extword-aligned. */
80
81 if (get_udatamodel() == DATAMODEL_ILP32) {
82 /*
83 * If this is a 32-bit program, chop the address accordingly.
84 * The intermediate uintptr_t casts prevent warnings under a
85 * certain compiler, and the temporary 32 bit storage is
86 * intended to force proper code generation and break up what
87 * would otherwise be a quadruple cast.
88 */
89 caddr32_t address32 = (caddr32_t)(uintptr_t)address;
90 address = (uint64_t *)(uintptr_t)address32;
91 }
92
93 if (fuword64(address, pvalue) == -1) {
94 pfpsd->fp_trapaddr = (caddr_t)address;
95 pfpsd->fp_traprw = S_READ;
96 return (ftt_fault);
97 }
98 return (ftt_none);
99 }
100
101 enum ftt_type
_fp_read_word(const uint32_t * address,uint32_t * pvalue,fp_simd_type * pfpsd)102 _fp_read_word(
103 const uint32_t *address, /* FPU data address. */
104 uint32_t *pvalue, /* Place for word value. */
105 fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */
106 {
107 if (((uintptr_t)address & 0x3) != 0)
108 return (ftt_alignment); /* Must be word-aligned. */
109
110 if (get_udatamodel() == DATAMODEL_ILP32) {
111 /*
112 * If this is a 32-bit program, chop the address accordingly.
113 * The intermediate uintptr_t casts prevent warnings under a
114 * certain compiler, and the temporary 32 bit storage is
115 * intended to force proper code generation and break up what
116 * would otherwise be a quadruple cast.
117 */
118 caddr32_t address32 = (caddr32_t)(uintptr_t)address;
119 address = (uint32_t *)(uintptr_t)address32;
120 }
121
122 if (fuword32(address, pvalue) == -1) {
123 pfpsd->fp_trapaddr = (caddr_t)address;
124 pfpsd->fp_traprw = S_READ;
125 return (ftt_fault);
126 }
127 return (ftt_none);
128 }
129
130 enum ftt_type
_fp_write_extword(uint64_t * address,uint64_t value,fp_simd_type * pfpsd)131 _fp_write_extword(
132 uint64_t *address, /* FPU data address. */
133 uint64_t value, /* Extended word value to write. */
134 fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */
135 {
136 if (((uintptr_t)address & 0x7) != 0)
137 return (ftt_alignment); /* Must be extword-aligned. */
138
139 if (get_udatamodel() == DATAMODEL_ILP32) {
140 /*
141 * If this is a 32-bit program, chop the address accordingly.
142 * The intermediate uintptr_t casts prevent warnings under a
143 * certain compiler, and the temporary 32 bit storage is
144 * intended to force proper code generation and break up what
145 * would otherwise be a quadruple cast.
146 */
147 caddr32_t address32 = (caddr32_t)(uintptr_t)address;
148 address = (uint64_t *)(uintptr_t)address32;
149 }
150
151 if (suword64(address, value) == -1) {
152 pfpsd->fp_trapaddr = (caddr_t)address;
153 pfpsd->fp_traprw = S_WRITE;
154 return (ftt_fault);
155 }
156 return (ftt_none);
157 }
158
159 enum ftt_type
_fp_write_word(uint32_t * address,uint32_t value,fp_simd_type * pfpsd)160 _fp_write_word(
161 uint32_t *address, /* FPU data address. */
162 uint32_t value, /* Word value to write. */
163 fp_simd_type *pfpsd) /* Pointer to fpu simulator data. */
164 {
165 if (((uintptr_t)address & 0x3) != 0)
166 return (ftt_alignment); /* Must be word-aligned. */
167
168 if (get_udatamodel() == DATAMODEL_ILP32) {
169 /*
170 * If this is a 32-bit program, chop the address accordingly.
171 * The intermediate uintptr_t casts prevent warnings under a
172 * certain compiler, and the temporary 32 bit storage is
173 * intended to force proper code generation and break up what
174 * would otherwise be a quadruple cast.
175 */
176 caddr32_t address32 = (caddr32_t)(uintptr_t)address;
177 address = (uint32_t *)(uintptr_t)address32;
178 }
179
180 if (suword32(address, value) == -1) {
181 pfpsd->fp_trapaddr = (caddr_t)address;
182 pfpsd->fp_traprw = S_WRITE;
183 return (ftt_fault);
184 }
185 return (ftt_none);
186 }
187
188 /*
189 * Reads integer unit's register n.
190 */
191 enum ftt_type
read_iureg(fp_simd_type * pfpsd,uint_t n,struct regs * pregs,void * prw,uint64_t * pvalue)192 read_iureg(
193 fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
194 uint_t n, /* IU register n */
195 struct regs *pregs, /* Pointer to PCB image of registers. */
196 void *prw, /* Pointer to locals and ins. */
197 uint64_t *pvalue) /* Place for extended word value. */
198 {
199 enum ftt_type ftt;
200
201 if (n == 0) {
202 *pvalue = 0;
203 return (ftt_none); /* Read global register 0. */
204 } else if (n < 16) {
205 long long *preg;
206
207 preg = &pregs->r_ps; /* globals and outs */
208 *pvalue = preg[n];
209 return (ftt_none);
210 } else if (USERMODE(pregs->r_tstate)) { /* locals and ins */
211 if (lwp_getdatamodel(curthread->t_lwp) == DATAMODEL_ILP32) {
212 uint32_t res, *addr, *rw;
213 caddr32_t rw32;
214
215 /*
216 * If this is a 32-bit program, chop the address
217 * accordingly. The intermediate uintptr_t casts
218 * prevent warnings under a certain compiler, and the
219 * temporary 32 bit storage is intended to force proper
220 * code generation and break up what would otherwise be
221 * a quadruple cast.
222 */
223 rw32 = (caddr32_t)(uintptr_t)prw;
224 rw = (uint32_t *)(uintptr_t)rw32;
225
226 addr = (uint32_t *)&rw[n - 16];
227 ftt = _fp_read_word(addr, &res, pfpsd);
228 *pvalue = (uint64_t)res;
229 } else {
230 uint64_t res, *addr, *rw = (uint64_t *)
231 ((uintptr_t)prw + STACK_BIAS);
232
233 addr = (uint64_t *)&rw[n - 16];
234 ftt = _fp_read_extword(addr, &res, pfpsd);
235 *pvalue = res;
236 }
237 return (ftt);
238 } else {
239 ulong_t *addr, *rw = (ulong_t *)((uintptr_t)prw + STACK_BIAS);
240 ulong_t res;
241
242 addr = (ulong_t *)&rw[n - 16];
243 res = *addr;
244 *pvalue = res;
245
246 return (ftt_none);
247 }
248 }
249
250 /*
251 * Writes integer unit's register n.
252 */
253 enum ftt_type
write_iureg(fp_simd_type * pfpsd,uint_t n,struct regs * pregs,void * prw,uint64_t * pvalue)254 write_iureg(
255 fp_simd_type *pfpsd, /* Pointer to fpu simulator data. */
256 uint_t n, /* IU register n. */
257 struct regs *pregs, /* Pointer to PCB image of registers. */
258 void *prw, /* Pointer to locals and ins. */
259 uint64_t *pvalue) /* Extended word value to write. */
260 {
261 long long *preg;
262 enum ftt_type ftt;
263
264 if (n == 0) {
265 return (ftt_none); /* Read global register 0. */
266 } else if (n < 16) {
267 preg = &pregs->r_ps; /* globals and outs */
268 preg[n] = *pvalue;
269 return (ftt_none);
270 } else if (USERMODE(pregs->r_tstate)) { /* locals and ins */
271 if (lwp_getdatamodel(curthread->t_lwp) == DATAMODEL_ILP32) {
272 uint32_t res, *addr, *rw;
273 caddr32_t rw32;
274
275 /*
276 * If this is a 32-bit program, chop the address
277 * accordingly. The intermediate uintptr_t casts
278 * prevent warnings under a certain compiler, and the
279 * temporary 32 bit storage is intended to force proper
280 * code generation and break up what would otherwise be
281 * a quadruple cast.
282 */
283 rw32 = (caddr32_t)(uintptr_t)prw;
284 rw = (uint32_t *)(uintptr_t)rw32;
285
286 addr = &rw[n - 16];
287 res = (uint_t)*pvalue;
288 ftt = _fp_write_word(addr, res, pfpsd);
289 } else {
290 uint64_t *addr, *rw = (uint64_t *)
291 ((uintptr_t)prw + STACK_BIAS);
292 uint64_t res;
293
294 addr = &rw[n - 16];
295 res = *pvalue;
296 ftt = _fp_write_extword(addr, res, pfpsd);
297 }
298 return (ftt);
299 } else {
300 ulong_t *addr, *rw = (ulong_t *)((uintptr_t)prw + STACK_BIAS);
301 ulong_t res = *pvalue;
302
303 addr = &rw[n - 16];
304 *addr = res;
305
306 return (ftt_none);
307 }
308 }
309