Print this page
patch as-lock-macro-simplification
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/sparc/v9/os/simulator.c
+++ new/usr/src/uts/sparc/v9/os/simulator.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /* common code with bug fixes from original version in trap.c */
27 27
28 28 #include <sys/param.h>
29 29 #include <sys/types.h>
30 30 #include <sys/systm.h>
31 31 #include <sys/archsystm.h>
32 32 #include <sys/vmsystm.h>
33 33 #include <sys/fpu/fpusystm.h>
34 34 #include <sys/fpu/fpu_simulator.h>
35 35 #include <sys/inline.h>
36 36 #include <sys/debug.h>
37 37 #include <sys/privregs.h>
38 38 #include <sys/machpcb.h>
39 39 #include <sys/simulate.h>
40 40 #include <sys/proc.h>
41 41 #include <sys/cmn_err.h>
42 42 #include <sys/stack.h>
43 43 #include <sys/watchpoint.h>
44 44 #include <sys/trap.h>
45 45 #include <sys/machtrap.h>
46 46 #include <sys/mman.h>
47 47 #include <sys/asi.h>
48 48 #include <sys/copyops.h>
49 49 #include <vm/as.h>
50 50 #include <vm/page.h>
51 51 #include <sys/model.h>
52 52 #include <vm/seg_vn.h>
53 53 #include <sys/byteorder.h>
54 54 #include <sys/time.h>
55 55
56 56 #define IS_IBIT_SET(x) (x & 0x2000)
57 57 #define IS_VIS1(op, op3)(op == 2 && op3 == 0x36)
58 58 #define IS_FLOAT_QUAD_OP(op, op3)(op == 2 && (op3 == 0x34 || \
59 59 op3 == 0x35))
60 60 #define IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(op, op3, asi) \
61 61 (op == 3 && (op3 == IOP_V8_LDDFA || \
62 62 op3 == IOP_V8_STDFA) && asi > ASI_SNFL)
63 63
64 64 static int aligndebug = 0;
65 65
66 66 /*
67 67 * For the sake of those who must be compatible with unaligned
68 68 * architectures, users can link their programs to use a
69 69 * corrective trap handler that will fix unaligned references
70 70 * a special trap #6 (T_FIX_ALIGN) enables this 'feature'.
71 71 * Returns 1 for success, 0 for failure.
72 72 */
73 73
74 74 int
75 75 do_unaligned(struct regs *rp, caddr_t *badaddr)
76 76 {
77 77 uint_t inst, op3, asi = 0;
78 78 uint_t rd, rs1, rs2;
79 79 int sz, nf = 0, ltlend = 0;
80 80 int floatflg;
81 81 int fsrflg;
82 82 int immflg;
83 83 int lddstdflg;
84 84 caddr_t addr;
85 85 uint64_t val;
86 86 union {
87 87 uint64_t l[2];
88 88 uint32_t i[4];
89 89 uint16_t s[8];
90 90 uint8_t c[16];
91 91 } data;
92 92
93 93 ASSERT(USERMODE(rp->r_tstate));
94 94 inst = fetch_user_instr((caddr_t)rp->r_pc);
95 95
96 96 op3 = (inst >> 19) & 0x3f;
97 97 rd = (inst >> 25) & 0x1f;
98 98 rs1 = (inst >> 14) & 0x1f;
99 99 rs2 = inst & 0x1f;
100 100 floatflg = (inst >> 24) & 1;
101 101 immflg = (inst >> 13) & 1;
102 102 lddstdflg = fsrflg = 0;
103 103
104 104 /* if not load or store do nothing */
105 105 if ((inst >> 30) != 3)
106 106 return (0);
107 107
108 108 /* if ldstub or swap, do nothing */
109 109 if ((inst & 0xc1680000) == 0xc0680000)
110 110 return (0);
111 111
112 112 /* if cas/casx, do nothing */
113 113 if ((inst & 0xc1e00000) == 0xc1e00000)
114 114 return (0);
115 115
116 116 if (floatflg) {
117 117 switch ((inst >> 19) & 3) { /* map size bits to a number */
118 118 case 0: sz = 4;
119 119 break; /* ldf{a}/stf{a} */
120 120 case 1: fsrflg = 1;
121 121 if (rd == 0)
122 122 sz = 4; /* ldfsr/stfsr */
123 123 else if (rd == 1)
124 124 sz = 8; /* ldxfsr/stxfsr */
125 125 else
126 126 return (SIMU_ILLEGAL);
127 127 break;
128 128 case 2: sz = 16;
129 129 break; /* ldqf{a}/stqf{a} */
130 130 case 3: sz = 8;
131 131 break; /* lddf{a}/stdf{a} */
132 132 }
133 133 /*
134 134 * Fix to access extra double register encoding plus
135 135 * compensate to access the correct fpu_dreg.
136 136 */
137 137 if ((sz > 4) && (fsrflg == 0)) {
138 138 if ((rd & 1) == 1)
139 139 rd = (rd & 0x1e) | 0x20;
140 140 rd = rd >> 1;
141 141 if ((sz == 16) && ((rd & 0x1) != 0))
142 142 return (SIMU_ILLEGAL);
143 143 }
144 144 } else {
145 145 int sz_bits = (inst >> 19) & 0xf;
146 146 switch (sz_bits) { /* map size bits to a number */
147 147 case 0: /* lduw{a} */
148 148 case 4: /* stw{a} */
149 149 case 8: /* ldsw{a} */
150 150 case 0xf: /* swap */
151 151 sz = 4; break;
152 152 case 1: /* ldub{a} */
153 153 case 5: /* stb{a} */
154 154 case 9: /* ldsb{a} */
155 155 case 0xd: /* ldstub */
156 156 sz = 1; break;
157 157 case 2: /* lduh{a} */
158 158 case 6: /* sth{a} */
159 159 case 0xa: /* ldsh{a} */
160 160 sz = 2; break;
161 161 case 3: /* ldd{a} */
162 162 case 7: /* std{a} */
163 163 lddstdflg = 1;
164 164 sz = 8; break;
165 165 case 0xb: /* ldx{a} */
166 166 case 0xe: /* stx{a} */
167 167 sz = 8; break;
168 168 }
169 169 }
170 170
171 171
172 172 /* only support primary and secondary asi's */
173 173 if ((op3 >> 4) & 1) {
174 174 if (immflg) {
175 175 asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) &
176 176 TSTATE_ASI_MASK;
177 177 } else {
178 178 asi = (inst >> 5) & 0xff;
179 179 }
180 180 switch (asi) {
181 181 case ASI_P:
182 182 case ASI_S:
183 183 break;
184 184 case ASI_PNF:
185 185 case ASI_SNF:
186 186 nf = 1;
187 187 break;
188 188 case ASI_PL:
189 189 case ASI_SL:
190 190 ltlend = 1;
191 191 break;
192 192 case ASI_PNFL:
193 193 case ASI_SNFL:
194 194 ltlend = 1;
195 195 nf = 1;
196 196 break;
197 197 default:
198 198 return (0);
199 199 }
200 200 /*
201 201 * Non-faulting stores generate a data_access_exception trap,
202 202 * according to the Spitfire manual, which should be signaled
203 203 * as an illegal instruction trap, because it can't be fixed.
204 204 */
205 205 if ((nf) && ((op3 == IOP_V8_STQFA) || (op3 == IOP_V8_STDFA)))
206 206 return (SIMU_ILLEGAL);
207 207 }
208 208
209 209 if (aligndebug) {
210 210 printf("unaligned access at %p, instruction: 0x%x\n",
211 211 (void *)rp->r_pc, inst);
212 212 printf("type %s", (((inst >> 21) & 1) ? "st" : "ld"));
213 213 if (((inst >> 21) & 1) == 0)
214 214 printf(" %s", (((inst >> 22) & 1) ?
215 215 "signed" : "unsigned"));
216 216 printf(" asi 0x%x size %d immflg %d\n", asi, sz, immflg);
217 217 printf("rd = %d, op3 = 0x%x, rs1 = %d, rs2 = %d, imm13=0x%x\n",
218 218 rd, op3, rs1, rs2, (inst & 0x1fff));
219 219 }
220 220
221 221 (void) flush_user_windows_to_stack(NULL);
222 222 if (getreg(rp, rs1, &val, badaddr))
223 223 return (SIMU_FAULT);
224 224 addr = (caddr_t)val; /* convert to 32/64 bit address */
225 225 if (aligndebug)
226 226 printf("addr 1 = %p\n", (void *)addr);
227 227
228 228 /* check immediate bit and use immediate field or reg (rs2) */
229 229 if (immflg) {
230 230 int imm;
231 231 imm = inst & 0x1fff; /* mask out immediate field */
232 232 imm <<= 19; /* sign extend it */
233 233 imm >>= 19;
234 234 addr += imm; /* compute address */
235 235 } else {
236 236 if (getreg(rp, rs2, &val, badaddr))
237 237 return (SIMU_FAULT);
238 238 addr += val;
239 239 }
240 240
241 241 /*
242 242 * If this is a 32-bit program, chop the address accordingly. The
243 243 * intermediate uintptr_t casts prevent warnings under a certain
244 244 * compiler, and the temporary 32 bit storage is intended to force
245 245 * proper code generation and break up what would otherwise be a
246 246 * quadruple cast.
247 247 */
248 248 if (curproc->p_model == DATAMODEL_ILP32) {
249 249 caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
250 250 addr = (caddr_t)(uintptr_t)addr32;
251 251 }
252 252
253 253 if (aligndebug)
254 254 printf("addr 2 = %p\n", (void *)addr);
255 255
256 256 if (addr >= curproc->p_as->a_userlimit) {
257 257 *badaddr = addr;
258 258 goto badret;
259 259 }
260 260
261 261 /* a single bit differentiates ld and st */
262 262 if ((inst >> 21) & 1) { /* store */
263 263 if (floatflg) {
264 264 klwp_id_t lwp = ttolwp(curthread);
265 265 kfpu_t *fp = lwptofpu(lwp);
266 266 /* Ensure fp has been enabled */
267 267 if (fpu_exists) {
268 268 if (!(_fp_read_fprs() & FPRS_FEF))
269 269 fp_enable();
270 270 } else {
271 271 if (!fp->fpu_en)
272 272 fp_enable();
273 273 }
274 274 /* if fpu_exists read fpu reg */
275 275 if (fpu_exists) {
276 276 if (fsrflg) {
277 277 _fp_read_pfsr(&data.l[0]);
278 278 } else {
279 279 if (sz == 4) {
280 280 data.i[0] = 0;
281 281 _fp_read_pfreg(
282 282 (unsigned *)&data.i[1], rd);
283 283 }
284 284 if (sz >= 8)
285 285 _fp_read_pdreg(
286 286 &data.l[0], rd);
287 287 if (sz == 16)
288 288 _fp_read_pdreg(
289 289 &data.l[1], rd+1);
290 290 }
291 291 } else {
292 292 if (fsrflg) {
293 293 /* Clear reserved bits, set version=7 */
294 294 fp->fpu_fsr &= ~0x30301000;
295 295 fp->fpu_fsr |= 0xE0000;
296 296 data.l[0] = fp->fpu_fsr;
297 297 } else {
298 298 if (sz == 4) {
299 299 data.i[0] = 0;
300 300 data.i[1] =
301 301 (unsigned)fp->
302 302 fpu_fr.fpu_regs[rd];
303 303 }
304 304 if (sz >= 8)
305 305 data.l[0] =
306 306 fp->fpu_fr.fpu_dregs[rd];
307 307 if (sz == 16)
308 308 data.l[1] =
309 309 fp->fpu_fr.fpu_dregs[rd+1];
310 310 }
311 311 }
312 312 } else {
313 313 if (lddstdflg) { /* combine the data */
314 314 if (getreg(rp, rd, &data.l[0], badaddr))
315 315 return (SIMU_FAULT);
316 316 if (getreg(rp, rd+1, &data.l[1], badaddr))
317 317 return (SIMU_FAULT);
318 318 if (ltlend) {
319 319 /*
320 320 * For STD, each 32-bit word is byte-
321 321 * swapped individually. For
322 322 * simplicity we don't want to do that
323 323 * below, so we swap the words now to
324 324 * get the desired result in the end.
325 325 */
326 326 data.i[0] = data.i[3];
327 327 } else {
328 328 data.i[0] = data.i[1];
329 329 data.i[1] = data.i[3];
330 330 }
331 331 } else {
332 332 if (getreg(rp, rd, &data.l[0], badaddr))
333 333 return (SIMU_FAULT);
334 334 }
335 335 }
336 336
337 337 if (aligndebug) {
338 338 if (sz == 16) {
339 339 printf("data %x %x %x %x\n",
340 340 data.i[0], data.i[1], data.i[2], data.c[3]);
341 341 } else {
342 342 printf("data %x %x %x %x %x %x %x %x\n",
343 343 data.c[0], data.c[1], data.c[2], data.c[3],
344 344 data.c[4], data.c[5], data.c[6], data.c[7]);
345 345 }
346 346 }
347 347
348 348 if (ltlend) {
349 349 if (sz == 1) {
350 350 if (xcopyout_little(&data.c[7], addr,
351 351 (size_t)sz) != 0)
352 352 goto badret;
353 353 } else if (sz == 2) {
354 354 if (xcopyout_little(&data.s[3], addr,
355 355 (size_t)sz) != 0)
356 356 goto badret;
357 357 } else if (sz == 4) {
358 358 if (xcopyout_little(&data.i[1], addr,
359 359 (size_t)sz) != 0)
360 360 goto badret;
361 361 } else {
362 362 if (xcopyout_little(&data.l[0], addr,
363 363 (size_t)sz) != 0)
364 364 goto badret;
365 365 }
366 366 } else {
367 367 if (sz == 1) {
368 368 if (copyout(&data.c[7], addr, (size_t)sz) == -1)
369 369 goto badret;
370 370 } else if (sz == 2) {
371 371 if (copyout(&data.s[3], addr, (size_t)sz) == -1)
372 372 goto badret;
373 373 } else if (sz == 4) {
374 374 if (copyout(&data.i[1], addr, (size_t)sz) == -1)
375 375 goto badret;
376 376 } else {
377 377 if (copyout(&data.l[0], addr, (size_t)sz) == -1)
378 378 goto badret;
379 379 }
380 380 }
381 381 } else { /* load */
382 382 if (sz == 1) {
383 383 if (ltlend) {
384 384 if (xcopyin_little(addr, &data.c[7],
385 385 (size_t)sz) != 0) {
386 386 if (nf)
387 387 data.c[7] = 0;
388 388 else
389 389 goto badret;
390 390 }
391 391 } else {
392 392 if (copyin(addr, &data.c[7],
393 393 (size_t)sz) == -1) {
394 394 if (nf)
395 395 data.c[7] = 0;
396 396 else
397 397 goto badret;
398 398 }
399 399 }
400 400 /* if signed and the sign bit is set extend it */
401 401 if (((inst >> 22) & 1) && ((data.c[7] >> 7) & 1)) {
402 402 data.i[0] = (uint_t)-1; /* extend sign bit */
403 403 data.s[2] = (ushort_t)-1;
404 404 data.c[6] = (uchar_t)-1;
405 405 } else {
406 406 data.i[0] = 0; /* clear upper 32+24 bits */
407 407 data.s[2] = 0;
408 408 data.c[6] = 0;
409 409 }
410 410 } else if (sz == 2) {
411 411 if (ltlend) {
412 412 if (xcopyin_little(addr, &data.s[3],
413 413 (size_t)sz) != 0) {
414 414 if (nf)
415 415 data.s[3] = 0;
416 416 else
417 417 goto badret;
418 418 }
419 419 } else {
420 420 if (copyin(addr, &data.s[3],
421 421 (size_t)sz) == -1) {
422 422 if (nf)
423 423 data.s[3] = 0;
424 424 else
425 425 goto badret;
426 426 }
427 427 }
428 428 /* if signed and the sign bit is set extend it */
429 429 if (((inst >> 22) & 1) && ((data.s[3] >> 15) & 1)) {
430 430 data.i[0] = (uint_t)-1; /* extend sign bit */
431 431 data.s[2] = (ushort_t)-1;
432 432 } else {
433 433 data.i[0] = 0; /* clear upper 32+16 bits */
434 434 data.s[2] = 0;
435 435 }
436 436 } else if (sz == 4) {
437 437 if (ltlend) {
438 438 if (xcopyin_little(addr, &data.i[1],
439 439 (size_t)sz) != 0) {
440 440 if (!nf)
441 441 goto badret;
442 442 data.i[1] = 0;
443 443 }
444 444 } else {
445 445 if (copyin(addr, &data.i[1],
446 446 (size_t)sz) == -1) {
447 447 if (!nf)
448 448 goto badret;
449 449 data.i[1] = 0;
450 450 }
451 451 }
452 452 /* if signed and the sign bit is set extend it */
453 453 if (((inst >> 22) & 1) && ((data.i[1] >> 31) & 1)) {
454 454 data.i[0] = (uint_t)-1; /* extend sign bit */
455 455 } else {
456 456 data.i[0] = 0; /* clear upper 32 bits */
457 457 }
458 458 } else {
459 459 if (ltlend) {
460 460 if (xcopyin_little(addr, &data.l[0],
461 461 (size_t)sz) != 0) {
462 462 if (!nf)
463 463 goto badret;
464 464 data.l[0] = 0;
465 465 }
466 466 } else {
467 467 if (copyin(addr, &data.l[0],
468 468 (size_t)sz) == -1) {
469 469 if (!nf)
470 470 goto badret;
471 471 data.l[0] = 0;
472 472 }
473 473 }
474 474 }
475 475
476 476 if (aligndebug) {
477 477 if (sz == 16) {
478 478 printf("data %x %x %x %x\n",
479 479 data.i[0], data.i[1], data.i[2], data.c[3]);
480 480 } else {
481 481 printf("data %x %x %x %x %x %x %x %x\n",
482 482 data.c[0], data.c[1], data.c[2], data.c[3],
483 483 data.c[4], data.c[5], data.c[6], data.c[7]);
484 484 }
485 485 }
486 486
487 487 if (floatflg) { /* if fpu_exists write fpu reg */
488 488 klwp_id_t lwp = ttolwp(curthread);
489 489 kfpu_t *fp = lwptofpu(lwp);
490 490 /* Ensure fp has been enabled */
491 491 if (fpu_exists) {
492 492 if (!(_fp_read_fprs() & FPRS_FEF))
493 493 fp_enable();
494 494 } else {
495 495 if (!fp->fpu_en)
496 496 fp_enable();
497 497 }
498 498 /* if fpu_exists read fpu reg */
499 499 if (fpu_exists) {
500 500 if (fsrflg) {
501 501 _fp_write_pfsr(&data.l[0]);
502 502 } else {
503 503 if (sz == 4)
504 504 _fp_write_pfreg(
505 505 (unsigned *)&data.i[1], rd);
506 506 if (sz >= 8)
507 507 _fp_write_pdreg(
508 508 &data.l[0], rd);
509 509 if (sz == 16)
510 510 _fp_write_pdreg(
511 511 &data.l[1], rd+1);
512 512 }
513 513 } else {
514 514 if (fsrflg) {
515 515 fp->fpu_fsr = data.l[0];
516 516 } else {
517 517 if (sz == 4)
518 518 fp->fpu_fr.fpu_regs[rd] =
519 519 (unsigned)data.i[1];
520 520 if (sz >= 8)
521 521 fp->fpu_fr.fpu_dregs[rd] =
522 522 data.l[0];
523 523 if (sz == 16)
524 524 fp->fpu_fr.fpu_dregs[rd+1] =
525 525 data.l[1];
526 526 }
527 527 }
528 528 } else {
529 529 if (lddstdflg) { /* split the data */
530 530 if (ltlend) {
531 531 /*
532 532 * For LDD, each 32-bit word is byte-
533 533 * swapped individually. We didn't
534 534 * do that above, but this will give
535 535 * us the desired result.
536 536 */
537 537 data.i[3] = data.i[0];
538 538 } else {
539 539 data.i[3] = data.i[1];
540 540 data.i[1] = data.i[0];
541 541 }
542 542 data.i[0] = 0;
543 543 data.i[2] = 0;
544 544 if (putreg(&data.l[0], rp, rd, badaddr) == -1)
545 545 goto badret;
546 546 if (putreg(&data.l[1], rp, rd+1, badaddr) == -1)
547 547 goto badret;
548 548 } else {
549 549 if (putreg(&data.l[0], rp, rd, badaddr) == -1)
550 550 goto badret;
551 551 }
552 552 }
553 553 }
554 554 return (SIMU_SUCCESS);
555 555 badret:
556 556 return (SIMU_FAULT);
557 557 }
558 558
559 559
560 560 int
561 561 simulate_lddstd(struct regs *rp, caddr_t *badaddr)
562 562 {
563 563 uint_t inst, op3, asi = 0;
564 564 uint_t rd, rs1, rs2;
565 565 int nf = 0, ltlend = 0, usermode;
566 566 int immflg;
567 567 uint64_t reven;
568 568 uint64_t rodd;
569 569 caddr_t addr;
570 570 uint64_t val;
571 571 uint64_t data;
572 572
573 573 usermode = USERMODE(rp->r_tstate);
574 574
575 575 if (usermode)
576 576 inst = fetch_user_instr((caddr_t)rp->r_pc);
577 577 else
578 578 inst = *(uint_t *)rp->r_pc;
579 579
580 580 op3 = (inst >> 19) & 0x3f;
581 581 rd = (inst >> 25) & 0x1f;
582 582 rs1 = (inst >> 14) & 0x1f;
583 583 rs2 = inst & 0x1f;
584 584 immflg = (inst >> 13) & 1;
585 585
586 586 if (USERMODE(rp->r_tstate))
587 587 (void) flush_user_windows_to_stack(NULL);
588 588 else
589 589 flush_windows();
590 590
591 591 if ((op3 >> 4) & 1) { /* is this LDDA/STDA? */
592 592 if (immflg) {
593 593 asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) &
594 594 TSTATE_ASI_MASK;
595 595 } else {
596 596 asi = (inst >> 5) & 0xff;
597 597 }
598 598 switch (asi) {
599 599 case ASI_P:
600 600 case ASI_S:
601 601 break;
602 602 case ASI_PNF:
603 603 case ASI_SNF:
604 604 nf = 1;
605 605 break;
606 606 case ASI_PL:
607 607 case ASI_SL:
608 608 ltlend = 1;
609 609 break;
610 610 case ASI_PNFL:
611 611 case ASI_SNFL:
612 612 ltlend = 1;
613 613 nf = 1;
614 614 break;
615 615 case ASI_AIUP:
616 616 case ASI_AIUS:
617 617 usermode = 1;
618 618 break;
619 619 case ASI_AIUPL:
620 620 case ASI_AIUSL:
621 621 usermode = 1;
622 622 ltlend = 1;
623 623 break;
624 624 default:
625 625 return (SIMU_ILLEGAL);
626 626 }
627 627 }
628 628
629 629 if (getreg(rp, rs1, &val, badaddr))
630 630 return (SIMU_FAULT);
631 631 addr = (caddr_t)val; /* convert to 32/64 bit address */
632 632
633 633 /* check immediate bit and use immediate field or reg (rs2) */
634 634 if (immflg) {
635 635 int imm;
636 636 imm = inst & 0x1fff; /* mask out immediate field */
637 637 imm <<= 19; /* sign extend it */
638 638 imm >>= 19;
639 639 addr += imm; /* compute address */
640 640 } else {
641 641 if (getreg(rp, rs2, &val, badaddr))
642 642 return (SIMU_FAULT);
643 643 addr += val;
644 644 }
645 645
646 646 /*
647 647 * T_UNIMP_LDD and T_UNIMP_STD are higher priority than
648 648 * T_ALIGNMENT. So we have to make sure that the address is
649 649 * kosher before trying to use it, because the hardware hasn't
650 650 * checked it for us yet.
651 651 */
652 652 if (((uintptr_t)addr & 0x7) != 0) {
653 653 if (curproc->p_fixalignment)
654 654 return (do_unaligned(rp, badaddr));
655 655 else
656 656 return (SIMU_UNALIGN);
657 657 }
658 658
659 659 /*
660 660 * If this is a 32-bit program, chop the address accordingly. The
661 661 * intermediate uintptr_t casts prevent warnings under a certain
662 662 * compiler, and the temporary 32 bit storage is intended to force
663 663 * proper code generation and break up what would otherwise be a
664 664 * quadruple cast.
665 665 */
666 666 if (curproc->p_model == DATAMODEL_ILP32 && usermode) {
667 667 caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
668 668 addr = (caddr_t)(uintptr_t)addr32;
669 669 }
670 670
671 671 if ((inst >> 21) & 1) { /* store */
672 672 if (getreg(rp, rd, &reven, badaddr))
673 673 return (SIMU_FAULT);
674 674 if (getreg(rp, rd+1, &rodd, badaddr))
675 675 return (SIMU_FAULT);
676 676 if (ltlend) {
677 677 reven = BSWAP_32(reven);
678 678 rodd = BSWAP_32(rodd);
679 679 }
680 680 data = (reven << 32) | rodd;
681 681 if (usermode) {
682 682 if (suword64_nowatch(addr, data) == -1)
683 683 return (SIMU_FAULT);
684 684 } else {
685 685 *(uint64_t *)addr = data;
686 686 }
687 687 } else { /* load */
688 688 if (usermode) {
689 689 if (fuword64_nowatch(addr, &data)) {
690 690 if (nf)
691 691 data = 0;
692 692 else
693 693 return (SIMU_FAULT);
694 694 }
695 695 } else
696 696 data = *(uint64_t *)addr;
697 697
698 698 reven = (data >> 32);
699 699 rodd = (uint64_t)(uint32_t)data;
700 700 if (ltlend) {
701 701 reven = BSWAP_32(reven);
702 702 rodd = BSWAP_32(rodd);
703 703 }
704 704
705 705 if (putreg(&reven, rp, rd, badaddr) == -1)
706 706 return (SIMU_FAULT);
707 707 if (putreg(&rodd, rp, rd+1, badaddr) == -1)
708 708 return (SIMU_FAULT);
709 709 }
710 710 return (SIMU_SUCCESS);
711 711 }
712 712
713 713
714 714 /*
715 715 * simulate popc
716 716 */
717 717 static int
718 718 simulate_popc(struct regs *rp, caddr_t *badaddr, uint_t inst)
719 719 {
720 720 uint_t rd, rs2, rs1;
721 721 uint_t immflg;
722 722 uint64_t val, cnt = 0;
723 723
724 724 rd = (inst >> 25) & 0x1f;
725 725 rs1 = (inst >> 14) & 0x1f;
726 726 rs2 = inst & 0x1f;
727 727 immflg = (inst >> 13) & 1;
728 728
729 729 if (rs1 > 0)
730 730 return (SIMU_ILLEGAL);
731 731
732 732 (void) flush_user_windows_to_stack(NULL);
733 733
734 734 /* check immediate bit and use immediate field or reg (rs2) */
735 735 if (immflg) {
736 736 int64_t imm;
737 737 imm = inst & 0x1fff; /* mask out immediate field */
738 738 imm <<= 51; /* sign extend it */
739 739 imm >>= 51;
740 740 if (imm != 0) {
741 741 for (cnt = 0; imm != 0; imm &= imm-1)
742 742 cnt++;
743 743 }
744 744 } else {
745 745 if (getreg(rp, rs2, &val, badaddr))
746 746 return (SIMU_FAULT);
747 747 if (val != 0) {
748 748 for (cnt = 0; val != 0; val &= val-1)
749 749 cnt++;
750 750 }
751 751 }
752 752
753 753 if (putreg(&cnt, rp, rd, badaddr) == -1)
754 754 return (SIMU_FAULT);
755 755
756 756 return (SIMU_SUCCESS);
757 757 }
758 758
759 759 /*
760 760 * simulate mulscc
761 761 */
762 762 static int
763 763 simulate_mulscc(struct regs *rp, caddr_t *badaddr, uint_t inst)
764 764 {
765 765 uint32_t s1, s2;
766 766 uint32_t c, d, v;
767 767 uint_t rd, rs1;
768 768 int64_t d64;
769 769 uint64_t ud64;
770 770 uint64_t drs1;
771 771
772 772 (void) flush_user_windows_to_stack(NULL);
773 773
774 774 if ((inst >> 13) & 1) { /* immediate */
775 775 d64 = inst & 0x1fff;
776 776 d64 <<= 51; /* sign extend it */
777 777 d64 >>= 51;
778 778 } else {
779 779 uint_t rs2;
780 780 uint64_t drs2;
781 781
782 782 if (inst & 0x1fe0) {
783 783 return (SIMU_ILLEGAL);
784 784 }
785 785 rs2 = inst & 0x1f;
786 786 if (getreg(rp, rs2, &drs2, badaddr)) {
787 787 return (SIMU_FAULT);
788 788 }
789 789 d64 = (int64_t)drs2;
790 790 }
791 791
792 792 rs1 = (inst >> 14) & 0x1f;
793 793 if (getreg(rp, rs1, &drs1, badaddr)) {
794 794 return (SIMU_FAULT);
795 795 }
796 796 /* icc.n xor icc.v */
797 797 s1 = ((rp->r_tstate & TSTATE_IN) >> (TSTATE_CCR_SHIFT + 3)) ^
798 798 ((rp->r_tstate & TSTATE_IV) >> (TSTATE_CCR_SHIFT + 1));
799 799 s1 = (s1 << 31) | (((uint32_t)drs1) >> 1);
800 800
801 801 if (rp->r_y & 1) {
802 802 s2 = (uint32_t)d64;
803 803 } else {
804 804 s2 = 0;
805 805 }
806 806 d = s1 + s2;
807 807
808 808 ud64 = (uint64_t)d;
809 809
810 810 /* set the icc flags */
811 811 v = (s1 & s2 & ~d) | (~s1 & ~s2 & d);
812 812 c = (s1 & s2) | (~d & (s1 | s2));
813 813 rp->r_tstate &= ~TSTATE_ICC;
814 814 rp->r_tstate |= (uint64_t)((c >> 31) & 1) << (TSTATE_CCR_SHIFT + 0);
815 815 rp->r_tstate |= (uint64_t)((v >> 31) & 1) << (TSTATE_CCR_SHIFT + 1);
816 816 rp->r_tstate |= (uint64_t)(d ? 0 : 1) << (TSTATE_CCR_SHIFT + 2);
817 817 rp->r_tstate |= (uint64_t)((d >> 31) & 1) << (TSTATE_CCR_SHIFT + 3);
818 818
819 819 if (rp->r_tstate & TSTATE_IC) {
820 820 ud64 |= (1ULL << 32);
821 821 }
822 822
823 823 /* set the xcc flags */
824 824 rp->r_tstate &= ~TSTATE_XCC;
825 825 if (ud64 == 0) {
826 826 rp->r_tstate |= TSTATE_XZ;
827 827 }
828 828
829 829 rd = (inst >> 25) & 0x1f;
830 830 if (putreg(&ud64, rp, rd, badaddr)) {
831 831 return (SIMU_FAULT);
832 832 }
833 833
834 834 d64 = (drs1 << 32) | (uint32_t)rp->r_y;
835 835 d64 >>= 1;
836 836 rp->r_y = (uint32_t)d64;
837 837
838 838 return (SIMU_SUCCESS);
839 839 }
840 840
841 841 /*
842 842 * simulate unimplemented instructions (popc, ldqf{a}, stqf{a})
843 843 */
844 844 int
845 845 simulate_unimp(struct regs *rp, caddr_t *badaddr)
846 846 {
847 847 uint_t inst, optype, op3, asi;
848 848 uint_t rs1, rd;
849 849 uint_t ignor, i;
850 850 machpcb_t *mpcb = lwptompcb(ttolwp(curthread));
851 851 int nomatch = 0;
852 852 caddr_t addr = (caddr_t)rp->r_pc;
853 853 struct as *as;
854 854 caddr_t ka;
855 855 pfn_t pfnum;
856 856 page_t *pp;
857 857 proc_t *p = ttoproc(curthread);
858 858 struct seg *mapseg;
859 859 struct segvn_data *svd;
860 860
861 861 ASSERT(USERMODE(rp->r_tstate));
862 862 inst = fetch_user_instr(addr);
863 863 if (inst == (uint_t)-1) {
864 864 mpcb->mpcb_illexcaddr = addr;
865 865 mpcb->mpcb_illexcinsn = (uint32_t)-1;
866 866 return (SIMU_ILLEGAL);
867 867 }
868 868
869 869 /*
870 870 * When fixing dirty v8 instructions there's a race if two processors
871 871 * are executing the dirty executable at the same time. If one
872 872 * cleans the instruction as the other is executing it the second
873 873 * processor will see a clean instruction when it comes through this
874 874 * code and will return SIMU_ILLEGAL. To work around the race
875 875 * this code will keep track of the last illegal instruction seen
876 876 * by each lwp and will only take action if the illegal instruction
877 877 * is repeatable.
878 878 */
879 879 if (addr != mpcb->mpcb_illexcaddr ||
880 880 inst != mpcb->mpcb_illexcinsn)
881 881 nomatch = 1;
882 882 mpcb->mpcb_illexcaddr = addr;
883 883 mpcb->mpcb_illexcinsn = inst;
884 884
885 885 /* instruction fields */
886 886 i = (inst >> 13) & 0x1;
887 887 rd = (inst >> 25) & 0x1f;
888 888 optype = (inst >> 30) & 0x3;
889 889 op3 = (inst >> 19) & 0x3f;
890 890 ignor = (inst >> 5) & 0xff;
891 891 if (IS_IBIT_SET(inst)) {
892 892 asi = (uint32_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
893 893 TSTATE_ASI_MASK);
894 894 } else {
895 895 asi = ignor;
896 896 }
897 897
898 898 if (IS_VIS1(optype, op3) ||
899 899 IS_PARTIAL_OR_SHORT_FLOAT_LD_ST(optype, op3, asi) ||
900 900 IS_FLOAT_QUAD_OP(optype, op3)) {
901 901 klwp_t *lwp = ttolwp(curthread);
902 902 kfpu_t *fp = lwptofpu(lwp);
903 903 if (fpu_exists) {
904 904 if (!(_fp_read_fprs() & FPRS_FEF))
905 905 fp_enable();
906 906 _fp_read_pfsr(&fp->fpu_fsr);
907 907 } else {
908 908 if (!fp->fpu_en)
909 909 fp_enable();
910 910 }
911 911 fp_precise(rp);
912 912 return (SIMU_RETRY);
913 913 }
914 914
915 915 if (optype == 2 && op3 == IOP_V8_POPC) {
916 916 return (simulate_popc(rp, badaddr, inst));
917 917 } else if (optype == 3 && op3 == IOP_V8_POPC) {
918 918 return (SIMU_ILLEGAL);
919 919 } else if (optype == OP_V8_ARITH && op3 == IOP_V8_MULScc) {
920 920 return (simulate_mulscc(rp, badaddr, inst));
921 921 }
922 922
923 923 if (optype == OP_V8_LDSTR) {
924 924 if (op3 == IOP_V8_LDQF || op3 == IOP_V8_LDQFA ||
925 925 op3 == IOP_V8_STQF || op3 == IOP_V8_STQFA)
926 926 return (do_unaligned(rp, badaddr));
927 927 }
928 928
929 929 /* This is a new instruction so illexccnt should also be set. */
930 930 if (nomatch) {
931 931 mpcb->mpcb_illexccnt = 0;
932 932 return (SIMU_RETRY);
933 933 }
934 934
935 935 /*
936 936 * In order to keep us from entering into an infinite loop while
937 937 * attempting to clean up faulty instructions, we will return
938 938 * SIMU_ILLEGAL once we've cleaned up the instruction as much
939 939 * as we can, and still end up here.
940 940 */
941 941 if (mpcb->mpcb_illexccnt >= 3)
942 942 return (SIMU_ILLEGAL);
943 943
944 944 mpcb->mpcb_illexccnt += 1;
945 945
946 946 /*
947 947 * The rest of the code handles v8 binaries with instructions
948 948 * that have dirty (non-zero) bits in reserved or 'ignored'
949 949 * fields; these will cause core dumps on v9 machines.
950 950 *
951 951 * We only clean dirty instructions in 32-bit programs (ie, v8)
952 952 * running on SPARCv9 processors. True v9 programs are forced
953 953 * to use the instruction set as intended.
954 954 */
955 955 if (lwp_getdatamodel(curthread->t_lwp) != DATAMODEL_ILP32)
956 956 return (SIMU_ILLEGAL);
957 957 switch (optype) {
958 958 case OP_V8_BRANCH:
959 959 case OP_V8_CALL:
960 960 return (SIMU_ILLEGAL); /* these don't have ignored fields */
961 961 /*NOTREACHED*/
962 962 case OP_V8_ARITH:
963 963 switch (op3) {
964 964 case IOP_V8_RETT:
965 965 if (rd == 0 && !(i == 0 && ignor))
966 966 return (SIMU_ILLEGAL);
967 967 if (rd)
968 968 inst &= ~(0x1f << 25);
969 969 if (i == 0 && ignor)
970 970 inst &= ~(0xff << 5);
971 971 break;
972 972 case IOP_V8_TCC:
973 973 if (i == 0 && ignor != 0) {
974 974 inst &= ~(0xff << 5);
975 975 } else if (i == 1 && (((inst >> 7) & 0x3f) != 0)) {
976 976 inst &= ~(0x3f << 7);
977 977 } else {
978 978 return (SIMU_ILLEGAL);
979 979 }
980 980 break;
981 981 case IOP_V8_JMPL:
982 982 case IOP_V8_RESTORE:
983 983 case IOP_V8_SAVE:
984 984 if ((op3 == IOP_V8_RETT && rd) ||
985 985 (i == 0 && ignor)) {
986 986 inst &= ~(0xff << 5);
987 987 } else {
988 988 return (SIMU_ILLEGAL);
989 989 }
990 990 break;
991 991 case IOP_V8_FCMP:
992 992 if (rd == 0)
993 993 return (SIMU_ILLEGAL);
994 994 inst &= ~(0x1f << 25);
995 995 break;
996 996 case IOP_V8_RDASR:
997 997 rs1 = ((inst >> 14) & 0x1f);
998 998 if (rs1 == 1 || (rs1 >= 7 && rs1 <= 14)) {
999 999 /*
1000 1000 * The instruction specifies an invalid
1001 1001 * state register - better bail out than
1002 1002 * "fix" it when we're not sure what was
1003 1003 * intended.
1004 1004 */
1005 1005 return (SIMU_ILLEGAL);
1006 1006 }
1007 1007 /*
1008 1008 * Note: this case includes the 'stbar'
1009 1009 * instruction (rs1 == 15 && i == 0).
1010 1010 */
1011 1011 if ((ignor = (inst & 0x3fff)) != 0)
1012 1012 inst &= ~(0x3fff);
1013 1013 break;
1014 1014 case IOP_V8_SRA:
1015 1015 case IOP_V8_SRL:
1016 1016 case IOP_V8_SLL:
1017 1017 if (ignor == 0)
1018 1018 return (SIMU_ILLEGAL);
1019 1019 inst &= ~(0xff << 5);
1020 1020 break;
1021 1021 case IOP_V8_ADD:
1022 1022 case IOP_V8_AND:
1023 1023 case IOP_V8_OR:
1024 1024 case IOP_V8_XOR:
1025 1025 case IOP_V8_SUB:
1026 1026 case IOP_V8_ANDN:
1027 1027 case IOP_V8_ORN:
1028 1028 case IOP_V8_XNOR:
1029 1029 case IOP_V8_ADDC:
1030 1030 case IOP_V8_UMUL:
1031 1031 case IOP_V8_SMUL:
1032 1032 case IOP_V8_SUBC:
1033 1033 case IOP_V8_UDIV:
1034 1034 case IOP_V8_SDIV:
1035 1035 case IOP_V8_ADDcc:
1036 1036 case IOP_V8_ANDcc:
1037 1037 case IOP_V8_ORcc:
1038 1038 case IOP_V8_XORcc:
1039 1039 case IOP_V8_SUBcc:
1040 1040 case IOP_V8_ANDNcc:
1041 1041 case IOP_V8_ORNcc:
1042 1042 case IOP_V8_XNORcc:
1043 1043 case IOP_V8_ADDCcc:
1044 1044 case IOP_V8_UMULcc:
1045 1045 case IOP_V8_SMULcc:
1046 1046 case IOP_V8_SUBCcc:
1047 1047 case IOP_V8_UDIVcc:
1048 1048 case IOP_V8_SDIVcc:
1049 1049 case IOP_V8_TADDcc:
1050 1050 case IOP_V8_TSUBcc:
1051 1051 case IOP_V8_TADDccTV:
1052 1052 case IOP_V8_TSUBccTV:
1053 1053 case IOP_V8_MULScc:
1054 1054 case IOP_V8_WRASR:
1055 1055 case IOP_V8_FLUSH:
1056 1056 if (i != 0 || ignor == 0)
1057 1057 return (SIMU_ILLEGAL);
1058 1058 inst &= ~(0xff << 5);
1059 1059 break;
1060 1060 default:
1061 1061 return (SIMU_ILLEGAL);
1062 1062 }
1063 1063 break;
1064 1064 case OP_V8_LDSTR:
1065 1065 switch (op3) {
1066 1066 case IOP_V8_STFSR:
1067 1067 case IOP_V8_LDFSR:
1068 1068 if (rd == 0 && !(i == 0 && ignor))
1069 1069 return (SIMU_ILLEGAL);
1070 1070 if (rd)
1071 1071 inst &= ~(0x1f << 25);
1072 1072 if (i == 0 && ignor)
1073 1073 inst &= ~(0xff << 5);
1074 1074 break;
1075 1075 default:
1076 1076 if (optype == OP_V8_LDSTR && !IS_LDST_ALT(op3) &&
1077 1077 i == 0 && ignor)
1078 1078 inst &= ~(0xff << 5);
1079 1079 else
↓ open down ↓ |
1079 lines elided |
↑ open up ↑ |
1080 1080 return (SIMU_ILLEGAL);
1081 1081 break;
1082 1082 }
1083 1083 break;
1084 1084 default:
1085 1085 return (SIMU_ILLEGAL);
1086 1086 }
1087 1087
1088 1088 as = p->p_as;
1089 1089
1090 - AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1090 + AS_LOCK_ENTER(as, RW_READER);
1091 1091 mapseg = as_findseg(as, (caddr_t)rp->r_pc, 0);
1092 1092 ASSERT(mapseg != NULL);
1093 1093 svd = (struct segvn_data *)mapseg->s_data;
1094 1094
1095 1095 /*
1096 1096 * We only create COW page for MAP_PRIVATE mappings.
1097 1097 */
1098 1098 SEGVN_LOCK_ENTER(as, &svd->lock, RW_READER);
1099 1099 if ((svd->type & MAP_TYPE) & MAP_SHARED) {
1100 1100 SEGVN_LOCK_EXIT(as, &svd->lock);
1101 - AS_LOCK_EXIT(as, &as->a_lock);
1101 + AS_LOCK_EXIT(as);
1102 1102 return (SIMU_ILLEGAL);
1103 1103 }
1104 1104 SEGVN_LOCK_EXIT(as, &svd->lock);
1105 - AS_LOCK_EXIT(as, &as->a_lock);
1105 + AS_LOCK_EXIT(as);
1106 1106
1107 1107 /*
1108 1108 * A "flush" instruction using the user PC's vaddr will not work
1109 1109 * here, at least on Spitfire. Instead we create a temporary kernel
1110 1110 * mapping to the user's text page, then modify and flush that.
1111 1111 * Break COW by locking user page.
1112 1112 */
1113 1113 if (as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK), PAGESIZE,
1114 1114 F_SOFTLOCK, S_READ))
1115 1115 return (SIMU_FAULT);
1116 1116
1117 - AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1117 + AS_LOCK_ENTER(as, RW_READER);
1118 1118 pfnum = hat_getpfnum(as->a_hat, (caddr_t)rp->r_pc);
1119 - AS_LOCK_EXIT(as, &as->a_lock);
1119 + AS_LOCK_EXIT(as);
1120 1120 if (pf_is_memory(pfnum)) {
1121 1121 pp = page_numtopp_nolock(pfnum);
1122 1122 ASSERT(pp == NULL || PAGE_LOCKED(pp));
1123 1123 } else {
1124 1124 (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
1125 1125 PAGESIZE, F_SOFTUNLOCK, S_READ);
1126 1126 return (SIMU_FAULT);
1127 1127 }
1128 1128
1129 - AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
1129 + AS_LOCK_ENTER(as, RW_READER);
1130 1130 ka = ppmapin(pp, PROT_READ|PROT_WRITE, (caddr_t)rp->r_pc);
1131 1131 *(uint_t *)(ka + (uintptr_t)(rp->r_pc % PAGESIZE)) = inst;
1132 1132 doflush(ka + (uintptr_t)(rp->r_pc % PAGESIZE));
1133 1133 ppmapout(ka);
1134 - AS_LOCK_EXIT(as, &as->a_lock);
1134 + AS_LOCK_EXIT(as);
1135 1135
1136 1136 (void) as_fault(as->a_hat, as, (caddr_t)(rp->r_pc & PAGEMASK),
1137 1137 PAGESIZE, F_SOFTUNLOCK, S_READ);
1138 1138 return (SIMU_RETRY);
1139 1139 }
1140 1140
1141 1141 /*
1142 1142 * Simulate a "rd %tick" or "rd %stick" (%asr24) instruction.
1143 1143 */
1144 1144 int
1145 1145 simulate_rdtick(struct regs *rp)
1146 1146 {
1147 1147 uint_t inst, op, op3, rd, rs1, i;
1148 1148 caddr_t badaddr;
1149 1149
1150 1150 inst = fetch_user_instr((caddr_t)rp->r_pc);
1151 1151 op = (inst >> 30) & 0x3;
1152 1152 rd = (inst >> 25) & 0x1F;
1153 1153 op3 = (inst >> 19) & 0x3F;
1154 1154 i = (inst >> 13) & 0x1;
1155 1155
1156 1156 /*
1157 1157 * Make sure this is either a %tick read (rs1 == 0x4) or
1158 1158 * a %stick read (rs1 == 0x18) instruction.
1159 1159 */
1160 1160 if (op == 2 && op3 == 0x28 && i == 0) {
1161 1161 rs1 = (inst >> 14) & 0x1F;
1162 1162
1163 1163 if (rs1 == 0x4) {
1164 1164 uint64_t tick;
1165 1165 (void) flush_user_windows_to_stack(NULL);
1166 1166 tick = gettick_counter();
1167 1167 if (putreg(&tick, rp, rd, &badaddr) == 0)
1168 1168 return (SIMU_SUCCESS);
1169 1169 } else if (rs1 == 0x18) {
1170 1170 uint64_t stick;
1171 1171 (void) flush_user_windows_to_stack(NULL);
1172 1172 stick = gethrtime_unscaled();
1173 1173 if (putreg(&stick, rp, rd, &badaddr) == 0)
1174 1174 return (SIMU_SUCCESS);
1175 1175 }
1176 1176 }
1177 1177
1178 1178 return (SIMU_FAULT);
1179 1179 }
1180 1180
1181 1181 /*
1182 1182 * Get the value of a register for instruction simulation
1183 1183 * by using the regs or window structure pointers.
1184 1184 * Return 0 for success, and -1 for failure. If there is a failure,
1185 1185 * save the faulting address using badaddr pointer.
1186 1186 * We have 64 bit globals and outs, and 32 or 64 bit ins and locals.
1187 1187 * Don't truncate globals/outs for 32 bit programs, for v8+ support.
1188 1188 */
1189 1189 int
1190 1190 getreg(struct regs *rp, uint_t reg, uint64_t *val, caddr_t *badaddr)
1191 1191 {
1192 1192 uint64_t *rgs, *sp;
1193 1193 int rv = 0;
1194 1194
1195 1195 rgs = (uint64_t *)&rp->r_ps; /* globals and outs */
1196 1196 sp = (uint64_t *)rp->r_sp; /* ins and locals */
1197 1197 if (reg == 0) {
1198 1198 *val = 0;
1199 1199 } else if (reg < 16) {
1200 1200 *val = rgs[reg];
1201 1201 } else if (IS_V9STACK(sp)) {
1202 1202 uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64);
1203 1203 uint64_t *addr = (uint64_t *)&rw[reg - 16];
1204 1204 uint64_t res;
1205 1205
1206 1206 if (USERMODE(rp->r_tstate)) {
1207 1207 if (fuword64_nowatch(addr, &res) == -1) {
1208 1208 *badaddr = (caddr_t)addr;
1209 1209 rv = -1;
1210 1210 }
1211 1211 } else {
1212 1212 res = *addr;
1213 1213 }
1214 1214 *val = res;
1215 1215 } else {
1216 1216 caddr32_t sp32 = (caddr32_t)(uintptr_t)sp;
1217 1217 uint32_t *rw = (uint32_t *)(uintptr_t)sp32;
1218 1218 uint32_t *addr = (uint32_t *)&rw[reg - 16];
1219 1219 uint32_t res;
1220 1220
1221 1221 if (USERMODE(rp->r_tstate)) {
1222 1222 if (fuword32_nowatch(addr, &res) == -1) {
1223 1223 *badaddr = (caddr_t)addr;
1224 1224 rv = -1;
1225 1225 }
1226 1226 } else {
1227 1227 res = *addr;
1228 1228 }
1229 1229 *val = (uint64_t)res;
1230 1230 }
1231 1231 return (rv);
1232 1232 }
1233 1233
1234 1234 /*
1235 1235 * Set the value of a register after instruction simulation
1236 1236 * by using the regs or window structure pointers.
1237 1237 * Return 0 for succes -1 failure.
1238 1238 * save the faulting address using badaddr pointer.
1239 1239 * We have 64 bit globals and outs, and 32 or 64 bit ins and locals.
1240 1240 * Don't truncate globals/outs for 32 bit programs, for v8+ support.
1241 1241 */
1242 1242 int
1243 1243 putreg(uint64_t *data, struct regs *rp, uint_t reg, caddr_t *badaddr)
1244 1244 {
1245 1245 uint64_t *rgs, *sp;
1246 1246 int rv = 0;
1247 1247
1248 1248 rgs = (uint64_t *)&rp->r_ps; /* globals and outs */
1249 1249 sp = (uint64_t *)rp->r_sp; /* ins and locals */
1250 1250 if (reg == 0) {
1251 1251 return (0);
1252 1252 } else if (reg < 16) {
1253 1253 rgs[reg] = *data;
1254 1254 } else if (IS_V9STACK(sp)) {
1255 1255 uint64_t *rw = (uint64_t *)((uintptr_t)sp + V9BIAS64);
1256 1256 uint64_t *addr = (uint64_t *)&rw[reg - 16];
1257 1257 uint64_t res;
1258 1258
1259 1259 if (USERMODE(rp->r_tstate)) {
1260 1260 struct machpcb *mpcb = lwptompcb(curthread->t_lwp);
1261 1261
1262 1262 res = *data;
1263 1263 if (suword64_nowatch(addr, res) != 0) {
1264 1264 *badaddr = (caddr_t)addr;
1265 1265 rv = -1;
1266 1266 }
1267 1267 /*
1268 1268 * We have changed a local or in register;
1269 1269 * nuke the watchpoint return windows.
1270 1270 */
1271 1271 mpcb->mpcb_rsp[0] = NULL;
1272 1272 mpcb->mpcb_rsp[1] = NULL;
1273 1273 } else {
1274 1274 res = *data;
1275 1275 *addr = res;
1276 1276 }
1277 1277 } else {
1278 1278 caddr32_t sp32 = (caddr32_t)(uintptr_t)sp;
1279 1279 uint32_t *rw = (uint32_t *)(uintptr_t)sp32;
1280 1280 uint32_t *addr = (uint32_t *)&rw[reg - 16];
1281 1281 uint32_t res;
1282 1282
1283 1283 if (USERMODE(rp->r_tstate)) {
1284 1284 struct machpcb *mpcb = lwptompcb(curthread->t_lwp);
1285 1285
1286 1286 res = (uint_t)*data;
1287 1287 if (suword32_nowatch(addr, res) != 0) {
1288 1288 *badaddr = (caddr_t)addr;
1289 1289 rv = -1;
1290 1290 }
1291 1291 /*
1292 1292 * We have changed a local or in register;
1293 1293 * nuke the watchpoint return windows.
1294 1294 */
1295 1295 mpcb->mpcb_rsp[0] = NULL;
1296 1296 mpcb->mpcb_rsp[1] = NULL;
1297 1297
1298 1298 } else {
1299 1299 res = (uint_t)*data;
1300 1300 *addr = res;
1301 1301 }
1302 1302 }
1303 1303 return (rv);
1304 1304 }
1305 1305
1306 1306 /*
1307 1307 * Calculate a memory reference address from instruction
1308 1308 * operands, used to return the address of a fault, instead
1309 1309 * of the instruction when an error occurs. This is code that is
1310 1310 * common with most of the routines that simulate instructions.
1311 1311 */
1312 1312 int
1313 1313 calc_memaddr(struct regs *rp, caddr_t *badaddr)
1314 1314 {
1315 1315 uint_t inst;
1316 1316 uint_t rd, rs1, rs2;
1317 1317 int sz;
1318 1318 int immflg;
1319 1319 int floatflg;
1320 1320 caddr_t addr;
1321 1321 uint64_t val;
1322 1322
1323 1323 if (USERMODE(rp->r_tstate))
1324 1324 inst = fetch_user_instr((caddr_t)rp->r_pc);
1325 1325 else
1326 1326 inst = *(uint_t *)rp->r_pc;
1327 1327
1328 1328 rd = (inst >> 25) & 0x1f;
1329 1329 rs1 = (inst >> 14) & 0x1f;
1330 1330 rs2 = inst & 0x1f;
1331 1331 floatflg = (inst >> 24) & 1;
1332 1332 immflg = (inst >> 13) & 1;
1333 1333
1334 1334 if (floatflg) {
1335 1335 switch ((inst >> 19) & 3) { /* map size bits to a number */
1336 1336 case 0: sz = 4; break; /* ldf/stf */
1337 1337 case 1: return (0); /* ld[x]fsr/st[x]fsr */
1338 1338 case 2: sz = 16; break; /* ldqf/stqf */
1339 1339 case 3: sz = 8; break; /* lddf/stdf */
1340 1340 }
1341 1341 /*
1342 1342 * Fix to access extra double register encoding plus
1343 1343 * compensate to access the correct fpu_dreg.
1344 1344 */
1345 1345 if (sz > 4) {
1346 1346 if ((rd & 1) == 1)
1347 1347 rd = (rd & 0x1e) | 0x20;
1348 1348 rd = rd >> 1;
1349 1349 }
1350 1350 } else {
1351 1351 switch ((inst >> 19) & 0xf) { /* map size bits to a number */
1352 1352 case 0: /* lduw */
1353 1353 case 4: /* stw */
1354 1354 case 8: /* ldsw */
1355 1355 case 0xf: /* swap */
1356 1356 sz = 4; break;
1357 1357 case 1: /* ldub */
1358 1358 case 5: /* stb */
1359 1359 case 9: /* ldsb */
1360 1360 case 0xd: /* ldstub */
1361 1361 sz = 1; break;
1362 1362 case 2: /* lduh */
1363 1363 case 6: /* sth */
1364 1364 case 0xa: /* ldsh */
1365 1365 sz = 2; break;
1366 1366 case 3: /* ldd */
1367 1367 case 7: /* std */
1368 1368 case 0xb: /* ldx */
1369 1369 case 0xe: /* stx */
1370 1370 sz = 8; break;
1371 1371 }
1372 1372 }
1373 1373
1374 1374 if (USERMODE(rp->r_tstate))
1375 1375 (void) flush_user_windows_to_stack(NULL);
1376 1376 else
1377 1377 flush_windows();
1378 1378
1379 1379 if (getreg(rp, rs1, &val, badaddr))
1380 1380 return (SIMU_FAULT);
1381 1381 addr = (caddr_t)val;
1382 1382
1383 1383 /* check immediate bit and use immediate field or reg (rs2) */
1384 1384 if (immflg) {
1385 1385 int imm;
1386 1386 imm = inst & 0x1fff; /* mask out immediate field */
1387 1387 imm <<= 19; /* sign extend it */
1388 1388 imm >>= 19;
1389 1389 addr += imm; /* compute address */
1390 1390 } else {
1391 1391 if (getreg(rp, rs2, &val, badaddr))
1392 1392 return (SIMU_FAULT);
1393 1393 addr += val;
1394 1394 }
1395 1395
1396 1396 /*
1397 1397 * If this is a 32-bit program, chop the address accordingly. The
1398 1398 * intermediate uintptr_t casts prevent warnings under a certain
1399 1399 * compiler, and the temporary 32 bit storage is intended to force
1400 1400 * proper code generation and break up what would otherwise be a
1401 1401 * quadruple cast.
1402 1402 */
1403 1403 if (curproc->p_model == DATAMODEL_ILP32 && USERMODE(rp->r_tstate)) {
1404 1404 caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
1405 1405 addr = (caddr_t)(uintptr_t)addr32;
1406 1406 }
1407 1407
1408 1408 *badaddr = addr;
1409 1409 return ((uintptr_t)addr & (sz - 1) ? SIMU_UNALIGN : SIMU_SUCCESS);
1410 1410 }
1411 1411
1412 1412 /*
1413 1413 * Return the size of a load or store instruction (1, 2, 4, 8, 16, 64).
1414 1414 * Also compute the precise address by instruction disassembly.
1415 1415 * (v9 page faults only provide the page address via the hardware.)
1416 1416 * Return 0 on failure (not a load or store instruction).
1417 1417 */
1418 1418 int
1419 1419 instr_size(struct regs *rp, caddr_t *addrp, enum seg_rw rdwr)
1420 1420 {
1421 1421 uint_t inst, op3, asi;
1422 1422 uint_t rd, rs1, rs2;
1423 1423 int sz = 0;
1424 1424 int immflg;
1425 1425 int floatflg;
1426 1426 caddr_t addr;
1427 1427 caddr_t badaddr;
1428 1428 uint64_t val;
1429 1429
1430 1430 if (rdwr == S_EXEC) {
1431 1431 *addrp = (caddr_t)rp->r_pc;
1432 1432 return (4);
1433 1433 }
1434 1434
1435 1435 /*
1436 1436 * Fetch the instruction from user-level.
1437 1437 * We would like to assert this:
1438 1438 * ASSERT(USERMODE(rp->r_tstate));
1439 1439 * but we can't because we can reach this point from a
1440 1440 * register window underflow/overflow and the v9 wbuf
1441 1441 * traps call trap() with T_USER even though r_tstate
1442 1442 * indicates a system trap, not a user trap.
1443 1443 */
1444 1444 inst = fetch_user_instr((caddr_t)rp->r_pc);
1445 1445
1446 1446 op3 = (inst >> 19) & 0x3f;
1447 1447 rd = (inst >> 25) & 0x1f;
1448 1448 rs1 = (inst >> 14) & 0x1f;
1449 1449 rs2 = inst & 0x1f;
1450 1450 floatflg = (inst >> 24) & 1;
1451 1451 immflg = (inst >> 13) & 1;
1452 1452
1453 1453 /* if not load or store do nothing. can't happen? */
1454 1454 if ((inst >> 30) != 3)
1455 1455 return (0);
1456 1456
1457 1457 if (immflg)
1458 1458 asi = (uint_t)((rp->r_tstate >> TSTATE_ASI_SHIFT) &
1459 1459 TSTATE_ASI_MASK);
1460 1460 else
1461 1461 asi = (inst >> 5) & 0xff;
1462 1462
1463 1463 if (floatflg) {
1464 1464 /* check for ld/st alternate and highest defined V9 asi */
1465 1465 if ((op3 & 0x30) == 0x30 && asi > ASI_SNFL) {
1466 1466 sz = extended_asi_size(asi);
1467 1467 } else {
1468 1468 switch (op3 & 3) {
1469 1469 case 0:
1470 1470 sz = 4; /* ldf/stf/cas */
1471 1471 break;
1472 1472 case 1:
1473 1473 if (rd == 0)
1474 1474 sz = 4; /* ldfsr/stfsr */
1475 1475 else
1476 1476 sz = 8; /* ldxfsr/stxfsr */
1477 1477 break;
1478 1478 case 2:
1479 1479 if (op3 == 0x3e)
1480 1480 sz = 8; /* casx */
1481 1481 else
1482 1482 sz = 16; /* ldqf/stqf */
1483 1483 break;
1484 1484 case 3:
1485 1485 sz = 8; /* lddf/stdf */
1486 1486 break;
1487 1487 }
1488 1488 }
1489 1489 } else {
1490 1490 switch (op3 & 0xf) { /* map size bits to a number */
1491 1491 case 0: /* lduw */
1492 1492 case 4: /* stw */
1493 1493 case 8: /* ldsw */
1494 1494 case 0xf: /* swap */
1495 1495 sz = 4; break;
1496 1496 case 1: /* ldub */
1497 1497 case 5: /* stb */
1498 1498 case 9: /* ldsb */
1499 1499 case 0xd: /* ldstub */
1500 1500 sz = 1; break;
1501 1501 case 2: /* lduh */
1502 1502 case 6: /* sth */
1503 1503 case 0xa: /* ldsh */
1504 1504 sz = 2; break;
1505 1505 case 3: /* ldd */
1506 1506 case 7: /* std */
1507 1507 case 0xb: /* ldx */
1508 1508 case 0xe: /* stx */
1509 1509 sz = 8; break;
1510 1510 }
1511 1511 }
1512 1512
1513 1513 if (sz == 0) /* can't happen? */
1514 1514 return (0);
1515 1515 (void) flush_user_windows_to_stack(NULL);
1516 1516
1517 1517 if (getreg(rp, rs1, &val, &badaddr))
1518 1518 return (0);
1519 1519 addr = (caddr_t)val;
1520 1520
1521 1521 /* cas/casx don't use rs2 / simm13 to compute the address */
1522 1522 if ((op3 & 0x3d) != 0x3c) {
1523 1523 /* check immediate bit and use immediate field or reg (rs2) */
1524 1524 if (immflg) {
1525 1525 int imm;
1526 1526 imm = inst & 0x1fff; /* mask out immediate field */
1527 1527 imm <<= 19; /* sign extend it */
1528 1528 imm >>= 19;
1529 1529 addr += imm; /* compute address */
1530 1530 } else {
1531 1531 /*
1532 1532 * asi's in the 0xCx range are partial store
1533 1533 * instructions. For these, rs2 is a mask, not part of
1534 1534 * the address.
1535 1535 */
1536 1536 if (!(floatflg && (asi & 0xf0) == 0xc0)) {
1537 1537 if (getreg(rp, rs2, &val, &badaddr))
1538 1538 return (0);
1539 1539 addr += val;
1540 1540 }
1541 1541 }
1542 1542 }
1543 1543
1544 1544 /*
1545 1545 * If this is a 32-bit program, chop the address accordingly. The
1546 1546 * intermediate uintptr_t casts prevent warnings under a certain
1547 1547 * compiler, and the temporary 32 bit storage is intended to force
1548 1548 * proper code generation and break up what would otherwise be a
1549 1549 * quadruple cast.
1550 1550 */
1551 1551 if (curproc->p_model == DATAMODEL_ILP32) {
1552 1552 caddr32_t addr32 = (caddr32_t)(uintptr_t)addr;
1553 1553 addr = (caddr_t)(uintptr_t)addr32;
1554 1554 }
1555 1555
1556 1556 *addrp = addr;
1557 1557 ASSERT(sz != 0);
1558 1558 return (sz);
1559 1559 }
1560 1560
1561 1561 /*
1562 1562 * Fetch an instruction from user-level.
1563 1563 * Deal with watchpoints, if they are in effect.
1564 1564 */
1565 1565 int32_t
1566 1566 fetch_user_instr(caddr_t vaddr)
1567 1567 {
1568 1568 proc_t *p = curproc;
1569 1569 int32_t instr;
1570 1570
1571 1571 /*
1572 1572 * If this is a 32-bit program, chop the address accordingly. The
1573 1573 * intermediate uintptr_t casts prevent warnings under a certain
1574 1574 * compiler, and the temporary 32 bit storage is intended to force
1575 1575 * proper code generation and break up what would otherwise be a
1576 1576 * quadruple cast.
1577 1577 */
1578 1578 if (p->p_model == DATAMODEL_ILP32) {
1579 1579 caddr32_t vaddr32 = (caddr32_t)(uintptr_t)vaddr;
1580 1580 vaddr = (caddr_t)(uintptr_t)vaddr32;
1581 1581 }
1582 1582
1583 1583 if (fuword32_nowatch(vaddr, (uint32_t *)&instr) == -1)
1584 1584 instr = -1;
1585 1585
1586 1586 return (instr);
1587 1587 }
↓ open down ↓ |
443 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX