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