arch/powerpc/kvm/book3s_64_mmu_host.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kvm/book3s_64_mmu_host.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kvm/book3s_64_mmu_host.c
Extension
.c
Size
10174 bytes
Lines
408
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (mmu_hash_ops.hpte_remove(hpteg) < 0) {
			r = -1;
			goto out_unlock;
		}

	ret = mmu_hash_ops.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags,
				       hpsize, hpsize, MMU_SEGSIZE_256M);

	if (ret == -1) {
		/* If we couldn't map a primary PTE, try a secondary */
		hash = ~hash;
		vflags ^= HPTE_V_SECONDARY;
		attempt++;
		goto map_again;
	} else if (ret < 0) {
		r = -EIO;
		goto out_unlock;
	} else {
		trace_kvm_book3s_64_mmu_map(rflags, hpteg,
					    vpn, hpaddr, orig_pte);

		/*
		 * The mmu_hash_ops code may give us a secondary entry even
		 * though we asked for a primary. Fix up.
		 */
		if ((ret & _PTEIDX_SECONDARY) && !(vflags & HPTE_V_SECONDARY)) {
			hash = ~hash;
			hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
		}

		cpte->slot = hpteg + (ret & 7);
		cpte->host_vpn = vpn;
		cpte->pte = *orig_pte;
		cpte->pfn = pfn;
		cpte->pagesize = hpsize;

		kvmppc_mmu_hpte_cache_map(vcpu, cpte);
		cpte = NULL;
	}

out_unlock:
	/* FIXME: Don't unconditionally pass unused=false. */
	kvm_release_faultin_page(kvm, page, false,
				 orig_pte->may_write && writable);
	spin_unlock(&kvm->mmu_lock);
	if (cpte)
		kvmppc_mmu_hpte_cache_free(cpte);

out:
	return r;
}

void kvmppc_mmu_unmap_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
{
	u64 mask = 0xfffffffffULL;
	u64 vsid;

	vcpu->arch.mmu.esid_to_vsid(vcpu, pte->eaddr >> SID_SHIFT, &vsid);
	if (vsid & VSID_64K)
		mask = 0xffffffff0ULL;
	kvmppc_mmu_pte_vflush(vcpu, pte->vpage, mask);
}

static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
{
	unsigned long vsid_bits = VSID_BITS_65_256M;
	struct kvmppc_sid_map *map;
	struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
	u16 sid_map_mask;
	static int backwards_map;

	if (kvmppc_get_msr(vcpu) & MSR_PR)
		gvsid |= VSID_PR;

	/* We might get collisions that trap in preceding order, so let's
	   map them differently */

	sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
	if (backwards_map)
		sid_map_mask = SID_MAP_MASK - sid_map_mask;

	map = &to_book3s(vcpu)->sid_map[sid_map_mask];

	/* Make sure we're taking the other map next time */
	backwards_map = !backwards_map;

	/* Uh-oh ... out of mappings. Let's flush! */
	if (vcpu_book3s->proto_vsid_next == vcpu_book3s->proto_vsid_max) {
		vcpu_book3s->proto_vsid_next = vcpu_book3s->proto_vsid_first;
		memset(vcpu_book3s->sid_map, 0,

Annotation

Implementation Notes