Esempio n. 1
0
static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_PPC_BOOK3S_64
	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
	if (svcpu->in_use) {
		kvmppc_copy_from_svcpu(vcpu, svcpu);
	}
	memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
	to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
	svcpu_put(svcpu);
#endif

	if (kvmppc_is_split_real(vcpu))
		kvmppc_unfixup_split_real(vcpu);

	kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
	kvmppc_giveup_fac(vcpu, FSCR_TAR_LG);

	/* Enable AIL if supported */
	if (cpu_has_feature(CPU_FTR_HVMODE) &&
	    cpu_has_feature(CPU_FTR_ARCH_207S))
		mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_AIL_3);

	vcpu->cpu = -1;
}
static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)
{
#ifdef CONFIG_PPC_BOOK3S_64
    struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
    memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb));
    svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
    svcpu->in_use = 0;
    svcpu_put(svcpu);
#endif
    vcpu->cpu = smp_processor_id();
#ifdef CONFIG_PPC_BOOK3S_32
    current->thread.kvm_shadow_vcpu = vcpu->arch.shadow_vcpu;
#endif
}
static void kvmppc_core_vcpu_put_pr(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_PPC_BOOK3S_64
    struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
    if (svcpu->in_use) {
        kvmppc_copy_from_svcpu(vcpu, svcpu);
    }
    memcpy(to_book3s(vcpu)->slb_shadow, svcpu->slb, sizeof(svcpu->slb));
    to_book3s(vcpu)->slb_shadow_max = svcpu->slb_max;
    svcpu_put(svcpu);
#endif

    kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
    vcpu->cpu = -1;
}
Esempio n. 4
0
static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvm_vcpu *vcpu,
				      u32 sre, gva_t eaddr,
				      bool primary)
{
	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
	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), eaddr, vcpu_book3s->sdr1, pteg,
		sr_vsid(sre));

	r = gfn_to_hva(vcpu->kvm, pteg >> PAGE_SHIFT);
	if (kvm_is_error_hva(r))
		return r;
	return r | (pteg & ~PAGE_MASK);
}
static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);

	trace_kvm_book3s_mmu_invalidate(pte);

	/* Different for 32 and 64 bit */
	kvmppc_mmu_invalidate_pte(vcpu, pte);

	spin_lock(&vcpu3s->mmu_lock);

	/* pte already invalidated in between? */
	if (hlist_unhashed(&pte->list_pte)) {
		spin_unlock(&vcpu3s->mmu_lock);
		return;
	}

	hlist_del_init_rcu(&pte->list_pte);
	hlist_del_init_rcu(&pte->list_pte_long);
	hlist_del_init_rcu(&pte->list_vpte);
	hlist_del_init_rcu(&pte->list_vpte_long);

	if (pte->pte.may_write)
		kvm_release_pfn_dirty(pte->pfn);
	else
		kvm_release_pfn_clean(pte->pfn);

	spin_unlock(&vcpu3s->mmu_lock);

	vcpu3s->hpte_cache_count--;
	call_rcu(&pte->rcu_head, free_pte_rcu);
}
void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
	u64 index;
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);

	trace_kvm_book3s_mmu_map(pte);

	spin_lock(&vcpu3s->mmu_lock);

	/* Add to ePTE list */
	index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
	hlist_add_head_rcu(&pte->list_pte, &vcpu3s->hpte_hash_pte[index]);

	/* Add to ePTE_long list */
	index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
	hlist_add_head_rcu(&pte->list_pte_long,
			   &vcpu3s->hpte_hash_pte_long[index]);

	/* Add to vPTE list */
	index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
	hlist_add_head_rcu(&pte->list_vpte, &vcpu3s->hpte_hash_vpte[index]);

	/* Add to vPTE_long list */
	index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
	hlist_add_head_rcu(&pte->list_vpte_long,
			   &vcpu3s->hpte_hash_vpte_long[index]);

	spin_unlock(&vcpu3s->mmu_lock);
}
/* Copy data touched by real-mode code from shadow vcpu back to vcpu */
void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
			    struct kvmppc_book3s_shadow_vcpu *svcpu)
{
	/*
	 * vcpu_put would just call us again because in_use hasn't
	 * been updated yet.
	 */
	preempt_disable();

	/*
	 * Maybe we were already preempted and synced the svcpu from
	 * our preempt notifiers. Don't bother touching this svcpu then.
	 */
	if (!svcpu->in_use)
		goto out;

	vcpu->arch.gpr[0] = svcpu->gpr[0];
	vcpu->arch.gpr[1] = svcpu->gpr[1];
	vcpu->arch.gpr[2] = svcpu->gpr[2];
	vcpu->arch.gpr[3] = svcpu->gpr[3];
	vcpu->arch.gpr[4] = svcpu->gpr[4];
	vcpu->arch.gpr[5] = svcpu->gpr[5];
	vcpu->arch.gpr[6] = svcpu->gpr[6];
	vcpu->arch.gpr[7] = svcpu->gpr[7];
	vcpu->arch.gpr[8] = svcpu->gpr[8];
	vcpu->arch.gpr[9] = svcpu->gpr[9];
	vcpu->arch.gpr[10] = svcpu->gpr[10];
	vcpu->arch.gpr[11] = svcpu->gpr[11];
	vcpu->arch.gpr[12] = svcpu->gpr[12];
	vcpu->arch.gpr[13] = svcpu->gpr[13];
	vcpu->arch.cr  = svcpu->cr;
	vcpu->arch.xer = svcpu->xer;
	vcpu->arch.ctr = svcpu->ctr;
	vcpu->arch.lr  = svcpu->lr;
	vcpu->arch.pc  = svcpu->pc;
	vcpu->arch.shadow_srr1 = svcpu->shadow_srr1;
	vcpu->arch.fault_dar   = svcpu->fault_dar;
	vcpu->arch.fault_dsisr = svcpu->fault_dsisr;
	vcpu->arch.last_inst   = svcpu->last_inst;
#ifdef CONFIG_PPC_BOOK3S_64
	vcpu->arch.shadow_fscr = svcpu->shadow_fscr;
#endif
	/*
	 * Update purr and spurr using time base on exit.
	 */
	vcpu->arch.purr += get_tb() - vcpu->arch.entry_tb;
	vcpu->arch.spurr += get_tb() - vcpu->arch.entry_tb;
	to_book3s(vcpu)->vtb += get_vtb() - vcpu->arch.entry_vtb;
	if (cpu_has_feature(CPU_FTR_ARCH_207S))
		vcpu->arch.ic += mfspr(SPRN_IC) - vcpu->arch.entry_ic;
	svcpu->in_use = false;

out:
	preempt_enable();
}
Esempio n. 8
0
static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index)
{
	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
	unsigned long pteg_addr;

	pte_index <<= 4;
	pte_index &= ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1) << 7 | 0x70;
	pteg_addr = vcpu_book3s->sdr1 & 0xfffffffffffc0000ULL;
	pteg_addr |= pte_index;

	return pteg_addr;
}
struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	struct hpte_cache *pte;

	pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
	vcpu3s->hpte_cache_count++;

	if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM)
		kvmppc_mmu_pte_flush_all(vcpu);

	return pte;
}
Esempio n. 10
0
static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr,
					  struct kvmppc_pte *pte, bool data,
					  bool iswrite)
{
	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 (kvmppc_get_msr(vcpu) & 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 (iswrite && !pte->may_write) {
				dprintk_pte("BAT is read-only!\n");
				continue;
			}

			return 0;
		}
	}
Esempio n. 11
0
static void kvmppc_core_vcpu_load_pr(struct kvm_vcpu *vcpu, int cpu)
{
#ifdef CONFIG_PPC_BOOK3S_64
	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
	memcpy(svcpu->slb, to_book3s(vcpu)->slb_shadow, sizeof(svcpu->slb));
	svcpu->slb_max = to_book3s(vcpu)->slb_shadow_max;
	svcpu->in_use = 0;
	svcpu_put(svcpu);
#endif

	/* Disable AIL if supported */
	if (cpu_has_feature(CPU_FTR_HVMODE) &&
	    cpu_has_feature(CPU_FTR_ARCH_207S))
		mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~LPCR_AIL);

	vcpu->cpu = smp_processor_id();
#ifdef CONFIG_PPC_BOOK3S_32
	current->thread.kvm_shadow_vcpu = vcpu->arch.shadow_vcpu;
#endif

	if (kvmppc_is_split_real(vcpu))
		kvmppc_fixup_split_real(vcpu);
}
static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	struct hpte_cache *pte;
	int i;

	rcu_read_lock();

	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
		struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i];

		hlist_for_each_entry_rcu(pte, list, list_vpte_long)
			invalidate_pte(vcpu, pte);
	}

	rcu_read_unlock();
}
int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);

	/* init hpte lookup hashes */
	kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte,
				  ARRAY_SIZE(vcpu3s->hpte_hash_pte));
	kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_pte_long,
				  ARRAY_SIZE(vcpu3s->hpte_hash_pte_long));
	kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte,
				  ARRAY_SIZE(vcpu3s->hpte_hash_vpte));
	kvmppc_mmu_hpte_init_hash(vcpu3s->hpte_hash_vpte_long,
				  ARRAY_SIZE(vcpu3s->hpte_hash_vpte_long));

	spin_lock_init(&vcpu3s->mmu_lock);

	return 0;
}
/* Flush with mask 0xfffffffff */
static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	struct hlist_head *list;
	struct hpte_cache *pte;
	u64 vp_mask = 0xfffffffffULL;

	list = &vcpu3s->hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];

	rcu_read_lock();

	/* Check the list for matching entries and invalidate */
	hlist_for_each_entry_rcu(pte, list, list_vpte)
		if ((pte->pte.vpage & vp_mask) == guest_vp)
			invalidate_pte(vcpu, pte);

	rcu_read_unlock();
}
static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	struct hlist_head *list;
	struct hpte_cache *pte;

	/* Find the list of entries in the map */
	list = &vcpu3s->hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];

	rcu_read_lock();

	/* Check the list for matching entries and invalidate */
	hlist_for_each_entry_rcu(pte, list, list_pte)
		if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
			invalidate_pte(vcpu, pte);

	rcu_read_unlock();
}
void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	struct hpte_cache *pte;
	int i;

	trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end);

	rcu_read_lock();

	for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
		struct hlist_head *list = &vcpu3s->hpte_hash_vpte_long[i];

		hlist_for_each_entry_rcu(pte, list, list_vpte_long)
			if ((pte->pte.raddr >= pa_start) &&
			    (pte->pte.raddr < pa_end))
				invalidate_pte(vcpu, pte);
	}

	rcu_read_unlock();
}