linux/arch/powerpc/kvm/e500_tlb.h
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
   3 *
   4 * Author: Yu Liu, yu.liu@freescale.com
   5 *
   6 * Description:
   7 * This file is based on arch/powerpc/kvm/44x_tlb.h,
   8 * by Hollis Blanchard <hollisb@us.ibm.com>.
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License, version 2, as
  12 * published by the Free Software Foundation.
  13 */
  14
  15#ifndef __KVM_E500_TLB_H__
  16#define __KVM_E500_TLB_H__
  17
  18#include <linux/kvm_host.h>
  19#include <asm/mmu-book3e.h>
  20#include <asm/tlb.h>
  21#include <asm/kvm_e500.h>
  22
  23#define KVM_E500_TLB0_WAY_SIZE_BIT      7       /* Fixed */
  24#define KVM_E500_TLB0_WAY_SIZE          (1UL << KVM_E500_TLB0_WAY_SIZE_BIT)
  25#define KVM_E500_TLB0_WAY_SIZE_MASK     (KVM_E500_TLB0_WAY_SIZE - 1)
  26
  27#define KVM_E500_TLB0_WAY_NUM_BIT       1       /* No greater than 7 */
  28#define KVM_E500_TLB0_WAY_NUM           (1UL << KVM_E500_TLB0_WAY_NUM_BIT)
  29#define KVM_E500_TLB0_WAY_NUM_MASK      (KVM_E500_TLB0_WAY_NUM - 1)
  30
  31#define KVM_E500_TLB0_SIZE  (KVM_E500_TLB0_WAY_SIZE * KVM_E500_TLB0_WAY_NUM)
  32#define KVM_E500_TLB1_SIZE  16
  33
  34#define index_of(tlbsel, esel)  (((tlbsel) << 16) | ((esel) & 0xFFFF))
  35#define tlbsel_of(index)        ((index) >> 16)
  36#define esel_of(index)          ((index) & 0xFFFF)
  37
  38#define E500_TLB_USER_PERM_MASK (MAS3_UX|MAS3_UR|MAS3_UW)
  39#define E500_TLB_SUPER_PERM_MASK (MAS3_SX|MAS3_SR|MAS3_SW)
  40#define MAS2_ATTRIB_MASK \
  41          (MAS2_X0 | MAS2_X1)
  42#define MAS3_ATTRIB_MASK \
  43          (MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3 \
  44           | E500_TLB_USER_PERM_MASK | E500_TLB_SUPER_PERM_MASK)
  45
  46extern void kvmppc_dump_tlbs(struct kvm_vcpu *);
  47extern int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *, ulong);
  48extern int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *);
  49extern int kvmppc_e500_emul_tlbre(struct kvm_vcpu *);
  50extern int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *, int, int);
  51extern int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *, int);
  52extern int kvmppc_e500_tlb_search(struct kvm_vcpu *, gva_t, unsigned int, int);
  53extern void kvmppc_e500_tlb_put(struct kvm_vcpu *);
  54extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int);
  55extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *);
  56extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *);
  57extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *);
  58extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *);
  59
  60/* TLB helper functions */
  61static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
  62{
  63        return (tlbe->mas1 >> 7) & 0x1f;
  64}
  65
  66static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
  67{
  68        return tlbe->mas2 & 0xfffff000;
  69}
  70
  71static inline u64 get_tlb_bytes(const struct tlbe *tlbe)
  72{
  73        unsigned int pgsize = get_tlb_size(tlbe);
  74        return 1ULL << 10 << pgsize;
  75}
  76
  77static inline gva_t get_tlb_end(const struct tlbe *tlbe)
  78{
  79        u64 bytes = get_tlb_bytes(tlbe);
  80        return get_tlb_eaddr(tlbe) + bytes - 1;
  81}
  82
  83static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
  84{
  85        u64 rpn = tlbe->mas7;
  86        return (rpn << 32) | (tlbe->mas3 & 0xfffff000);
  87}
  88
  89static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
  90{
  91        return (tlbe->mas1 >> 16) & 0xff;
  92}
  93
  94static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
  95{
  96        return (tlbe->mas1 >> 12) & 0x1;
  97}
  98
  99static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
 100{
 101        return (tlbe->mas1 >> 31) & 0x1;
 102}
 103
 104static inline unsigned int get_tlb_iprot(const struct tlbe *tlbe)
 105{
 106        return (tlbe->mas1 >> 30) & 0x1;
 107}
 108
 109static inline unsigned int get_cur_pid(struct kvm_vcpu *vcpu)
 110{
 111        return vcpu->arch.pid & 0xff;
 112}
 113
 114static inline unsigned int get_cur_as(struct kvm_vcpu *vcpu)
 115{
 116        return !!(vcpu->arch.shared->msr & (MSR_IS | MSR_DS));
 117}
 118
 119static inline unsigned int get_cur_pr(struct kvm_vcpu *vcpu)
 120{
 121        return !!(vcpu->arch.shared->msr & MSR_PR);
 122}
 123
 124static inline unsigned int get_cur_spid(
 125                const struct kvmppc_vcpu_e500 *vcpu_e500)
 126{
 127        return (vcpu_e500->mas6 >> 16) & 0xff;
 128}
 129
 130static inline unsigned int get_cur_sas(
 131                const struct kvmppc_vcpu_e500 *vcpu_e500)
 132{
 133        return vcpu_e500->mas6 & 0x1;
 134}
 135
 136static inline unsigned int get_tlb_tlbsel(
 137                const struct kvmppc_vcpu_e500 *vcpu_e500)
 138{
 139        /*
 140         * Manual says that tlbsel has 2 bits wide.
 141         * Since we only have two TLBs, only lower bit is used.
 142         */
 143        return (vcpu_e500->mas0 >> 28) & 0x1;
 144}
 145
 146static inline unsigned int get_tlb_nv_bit(
 147                const struct kvmppc_vcpu_e500 *vcpu_e500)
 148{
 149        return vcpu_e500->mas0 & 0xfff;
 150}
 151
 152static inline unsigned int get_tlb_esel_bit(
 153                const struct kvmppc_vcpu_e500 *vcpu_e500)
 154{
 155        return (vcpu_e500->mas0 >> 16) & 0xfff;
 156}
 157
 158static inline unsigned int get_tlb_esel(
 159                const struct kvmppc_vcpu_e500 *vcpu_e500,
 160                int tlbsel)
 161{
 162        unsigned int esel = get_tlb_esel_bit(vcpu_e500);
 163
 164        if (tlbsel == 0) {
 165                esel &= KVM_E500_TLB0_WAY_NUM_MASK;
 166                esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK)
 167                                << KVM_E500_TLB0_WAY_NUM_BIT;
 168        } else {
 169                esel &= KVM_E500_TLB1_SIZE - 1;
 170        }
 171
 172        return esel;
 173}
 174
 175static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
 176                        const struct tlbe *tlbe)
 177{
 178        gpa_t gpa;
 179
 180        if (!get_tlb_v(tlbe))
 181                return 0;
 182
 183        /* Does it match current guest AS? */
 184        /* XXX what about IS != DS? */
 185        if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
 186                return 0;
 187
 188        gpa = get_tlb_raddr(tlbe);
 189        if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
 190                /* Mapping is not for RAM. */
 191                return 0;
 192
 193        return 1;
 194}
 195
 196#endif /* __KVM_E500_TLB_H__ */
 197