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 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Copyright 2019 Peter Tribble.
27 */
28
29#ifndef	_SYS_MACHTHREAD_H
30#define	_SYS_MACHTHREAD_H
31
32#include <sys/asi.h>
33#include <sys/sun4asi.h>
34#include <sys/machasi.h>
35#include <sys/bitmap.h>
36#include <sys/opl_olympus_regs.h>
37
38#ifdef	__cplusplus
39extern "C" {
40#endif
41
42#ifdef	_ASM
43
44#define	THREAD_REG	%g7		/* pointer to current thread data */
45
46/*
47 * Get the processor implementation from the version register.
48 */
49#define	GET_CPU_IMPL(out)		\
50	rdpr	%ver,	out;		\
51	srlx	out, 32, out;		\
52	sll	out, 16, out;		\
53	srl	out, 16, out;
54
55#ifdef _OPL
56/*
57 * For OPL platform, we get CPU_INDEX from ASI_EIDR.
58 */
59#define	CPU_INDEX(r, scr)		\
60	ldxa	[%g0]ASI_EIDR, r;	\
61	and	r, 0xfff, r
62
63
64#else /* _OPL */
65
66/*
67 * UPA supports up to 32 devices while Safari supports up to
68 * 1024 devices (utilizing the SSM protocol). Based upon the
69 * value of NCPU, a 5- or 10-bit mask will be needed for
70 * extracting the cpu id.
71 */
72#if NCPU > 32
73#define	CPU_MASK	0x3ff
74#else
75#define	CPU_MASK	0x1f
76#endif	/* NCPU > 32 */
77
78/*
79 * CPU_INDEX(r, scr)
80 * Returns cpu id in r.
81 * For UPA based systems, the cpu id corresponds to the mid field in
82 * the UPA config register. For Safari based machines, the cpu id
83 * corresponds to the aid field in the Safari config register.
84 *
85 * XXX - scr reg is not used here.
86 */
87#define	CPU_INDEX(r, scr)		\
88	ldxa	[%g0]ASI_UPA_CONFIG, r;	\
89	srlx	r, 17, r;		\
90	and	r, CPU_MASK, r
91
92#endif	/* _OPL */
93
94/*
95 * Given a cpu id extract the appropriate word
96 * in the cpuset mask for this cpu id.
97 */
98#if CPUSET_SIZE > CLONGSIZE
99#define	CPU_INDEXTOSET(base, index, scr)	\
100	srl	index, BT_ULSHIFT, scr;		\
101	and	index, BT_ULMASK, index;	\
102	sll	scr, CLONGSHIFT, scr;		\
103	add	base, scr, base
104#else
105#define	CPU_INDEXTOSET(base, index, scr)
106#endif	/* CPUSET_SIZE */
107
108
109/*
110 * Assembly macro to find address of the current CPU.
111 * Used when coming in from a user trap - cannot use THREAD_REG.
112 * Args are destination register and one scratch register.
113 */
114#define	CPU_ADDR(reg, scr) 		\
115	.global	cpu;			\
116	CPU_INDEX(scr, reg);		\
117	sll	scr, CPTRSHIFT, scr;	\
118	set	cpu, reg;		\
119	ldn	[reg + scr], reg
120
121#define	CINT64SHIFT	3
122
123/*
124 * Assembly macro to find the physical address of the current CPU.
125 * All memory references using VA must be limited to nucleus
126 * memory to avoid any MMU side effect.
127 */
128#define	CPU_PADDR(reg, scr)				\
129	.global cpu_pa;					\
130	CPU_INDEX(scr, reg);				\
131	sll	scr, CINT64SHIFT, scr;			\
132	set	cpu_pa, reg;				\
133	ldx	[reg + scr], reg
134
135#endif	/* _ASM */
136
137/*
138 * If a high level trap handler decides to call sys_trap() to execute some
139 * base level code, context and other registers must be set to proper
140 * values to run kernel. This is true for most part of the kernel, except
141 * for user_rtt, a substantial part of which is executed with registers
142 * ready to run user code. The following macro may be used to detect this
143 * condition and handle it. Please note that, in general, we can't restart
144 * arbitrary piece of code running at tl > 0; user_rtt is a special case
145 * that can be handled.
146 *
147 * Entry condition:
148 *
149 * %tl = 2
150 * pstate.ag = 1
151 *
152 * Register usage:
153 *
154 * scr1, scr2 - destroyed
155 * normal %g5 and %g6 - destroyed
156 *
157 */
158/* BEGIN CSTYLED */
159#define	RESET_USER_RTT_REGS(scr1, scr2, label)				\
160	/*								\
161	 * do nothing if %tl != 2. this an attempt to stop this		\
162	 * piece of code from executing more than once before going	\
163	 * back to TL=0. more specifically, the changes we are doing	\
164	 * to %wstate, %canrestore and %otherwin can't be done more	\
165	 * than once before going to TL=0. note that it is okay to	\
166	 * execute this more than once if we restart at user_rtt and	\
167	 * come back from there.					\
168	 */								\
169	rdpr	%tl, scr1;						\
170	cmp	scr1, 2;						\
171	bne,a,pn %xcc, label;						\
172	nop;								\
173	/*								\
174	 * read tstate[2].%tpc. do nothing if it is not			\
175	 * between rtt_ctx_start and rtt_ctx_end.			\
176	 */								\
177	rdpr	%tpc, scr1;						\
178	set	rtt_ctx_end, scr2;					\
179	cmp	scr1, scr2;						\
180	bgu,a,pt %xcc, label;						\
181	nop;								\
182	set	rtt_ctx_start, scr2;					\
183	cmp	scr1, scr2;						\
184	blu,a,pt %xcc, label;						\
185	nop;								\
186	/*								\
187	 * pickup tstate[2].cwp						\
188	 */								\
189	rdpr	%tstate, scr1;						\
190	and	scr1, TSTATE_CWP, scr1;					\
191	/*								\
192	 * set tstate[1].cwp to tstate[2].cwp. fudge			\
193	 * tstate[1].tpc and tstate[1].tnpc to restart			\
194	 * user_rtt.							\
195	 */								\
196	wrpr	%g0, 1, %tl;						\
197	set	TSTATE_KERN | TSTATE_IE, scr2;				\
198	or	scr1, scr2, scr2;					\
199	wrpr    %g0, scr2, %tstate;					\
200	set	user_rtt, scr1;						\
201	wrpr	%g0, scr1, %tpc;					\
202	add	scr1, 4, scr1;						\
203	wrpr	%g0, scr1, %tnpc;					\
204	/*								\
205	 * restore %tl							\
206	 */								\
207	wrpr	%g0, 2, %tl;						\
208	/*								\
209	 * set %wstate							\
210	 */								\
211	rdpr	%wstate, scr1;						\
212	sllx	scr1, WSTATE_SHIFT, scr1;				\
213	wrpr    scr1, WSTATE_K64, %wstate;				\
214	/*								\
215	 * setup window registers					\
216	 * %cleanwin <-- nwin - 1					\
217	 * %otherwin <-- %canrestore					\
218	 * %canrestore <-- 0						\
219	 */								\
220	sethi   %hi(nwin_minus_one), scr1;				\
221	ld	[scr1 + %lo(nwin_minus_one)], scr1;			\
222	wrpr    %g0, scr1, %cleanwin;					\
223	rdpr	%canrestore, scr1;					\
224	wrpr	%g0, scr1, %otherwin;					\
225	wrpr	%g0, 0, %canrestore;					\
226	/*								\
227	 * set THREAD_REG, as we have restored user			\
228	 * registers in user_rtt. we trash %g5 and %g6			\
229	 * in the process.						\
230	 */								\
231	rdpr    %pstate, scr1;						\
232	wrpr	scr1, PSTATE_AG, %pstate;				\
233	/*								\
234	 * using normal globals now					\
235	 */								\
236	CPU_ADDR(%g5, %g6);						\
237	ldn	[%g5 + CPU_THREAD], %g6;				\
238	mov	%g6, THREAD_REG;					\
239	rdpr	%pstate, %g5;						\
240	wrpr	%g5, PSTATE_AG, %pstate;				\
241	/*								\
242	 * back to alternate globals.					\
243	 * set PCONTEXT to run kernel.					\
244	 * A demap of I/DTLB is required if the nucleus bits differ	\
245	 * from kcontextreg.						\
246	 */								\
247	mov	MMU_PCONTEXT, scr1;					\
248	sethi	%hi(kcontextreg), scr2;					\
249	ldx     [scr2 + %lo(kcontextreg)], scr2;			\
250	ldxa	[scr1]ASI_MMU_CTX, scr1;				\
251	xor	scr2, scr1, scr1;					\
252	srlx	scr1, CTXREG_NEXT_SHIFT, scr1;				\
253	/*								\
254	 * If N_pgsz0/1 changed, need to demap.				\
255	 */								\
256	brz	scr1, label/**/_0;					\
257	nop;								\
258	mov	DEMAP_ALL_TYPE, scr1;					\
259	stxa	%g0, [scr1]ASI_DTLB_DEMAP;				\
260	stxa	%g0, [scr1]ASI_ITLB_DEMAP;				\
261label/**/_0:								\
262	mov	MMU_PCONTEXT, scr1;					\
263	stxa    scr2, [scr1]ASI_MMU_CTX;				\
264	sethi   %hi(FLUSH_ADDR), scr1;					\
265	flush	scr1
266
267/* END CSTYLED */
268
269#ifdef	__cplusplus
270}
271#endif
272
273#endif	/* _SYS_MACHTHREAD_H */
274