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: Alexander Graf <agraf@suse.de>
This commit is contained in:
committed by
Avi Kivity
parent
9432ba6015
commit
317a8fa304
@@ -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;
|
||||||
|
Reference in New Issue
Block a user