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 \
86 is_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 \
95 hash_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 \
120 bspage: /* 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 */ \
161 search_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 \
182 search_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 \
218 ttep_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 */
277 1: 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
300 1: mulx %g3, 3, %g4 /* 3: see TTE_BSZS_SHIFT */
301 add %g4, MMU_PAGESHIFT, %g4
302
303 3: 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
314 4: ba,a 6f
315
316 5: 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
325 6: jmp %g7
326 nop
327 SET_SIZE(kdi_trap_vatotte)
328