diff options
Diffstat (limited to 'ANDROID_3.4.5/arch/powerpc/kvm/book3s_32_mmu.c')
-rw-r--r-- | ANDROID_3.4.5/arch/powerpc/kvm/book3s_32_mmu.c | 419 |
1 files changed, 0 insertions, 419 deletions
diff --git a/ANDROID_3.4.5/arch/powerpc/kvm/book3s_32_mmu.c b/ANDROID_3.4.5/arch/powerpc/kvm/book3s_32_mmu.c deleted file mode 100644 index c8cefdd1..00000000 --- a/ANDROID_3.4.5/arch/powerpc/kvm/book3s_32_mmu.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright SUSE Linux Products GmbH 2009 - * - * Authors: Alexander Graf <agraf@suse.de> - */ - -#include <linux/types.h> -#include <linux/string.h> -#include <linux/kvm.h> -#include <linux/kvm_host.h> -#include <linux/highmem.h> - -#include <asm/tlbflush.h> -#include <asm/kvm_ppc.h> -#include <asm/kvm_book3s.h> - -/* #define DEBUG_MMU */ -/* #define DEBUG_MMU_PTE */ -/* #define DEBUG_MMU_PTE_IP 0xfff14c40 */ - -#ifdef DEBUG_MMU -#define dprintk(X...) printk(KERN_INFO X) -#else -#define dprintk(X...) do { } while(0) -#endif - -#ifdef DEBUG_MMU_PTE -#define dprintk_pte(X...) printk(KERN_INFO X) -#else -#define dprintk_pte(X...) do { } while(0) -#endif - -#define PTEG_FLAG_ACCESSED 0x00000100 -#define PTEG_FLAG_DIRTY 0x00000080 -#ifndef SID_SHIFT -#define SID_SHIFT 28 -#endif - -static inline bool check_debug_ip(struct kvm_vcpu *vcpu) -{ -#ifdef DEBUG_MMU_PTE_IP - return vcpu->arch.pc == DEBUG_MMU_PTE_IP; -#else - return true; -#endif -} - -static inline u32 sr_vsid(u32 sr_raw) -{ - return sr_raw & 0x0fffffff; -} - -static inline bool sr_valid(u32 sr_raw) -{ - return (sr_raw & 0x80000000) ? false : true; -} - -static inline bool sr_ks(u32 sr_raw) -{ - return (sr_raw & 0x40000000) ? true: false; -} - -static inline bool sr_kp(u32 sr_raw) -{ - return (sr_raw & 0x20000000) ? true: false; -} - -static inline bool sr_nx(u32 sr_raw) -{ - return (sr_raw & 0x10000000) ? true: false; -} - -static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *pte, bool data); -static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, - u64 *vsid); - -static u32 find_sr(struct kvm_vcpu *vcpu, gva_t eaddr) -{ - return vcpu->arch.shared->sr[(eaddr >> 28) & 0xf]; -} - -static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, - bool data) -{ - u64 vsid; - struct kvmppc_pte pte; - - if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data)) - return pte.vpage; - - kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid); - return (((u64)eaddr >> 12) & 0xffff) | (vsid << 16); -} - -static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) -{ - kvmppc_set_msr(vcpu, 0); -} - -static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, - u32 sre, gva_t eaddr, - bool primary) -{ - u32 page, hash, pteg, htabmask; - hva_t r; - - page = (eaddr & 0x0FFFFFFF) >> 12; - htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; - - hash = ((sr_vsid(sre) ^ page) << 6); - if (!primary) - hash = ~hash; - hash &= htabmask; - - pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; - - dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", - kvmppc_get_pc(&vcpu_book3s->vcpu), eaddr, vcpu_book3s->sdr1, pteg, - sr_vsid(sre)); - - r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); - if (kvm_is_error_hva(r)) - return r; - return r | (pteg & ~PAGE_MASK); -} - -static u32 kvmppc_mmu_book3s_32_get_ptem(u32 sre, gva_t eaddr, bool primary) -{ - return ((eaddr & 0x0fffffff) >> 22) | (sr_vsid(sre) << 7) | - (primary ? 0 : 0x40) | 0x80000000; -} - -static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *pte, bool data) -{ - struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); - struct kvmppc_bat *bat; - int i; - - for (i = 0; i < 8; i++) { - if (data) - bat = &vcpu_book3s->dbat[i]; - else - bat = &vcpu_book3s->ibat[i]; - - if (vcpu->arch.shared->msr & MSR_PR) { - if (!bat->vp) - continue; - } else { - if (!bat->vs) - continue; - } - - if (check_debug_ip(vcpu)) - { - dprintk_pte("%cBAT %02d: 0x%lx - 0x%x (0x%x)\n", - data ? 'd' : 'i', i, eaddr, bat->bepi, - bat->bepi_mask); - } - if ((eaddr & bat->bepi_mask) == bat->bepi) { - u64 vsid; - kvmppc_mmu_book3s_32_esid_to_vsid(vcpu, - eaddr >> SID_SHIFT, &vsid); - vsid <<= 16; - pte->vpage = (((u64)eaddr >> 12) & 0xffff) | vsid; - - pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask); - pte->may_read = bat->pp; - pte->may_write = bat->pp > 1; - pte->may_execute = true; - if (!pte->may_read) { - printk(KERN_INFO "BAT is not readable!\n"); - continue; - } - if (!pte->may_write) { - /* let's treat r/o BATs as not-readable for now */ - dprintk_pte("BAT is read-only!\n"); - continue; - } - - return 0; - } - } - - return -ENOENT; -} - -static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *pte, bool data, - bool primary) -{ - struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); - u32 sre; - hva_t ptegp; - u32 pteg[16]; - u32 ptem = 0; - int i; - int found = 0; - - sre = find_sr(vcpu, eaddr); - - dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, - sr_vsid(sre), sre); - - pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); - - ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu_book3s, sre, eaddr, primary); - if (kvm_is_error_hva(ptegp)) { - printk(KERN_INFO "KVM: Invalid PTEG!\n"); - goto no_page_found; - } - - ptem = kvmppc_mmu_book3s_32_get_ptem(sre, eaddr, primary); - - if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) { - printk(KERN_ERR "KVM: Can't copy data from 0x%lx!\n", ptegp); - goto no_page_found; - } - - for (i=0; i<16; i+=2) { - if (ptem == pteg[i]) { - u8 pp; - - pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); - pp = pteg[i+1] & 3; - - if ((sr_kp(sre) && (vcpu->arch.shared->msr & MSR_PR)) || - (sr_ks(sre) && !(vcpu->arch.shared->msr & MSR_PR))) - pp |= 4; - - pte->may_write = false; - pte->may_read = false; - pte->may_execute = true; - switch (pp) { - case 0: - case 1: - case 2: - case 6: - pte->may_write = true; - case 3: - case 5: - case 7: - pte->may_read = true; - break; - } - - if ( !pte->may_read ) - continue; - - dprintk_pte("MMU: Found PTE -> %x %x - %x\n", - pteg[i], pteg[i+1], pp); - found = 1; - break; - } - } - - /* Update PTE C and A bits, so the guest's swapper knows we used the - page */ - if (found) { - u32 oldpte = pteg[i+1]; - - if (pte->may_read) - pteg[i+1] |= PTEG_FLAG_ACCESSED; - if (pte->may_write) - pteg[i+1] |= PTEG_FLAG_DIRTY; - else - dprintk_pte("KVM: Mapping read-only page!\n"); - - /* Write back into the PTEG */ - if (pteg[i+1] != oldpte) - copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); - - return 0; - } - -no_page_found: - - if (check_debug_ip(vcpu)) { - dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", - to_book3s(vcpu)->sdr1, ptegp); - for (i=0; i<16; i+=2) { - dprintk_pte(" %02d: 0x%x - 0x%x (0x%x)\n", - i, pteg[i], pteg[i+1], ptem); - } - } - - return -ENOENT; -} - -static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, - struct kvmppc_pte *pte, bool data) -{ - int r; - ulong mp_ea = vcpu->arch.magic_page_ea; - - pte->eaddr = eaddr; - - /* Magic page override */ - if (unlikely(mp_ea) && - unlikely((eaddr & ~0xfffULL) == (mp_ea & ~0xfffULL)) && - !(vcpu->arch.shared->msr & MSR_PR)) { - pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); - pte->raddr = vcpu->arch.magic_page_pa | (pte->raddr & 0xfff); - pte->raddr &= KVM_PAM; - pte->may_execute = true; - pte->may_read = true; - pte->may_write = true; - - return 0; - } - - r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); - if (r < 0) - r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); - if (r < 0) - r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, false); - - return r; -} - - -static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) -{ - return vcpu->arch.shared->sr[srnum]; -} - -static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, - ulong value) -{ - vcpu->arch.shared->sr[srnum] = value; - kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); -} - -static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large) -{ - kvmppc_mmu_pte_flush(vcpu, ea, 0x0FFFF000); -} - -static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid, - u64 *vsid) -{ - ulong ea = esid << SID_SHIFT; - u32 sr; - u64 gvsid = esid; - - if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { - sr = find_sr(vcpu, ea); - if (sr_valid(sr)) - gvsid = sr_vsid(sr); - } - - /* In case we only have one of MSR_IR or MSR_DR set, let's put - that in the real-mode context (and hope RM doesn't access - high memory) */ - switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) { - case 0: - *vsid = VSID_REAL | esid; - break; - case MSR_IR: - *vsid = VSID_REAL_IR | gvsid; - break; - case MSR_DR: - *vsid = VSID_REAL_DR | gvsid; - break; - case MSR_DR|MSR_IR: - if (sr_valid(sr)) - *vsid = sr_vsid(sr); - else - *vsid = VSID_BAT | gvsid; - break; - default: - BUG(); - } - - if (vcpu->arch.shared->msr & MSR_PR) - *vsid |= VSID_PR; - - return 0; -} - -static bool kvmppc_mmu_book3s_32_is_dcbz32(struct kvm_vcpu *vcpu) -{ - return true; -} - - -void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu) -{ - struct kvmppc_mmu *mmu = &vcpu->arch.mmu; - - mmu->mtsrin = kvmppc_mmu_book3s_32_mtsrin; - mmu->mfsrin = kvmppc_mmu_book3s_32_mfsrin; - mmu->xlate = kvmppc_mmu_book3s_32_xlate; - mmu->reset_msr = kvmppc_mmu_book3s_32_reset_msr; - mmu->tlbie = kvmppc_mmu_book3s_32_tlbie; - mmu->esid_to_vsid = kvmppc_mmu_book3s_32_esid_to_vsid; - mmu->ea_to_vp = kvmppc_mmu_book3s_32_ea_to_vp; - mmu->is_dcbz32 = kvmppc_mmu_book3s_32_is_dcbz32; - - mmu->slbmte = NULL; - mmu->slbmfee = NULL; - mmu->slbmfev = NULL; - mmu->slbie = NULL; - mmu->slbia = NULL; -} |