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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * General machine architecture & implementation specific
30 * assembly language routines.
31 */
32 #if defined(lint)
33 #include <sys/types.h>
34 #include <sys/machsystm.h>
35 #include <sys/t_lock.h>
36 #else /* lint */
37 #include "assym.h"
38 #endif /* lint */
39
40 #include <sys/asm_linkage.h>
41 #include <sys/async.h>
42 #include <sys/machthread.h>
43 #include <sys/vis.h>
44 #include <sys/machsig.h>
45
46 #if defined(lint)
47 caddr_t
48 set_trap_table(void)
49 {
50 return ((caddr_t)0);
51 }
52 #else /* lint */
53
54 ENTRY(set_trap_table)
55 set trap_table, %o1
56 rdpr %tba, %o0
57 wrpr %o1, %tba
58 retl
59 wrpr %g0, WSTATE_KERN, %wstate
60 SET_SIZE(set_trap_table)
61
62 #endif /* lint */
63
64 #if defined(lint)
65
66 /*ARGSUSED*/
67 void
68 stphys(uint64_t physaddr, int value)
69 {}
70
71 /*ARGSUSED*/
72 int
73 ldphys(uint64_t physaddr)
74 { return (0); }
75
76 /*ARGSUSED*/
77 void
78 stdphys(uint64_t physaddr, uint64_t value)
79 {}
80
81 /*ARGSUSED*/
82 uint64_t
83 lddphys(uint64_t physaddr)
84 { return (0x0ull); }
85
86 /* ARGSUSED */
87 void
88 stphysio(u_longlong_t physaddr, uint_t value)
89 {}
90
91 /* ARGSUSED */
92 uint_t
93 ldphysio(u_longlong_t physaddr)
94 { return(0); }
95
96 /* ARGSUSED */
97 void
98 sthphysio(u_longlong_t physaddr, ushort_t value)
99 {}
100
101 /* ARGSUSED */
102 ushort_t
103 ldhphysio(u_longlong_t physaddr)
104 { return(0); }
105
106 /* ARGSUSED */
107 void
108 stbphysio(u_longlong_t physaddr, uchar_t value)
109 {}
110
111 /* ARGSUSED */
112 uchar_t
113 ldbphysio(u_longlong_t physaddr)
114 { return(0); }
115
116 /*ARGSUSED*/
117 void
118 stdphysio(u_longlong_t physaddr, u_longlong_t value)
119 {}
120
121 /*ARGSUSED*/
122 u_longlong_t
123 lddphysio(u_longlong_t physaddr)
124 { return (0ull); }
125
126 #else
127
128 ! Store long word value at physical address
129 !
130 ! void stdphys(uint64_t physaddr, uint64_t value)
131 !
132 ENTRY(stdphys)
133 /*
134 * disable interrupts, clear Address Mask to access 64 bit physaddr
135 */
136 rdpr %pstate, %o4
137 andn %o4, PSTATE_IE | PSTATE_AM, %o5
138 wrpr %o5, 0, %pstate
139 stxa %o1, [%o0]ASI_MEM
140 retl
141 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
142 SET_SIZE(stdphys)
143
144
145 ! Store long word value at physical i/o address
146 !
147 ! void stdphysio(u_longlong_t physaddr, u_longlong_t value)
148 !
149 ENTRY(stdphysio)
150 /*
151 * disable interrupts, clear Address Mask to access 64 bit physaddr
152 */
153 rdpr %pstate, %o4
154 andn %o4, PSTATE_IE | PSTATE_AM, %o5
155 wrpr %o5, 0, %pstate ! clear IE, AM bits
156 stxa %o1, [%o0]ASI_IO
157 retl
158 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
159 SET_SIZE(stdphysio)
160
161
162 !
163 ! Load long word value at physical address
164 !
165 ! uint64_t lddphys(uint64_t physaddr)
166 !
167 ENTRY(lddphys)
168 rdpr %pstate, %o4
169 andn %o4, PSTATE_IE | PSTATE_AM, %o5
170 wrpr %o5, 0, %pstate
171 ldxa [%o0]ASI_MEM, %o0
172 retl
173 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
174 SET_SIZE(lddphys)
175
176 !
177 ! Load long word value at physical i/o address
178 !
179 ! unsigned long long lddphysio(u_longlong_t physaddr)
180 !
181 ENTRY(lddphysio)
182 rdpr %pstate, %o4
183 andn %o4, PSTATE_IE | PSTATE_AM, %o5
184 wrpr %o5, 0, %pstate ! clear IE, AM bits
185 ldxa [%o0]ASI_IO, %o0
186 retl
187 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
188 SET_SIZE(lddphysio)
189
190 !
191 ! Store value at physical address
192 !
193 ! void stphys(uint64_t physaddr, int value)
194 !
195 ENTRY(stphys)
196 rdpr %pstate, %o4
197 andn %o4, PSTATE_IE | PSTATE_AM, %o5
198 wrpr %o5, 0, %pstate
199 sta %o1, [%o0]ASI_MEM
200 retl
201 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
202 SET_SIZE(stphys)
203
204
205 !
206 ! load value at physical address
207 !
208 ! int ldphys(uint64_t physaddr)
209 !
210 ENTRY(ldphys)
211 rdpr %pstate, %o4
212 andn %o4, PSTATE_IE | PSTATE_AM, %o5
213 wrpr %o5, 0, %pstate
214 lda [%o0]ASI_MEM, %o0
215 srl %o0, 0, %o0 ! clear upper 32 bits
216 retl
217 wrpr %g0, %o4, %pstate ! restore earlier pstate register value
218 SET_SIZE(ldphys)
219
220 !
221 ! Store value into physical address in I/O space
222 !
223 ! void stphysio(u_longlong_t physaddr, uint_t value)
224 !
225 ENTRY_NP(stphysio)
226 rdpr %pstate, %o4 /* read PSTATE reg */
227 andn %o4, PSTATE_IE | PSTATE_AM, %o5
228 wrpr %o5, 0, %pstate
229 stwa %o1, [%o0]ASI_IO /* store value via bypass ASI */
230 retl
231 wrpr %g0, %o4, %pstate /* restore the PSTATE */
232 SET_SIZE(stphysio)
233
234 !
235 ! Store value into physical address in I/O space
236 !
237 ! void sthphysio(u_longlong_t physaddr, ushort_t value)
238 !
239 ENTRY_NP(sthphysio)
240 rdpr %pstate, %o4 /* read PSTATE reg */
241 andn %o4, PSTATE_IE | PSTATE_AM, %o5
242 wrpr %o5, 0, %pstate
243 stha %o1, [%o0]ASI_IO /* store value via bypass ASI */
244 retl
245 wrpr %g0, %o4, %pstate /* restore the PSTATE */
246 SET_SIZE(sthphysio)
247
248 !
249 ! Store value into one byte physical address in I/O space
250 !
251 ! void stbphysio(u_longlong_t physaddr, uchar_t value)
252 !
253 ENTRY_NP(stbphysio)
254 rdpr %pstate, %o4 /* read PSTATE reg */
255 andn %o4, PSTATE_IE | PSTATE_AM, %o5
256 wrpr %o5, 0, %pstate
257 stba %o1, [%o0]ASI_IO /* store byte via bypass ASI */
258 retl
259 wrpr %g0, %o4, %pstate /* restore the PSTATE */
260 SET_SIZE(stbphysio)
261
262 !
263 ! load value at physical address in I/O space
264 !
265 ! uint_t ldphysio(u_longlong_t physaddr)
266 !
267 ENTRY_NP(ldphysio)
268 rdpr %pstate, %o4 /* read PSTATE reg */
269 andn %o4, PSTATE_IE | PSTATE_AM, %o5
270 wrpr %o5, 0, %pstate
271 lduwa [%o0]ASI_IO, %o0 /* load value via bypass ASI */
272 retl
273 wrpr %g0, %o4, %pstate /* restore pstate */
274 SET_SIZE(ldphysio)
275
276 !
277 ! load value at physical address in I/O space
278 !
279 ! ushort_t ldhphysio(u_longlong_t physaddr)
280 !
281 ENTRY_NP(ldhphysio)
282 rdpr %pstate, %o4 /* read PSTATE reg */
283 andn %o4, PSTATE_IE | PSTATE_AM, %o5
284 wrpr %o5, 0, %pstate
285 lduha [%o0]ASI_IO, %o0 /* load value via bypass ASI */
286 retl
287 wrpr %g0, %o4, %pstate /* restore pstate */
288 SET_SIZE(ldhphysio)
289
290 !
291 ! load byte value at physical address in I/O space
292 !
293 ! uchar_t ldbphysio(u_longlong_t physaddr)
294 !
295 ENTRY_NP(ldbphysio)
296 rdpr %pstate, %o4 /* read PSTATE reg */
297 andn %o4, PSTATE_IE | PSTATE_AM, %o5
298 wrpr %o5, 0, %pstate
299 lduba [%o0]ASI_IO, %o0 /* load value via bypass ASI */
300 retl
301 wrpr %g0, %o4, %pstate /* restore pstate */
302 SET_SIZE(ldbphysio)
303 #endif /* lint */
304
305 /*
306 * save_gsr(kfpu_t *fp)
307 * Store the graphics status register
308 */
309
310 #if defined(lint) || defined(__lint)
311
312 /* ARGSUSED */
313 void
314 save_gsr(kfpu_t *fp)
315 {}
316
317 #else /* lint */
318
319 ENTRY_NP(save_gsr)
320 rd %gsr, %g2 ! save gsr
321 retl
322 stx %g2, [%o0 + FPU_GSR]
323 SET_SIZE(save_gsr)
324
325 #endif /* lint */
326
327 #if defined(lint) || defined(__lint)
328
329 /* ARGSUSED */
330 void
331 restore_gsr(kfpu_t *fp)
332 {}
333
334 #else /* lint */
335
336 ENTRY_NP(restore_gsr)
337 ldx [%o0 + FPU_GSR], %g2
338 wr %g2, %g0, %gsr
339 retl
340 nop
341 SET_SIZE(restore_gsr)
342
343 #endif /* lint */
344
345 /*
346 * uint64_t
347 * _fp_read_pgsr()
348 * Get the graphics status register info from fp and return it
349 */
350
351 #if defined(lint) || defined(__lint)
352
353 /* ARGSUSED */
354 uint64_t
355 _fp_read_pgsr(kfpu_t *fp)
356 { return 0; }
357
358 #else /* lint */
359
360 ENTRY_NP(_fp_read_pgsr)
361 retl
362 rd %gsr, %o0
363 SET_SIZE(_fp_read_pgsr)
364
365 #endif /* lint */
366
367
368 /*
369 * uint64_t
370 * get_gsr(kfpu_t *fp)
371 * Get the graphics status register info from fp and return it
372 */
373
374 #if defined(lint) || defined(__lint)
375
376 /* ARGSUSED */
377 uint64_t
378 get_gsr(kfpu_t *fp)
379 { return 0; }
380
381 #else /* lint */
382
383 ENTRY_NP(get_gsr)
384 retl
385 ldx [%o0 + FPU_GSR], %o0
386 SET_SIZE(get_gsr)
387
388 #endif
389
390 /*
391 * _fp_write_pgsr(uint64_t *buf, kfpu_t *fp)
392 * Set the graphics status register info to fp from buf
393 */
394
395 #if defined(lint) || defined(__lint)
396
397 /* ARGSUSED */
398 void
399 _fp_write_pgsr(uint64_t buf, kfpu_t *fp)
400 {}
401
402 #else /* lint */
403
404 ENTRY_NP(_fp_write_pgsr)
405 retl
406 mov %o0, %gsr
407 SET_SIZE(_fp_write_pgsr)
408
409 #endif /* lint */
410
411 /*
412 * set_gsr(uint64_t buf, kfpu_t *fp)
413 * Set the graphics status register info to fp from buf
414 */
415
416 #if defined(lint) || defined(__lint)
417
418 /* ARGSUSED */
419 void
420 set_gsr(uint64_t buf, kfpu_t *fp)
421 {}
422
423 #else /* lint */
424
425 ENTRY_NP(set_gsr)
426 retl
427 stx %o0, [%o1 + FPU_GSR]
428 SET_SIZE(set_gsr)
429
430 #endif /* lint */
431
432 #if defined(lint) || defined(__lint)
433 void
434 kdi_cpu_index(void)
435 {
436 }
437
438 #else /* lint */
439
440 ENTRY_NP(kdi_cpu_index)
441 CPU_INDEX(%g1, %g2)
442 jmp %g7
443 nop
444 SET_SIZE(kdi_cpu_index)
445
446 #endif /* lint */
447
448 #if defined(lint) || defined(__lint)
449 void
450 kmdb_enter(void)
451 {
452 }
453
454 #else /* lint */
455
456 ENTRY_NP(kmdb_enter)
457 t ST_KMDB_TRAP
458 retl
459 nop
460 SET_SIZE(kmdb_enter)
461
462 #endif /* lint */
463
464 /*
465 * The Spitfire floating point code has been changed not to use install/
466 * save/restore/fork/freectx() because of the special memcpy library
467 * routines, which will lose too much performance if they have to go
468 * through the fp_disabled trap (which used to call installctx()). So
469 * now fp_save/fp_restore are called from resume, and they don't care
470 * whether floating point was enabled from the user program via the
471 * fp_enabled trap or from the memcpy library, which just turns on floating
472 * point in the fprs register itself. The new routine lwp_freeregs is
473 * called everywhere freectx is called, and code was added to the sun4u-
474 * specific version of lwp_forkregs (which is called everywhere forkctx
475 * is called) to handle forking the floating point registers.
476 *
477 * Note that for the fprs dirty upper/lower bits are not used for now,
478 * because the #instructions to determine if we need to use them is probably
479 * greater than the #insructions just using them. This is a possible future
480 * optimization, only do it with very careful benchmarking!
481 *
482 * The fp_fksave and and fp_load were split into two routines for the
483 * sake of efficiency between the getfpregs/xregs_getfpregs and
484 * setfpregs/xregs_setfpregs. But note that for saving and restoring
485 * context, both *must* happen. For prmachdep, aka access from [k]adb,
486 * it's OK if only one part happens.
487 */
488
489 /*
490 * fp_save(kfpu_t *fp)
491 * fp_fksave(kfpu_t *fp)
492 * Store the floating point registers.
493 */
494
495 #if defined(lint) || defined(__lint)
496
497 /* ARGSUSED */
498 void
499 fp_save(kfpu_t *fp)
500 {}
501
502 /* ARGSUSED */
503 void
504 fp_fksave(kfpu_t *fp)
505 {}
506
507 #else /* lint */
508
509 ENTRY_NP(fp_save)
510 ALTENTRY(fp_fksave)
511 BSTORE_FPREGS(%o0, %o1) ! store V9 regs
512 retl
513 stx %fsr, [%o0 + FPU_FSR] ! store fsr
514 SET_SIZE(fp_fksave)
515 SET_SIZE(fp_save)
516
517 #endif /* lint */
518
519 /*
520 * fp_v8_fksave(kfpu_t *fp)
521 *
522 * This is like the above routine but only saves the lower half.
523 */
524
525 #if defined(lint) || defined(__lint)
526
527 /* ARGSUSED */
528 void
529 fp_v8_fksave(kfpu_t *fp)
530 {}
531
532 #else /* lint */
533
534 ENTRY_NP(fp_v8_fksave)
535 BSTORE_V8_FPREGS(%o0, %o1) ! store V8 regs
536 retl
537 stx %fsr, [%o0 + FPU_FSR] ! store fsr
538 SET_SIZE(fp_v8_fksave)
539
540 #endif /* lint */
541
542 /*
543 * fp_v8p_fksave(kfpu_t *fp)
544 *
545 * This is like the above routine but only saves the upper half.
546 */
547
548 #if defined(lint) || defined(__lint)
549
550 /* ARGSUSED */
551 void
552 fp_v8p_fksave(kfpu_t *fp)
553 {}
554
555 #else /* lint */
556
557 ENTRY_NP(fp_v8p_fksave)
558 BSTORE_V8P_FPREGS(%o0, %o1) ! store V9 extra regs
559 retl
560 stx %fsr, [%o0 + FPU_FSR] ! store fsr
561 SET_SIZE(fp_v8p_fksave)
562
563 #endif /* lint */
564
565 /*
566 * fp_restore(kfpu_t *fp)
567 */
568
569 #if defined(lint) || defined(__lint)
570
571 /* ARGSUSED */
572 void
573 fp_restore(kfpu_t *fp)
574 {}
575
576 #else /* lint */
577
578 ENTRY_NP(fp_restore)
579 BLOAD_FPREGS(%o0, %o1) ! load V9 regs
580 retl
581 ldx [%o0 + FPU_FSR], %fsr ! restore fsr
582 SET_SIZE(fp_restore)
583
584 #endif /* lint */
585
586 /*
587 * fp_v8_load(kfpu_t *fp)
588 */
589
590 #if defined(lint) || defined(__lint)
591
592 /* ARGSUSED */
593 void
594 fp_v8_load(kfpu_t *fp)
595 {}
596
597 #else /* lint */
598
599 ENTRY_NP(fp_v8_load)
600 BLOAD_V8_FPREGS(%o0, %o1) ! load V8 regs
601 retl
602 ldx [%o0 + FPU_FSR], %fsr ! restore fsr
603 SET_SIZE(fp_v8_load)
604
605 #endif /* lint */
606
607 /*
608 * fp_v8p_load(kfpu_t *fp)
609 */
610
611 #if defined(lint) || defined(__lint)
612
613 /* ARGSUSED */
614 void
615 fp_v8p_load(kfpu_t *fp)
616 {}
617
618 #else /* lint */
619
620 ENTRY_NP(fp_v8p_load)
621 BLOAD_V8P_FPREGS(%o0, %o1) ! load V9 extra regs
622 retl
623 ldx [%o0 + FPU_FSR], %fsr ! restore fsr
624 SET_SIZE(fp_v8p_load)
625
626 #endif /* lint */