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