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 */