sfmmu_kdi.s revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if !defined(lint)
#include <sys/asm_linkage.h>
#include "assym.h"
#endif
#include <sys/sun4asi.h>
#include <sys/machparam.h>
#include <vm/hat_sfmmu.h>
/*
* This file contains a kmdb-support function which retrieves the TTE for a
* given VA/context pair, and returns it to the caller if the TTE is valid.
* The code here is essentially an assembly implementation of the unix-tte
* word used to allow OBP to do the same thing.
*
* Depending on the invocation context, the translator may be invoked either
* as a normal function (kdi_vatotte) or as a trap handler fragment
* (kdi_trap_vatotte).
*/
/*
* uint64_t
* kdi_hme_hash_function(sfmmu_t *sfmmup, uintptr_t va, uint_t hmeshift)
* {
* uintptr_t hash = (uintptr_t)sfmmup ^ (va >> hmeshift);
*
* if (sfmmup == KHATID) {
* return (khme_hash_pa + (hash & KHMEHASH_SZ) *
* sizeof (struct hmehash_bucket));
* } else {
* return (uhme_hash_pa + (hash & UHMEHASH_SZ) *
* sizeof (struct hmehash_bucket));
* }
* }
*/
/*
* Parameters: %g1: VA, %g2: sfmmup, %g4: hmeshift
* Scratch: %g4, %g5, %g6 available
* Return: Hash value in %g4
*/
#define KDI_HME_HASH_FUNCTION \
srlx %g1, %g4, %g4; /* va >> hmeshift */ \
xor %g4, %g2, %g4; /* hash in g4 */ \
set KHATID, %g5; \
ldx [%g5], %g5; \
cmp %g2, %g5; \
be %xcc, is_khat; \
nop; \
\
/* sfmmup != KHATID */ \
set UHMEHASH_SZ, %g5; \
ld [%g5], %g5; \
and %g4, %g5, %g4; \
mulx %g4, HMEBUCK_SIZE, %g4; /* g4 = off from hash_pa */ \
set uhme_hash_pa, %g5; \
ldx [%g5], %g5; \
ba hash_done; \
add %g4, %g5, %g4; \
\
is_khat: /* sfmmup == KHATID */ \
set KHMEHASH_SZ, %g5; \
ld [%g5], %g5; \
and %g4, %g5, %g4; \
mulx %g4, HMEBUCK_SIZE, %g4; /* g4 = off from hash_pa */ \
set khme_hash_pa, %g5; \
ldx [%g5], %g5; \
add %g4, %g5, %g4; \
\
hash_done:
/*
* uint64_t
* kdi_hme_hash_tag(uint64_t rehash, uintptr_t va)
* {
* uint_t hmeshift = HME_HASH_SHIFT(rehash);
* uint64_t bspage = HME_HASH_BSPAGE(va, hmeshift);
* return (rehash | (bspage << HTAG_REHASHSZ));
* }
*/
/*
* Parameters: %g1: VA, %g3: rehash
* Scratch: %g5, %g6 available
* Return: hmeblk tag in %g5
*/
#define KDI_HME_HASH_TAG \
cmp %g3, TTE8K; \
be,a %xcc, bspage; \
mov HBLK_RANGE_SHIFT, %g5; \
mulx %g3, 3, %g5; \
add %g5, MMU_PAGESHIFT, %g5; \
\
bspage: /* TTE_PAGE_SHIFT in %g5 */ \
srlx %g1, %g5, %g6; \
sub %g5, MMU_PAGESHIFT, %g5; \
sllx %g6, %g5, %g5; \
\
/* BSPAGE in %g5 */ \
sllx %g5, HTAG_REHASHSZ, %g5; \
or %g5, %g3, %g5
/*
* uint64_t
* kdi_hme_hash_table_search(sfmmu_t *sfmmup, uint64_t hmebpa, uint64_t hblktag)
* {
* struct hme_blk *hblkp;
* uint64_t blkpap = hmebpa + HMEBP_HBLK;
* uint64_t blkpa;
*
* while ((blkpa = lddphys(blkpap)) != NULL) {
* if (lddphys(blkpa + HMEBLK_TAG) == hblktag) {
* if ((sfmmu_t *)lddphys(blkpa + HMEBLK_TAG + 8) ==
* sfmmup)
* return (blkpa);
* }
*
* blkpap = blkpa + HMEBLK_NEXTPA;
* }
*
* return (NULL);
* }
*/
/*
* Parameters: %g2: sfmmup, %g4: hmebp PA, %g5: hmeblk tag
* Scratch: %g4, %g5, %g6 available
* Return: hmeblk PA in %g4
*/
#define KDI_HME_HASH_TABLE_SEARCH \
add %g4, HMEBUCK_NEXTPA, %g4; /* %g4 is hmebucket PA */ \
search_loop: \
ldxa [%g4]ASI_MEM, %g4; \
brz %g4, search_done; \
nop; \
\
add %g4, HMEBLK_TAG, %g4; /* %g4 is now hmeblk PA */ \
ldxa [%g4]ASI_MEM, %g6; \
sub %g4, HMEBLK_TAG, %g4; \
cmp %g5, %g6; \
bne,a %xcc, search_loop; \
add %g4, HMEBLK_NEXTPA, %g4; \
\
/* Found a match. Is it in the right address space? */ \
add %g4, (HMEBLK_TAG + 8), %g4; \
ldxa [%g4]ASI_MEM, %g6; \
sub %g4, (HMEBLK_TAG + 8), %g4; \
cmp %g6, %g2; \
bne,a %xcc, search_loop; \
add %g4, HMEBLK_NEXTPA, %g4; \
\
search_done:
/*
* uint64_t
* kdi_hblk_to_ttep(uint64_t hmeblkpa, uintptr_t va)
* {
* size_t ttesz = ldphys(hmeblkpa + HMEBLK_MISC) & HBLK_SZMASK;
* uint_t idx;
*
* if (ttesz == TTE8K)
* idx = (va >> MMU_PAGESHIFT) & (NHMENTS - 1);
* else
* idx = 0;
*
* return (hmeblkpa + (idx * sizeof (struct sf_hment)) +
* HMEBLK_HME + SFHME_TTE);
* }
*/
/*
* Parameters: %g1: VA, %g4: hmeblk PA
* Scratch: %g1, %g2, %g3, %g4, %g5, %g6 available
* Return: TTE PA in %g2
*/
#define KDI_HBLK_TO_TTEP \
add %g4, HMEBLK_MISC, %g3; \
lda [%g3]ASI_MEM, %g3; \
and %g3, HBLK_SZMASK, %g3; /* ttesz in %g3 */ \
\
cmp %g3, TTE8K; \
bne,a ttep_calc; \
clr %g1; \
srlx %g1, MMU_PAGESHIFT, %g1; \
and %g1, NHMENTS - 1, %g1; \
\
ttep_calc: /* idx in %g1 */ \
mulx %g1, SFHME_SIZE, %g2; \
add %g2, %g4, %g2; \
add %g2, (HMEBLK_HME1 + SFHME_TTE), %g2;
/*
* uint64_t
* kdi_vatotte(uintptr_t va, int cnum)
* {
* sfmmu_t *sfmmup = ctxs[cnum].ctx_sfmmu;
* uint64_t hmebpa, hmetag, hmeblkpa;
* int i;
*
* for (i = 1; i < DEFAULT_MAX_HASHCNT + 1; i++) {
* hmebpa = kdi_c_hme_hash_function(sfmmup, va, HME_HASH_SHIFT(i));
* hmetag = kdi_c_hme_hash_tag(i, va);
* hmeblkpa = kdi_c_hme_hash_table_search(sfmmup, hmebpa, hmetag);
*
* if (hmeblkpa != NULL) {
* uint64_t tte = lddphys(kdi_c_hblk_to_ttep(hmeblkpa,
* va));
*
* if ((int64_t)tte < 0)
* return (tte);
* else
* return (0);
* }
* }
*
* return (0);
* }
*/
#if defined(lint)
/*ARGSUSED*/
int
kdi_vatotte(uintptr_t va, int cnum, tte_t *ttep)
{
return (0);
}
void
kdi_trap_vatotte(void)
{
}
#else
/*
* Invocation in normal context as a VA-to-TTE translator.
*/
ENTRY_NP(kdi_vatotte)
mov %o0, %g1 /* VA in %g1 */
mov %o1, %g2 /* cnum in %g2 */
set kdi_trap_vatotte, %g3
jmpl %g3, %g7 /* => %g1: TTE or 0 */
add %g7, 8, %g7
brz %g1, 1f
nop
/* Got a valid TTE */
stx %g1, [%o2]
retl
clr %o0
/* Failed translation */
1: retl
mov -1, %o0
SET_SIZE(kdi_vatotte)
ENTRY_NP(kdi_trap_vatotte)
set nctxs, %g3
ld [%g3], %g3
cmp %g2, %g3
bge,a %xcc, 6f
clr %g1
set ctxs, %g3
ldx [%g3], %g3
mulx %g2, CTX_SIZE, %g2
add %g2, %g3, %g2
add %g2, CTX_SFMMUP, %g2
ldx [%g2], %g2 /* VA %g1, sfmmup %g2 */
mov 1, %g3 /* VA %g1, sfmmup %g2, idx %g3 */
1: mov HBLK_RANGE_SHIFT, %g4
mulx %g3, 3, %g4
add %g4, MMU_PAGESHIFT, %g4
3: KDI_HME_HASH_FUNCTION /* %g1, %g2, %g4 => hash in %g4 */
KDI_HME_HASH_TAG /* %g1, %g3 => tag in %g5 */
KDI_HME_HASH_TABLE_SEARCH /* %g2, %g4, %g5 => hmeblk PA in %g4 */
brz %g4, 5f
nop
KDI_HBLK_TO_TTEP /* %g1, %g4 => TTE PA in %g2 */
ldxa [%g2]ASI_MEM, %g1
brgez,a %g1, 4f
clr %g1
4: ba,a 6f
5: add %g3, 1, %g3
#ifdef sun4v
cmp %g3, MAX_HASHCNT
#else
cmp %g3, DEFAULT_MAX_HASHCNT /* no 32/256M kernel pages */
#endif
ble 1b
nop
clr %g1
6: jmp %g7
nop
SET_SIZE(kdi_trap_vatotte)
#endif /* lint */