Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 317a8fa3 authored by Alexander Graf's avatar Alexander Graf Committed by Avi Kivity
Browse files

KVM: PPC: Check privilege level on SPRs



We have 3 privilege levels: problem state, supervisor state and hypervisor
state. Each of them can access different SPRs, so we need to check on every
SPR if it's accessible in the respective mode.

Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 9432ba60
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -63,6 +63,25 @@
 * function pointers, so let's just disable the define. */
 * function pointers, so let's just disable the define. */
#undef mfsrin
#undef mfsrin


enum priv_level {
	PRIV_PROBLEM = 0,
	PRIV_SUPER = 1,
	PRIV_HYPER = 2,
};

static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level)
{
	/* PAPR VMs only access supervisor SPRs */
	if (vcpu->arch.papr_enabled && (level > PRIV_SUPER))
		return false;

	/* Limit user space to its own small SPR set */
	if ((vcpu->arch.shared->msr & MSR_PR) && level > PRIV_PROBLEM)
		return false;

	return true;
}

int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                           unsigned int inst, int *advance)
                           unsigned int inst, int *advance)
{
{
@@ -296,6 +315,8 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)


	switch (sprn) {
	switch (sprn) {
	case SPRN_SDR1:
	case SPRN_SDR1:
		if (!spr_allowed(vcpu, PRIV_HYPER))
			goto unprivileged;
		to_book3s(vcpu)->sdr1 = spr_val;
		to_book3s(vcpu)->sdr1 = spr_val;
		break;
		break;
	case SPRN_DSISR:
	case SPRN_DSISR:
@@ -390,6 +411,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
	case SPRN_PMC4_GEKKO:
	case SPRN_PMC4_GEKKO:
	case SPRN_WPAR_GEKKO:
	case SPRN_WPAR_GEKKO:
		break;
		break;
unprivileged:
	default:
	default:
		printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);
		printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn);
#ifndef DEBUG_SPR
#ifndef DEBUG_SPR
@@ -421,6 +443,8 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
		break;
		break;
	}
	}
	case SPRN_SDR1:
	case SPRN_SDR1:
		if (!spr_allowed(vcpu, PRIV_HYPER))
			goto unprivileged;
		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
		kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1);
		break;
		break;
	case SPRN_DSISR:
	case SPRN_DSISR:
@@ -476,6 +500,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
		kvmppc_set_gpr(vcpu, rt, 0);
		kvmppc_set_gpr(vcpu, rt, 0);
		break;
		break;
	default:
	default:
unprivileged:
		printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn);
		printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn);
#ifndef DEBUG_SPR
#ifndef DEBUG_SPR
		emulated = EMULATE_FAIL;
		emulated = EMULATE_FAIL;