xref: /illumos-gate/usr/src/uts/sparc/v9/fpu/uword.c (revision aad98a6d)
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