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 #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 \
88 is_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 \
97 hash_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 \
122 bspage: /* 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 */ \
163 search_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 \
184 search_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 \
220 ttep_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*/
255 int
256 kdi_vatotte(uintptr_t va, int cnum, tte_t *ttep)
257 {
258 return (0);
259 }
260
261 void
262 kdi_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 */
294 1: 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
317 1: mulx %g3, 3, %g4 /* 3: see TTE_BSZS_SHIFT */
318 add %g4, MMU_PAGESHIFT, %g4
319
320 3: 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
331 4: ba,a 6f
332
333 5: add %g3, 1, %g3
334 set mmu_hashcnt, %g4
335 lduw [%g4], %g4
336 cmp %g3, %g4
337 ble 1b
338 nop
339
340 clr %g1
341
342 6: jmp %g7
343 nop
344 SET_SIZE(kdi_trap_vatotte)
345
346 #endif /* lint */