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