arch/powerpc/kvm/book3s_pr_papr.c

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

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kvm/book3s_pr_papr.c
Extension
.c
Size
12553 bytes
Lines
497
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 ((tsh & H_BULK_REMOVE_TYPE) == H_BULK_REMOVE_END) {
			break; /* Exit success */
		} else if ((tsh & H_BULK_REMOVE_TYPE) !=
			   H_BULK_REMOVE_REQUEST) {
			ret = H_PARAMETER;
			break; /* Exit fail */
		}

		tsh &= H_BULK_REMOVE_PTEX | H_BULK_REMOVE_FLAGS;
		tsh |= H_BULK_REMOVE_RESPONSE;

		if ((tsh & H_BULK_REMOVE_ANDCOND) &&
		    (tsh & H_BULK_REMOVE_AVPN)) {
			tsh |= H_BULK_REMOVE_PARM;
			kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
			ret = H_PARAMETER;
			break; /* Exit fail */
		}

		pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
		if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) {
			ret = H_FUNCTION;
			break;
		}
		pte[0] = be64_to_cpu((__force __be64)pte[0]);
		pte[1] = be64_to_cpu((__force __be64)pte[1]);

		/* tsl = AVPN */
		flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26;

		if ((pte[0] & HPTE_V_VALID) == 0 ||
		    ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != tsl) ||
		    ((flags & H_ANDCOND) && (pte[0] & tsl) != 0)) {
			tsh |= H_BULK_REMOVE_NOT_FOUND;
		} else {
			/* Splat the pteg in (userland) hpt */
			if (copy_to_user((void __user *)pteg, &v, sizeof(v))) {
				ret = H_FUNCTION;
				break;
			}

			rb = compute_tlbie_rb(pte[0], pte[1],
					      tsh & H_BULK_REMOVE_PTEX);
			vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
			tsh |= H_BULK_REMOVE_SUCCESS;
			tsh |= (pte[1] & (HPTE_R_C | HPTE_R_R)) << 43;
		}
		kvmppc_set_gpr(vcpu, paramnr+(2*i), tsh);
	}
	mutex_unlock(&vcpu->kvm->arch.hpt_mutex);
	kvmppc_set_gpr(vcpu, 3, ret);

	return EMULATE_DONE;
}

static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
{
	unsigned long flags = kvmppc_get_gpr(vcpu, 4);
	unsigned long pte_index = kvmppc_get_gpr(vcpu, 5);
	unsigned long avpn = kvmppc_get_gpr(vcpu, 6);
	unsigned long rb, pteg, r, v;
	unsigned long pte[2];
	long int ret;

	pteg = get_pteg_addr(vcpu, pte_index);
	mutex_lock(&vcpu->kvm->arch.hpt_mutex);
	ret = H_FUNCTION;
	if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
		goto done;
	pte[0] = be64_to_cpu((__force __be64)pte[0]);
	pte[1] = be64_to_cpu((__force __be64)pte[1]);

	ret = H_NOT_FOUND;
	if ((pte[0] & HPTE_V_VALID) == 0 ||
	    ((flags & H_AVPN) && (pte[0] & ~0x7fUL) != avpn))
		goto done;

	v = pte[0];
	r = pte[1];
	r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_HI |
	       HPTE_R_KEY_LO);
	r |= (flags << 55) & HPTE_R_PP0;
	r |= (flags << 48) & HPTE_R_KEY_HI;
	r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);

	pte[1] = r;

	rb = compute_tlbie_rb(v, r, pte_index);
	vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
	pte[0] = (__force u64)cpu_to_be64(pte[0]);

Annotation

Implementation Notes