xref: /titanic_44/usr/src/uts/sun4v/ml/mach_subr_asm.s (revision a4aeef46cda1835da2b19f8f62b4526de6521e6c)
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/machclock.h>
41#include <sys/privregs.h>
42#include <sys/cmpregs.h>
43#include <sys/clock.h>
44#include <sys/fpras.h>
45#include <sys/soft_state.h>
46
47#if defined(lint)
48
49uint64_t
50ultra_gettick(void)
51{ return (0); }
52
53#else	/* lint */
54
55/*
56 * This isn't the routine you're looking for.
57 *
58 * The routine simply returns the value of %tick on the *current* processor.
59 * Most of the time, gettick() [which in turn maps to %stick on platforms
60 * that have different CPU %tick rates] is what you want.
61 */
62
63	ENTRY(ultra_gettick)
64	RD_TICK(%o0,%o1,%o2,__LINE__)
65	retl
66	nop
67	SET_SIZE(ultra_gettick)
68
69#endif	/* lint */
70
71#if defined(lint)
72/* ARGSUSED */
73void
74set_mmfsa_scratchpad(caddr_t vaddr)
75{ }
76
77#else	/* lint */
78
79	ENTRY(set_mmfsa_scratchpad)
80	stxa	%o0, [%g0]ASI_SCRATCHPAD
81	retl
82	nop
83	SET_SIZE(set_mmfsa_scratchpad)
84#endif	/* lint */
85
86#if defined(lint)
87caddr_t
88get_mmfsa_scratchpad()
89{  return (0); }
90
91#else	/* lint */
92
93	ENTRY(get_mmfsa_scratchpad)
94	ldxa	[%g0]ASI_SCRATCHPAD, %o0
95	retl
96	nop
97	SET_SIZE(get_mmfsa_scratchpad)
98#endif	/* lint */
99
100
101
102#if defined(lint)
103/* ARGSUSED */
104void
105cpu_intrq_unregister_powerdown(uint64_t doneflag_va)
106{}
107
108#else	/* lint */
109
110/*
111 * Called from a x-trap at tl1 must use %g1 as arg
112 * and save/restore %o0-%o5 after hypervisor calls
113 */
114
115	ENTRY(cpu_intrq_unregister_powerdown)
116
117	CPU_ADDR(%g2, %g3)
118	add %g2, CPU_MCPU, %g2
119	/*
120	 * Save %o regs
121	 */
122	mov %o0, %g3
123	mov %o1, %g4
124	mov %o2, %g5
125	mov %o5, %g6
126
127	ldx [%g2 + MCPU_CPU_Q_BASE], %o1
128	mov INTR_CPU_Q, %o0
129	call hv_cpu_qconf
130	mov %g0, %o2
131
132	ldx [%g2 + MCPU_DEV_Q_BASE], %o1
133	mov INTR_DEV_Q, %o0
134	call hv_cpu_qconf
135	mov %g0, %o2
136
137	ldx [%g2 + MCPU_RQ_BASE], %o1
138	mov CPU_RQ, %o0
139	call hv_cpu_qconf
140	mov %g0, %o2
141
142	ldx [%g2 + MCPU_NRQ_BASE], %o1
143	mov CPU_NRQ, %o0
144	call hv_cpu_qconf
145	mov %g0, %o2
146
147	/*
148	 * set done flag to 0
149	 */
150	stub %g0, [%g1]
151
152	/*
153	 * Restore %o regs
154	 */
155	mov %g3, %o0
156	mov %g4, %o1
157	mov %g5, %o2
158	mov %g6, %o5
159
160	/*
161	 * This CPU is on its way out. Spin here
162	 * until the DR unconfigure code stops it.
163	 * Returning would put it back in the OS
164	 * where it might grab resources like locks,
165	 * causing some nastiness to occur.
166	 */
1670:
168	ba,a	0b
169
170	SET_SIZE(cpu_intrq_unregister_powerdown)
171#endif	/* lint */
172
173
174#if defined(lint)
175/* ARGSUSED */
176int
177getprocessorid(void)
178{ return (0); }
179
180#else	/* lint */
181
182/*
183 * Get the processor ID.
184 * === MID reg as specified in 15dec89 sun4u spec, sec 5.4.3
185 */
186
187	ENTRY(getprocessorid)
188	CPU_INDEX(%o0, %o1)
189	retl
190	nop
191	SET_SIZE(getprocessorid)
192
193#endif	/* lint */
194
195#if defined(lint) || defined(__lint)
196
197/* ARGSUSED */
198hrtime_t
199tick2ns(hrtime_t tick, uint_t cpuid)
200{ return 0; }
201
202#else	/* lint */
203
204	ENTRY_NP(tick2ns)
205	sethi	%hi(cpunodes), %o4
206	or	%o4, %lo(cpunodes), %o4		! %o4 = &cpunodes
207	! Register usage:
208	!
209	! o0 = timestamp
210	! o2 = byte offset into cpunodes for tick_nsec_scale of this CPU
211	! o4 = &cpunodes
212	!
213	mulx	%o1, CPU_NODE_SIZE, %o2	! %o2 = byte offset into cpunodes
214	add	%o2, TICK_NSEC_SCALE, %o2
215	ld	[%o4 + %o2], %o2	! %o2 = cpunodes[cpuid].tick_nsec_scale
216	NATIVE_TIME_TO_NSEC_SCALE(%o0, %o2, %o3, TICK_NSEC_SHIFT)
217	retl
218	nop
219	SET_SIZE(tick2ns)
220
221#endif  /* lint */
222
223#if defined(lint)
224
225/* ARGSUSED */
226void
227set_cmp_error_steering(void)
228{}
229
230#else	/* lint */
231
232	ENTRY(set_cmp_error_steering)
233	retl
234	nop
235	SET_SIZE(set_cmp_error_steering)
236
237#endif	/* lint */
238
239#if defined(lint)
240
241/* ARGSUSED */
242uint64_t
243ultra_getver(void)
244{
245	return (0);
246}
247
248#else /* lint */
249
250	ENTRY(ultra_getver)
251	retl
252	mov	-1, %o0		! XXXQ no version available
253	SET_SIZE(ultra_getver)
254
255#endif /* lint */
256
257#if defined(lint)
258
259int
260fpras_chkfn_type1(void)
261{ return 0; }
262
263#else	/* lint */
264
265	/*
266	 * Check instructions using just the AX pipelines, designed by
267	 * C.B. Liaw of PNP.
268	 *
269	 * This function must match a struct fpras_chkfn and must be
270	 * block aligned.  A zero return means all was well.  These
271	 * instructions are chosen to be sensitive to bit corruptions
272	 * on the fpras rewrite, so if a bit corruption still produces
273	 * a valid instruction we should still get an incorrect result
274	 * here.  This function is never called directly - it is copied
275	 * into per-cpu and per-operation buffers;  it must therefore
276	 * be absolutely position independent.  If an illegal instruction
277	 * is encountered then the trap handler trampolines to the final
278	 * three instructions of this function.
279	 *
280	 * We want two instructions that are complements of one another,
281	 * and which can perform a calculation with a known result.
282	 *
283	 * SETHI:
284	 *
285	 * | 0 0 |  rd   | 1 0 0 |	imm22				|
286	 *  31 30 29   25 24   22 21				       0
287	 *
288	 * ADDCCC with two source registers:
289	 *
290	 * | 1 0 |  rd   | 0 1 1   0 0 0 |  rs1  | 0 |	   -	|  rs2  |
291	 *  31 30 29   25 24           19 18   14 13  12       5 4     0
292	 *
293	 * We can choose rd and imm2 of the SETHI and rd, rs1 and rs2 of
294	 * the ADDCCC to obtain instructions that are complements in all but
295	 * bit 30.
296	 *
297	 * Registers are numbered as follows:
298	 *
299	 * r[31]	%i7
300	 * r[30]	%i6
301	 * r[29]	%i5
302	 * r[28]	%i4
303	 * r[27]	%i3
304	 * r[26]	%i2
305	 * r[25]	%i1
306	 * r[24]	%i0
307	 * r[23]	%l7
308	 * r[22]	%l6
309	 * r[21]	%l5
310	 * r[20]	%l4
311	 * r[19]	%l3
312	 * r[18]	%l2
313	 * r[17]	%l1
314	 * r[16]	%l0
315	 * r[15]	%o7
316	 * r[14]	%o6
317	 * r[13]	%o5
318	 * r[12]	%o4
319	 * r[11]	%o3
320	 * r[10]	%o2
321	 * r[9]		%o1
322	 * r[8]		%o0
323	 * r[7]		%g7
324	 * r[6]		%g6
325	 * r[5]		%g5
326	 * r[4]		%g4
327	 * r[3]		%g3
328	 * r[2]		%g2
329	 * r[1]		%g1
330	 * r[0]		%g0
331	 *
332	 * For register r[n], register r[31-n] is the complement.  We must
333	 * avoid use of %i6/%i7 and %o6/%o7 as well as %g7.  Clearly we need
334	 * to use a local or input register as one half of the pair, which
335	 * requires us to obtain our own register window or take steps
336	 * to preserve any local or input we choose to use.  We choose
337	 * %o1 as rd for the SETHI, so rd of the ADDCCC must be %l6.
338	 * We'll use %o1 as rs1 and %l6 as rs2 of the ADDCCC, which then
339	 * requires that imm22 be 0b111 10110 1 11111111 01001 or 0x3dbfe9,
340	 * or %hi(0xf6ffa400).  This determines the value of the constant
341	 * CBV2 below.
342	 *
343	 * The constant CBV1 is chosen such that an initial subcc %g0, CBV1
344	 * will set the carry bit and every addccc thereafter will continue
345	 * to generate a carry.  Other values are possible for CBV1 - this
346	 * is just one that works this way.
347	 *
348	 * Finally CBV3 is the expected answer when we perform our repeated
349	 * calculations on CBV1 and CBV2 - it is not otherwise specially
350	 * derived.  If this result is not obtained then a corruption has
351	 * occured during the FPRAS_REWRITE of one of the two blocks of
352	 * 16 instructions.  A corruption could also result in an illegal
353	 * instruction or other unexpected trap - we catch illegal
354	 * instruction traps in the PC range and trampoline to the
355	 * last instructions of the function to return a failure indication.
356	 *
357	 */
358
359#define	CBV1		0xc11
360#define	CBV2		0xf6ffa400
361#define	CBV3		0x66f9d800
362#define	CBR1		%o1
363#define	CBR2		%l6
364#define	CBO2		%o2
365#define	SETHI_CBV2_CBR1		sethi %hi(CBV2), CBR1
366#define	ADDCCC_CBR1_CBR2_CBR2	addccc CBR1, CBR2, CBR2
367
368	.align	64
369	ENTRY_NP(fpras_chkfn_type1)
370	mov	CBR2, CBO2		! 1, preserve CBR2 of (callers) window
371	mov	FPRAS_OK, %o0		! 2, default return value
372	ba,pt	%icc, 1f		! 3
373	  subcc %g0, CBV1, CBR2		! 4
374					! 5 - 16
375	.align	64
3761:	SETHI_CBV2_CBR1			! 1
377	ADDCCC_CBR1_CBR2_CBR2		! 2
378	SETHI_CBV2_CBR1			! 3
379	ADDCCC_CBR1_CBR2_CBR2		! 4
380	SETHI_CBV2_CBR1			! 5
381	ADDCCC_CBR1_CBR2_CBR2		! 6
382	SETHI_CBV2_CBR1			! 7
383	ADDCCC_CBR1_CBR2_CBR2		! 8
384	SETHI_CBV2_CBR1			! 9
385	ADDCCC_CBR1_CBR2_CBR2		! 10
386	SETHI_CBV2_CBR1			! 11
387	ADDCCC_CBR1_CBR2_CBR2		! 12
388	SETHI_CBV2_CBR1			! 13
389	ADDCCC_CBR1_CBR2_CBR2		! 14
390	SETHI_CBV2_CBR1			! 15
391	ADDCCC_CBR1_CBR2_CBR2		! 16
392
393	ADDCCC_CBR1_CBR2_CBR2		! 1
394	SETHI_CBV2_CBR1			! 2
395	ADDCCC_CBR1_CBR2_CBR2		! 3
396	SETHI_CBV2_CBR1			! 4
397	ADDCCC_CBR1_CBR2_CBR2		! 5
398	SETHI_CBV2_CBR1			! 6
399	ADDCCC_CBR1_CBR2_CBR2		! 7
400	SETHI_CBV2_CBR1			! 8
401	ADDCCC_CBR1_CBR2_CBR2		! 9
402	SETHI_CBV2_CBR1			! 10
403	ADDCCC_CBR1_CBR2_CBR2		! 11
404	SETHI_CBV2_CBR1			! 12
405	ADDCCC_CBR1_CBR2_CBR2		! 13
406	SETHI_CBV2_CBR1			! 14
407	ADDCCC_CBR1_CBR2_CBR2		! 15
408	SETHI_CBV2_CBR1			! 16
409
410	addc	CBR1, CBR2, CBR2	! 1
411	sethi	%hi(CBV3), CBR1		! 2
412	cmp	CBR1, CBR2		! 3
413	movnz	%icc, FPRAS_BADCALC, %o0! 4, how detected
414	retl				! 5
415	  mov	CBO2, CBR2		! 6, restore borrowed register
416	.skip 4*(13-7+1)		! 7 - 13
417					!
418					! illegal instr'n trap comes here
419					!
420	mov	CBO2, CBR2		! 14, restore borrowed register
421	retl				! 15
422	  mov	FPRAS_BADTRAP, %o0	! 16, how detected
423	SET_SIZE(fpras_chkfn_type1)
424#endif	/* lint */
425
426#if defined(lint)
427char	soft_state_message_strings[SOLARIS_SOFT_STATE_MSG_CNT][SSM_SIZE];
428#else	/* lint */
429	.seg	".data"
430	.global soft_state_message_strings
431
432	.align	SSM_SIZE
433soft_state_message_strings:
434	.asciz	SOLARIS_SOFT_STATE_BOOT_MSG_STR
435	.align	SSM_SIZE
436	.asciz	SOLARIS_SOFT_STATE_RUN_MSG_STR
437	.align	SSM_SIZE
438	.asciz	SOLARIS_SOFT_STATE_HALT_MSG_STR
439	.align	SSM_SIZE
440	.asciz	SOLARIS_SOFT_STATE_POWER_MSG_STR
441	.align	SSM_SIZE
442	.asciz	SOLARIS_SOFT_STATE_PANIC_MSG_STR
443	.align	SSM_SIZE
444	.asciz	SOLARIS_SOFT_STATE_REBOOT_MSG_STR
445	.align	SSM_SIZE
446	.asciz	SOLARIS_SOFT_STATE_DEBUG_MSG_STR
447	.align	SSM_SIZE
448	.skip	SSM_SIZE			/* saved message */
449	.nword	0
450
451	.seg	".text"
452#endif	/* lint */
453