xref: /titanic_52/usr/src/uts/sun4u/ml/mach_subr_asm.s (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
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 2006 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/t_lock.h>
35#else	/* lint */
36#include "assym.h"
37#endif	/* lint */
38
39#include <sys/asm_linkage.h>
40#include <sys/machsystm.h>
41#include <sys/machthread.h>
42#include <sys/privregs.h>
43#include <sys/cmpregs.h>
44#include <sys/clock.h>
45#include <sys/fpras.h>
46
47#if defined(lint)
48
49/*ARGSUSED*/
50int
51getprocessorid(void)
52{ return (0); }
53
54#else	/* lint */
55
56/*
57 * Get the processor ID.
58 * === MID reg as specified in 15dec89 sun4u spec, sec 5.4.3
59 */
60
61	ENTRY(getprocessorid)
62	CPU_INDEX(%o0, %o1)
63	retl
64	nop
65	SET_SIZE(getprocessorid)
66
67#endif	/* lint */
68
69#if defined(lint)
70/*ARGSUSED*/
71void
72set_error_enable_tl1(uint64_t neer, uint64_t action)
73{}
74
75/* ARGSUSED */
76void
77set_error_enable(uint64_t neer)
78{}
79
80uint64_t
81get_error_enable()
82{
83	return ((uint64_t)0);
84}
85#else /* lint */
86
87	ENTRY(set_error_enable_tl1)
88	cmp	%g2, EER_SET_ABSOLUTE
89	be	%xcc, 1f
90	  nop
91	ldxa	[%g0]ASI_ESTATE_ERR, %g3
92	membar	#Sync
93	cmp	%g2, EER_SET_SETBITS
94	be,a	%xcc, 1f
95	  or	%g3, %g1, %g1
96	andn	%g3, %g1, %g1			/* EER_SET_CLRBITS */
971:
98	stxa	%g1, [%g0]ASI_ESTATE_ERR	/* ecache error enable reg */
99	membar	#Sync
100	retry
101	SET_SIZE(set_error_enable_tl1)
102
103	ENTRY(set_error_enable)
104	stxa	%o0, [%g0]ASI_ESTATE_ERR	/* ecache error enable reg */
105	membar	#Sync
106	retl
107	nop
108	SET_SIZE(set_error_enable)
109
110	ENTRY(get_error_enable)
111	retl
112	ldxa	[%g0]ASI_ESTATE_ERR, %o0	/* ecache error enable reg */
113	SET_SIZE(get_error_enable)
114
115#endif /* lint */
116
117#if defined(lint)
118void
119get_asyncflt(uint64_t *afsr)
120{
121	afsr = afsr;
122}
123#else /* lint */
124
125	ENTRY(get_asyncflt)
126	ldxa	[%g0]ASI_AFSR, %o1		! afsr reg
127	retl
128	stx	%o1, [%o0]
129	SET_SIZE(get_asyncflt)
130
131#endif /* lint */
132
133#if defined(lint)
134void
135set_asyncflt(uint64_t afsr)
136{
137	afsr = afsr;
138}
139#else /* lint */
140
141	ENTRY(set_asyncflt)
142	stxa	%o0, [%g0]ASI_AFSR		! afsr reg
143	membar	#Sync
144	retl
145	nop
146	SET_SIZE(set_asyncflt)
147
148#endif /* lint */
149
150#if defined(lint)
151void
152get_asyncaddr(uint64_t *afar)
153{
154	afar = afar;
155}
156#else /* lint */
157
158	ENTRY(get_asyncaddr)
159	ldxa	[%g0]ASI_AFAR, %o1		! afar reg
160	retl
161	stx	%o1, [%o0]
162	SET_SIZE(get_asyncaddr)
163
164#endif /* lint */
165
166#if defined(lint) || defined(__lint)
167
168/* ARGSUSED */
169hrtime_t
170tick2ns(hrtime_t tick, uint_t cpuid)
171{ return 0; }
172
173#else	/* lint */
174
175	ENTRY_NP(tick2ns)
176	sethi	%hi(cpunodes), %o4
177	or	%o4, %lo(cpunodes), %o4		! %o4 = &cpunodes
178	! Register usage:
179	!
180	! o0 = timestamp
181	! o2 = byte offset into cpunodes for tick_nsec_scale of this CPU
182	! o4 = &cpunodes
183	!
184	mulx	%o1, CPU_NODE_SIZE, %o2	! %o2 = byte offset into cpunodes
185	add	%o2, TICK_NSEC_SCALE, %o2
186	ld	[%o4 + %o2], %o2	! %o2 = cpunodes[cpuid].tick_nsec_scale
187	NATIVE_TIME_TO_NSEC_SCALE(%o0, %o2, %o3, TICK_NSEC_SHIFT)
188	retl
189	nop
190	SET_SIZE(tick2ns)
191
192#endif  /* lint */
193
194#if defined(lint)
195
196/* ARGSUSED */
197void
198set_cmp_error_steering(void)
199{}
200
201#else	/* lint */
202
203	ENTRY(set_cmp_error_steering)
204	membar	#Sync
205	set	ASI_CORE_ID, %o0		! %o0 = ASI_CORE_ID
206	ldxa	[%o0]ASI_CMP_PER_CORE, %o0	! get ASI_CORE_ID
207	and	%o0, COREID_MASK, %o0
208	set	ASI_CMP_ERROR_STEERING, %o1	! %o1 = ERROR_STEERING_REG
209	stxa	%o0, [%o1]ASI_CMP_SHARED	! this core now hadles
210	membar	#Sync				!  non-core specific errors
211	retl
212	nop
213	SET_SIZE(set_cmp_error_steering)
214
215#endif	/* lint */
216
217#if defined(lint)
218
219/* ARGSUSED */
220uint64_t
221ultra_getver(void)
222{
223	return (0);
224}
225
226#else /* lint */
227
228	ENTRY(ultra_getver)
229	retl
230	rdpr	%ver, %o0
231	SET_SIZE(ultra_getver)
232
233#endif /* lint */
234
235#if defined(lint)
236
237int
238fpras_chkfn_type1(void)
239{ return 0; }
240
241#else	/* lint */
242
243	/*
244	 * Check instructions using just the AX pipelines, designed by
245	 * C.B. Liaw of PNP.
246	 *
247	 * This function must match a struct fpras_chkfn and must be
248	 * block aligned.  A zero return means all was well.  These
249	 * instructions are chosen to be sensitive to bit corruptions
250	 * on the fpras rewrite, so if a bit corruption still produces
251	 * a valid instruction we should still get an incorrect result
252	 * here.  This function is never called directly - it is copied
253	 * into per-cpu and per-operation buffers;  it must therefore
254	 * be absolutely position independent.  If an illegal instruction
255	 * is encountered then the trap handler trampolines to the final
256	 * three instructions of this function.
257	 *
258	 * We want two instructions that are complements of one another,
259	 * and which can perform a calculation with a known result.
260	 *
261	 * SETHI:
262	 *
263	 * | 0 0 |  rd   | 1 0 0 |	imm22				|
264	 *  31 30 29   25 24   22 21				       0
265	 *
266	 * ADDCCC with two source registers:
267	 *
268	 * | 1 0 |  rd   | 0 1 1   0 0 0 |  rs1  | 0 |	   -	|  rs2  |
269	 *  31 30 29   25 24           19 18   14 13  12       5 4     0
270	 *
271	 * We can choose rd and imm2 of the SETHI and rd, rs1 and rs2 of
272	 * the ADDCCC to obtain instructions that are complements in all but
273	 * bit 30.
274	 *
275	 * Registers are numbered as follows:
276	 *
277	 * r[31]	%i7
278	 * r[30]	%i6
279	 * r[29]	%i5
280	 * r[28]	%i4
281	 * r[27]	%i3
282	 * r[26]	%i2
283	 * r[25]	%i1
284	 * r[24]	%i0
285	 * r[23]	%l7
286	 * r[22]	%l6
287	 * r[21]	%l5
288	 * r[20]	%l4
289	 * r[19]	%l3
290	 * r[18]	%l2
291	 * r[17]	%l1
292	 * r[16]	%l0
293	 * r[15]	%o7
294	 * r[14]	%o6
295	 * r[13]	%o5
296	 * r[12]	%o4
297	 * r[11]	%o3
298	 * r[10]	%o2
299	 * r[9]		%o1
300	 * r[8]		%o0
301	 * r[7]		%g7
302	 * r[6]		%g6
303	 * r[5]		%g5
304	 * r[4]		%g4
305	 * r[3]		%g3
306	 * r[2]		%g2
307	 * r[1]		%g1
308	 * r[0]		%g0
309	 *
310	 * For register r[n], register r[31-n] is the complement.  We must
311	 * avoid use of %i6/%i7 and %o6/%o7 as well as %g7.  Clearly we need
312	 * to use a local or input register as one half of the pair, which
313	 * requires us to obtain our own register window or take steps
314	 * to preserve any local or input we choose to use.  We choose
315	 * %o1 as rd for the SETHI, so rd of the ADDCCC must be %l6.
316	 * We'll use %o1 as rs1 and %l6 as rs2 of the ADDCCC, which then
317	 * requires that imm22 be 0b111 10110 1 11111111 01001 or 0x3dbfe9,
318	 * or %hi(0xf6ffa400).  This determines the value of the constant
319	 * CBV2 below.
320	 *
321	 * The constant CBV1 is chosen such that an initial subcc %g0, CBV1
322	 * will set the carry bit and every addccc thereafter will continue
323	 * to generate a carry.  Other values are possible for CBV1 - this
324	 * is just one that works this way.
325	 *
326	 * Finally CBV3 is the expected answer when we perform our repeated
327	 * calculations on CBV1 and CBV2 - it is not otherwise specially
328	 * derived.  If this result is not obtained then a corruption has
329	 * occured during the FPRAS_REWRITE of one of the two blocks of
330	 * 16 instructions.  A corruption could also result in an illegal
331	 * instruction or other unexpected trap - we catch illegal
332	 * instruction traps in the PC range and trampoline to the
333	 * last instructions of the function to return a failure indication.
334	 *
335	 */
336
337#define	CBV1		0xc11
338#define	CBV2		0xf6ffa400
339#define	CBV3		0x66f9d800
340#define	CBR1		%o1
341#define	CBR2		%l6
342#define	CBO2		%o2
343#define	SETHI_CBV2_CBR1		sethi %hi(CBV2), CBR1
344#define	ADDCCC_CBR1_CBR2_CBR2	addccc CBR1, CBR2, CBR2
345
346	.align	64
347	ENTRY_NP(fpras_chkfn_type1)
348	mov	CBR2, CBO2		! 1, preserve CBR2 of (callers) window
349	mov	FPRAS_OK, %o0		! 2, default return value
350	ba,pt	%icc, 1f		! 3
351	  subcc %g0, CBV1, CBR2		! 4
352					! 5 - 16
353	.align	64
3541:	SETHI_CBV2_CBR1			! 1
355	ADDCCC_CBR1_CBR2_CBR2		! 2
356	SETHI_CBV2_CBR1			! 3
357	ADDCCC_CBR1_CBR2_CBR2		! 4
358	SETHI_CBV2_CBR1			! 5
359	ADDCCC_CBR1_CBR2_CBR2		! 6
360	SETHI_CBV2_CBR1			! 7
361	ADDCCC_CBR1_CBR2_CBR2		! 8
362	SETHI_CBV2_CBR1			! 9
363	ADDCCC_CBR1_CBR2_CBR2		! 10
364	SETHI_CBV2_CBR1			! 11
365	ADDCCC_CBR1_CBR2_CBR2		! 12
366	SETHI_CBV2_CBR1			! 13
367	ADDCCC_CBR1_CBR2_CBR2		! 14
368	SETHI_CBV2_CBR1			! 15
369	ADDCCC_CBR1_CBR2_CBR2		! 16
370
371	ADDCCC_CBR1_CBR2_CBR2		! 1
372	SETHI_CBV2_CBR1			! 2
373	ADDCCC_CBR1_CBR2_CBR2		! 3
374	SETHI_CBV2_CBR1			! 4
375	ADDCCC_CBR1_CBR2_CBR2		! 5
376	SETHI_CBV2_CBR1			! 6
377	ADDCCC_CBR1_CBR2_CBR2		! 7
378	SETHI_CBV2_CBR1			! 8
379	ADDCCC_CBR1_CBR2_CBR2		! 9
380	SETHI_CBV2_CBR1			! 10
381	ADDCCC_CBR1_CBR2_CBR2		! 11
382	SETHI_CBV2_CBR1			! 12
383	ADDCCC_CBR1_CBR2_CBR2		! 13
384	SETHI_CBV2_CBR1			! 14
385	ADDCCC_CBR1_CBR2_CBR2		! 15
386	SETHI_CBV2_CBR1			! 16
387
388	addc	CBR1, CBR2, CBR2	! 1
389	sethi	%hi(CBV3), CBR1		! 2
390	cmp	CBR1, CBR2		! 3
391	movnz	%icc, FPRAS_BADCALC, %o0! 4, how detected
392	retl				! 5
393	  mov	CBO2, CBR2		! 6, restore borrowed register
394	.skip 4*(13-7+1)		! 7 - 13
395					!
396					! illegal instr'n trap comes here
397					!
398	mov	CBO2, CBR2		! 14, restore borrowed register
399	retl				! 15
400	  mov	FPRAS_BADTRAP, %o0	! 16, how detected
401	SET_SIZE(fpras_chkfn_type1)
402
403#endif	/* lint */
404
405/*
406 * fp_zero() - clear all fp data registers and the fsr
407 */
408
409#if defined(lint) || defined(__lint)
410
411void
412fp_zero(void)
413{}
414
415#else	/* lint */
416
417	ENTRY_NP(fp_zero)
418	std	%g0, [%sp + ARGPUSH + STACK_BIAS]
419	fzero	%f0
420	fzero	%f2
421	ldd	[%sp + ARGPUSH + STACK_BIAS], %fsr
422	faddd	%f0, %f2, %f4
423	fmuld	%f0, %f2, %f6
424	faddd	%f0, %f2, %f8
425	fmuld	%f0, %f2, %f10
426	faddd	%f0, %f2, %f12
427	fmuld	%f0, %f2, %f14
428	faddd	%f0, %f2, %f16
429	fmuld	%f0, %f2, %f18
430	faddd	%f0, %f2, %f20
431	fmuld	%f0, %f2, %f22
432	faddd	%f0, %f2, %f24
433	fmuld	%f0, %f2, %f26
434	faddd	%f0, %f2, %f28
435	fmuld	%f0, %f2, %f30
436	faddd	%f0, %f2, %f32
437	fmuld	%f0, %f2, %f34
438	faddd	%f0, %f2, %f36
439	fmuld	%f0, %f2, %f38
440	faddd	%f0, %f2, %f40
441	fmuld	%f0, %f2, %f42
442	faddd	%f0, %f2, %f44
443	fmuld	%f0, %f2, %f46
444	faddd	%f0, %f2, %f48
445	fmuld	%f0, %f2, %f50
446	faddd	%f0, %f2, %f52
447	fmuld	%f0, %f2, %f54
448	faddd	%f0, %f2, %f56
449	fmuld	%f0, %f2, %f58
450	faddd	%f0, %f2, %f60
451	retl
452	fmuld	%f0, %f2, %f62
453	SET_SIZE(fp_zero)
454
455#endif	/* lint */
456