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