diff options
author | Alexander Graf <agraf@suse.de> | 2011-08-08 10:07:16 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-09-25 12:52:20 -0400 |
commit | 317a8fa304f8ba3cd8b67b0f5f38e366e8c3cf1d (patch) | |
tree | 874c27833a8dbaddce52f5313c7c6af41143369d /arch/powerpc | |
parent | 9432ba6015371f186926cd62e2395718217a17a1 (diff) |
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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kvm/book3s_emulate.c | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 466846557089..bf0ddcd98bcc 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c | |||
@@ -63,6 +63,25 @@ | |||
63 | * function pointers, so let's just disable the define. */ | 63 | * function pointers, so let's just disable the define. */ |
64 | #undef mfsrin | 64 | #undef mfsrin |
65 | 65 | ||
66 | enum priv_level { | ||
67 | PRIV_PROBLEM = 0, | ||
68 | PRIV_SUPER = 1, | ||
69 | PRIV_HYPER = 2, | ||
70 | }; | ||
71 | |||
72 | static bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level) | ||
73 | { | ||
74 | /* PAPR VMs only access supervisor SPRs */ | ||
75 | if (vcpu->arch.papr_enabled && (level > PRIV_SUPER)) | ||
76 | return false; | ||
77 | |||
78 | /* Limit user space to its own small SPR set */ | ||
79 | if ((vcpu->arch.shared->msr & MSR_PR) && level > PRIV_PROBLEM) | ||
80 | return false; | ||
81 | |||
82 | return true; | ||
83 | } | ||
84 | |||
66 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | 85 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, |
67 | unsigned int inst, int *advance) | 86 | unsigned int inst, int *advance) |
68 | { | 87 | { |
@@ -296,6 +315,8 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | |||
296 | 315 | ||
297 | switch (sprn) { | 316 | switch (sprn) { |
298 | case SPRN_SDR1: | 317 | case SPRN_SDR1: |
318 | if (!spr_allowed(vcpu, PRIV_HYPER)) | ||
319 | goto unprivileged; | ||
299 | to_book3s(vcpu)->sdr1 = spr_val; | 320 | to_book3s(vcpu)->sdr1 = spr_val; |
300 | break; | 321 | break; |
301 | case SPRN_DSISR: | 322 | case SPRN_DSISR: |
@@ -390,6 +411,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | |||
390 | case SPRN_PMC4_GEKKO: | 411 | case SPRN_PMC4_GEKKO: |
391 | case SPRN_WPAR_GEKKO: | 412 | case SPRN_WPAR_GEKKO: |
392 | break; | 413 | break; |
414 | unprivileged: | ||
393 | default: | 415 | default: |
394 | printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); | 416 | printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); |
395 | #ifndef DEBUG_SPR | 417 | #ifndef DEBUG_SPR |
@@ -421,6 +443,8 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | |||
421 | break; | 443 | break; |
422 | } | 444 | } |
423 | case SPRN_SDR1: | 445 | case SPRN_SDR1: |
446 | if (!spr_allowed(vcpu, PRIV_HYPER)) | ||
447 | goto unprivileged; | ||
424 | kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1); | 448 | kvmppc_set_gpr(vcpu, rt, to_book3s(vcpu)->sdr1); |
425 | break; | 449 | break; |
426 | case SPRN_DSISR: | 450 | case SPRN_DSISR: |
@@ -476,6 +500,7 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | |||
476 | kvmppc_set_gpr(vcpu, rt, 0); | 500 | kvmppc_set_gpr(vcpu, rt, 0); |
477 | break; | 501 | break; |
478 | default: | 502 | default: |
503 | unprivileged: | ||
479 | printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn); | 504 | printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn); |
480 | #ifndef DEBUG_SPR | 505 | #ifndef DEBUG_SPR |
481 | emulated = EMULATE_FAIL; | 506 | emulated = EMULATE_FAIL; |