xref: /titanic_50/usr/src/uts/sfmmu/ml/sfmmu_kdi.s (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
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/*
23 * Copyright 2007 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#if !defined(lint)
30#include <sys/asm_linkage.h>
31#include "assym.h"
32#endif
33
34#include <sys/sun4asi.h>
35#include <sys/machparam.h>
36#include <vm/hat_sfmmu.h>
37
38/*
39 * This file contains a kmdb-support function which retrieves the TTE for a
40 * given VA/context pair, and returns it to the caller if the TTE is valid.
41 * The code here is essentially an assembly implementation of the unix-tte
42 * word used to allow OBP to do the same thing.
43 *
44 * Depending on the invocation context, the translator may be invoked either
45 * as a normal function (kdi_vatotte) or as a trap handler fragment
46 * (kdi_trap_vatotte).
47 */
48
49/*
50 * uint64_t
51 * kdi_hme_hash_function(sfmmu_t *sfmmup, uintptr_t va, uint_t hmeshift)
52 * {
53 *	uintptr_t hash = (uintptr_t)sfmmup ^ (va >> hmeshift);
54 *
55 *	if (sfmmup == KHATID) {
56 *		return (khme_hash_pa + (hash & KHMEHASH_SZ) *
57 *		    sizeof (struct hmehash_bucket));
58 *	} else {
59 *		return (uhme_hash_pa + (hash & UHMEHASH_SZ) *
60 *		    sizeof (struct hmehash_bucket));
61 *	}
62 * }
63 */
64
65/*
66 * Parameters:	%g1: VA, %g2: sfmmup, %g4: hmeshift
67 * Scratch:	%g4, %g5, %g6 available
68 * Return:	Hash value in %g4
69 */
70
71#define	KDI_HME_HASH_FUNCTION \
72	srlx	%g1, %g4, %g4;		/* va >> hmeshift */		\
73	xor	%g4, %g2, %g4;		/* hash in g4 */		\
74	set	KHATID, %g5;						\
75	ldx	[%g5], %g5;						\
76	cmp	%g2, %g5;						\
77	be	%xcc, is_khat;						\
78	nop;								\
79									\
80	/* sfmmup != KHATID */						\
81	set	UHMEHASH_SZ, %g5;					\
82	ld	[%g5], %g5;						\
83	and	%g4, %g5, %g4;						\
84	mulx	%g4, HMEBUCK_SIZE, %g4; /* g4 = off from hash_pa */	\
85	set	uhme_hash_pa, %g5;					\
86	ldx	[%g5], %g5;						\
87	ba	hash_done;						\
88	add	%g4, %g5, %g4;						\
89									\
90is_khat: /* sfmmup == KHATID */						\
91	set	KHMEHASH_SZ, %g5;					\
92	ld	[%g5], %g5;						\
93	and	%g4, %g5, %g4;						\
94	mulx	%g4, HMEBUCK_SIZE, %g4;	/* g4 = off from hash_pa */	\
95	set	khme_hash_pa, %g5;					\
96	ldx	[%g5], %g5;						\
97	add	%g4, %g5, %g4;						\
98									\
99hash_done:
100
101/*
102 * uint64_t
103 * kdi_hme_hash_tag(uint64_t rehash, uintptr_t va)
104 * {
105 *	uint_t hmeshift = HME_HASH_SHIFT(rehash);
106 *	uint64_t bspage = HME_HASH_BSPAGE(va, hmeshift);
107 *	return (rehash | (bspage << HTAG_BSPAGE_SHIFT));
108 * }
109 */
110
111/*
112 * Parameters:	%g1: VA, %g3: rehash
113 * Scratch:	%g5, %g6 available
114 * Return:	hmeblk tag in %g5
115 */
116
117#define	KDI_HME_HASH_TAG \
118	cmp	%g3, TTE8K;					\
119	be,a	%xcc, bspage;					\
120	mov	HBLK_RANGE_SHIFT, %g5;				\
121	mulx	%g3, 3, %g5;					\
122	add	%g5, MMU_PAGESHIFT, %g5;			\
123								\
124bspage:	/* TTE_PAGE_SHIFT in %g5 */				\
125	srlx	%g1, %g5, %g6;					\
126	sub	%g5, MMU_PAGESHIFT, %g5;			\
127	sllx	%g6, %g5, %g5;					\
128								\
129	/* BSPAGE in %g5 */					\
130	sllx	%g5, HTAG_BSPAGE_SHIFT, %g5;			\
131	sllx	%g3, HTAG_REHASH_SHIFT, %g6;			\
132	or	%g6, SFMMU_INVALID_SHMERID, %g6;		\
133	or	%g5, %g6, %g5
134
135/*
136 * uint64_t
137 * kdi_hme_hash_table_search(sfmmu_t *sfmmup, uint64_t hmebpa, uint64_t hblktag)
138 * {
139 *	struct hme_blk *hblkp;
140 *	uint64_t blkpap = hmebpa + HMEBP_HBLK;
141 *	uint64_t blkpa;
142 *
143 *	while ((blkpa = lddphys(blkpap)) != NULL) {
144 *		if (lddphys(blkpa + HMEBLK_TAG) == hblktag) {
145 *			if ((sfmmu_t *)lddphys(blkpa + HMEBLK_TAG + 8) ==
146 *			    sfmmup)
147 *				return (blkpa);
148 *		}
149 *
150 *		blkpap = blkpa + HMEBLK_NEXTPA;
151 *	}
152 *
153 *	return (NULL);
154 * }
155 */
156
157/*
158 * Parameters:	%g2: sfmmup, %g4: hmebp PA, %g5: hmeblk tag
159 * Scratch:	%g4, %g5, %g6 available
160 * Return:	hmeblk PA in %g4
161 */
162
163#define	KDI_HME_HASH_TABLE_SEARCH \
164	add	%g4, HMEBUCK_NEXTPA, %g4; /* %g4 is hmebucket PA */	\
165search_loop:								\
166	ldxa	[%g4]ASI_MEM, %g4;					\
167	brz	%g4, search_done;					\
168	nop;								\
169									\
170	add	%g4, HMEBLK_TAG, %g4;	/* %g4 is now hmeblk PA */	\
171	ldxa	[%g4]ASI_MEM, %g6;					\
172	sub	%g4, HMEBLK_TAG, %g4;					\
173	cmp	%g5, %g6;						\
174	bne,a	%xcc, search_loop;					\
175	add	%g4, HMEBLK_NEXTPA, %g4;				\
176									\
177	/* Found a match.  Is it in the right address space? */		\
178	add	%g4, (HMEBLK_TAG + 8), %g4;				\
179	ldxa	[%g4]ASI_MEM, %g6;					\
180	sub	%g4, (HMEBLK_TAG + 8), %g4;				\
181	cmp	%g6, %g2;						\
182	bne,a	%xcc, search_loop;					\
183	add	%g4, HMEBLK_NEXTPA, %g4;				\
184									\
185search_done:
186
187/*
188 * uint64_t
189 * kdi_hblk_to_ttep(uint64_t hmeblkpa, uintptr_t va)
190 * {
191 *	size_t ttesz = ldphys(hmeblkpa + HMEBLK_MISC) & HBLK_SZMASK;
192 *	uint_t idx;
193 *
194 *	if (ttesz == TTE8K)
195 *		idx = (va >> MMU_PAGESHIFT) & (NHMENTS - 1);
196 *	else
197 *		idx = 0;
198 *
199 *	return (hmeblkpa + (idx * sizeof (struct sf_hment)) +
200 *	    HMEBLK_HME + SFHME_TTE);
201 * }
202 */
203
204/*
205 * Parameters:	%g1: VA, %g4: hmeblk PA
206 * Scratch:	%g1, %g2, %g3, %g4, %g5, %g6 available
207 * Return:	TTE PA in %g2
208 */
209
210#define	KDI_HBLK_TO_TTEP \
211	add	%g4, HMEBLK_MISC, %g3;				\
212	lda	[%g3]ASI_MEM, %g3;				\
213	and	%g3, HBLK_SZMASK, %g3;	/* ttesz in %g3 */	\
214								\
215	cmp	%g3, TTE8K;					\
216	bne,a	ttep_calc;					\
217	clr	%g1;						\
218	srlx	%g1, MMU_PAGESHIFT, %g1;			\
219	and	%g1, NHMENTS - 1, %g1;				\
220								\
221ttep_calc:	/* idx in %g1 */				\
222	mulx	%g1, SFHME_SIZE, %g2;				\
223	add	%g2, %g4, %g2;					\
224	add	%g2, (HMEBLK_HME1 + SFHME_TTE), %g2;
225
226/*
227 * uint64_t
228 * kdi_vatotte(uintptr_t va, int cnum)
229 * {
230 *	sfmmu_t *sfmmup = ksfmmup;
231 *	uint64_t hmebpa, hmetag, hmeblkpa;
232 *	int i;
233 *
234 *	for (i = 1; i < DEFAULT_MAX_HASHCNT + 1; i++) {
235 *		hmebpa = kdi_c_hme_hash_function(sfmmup, va, HME_HASH_SHIFT(i));
236 *		hmetag = kdi_c_hme_hash_tag(i, va);
237 *		hmeblkpa = kdi_c_hme_hash_table_search(sfmmup, hmebpa, hmetag);
238 *
239 *		if (hmeblkpa != NULL) {
240 *			uint64_t tte = lddphys(kdi_c_hblk_to_ttep(hmeblkpa,
241 *			    va));
242 *
243 *			if ((int64_t)tte < 0)
244 *				return (tte);
245 *			else
246 *				return (0);
247 *		}
248 *	}
249 *
250 *	return (0);
251 * }
252 */
253
254#if defined(lint)
255/*ARGSUSED*/
256int
257kdi_vatotte(uintptr_t va, int cnum, tte_t *ttep)
258{
259	return (0);
260}
261
262void
263kdi_trap_vatotte(void)
264{
265}
266
267#else
268
269	/*
270	 * Invocation in normal context as a VA-to-TTE translator
271	 * for kernel context only. This routine returns 0 on
272	 * success and -1 on error.
273	 *
274	 * %o0 = VA, input register
275	 * %o1 = KCONTEXT
276	 * %o2 = ttep, output register
277	 */
278	ENTRY_NP(kdi_vatotte)
279	mov	%o0, %g1		/* VA in %g1 */
280	mov	%o1, %g2		/* cnum in %g2 */
281
282	set	kdi_trap_vatotte, %g3
283	jmpl	%g3, %g7		/* => %g1: TTE or 0 */
284	add	%g7, 8, %g7
285
286	brz	%g1, 1f
287	nop
288
289	/* Got a valid TTE */
290	stx	%g1, [%o2]
291	retl
292	clr	%o0
293
294	/* Failed translation */
2951:	retl
296	mov	-1, %o0
297	SET_SIZE(kdi_vatotte)
298
299	/*
300	 * %g1 = vaddr passed in, tte or 0 (error) when return
301	 * %g2 = KCONTEXT
302	 * %g7 = return address
303	 */
304	ENTRY_NP(kdi_trap_vatotte)
305
306	cmp	%g2, KCONTEXT		/* make sure called in kernel ctx */
307	bne,a,pn %icc, 6f
308	  clr	%g1
309
310	sethi   %hi(ksfmmup), %g2
311        ldx     [%g2 + %lo(ksfmmup)], %g2
312
313	mov	1, %g3			/* VA %g1, ksfmmup %g2, idx %g3 */
314	mov	HBLK_RANGE_SHIFT, %g4
315	ba	3f
316	nop
317
3181:	mulx	%g3, 3, %g4		/* 3: see TTE_BSZS_SHIFT */
319	add	%g4, MMU_PAGESHIFT, %g4
320
3213:	KDI_HME_HASH_FUNCTION		/* %g1, %g2, %g4 => hash in %g4 */
322	KDI_HME_HASH_TAG		/* %g1, %g3 => tag in %g5 */
323	KDI_HME_HASH_TABLE_SEARCH	/* %g2, %g4, %g5 => hmeblk PA in %g4 */
324
325	brz	%g4, 5f
326	nop
327
328	KDI_HBLK_TO_TTEP		/* %g1, %g4 => TTE PA in %g2 */
329	ldxa	[%g2]ASI_MEM, %g1
330	brgez,a	%g1, 4f
331	clr	%g1
3324:	ba,a	6f
333
3345:	add	%g3, 1, %g3
335	set	mmu_hashcnt, %g4
336	lduw	[%g4], %g4
337	cmp	%g3, %g4
338	ble	1b
339	nop
340
341	clr	%g1
342
3436:	jmp	%g7
344	nop
345	SET_SIZE(kdi_trap_vatotte)
346
347#endif	/* lint */
348