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)
47caddr_t
48set_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*/
67void
68stphys(uint64_t physaddr, int value)
69{}
70
71/*ARGSUSED*/
72int
73ldphys(uint64_t physaddr)
74{ return (0); }
75
76/*ARGSUSED*/
77void
78stdphys(uint64_t physaddr, uint64_t value)
79{}
80
81/*ARGSUSED*/
82uint64_t
83lddphys(uint64_t physaddr)
84{ return (0x0ull); }
85
86/* ARGSUSED */
87void
88stphysio(u_longlong_t physaddr, uint_t value)
89{}
90
91/* ARGSUSED */
92uint_t
93ldphysio(u_longlong_t physaddr)
94{ return(0); }
95
96/* ARGSUSED */
97void
98sthphysio(u_longlong_t physaddr, ushort_t value)
99{}
100
101/* ARGSUSED */
102ushort_t
103ldhphysio(u_longlong_t physaddr)
104{ return(0); }
105
106/* ARGSUSED */
107void
108stbphysio(u_longlong_t physaddr, uchar_t value)
109{}
110
111/* ARGSUSED */
112uchar_t
113ldbphysio(u_longlong_t physaddr)
114{ return(0); }
115
116/*ARGSUSED*/
117void
118stdphysio(u_longlong_t physaddr, u_longlong_t value)
119{}
120
121/*ARGSUSED*/
122u_longlong_t
123lddphysio(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 */
313void
314save_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 */
330void
331restore_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 */
354uint64_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 */
377uint64_t
378get_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 */
398void
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 */
419void
420set_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)
433void
434kdi_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)
449void
450kmdb_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 */
498void
499fp_save(kfpu_t *fp)
500{}
501
502/* ARGSUSED */
503void
504fp_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 */
528void
529fp_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 */
551void
552fp_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 */
572void
573fp_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 */
593void
594fp_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 */
614void
615fp_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 */
627