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