1 /*
2 Copyright (c) 2003-2006 Hewlett-Packard Development Company, L.P.
3 Permission is hereby granted, free of charge, to any person
4 obtaining a copy of this software and associated documentation
5 files (the "Software"), to deal in the Software without
6 restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following
10 conditions:
11 
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
14 
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
23 */
24 
25 #include "uwx_env.h"
26 #include "uwx_scoreboard.h"
27 #include "uwx_step.h"
28 #include "uwx_trace.h"
29 
uwx_init_context(struct uwx_env * env,uint64_t ip,uint64_t sp,uint64_t bsp,uint64_t cfm)30 int uwx_init_context(
31     struct uwx_env *env,
32     uint64_t ip,
33     uint64_t sp,
34     uint64_t bsp,
35     uint64_t cfm)
36 {
37     int i;
38 
39     if (env == 0)
40 	return UWX_ERR_NOENV;
41 
42     env->context.special[UWX_REG_IP] = ip;
43     env->context.special[UWX_REG_SP] = sp;
44     env->context.special[UWX_REG_BSP] = bsp;
45     env->context.special[UWX_REG_CFM] = cfm;
46     for (i = UWX_REG_RP; i < NSPECIALREG; i++)
47 	env->context.special[i] = 0;
48     for (i = 0; i < NPRESERVEDGR; i++)
49 	env->context.gr[i] = 0;
50     env->context.valid_regs = VALID_BASIC4;
51     env->context.valid_frs = 0;
52     env->rstate = 0;
53     (void)uwx_init_history(env);
54     return UWX_OK;
55 }
56 
uwx_get_reg(struct uwx_env * env,int regid,uint64_t * valp)57 int uwx_get_reg(struct uwx_env *env, int regid, uint64_t *valp)
58 {
59     int status;
60     int sor;
61     int rrb_gr;
62     uint64_t bsp;
63     int n;
64 
65     if (env == 0)
66 	return UWX_ERR_NOENV;
67 
68     status = UWX_OK;
69 
70     if (regid == UWX_REG_GR(12))
71 	regid = UWX_REG_SP;
72     if (regid < NSPECIALREG && (env->context.valid_regs & (1 << regid)))
73 	*valp = env->context.special[regid];
74     else if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
75 					regid == UWX_REG_PFS) {
76 	status = uwx_restore_markers(env);
77 	if (status != UWX_OK)
78 	    return status;
79 	*valp = env->context.special[regid];
80     }
81     else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
82 		(env->context.valid_regs &
83 		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) )
84 	*valp = env->context.gr[regid - UWX_REG_GR(4)];
85     else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
86 	if (env->copyin == 0)
87 	    return UWX_ERR_NOCALLBACKS;
88 	bsp = env->context.special[UWX_REG_BSP];
89 	TRACE_C_GET_REG(regid, bsp)
90 	regid -= UWX_REG_GR(32);
91 	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
92 	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
93 	if (sor != 0 && rrb_gr != 0 && regid < sor) {
94 	    TRACE_C_ROTATE_GR(regid, sor, rrb_gr, (regid+rrb_gr)%sor)
95 	    regid = (regid + rrb_gr) % sor;
96 	}
97 	bsp = uwx_add_to_bsp(bsp, regid);
98 	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)valp,
99 		    bsp, DWORDSZ, env->cb_token);
100 	if (n != DWORDSZ)
101 	    status = UWX_ERR_COPYIN_RSTK;
102     }
103     else if (regid == UWX_REG_GR(0))
104 	*valp = 0;
105     else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5) &&
106 		(env->context.valid_regs &
107 		    (1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT))) )
108 	*valp = env->context.br[regid - UWX_REG_BR(1)];
109     else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5) &&
110 	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(2)))) ) {
111 	valp[0] = env->context.fr[regid - UWX_REG_FR(2)].part0;
112 	valp[1] = env->context.fr[regid - UWX_REG_FR(2)].part1;
113     }
114     else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31) &&
115 	    (env->context.valid_frs & (1 << (regid - UWX_REG_FR(16) + 4))) ) {
116 	valp[0] = env->context.fr[regid - UWX_REG_FR(16) + 4].part0;
117 	valp[1] = env->context.fr[regid - UWX_REG_FR(16) + 4].part1;
118     }
119     else if ( (regid < NSPECIALREG) ||
120 		(regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
121 		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ) {
122 	if (env->copyin == 0)
123 	    return UWX_ERR_NOCALLBACKS;
124 	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
125 			    regid, DWORDSZ, env->cb_token);
126 	if (n != DWORDSZ)
127 	    status = UWX_ERR_COPYIN_REG;
128     }
129     else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) {
130 	if (env->copyin == 0)
131 	    return UWX_ERR_NOCALLBACKS;
132 	n = (*env->copyin)(UWX_COPYIN_REG, (char *)valp,
133 			    regid, 2*DWORDSZ, env->cb_token);
134 	if (n != 2*DWORDSZ)
135 	    status = UWX_ERR_COPYIN_REG;
136     }
137     else if (regid == UWX_REG_FR(0)) {
138 	valp[0] = 0;
139 	valp[1] = 0;
140     }
141     else if (regid == UWX_REG_FR(1)) {
142 	valp[0] = 0x000000000000ffffULL;
143 	valp[1] = 0x8000000000000000ULL;
144     }
145     else
146 	status = UWX_ERR_BADREGID;
147     return status;
148 }
149 
uwx_get_nat(struct uwx_env * env,int regid,int * natp)150 int uwx_get_nat(struct uwx_env *env, int regid, int *natp)
151 {
152     int status;
153     int sor;
154     int rrb_gr;
155     uint64_t bsp;
156     uint64_t natcollp;
157     uint64_t natcoll;
158     int n;
159 
160     if (env == 0)
161 	return UWX_ERR_NOENV;
162 
163     status = UWX_OK;
164 
165     if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7) &&
166 		(env->context.valid_regs &
167 		    (1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT))) ) {
168 	*natp = (env->context.special[UWX_REG_PRIUNAT] >>
169 				(regid - UWX_REG_GR(4)) ) & 0x01;
170     }
171     else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
172 	if (env->copyin == 0)
173 	    return UWX_ERR_NOCALLBACKS;
174 	bsp = env->context.special[UWX_REG_BSP];
175 	regid -= UWX_REG_GR(32);
176 	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
177 	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
178 	if (sor != 0 && rrb_gr != 0 && regid < sor) {
179 	    regid = (regid + rrb_gr) % sor;
180 	}
181 	bsp = uwx_add_to_bsp(bsp, regid);
182 	natcollp = bsp | 0x01f8;
183 	n = (*env->copyin)(UWX_COPYIN_RSTACK, (char *)&natcoll,
184 			natcollp, DWORDSZ, env->cb_token);
185 	if (n != DWORDSZ)
186 	    return UWX_ERR_COPYIN_RSTK;
187 	*natp = (int)(natcoll >> (((int)bsp >> 3) & 0x3f)) & 0x01;
188     }
189     else if (regid == UWX_REG_GR(0))
190 	*natp = 0;
191     else
192 	status = UWX_ERR_BADREGID;
193     return status;
194 }
195 
uwx_get_spill_loc(struct uwx_env * env,int regid,uint64_t * dispp)196 int uwx_get_spill_loc(struct uwx_env *env, int regid, uint64_t *dispp)
197 {
198     int status;
199     int sor;
200     int rrb_gr;
201     uint64_t bsp;
202 
203     if (env == 0)
204 	return UWX_ERR_NOENV;
205 
206     status = UWX_OK;
207 
208     if (regid == UWX_REG_GR(12))
209 	regid = UWX_REG_SP;
210     if (regid < NSPECIALREG) {
211 	if (regid == UWX_REG_PSP || regid == UWX_REG_RP ||
212 						regid == UWX_REG_PFS) {
213 	    if (!(env->context.valid_regs & (1 << regid))) {
214 		status = uwx_restore_markers(env);
215 		if (status != UWX_OK)
216 		    return status;
217 	    }
218 	}
219 	*dispp = env->history.special[regid];
220     }
221     else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7))
222 	*dispp = env->history.gr[regid - UWX_REG_GR(4)];
223     else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
224 	bsp = env->context.special[UWX_REG_BSP];
225 	regid -= UWX_REG_GR(32);
226 	sor = (((int) env->context.special[UWX_REG_CFM] >> 14) & 0x0f) * 8;
227 	rrb_gr = ((int) env->context.special[UWX_REG_CFM] >> 18) & 0x7f;
228 	if (sor != 0 && rrb_gr != 0 && regid < sor)
229 	    regid = (regid + rrb_gr) % sor;
230 	bsp = uwx_add_to_bsp(bsp, regid);
231 	*dispp = UWX_DISP_RSTK(bsp);
232     }
233     else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_GR(5))
234 	*dispp = env->history.br[regid - UWX_REG_BR(1)];
235     else if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
236 	*dispp = env->history.fr[regid - UWX_REG_FR(2)];
237     else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
238 	*dispp = env->history.fr[regid - UWX_REG_FR(16) + 4];
239     else if ( (regid >= UWX_REG_GR(1) && regid <= UWX_REG_GR(31)) ||
240 		(regid >= UWX_REG_BR(0) && regid <= UWX_REG_BR(7)) ||
241 		(regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(127)) )
242 	*dispp = UWX_DISP_REG(regid);
243     else
244 	status = UWX_ERR_BADREGID;
245     return status;
246 }
247 
uwx_set_reg(struct uwx_env * env,int regid,uint64_t val)248 int uwx_set_reg(struct uwx_env *env, int regid, uint64_t val)
249 {
250     int status;
251 
252     if (env == 0)
253 	return UWX_ERR_NOENV;
254 
255     if (regid == UWX_REG_GR(12))
256 	regid = UWX_REG_SP;
257     if (regid < NSPECIALREG) {
258 	env->context.special[regid] = val;
259 	env->context.valid_regs |= 1 << regid;
260 	status = UWX_OK;
261     }
262     else if (regid >= UWX_REG_GR(4) && regid <= UWX_REG_GR(7)) {
263 	env->context.gr[regid - UWX_REG_GR(4)] = val;
264 	env->context.valid_regs |=
265 			1 << (regid - UWX_REG_GR(4) + VALID_GR_SHIFT);
266 	status = UWX_OK;
267     }
268     else if (regid >= UWX_REG_GR(32) && regid <= UWX_REG_GR(127)) {
269 	status = UWX_ERR_BADREGID;
270     }
271     else if (regid >= UWX_REG_BR(1) && regid <= UWX_REG_BR(5)) {
272 	env->context.br[regid - UWX_REG_BR(1)] = val;
273 	env->context.valid_regs |=
274 			1 << (regid - UWX_REG_BR(1) + VALID_BR_SHIFT);
275 	status = UWX_OK;
276     }
277     else
278 	status = UWX_ERR_BADREGID;
279     return status;
280 }
281 
uwx_set_fr(struct uwx_env * env,int regid,uint64_t * val)282 int uwx_set_fr(struct uwx_env *env, int regid, uint64_t *val)
283 {
284 
285     if (regid >= UWX_REG_FR(2) && regid <= UWX_REG_FR(5))
286 	regid -= UWX_REG_FR(2);
287     else if (regid >= UWX_REG_FR(16) && regid <= UWX_REG_FR(31))
288 	regid -= UWX_REG_FR(16) - 4;
289     else
290 	return UWX_ERR_BADREGID;
291 
292     env->context.fr[regid].part0 = val[0];
293     env->context.fr[regid].part1 = val[1];
294     env->context.valid_frs |= 1 << regid;
295     env->nsbreg = NSBREG;
296     return UWX_OK;
297 }
298 
uwx_add_to_bsp(uint64_t bsp,int nslots)299 uint64_t uwx_add_to_bsp(uint64_t bsp, int nslots)
300 {
301     int bias;
302 
303     /*
304      *  Here's a picture of the backing store as modeled in
305      *  the computations below. "X" marks NaT collections at
306      *  every 0x1f8 mod 0x200 address.
307      *
308      *  To make the NaT adjustments easier, we bias the current bsp
309      *  by enough slots to place it at the previous NaT collection.
310      *  Then we need to add the bias to the number of slots,
311      *  then add 1 for every 63 slots to account for NaT collections.
312      *  Then we can remove the bias again and add the adjusted
313      *  number of slots to the bsp.
314      *
315      *   0                           1f8                             3f8
316      *  +---------------------------------------------------------------+
317      *  |                              X                               X|
318      *  +---------------------------------------------------------------+
319      *   <-------- bias -------->
320      *                           <--- nslots --->
321      *                           ^
322      *                           |
323      *                          bsp
324      *   <------------ nslots + bias ----------->
325 
326      *  When subtracting from bsp, we avoid depending on the sign of
327      *  the quotient by adding 63*8 before division and subtracting 8
328      *  after division. (Assumes that we will never be called upon
329      *  to subtract more than 504 slots from bsp.)
330      *
331      *   0                           1f8                             3f8
332      *  +---------------------------------------------------------------+
333      *  |                              X                               X|
334      *  +---------------------------------------------------------------+
335      *                                  <-- bias -->
336      *                           <--- (-nslots) --->
337      *                                              ^
338      *                                              |
339      *                                             bsp
340      *                           <----------------->
341      *                             -(nslots + bias)
342      */
343 
344     bias = ((unsigned int)bsp & 0x1f8) / DWORDSZ;
345     nslots += (nslots + bias + 63*8) / 63 - 8;
346     return bsp + nslots * DWORDSZ;
347 }
348 
349 #if 0
350 int uwx_selftest_bsp_arithmetic()
351 {
352     int i;
353     int j;
354     int r;
355     uint64_t bstore[161];
356     uint64_t *bsp;
357     uint64_t *p;
358     int failed = 0;
359 
360     printf("uwx_selftest_bsp_arithmetic: bsp at %08lx\n", (unsigned int)bstore);
361     r = 0;
362     bsp = bstore;
363     for (i = 0; i < 161; i++) {
364 	if (((unsigned int)bsp & 0x1f8) == 0x1f8)
365 	    *bsp++ = 1000 + r;
366 	else
367 	    *bsp++ = r++;
368     }
369 
370     printf("uwx_selftest_bsp_arithmetic: plus tests...\n");
371     bsp = bstore;
372     for (i = 0; i < 64; i++) {
373 	r = (int)*bsp;
374 	if (r >= 1000)
375 	    r -= 1000;
376 	for (j = 0; j < 96; j++) {
377 	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, j);
378 	    if (*p != (r + j)) {
379 		failed++;
380 		printf("%d [%08lx] + %d -> %08lx ",
381 				i, (unsigned int)bsp, j, (unsigned int)p);
382 		printf("(read %d instead of %d)\n", (int)*p, r + j);
383 	    }
384 	}
385 	bsp++;
386     }
387 
388     printf("uwx_selftest_bsp_arithmetic: minus tests...\n");
389     bsp = &bstore[161];
390     for (i = 63; i >= 0; i--) {
391 	bsp--;
392 	r = (int)*bsp;
393 	if (r >= 1000)
394 	    r -= 1000;
395 	for (j = 0; j < 96; j++) {
396 	    p = (uint64_t *)(intptr_t)uwx_add_to_bsp((uint64_t)bsp, -j);
397 	    if (*p != (r - j)) {
398 		failed++;
399 		printf("%d [%08lx] - %d -> %08lx ",
400 				i, (unsigned int)bsp, j, (unsigned int)p);
401 		printf("(read %d instead of %d)\n", (int)*p, r - j);
402 	    }
403 	}
404     }
405 
406     return failed;
407 }
408 #endif
409