xref: /illumos-gate/usr/src/uts/sun4/ml/subr_asm.S (revision b3385a702fe5f8caba5ad4c451836514efff0bfa)
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/*
27 * General machine architecture & implementation specific
28 * assembly language routines.
29 */
30#include "assym.h"
31
32#include <sys/asm_linkage.h>
33#include <sys/async.h>
34#include <sys/machthread.h>
35#include <sys/vis.h>
36#include <sys/machsig.h>
37
38	ENTRY(set_trap_table)
39	set	trap_table, %o1
40	rdpr	%tba, %o0
41	wrpr	%o1, %tba
42	retl
43	wrpr	%g0, WSTATE_KERN, %wstate
44	SET_SIZE(set_trap_table)
45
46	! Store long word value at physical address
47	!
48	! void  stdphys(uint64_t physaddr, uint64_t value)
49	!
50	ENTRY(stdphys)
51	/*
52	 * disable interrupts, clear Address Mask to access 64 bit physaddr
53	 */
54	rdpr	%pstate, %o4
55	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
56	wrpr	%o5, 0, %pstate
57	stxa	%o1, [%o0]ASI_MEM
58	retl
59	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
60	SET_SIZE(stdphys)
61
62
63	! Store long word value at physical i/o address
64	!
65	! void  stdphysio(u_longlong_t physaddr, u_longlong_t value)
66	!
67	ENTRY(stdphysio)
68	/*
69	 * disable interrupts, clear Address Mask to access 64 bit physaddr
70	 */
71	rdpr	%pstate, %o4
72	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
73	wrpr	%o5, 0, %pstate		! clear IE, AM bits
74	stxa	%o1, [%o0]ASI_IO
75	retl
76	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
77	SET_SIZE(stdphysio)
78
79
80	!
81	! Load long word value at physical address
82	!
83	! uint64_t lddphys(uint64_t physaddr)
84	!
85	ENTRY(lddphys)
86	rdpr	%pstate, %o4
87	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
88	wrpr	%o5, 0, %pstate
89	ldxa	[%o0]ASI_MEM, %o0
90	retl
91	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
92	SET_SIZE(lddphys)
93
94	!
95	! Load long word value at physical i/o address
96	!
97	! unsigned long long lddphysio(u_longlong_t physaddr)
98	!
99	ENTRY(lddphysio)
100	rdpr	%pstate, %o4
101	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
102	wrpr	%o5, 0, %pstate	! clear IE, AM bits
103	ldxa	[%o0]ASI_IO, %o0
104	retl
105	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
106	SET_SIZE(lddphysio)
107
108	!
109	! Store value at physical address
110	!
111	! void  stphys(uint64_t physaddr, int value)
112	!
113	ENTRY(stphys)
114	rdpr	%pstate, %o4
115	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
116	wrpr	%o5, 0, %pstate
117	sta	%o1, [%o0]ASI_MEM
118	retl
119	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
120	SET_SIZE(stphys)
121
122
123	!
124	! load value at physical address
125	!
126	! int   ldphys(uint64_t physaddr)
127	!
128	ENTRY(ldphys)
129	rdpr	%pstate, %o4
130	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
131	wrpr	%o5, 0, %pstate
132	lda	[%o0]ASI_MEM, %o0
133	srl	%o0, 0, %o0	! clear upper 32 bits
134	retl
135	wrpr	%g0, %o4, %pstate	! restore earlier pstate register value
136	SET_SIZE(ldphys)
137
138	!
139	! Store value into physical address in I/O space
140	!
141	! void stphysio(u_longlong_t physaddr, uint_t value)
142	!
143	ENTRY_NP(stphysio)
144	rdpr	%pstate, %o4		/* read PSTATE reg */
145	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
146	wrpr	%o5, 0, %pstate
147	stwa	%o1, [%o0]ASI_IO	/* store value via bypass ASI */
148	retl
149	wrpr	%g0, %o4, %pstate	/* restore the PSTATE */
150	SET_SIZE(stphysio)
151
152	!
153	! Store value into physical address in I/O space
154	!
155	! void sthphysio(u_longlong_t physaddr, ushort_t value)
156	!
157	ENTRY_NP(sthphysio)
158	rdpr	%pstate, %o4		/* read PSTATE reg */
159	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
160	wrpr	%o5, 0, %pstate
161	stha	%o1, [%o0]ASI_IO	/* store value via bypass ASI */
162	retl
163	wrpr	%g0, %o4, %pstate		/* restore the PSTATE */
164	SET_SIZE(sthphysio)
165
166	!
167	! Store value into one byte physical address in I/O space
168	!
169	! void stbphysio(u_longlong_t physaddr, uchar_t value)
170	!
171	ENTRY_NP(stbphysio)
172	rdpr	%pstate, %o4		/* read PSTATE reg */
173	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
174	wrpr	%o5, 0, %pstate
175	stba	%o1, [%o0]ASI_IO	/* store byte via bypass ASI */
176	retl
177	wrpr	%g0, %o4, %pstate	/* restore the PSTATE */
178	SET_SIZE(stbphysio)
179
180	!
181	! load value at physical address in I/O space
182	!
183	! uint_t   ldphysio(u_longlong_t physaddr)
184	!
185	ENTRY_NP(ldphysio)
186	rdpr	%pstate, %o4		/* read PSTATE reg */
187	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
188	wrpr	%o5, 0, %pstate
189	lduwa	[%o0]ASI_IO, %o0	/* load value via bypass ASI */
190	retl
191	wrpr	%g0, %o4, %pstate	/* restore pstate */
192	SET_SIZE(ldphysio)
193
194	!
195	! load value at physical address in I/O space
196	!
197	! ushort_t   ldhphysio(u_longlong_t physaddr)
198	!
199	ENTRY_NP(ldhphysio)
200	rdpr	%pstate, %o4		/* read PSTATE reg */
201	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
202	wrpr	%o5, 0, %pstate
203	lduha	[%o0]ASI_IO, %o0	/* load value via bypass ASI */
204	retl
205	wrpr	%g0, %o4, %pstate	/* restore pstate */
206	SET_SIZE(ldhphysio)
207
208	!
209	! load byte value at physical address in I/O space
210	!
211	! uchar_t   ldbphysio(u_longlong_t physaddr)
212	!
213	ENTRY_NP(ldbphysio)
214	rdpr	%pstate, %o4		/* read PSTATE reg */
215	andn	%o4, PSTATE_IE | PSTATE_AM, %o5
216	wrpr	%o5, 0, %pstate
217	lduba	[%o0]ASI_IO, %o0	/* load value via bypass ASI */
218	retl
219	wrpr	%g0, %o4, %pstate	/* restore pstate */
220	SET_SIZE(ldbphysio)
221
222/*
223 * save_gsr(kfpu_t *fp)
224 * Store the graphics status register
225 */
226
227	ENTRY_NP(save_gsr)
228	rd	%gsr, %g2			! save gsr
229	retl
230	stx	%g2, [%o0 + FPU_GSR]
231	SET_SIZE(save_gsr)
232
233	ENTRY_NP(restore_gsr)
234	ldx	[%o0 + FPU_GSR], %g2
235	wr	%g2, %g0, %gsr
236	retl
237	nop
238	SET_SIZE(restore_gsr)
239
240/*
241 * uint64_t
242 * _fp_read_pgsr()
243 * Get the graphics status register info from fp and return it
244 */
245
246	ENTRY_NP(_fp_read_pgsr)
247	retl
248	rd	%gsr, %o0
249	SET_SIZE(_fp_read_pgsr)
250
251
252/*
253 * uint64_t
254 * get_gsr(kfpu_t *fp)
255 * Get the graphics status register info from fp and return it
256 */
257
258	ENTRY_NP(get_gsr)
259	retl
260	ldx	[%o0 + FPU_GSR], %o0
261	SET_SIZE(get_gsr)
262
263/*
264 * _fp_write_pgsr(uint64_t *buf, kfpu_t *fp)
265 * Set the graphics status register info to fp from buf
266 */
267
268	ENTRY_NP(_fp_write_pgsr)
269	retl
270	mov	%o0, %gsr
271	SET_SIZE(_fp_write_pgsr)
272
273/*
274 * set_gsr(uint64_t buf, kfpu_t *fp)
275 * Set the graphics status register info to fp from buf
276 */
277
278	ENTRY_NP(set_gsr)
279	retl
280	stx	%o0, [%o1 + FPU_GSR]
281	SET_SIZE(set_gsr)
282
283	ENTRY_NP(kdi_cpu_index)
284	CPU_INDEX(%g1, %g2)
285	jmp	%g7
286	nop
287	SET_SIZE(kdi_cpu_index)
288
289	ENTRY_NP(kmdb_enter)
290	t	ST_KMDB_TRAP
291	retl
292	nop
293	SET_SIZE(kmdb_enter)
294
295/*
296 * The Spitfire floating point code has been changed not to use install/
297 * save/restore/fork/freectx() because of the special memcpy library
298 * routines, which will lose too much performance if they have to go
299 * through the fp_disabled trap (which used to call ctxop_install()). So
300 * now fp_save/fp_restore are called from resume, and they don't care
301 * whether floating point was enabled from the user program via the
302 * fp_enabled trap or from the memcpy library, which just turns on floating
303 * point in the fprs register itself. The new routine lwp_freeregs is
304 * called everywhere freectx is called, and code was added to the sun4u-
305 * specific version of lwp_forkregs (which is called everywhere forkctx
306 * is called) to handle forking the floating point registers.
307 *
308 * Note that for the fprs dirty upper/lower bits are not used for now,
309 * because the #instructions to determine if we need to use them is probably
310 * greater than the #insructions just using them. This is a possible future
311 * optimization, only do it with very careful benchmarking!
312 *
313 * The fp_fksave and and fp_load were split into two routines for the
314 * sake of efficiency between the getfpregs/xregs_getfpregs and
315 * setfpregs/xregs_setfpregs. But note that for saving and restoring
316 * context, both *must* happen. For prmachdep, aka access from [k]adb,
317 * it's OK if only one part happens.
318 */
319
320/*
321 * fp_save(kfpu_t *fp)
322 * fp_fksave(kfpu_t *fp)
323 * Store the floating point registers.
324 */
325
326	ENTRY_NP(fp_save)
327	ALTENTRY(fp_fksave)
328	BSTORE_FPREGS(%o0, %o1)			! store V9 regs
329	retl
330	stx	%fsr, [%o0 + FPU_FSR]		! store fsr
331	SET_SIZE(fp_fksave)
332	SET_SIZE(fp_save)
333
334/*
335 * fp_v8_fksave(kfpu_t *fp)
336 *
337 * This is like the above routine but only saves the lower half.
338 */
339
340	ENTRY_NP(fp_v8_fksave)
341	BSTORE_V8_FPREGS(%o0, %o1)		! store V8 regs
342	retl
343	stx	%fsr, [%o0 + FPU_FSR]		! store fsr
344	SET_SIZE(fp_v8_fksave)
345
346/*
347 * fp_v8p_fksave(kfpu_t *fp)
348 *
349 * This is like the above routine but only saves the upper half.
350 */
351
352	ENTRY_NP(fp_v8p_fksave)
353	BSTORE_V8P_FPREGS(%o0, %o1)		! store V9 extra regs
354	retl
355	stx	%fsr, [%o0 + FPU_FSR]		! store fsr
356	SET_SIZE(fp_v8p_fksave)
357
358/*
359 * fp_restore(kfpu_t *fp)
360 */
361
362	ENTRY_NP(fp_restore)
363	BLOAD_FPREGS(%o0, %o1)			! load V9 regs
364	retl
365	ldx	[%o0 + FPU_FSR], %fsr		! restore fsr
366	SET_SIZE(fp_restore)
367
368/*
369 * fp_v8_load(kfpu_t *fp)
370 */
371
372	ENTRY_NP(fp_v8_load)
373	BLOAD_V8_FPREGS(%o0, %o1)		! load V8 regs
374	retl
375	ldx	[%o0 + FPU_FSR], %fsr		! restore fsr
376	SET_SIZE(fp_v8_load)
377
378/*
379 * fp_v8p_load(kfpu_t *fp)
380 */
381
382	ENTRY_NP(fp_v8p_load)
383	BLOAD_V8P_FPREGS(%o0, %o1)		! load V9 extra regs
384	retl
385	ldx	[%o0 + FPU_FSR], %fsr		! restore fsr
386	SET_SIZE(fp_v8p_load)
387
388