Commit 5c6cedf4 authored by Alexander Graf's avatar Alexander Graf Committed by Avi Kivity

KVM: PPC: Add PV guest critical sections

When running in hooked code we need a way to disable interrupts without
clobbering any interrupts or exiting out to the hypervisor.

To achieve this, we have an additional critical field in the shared page. If
that field is equal to the r1 register of the guest, it tells the hypervisor
that we're in such a critical section and thus may not receive any interrupts.
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 2a342ed5
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/of.h> #include <linux/of.h>
struct kvm_vcpu_arch_shared { struct kvm_vcpu_arch_shared {
__u64 critical; /* Guest may not get interrupts if == r1 */
__u64 sprg0; __u64 sprg0;
__u64 sprg1; __u64 sprg1;
__u64 sprg2; __u64 sprg2;
......
...@@ -251,14 +251,28 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) ...@@ -251,14 +251,28 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
int deliver = 1; int deliver = 1;
int vec = 0; int vec = 0;
ulong flags = 0ULL; ulong flags = 0ULL;
ulong crit_raw = vcpu->arch.shared->critical;
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
bool crit;
/* Truncate crit indicators in 32 bit mode */
if (!(vcpu->arch.shared->msr & MSR_SF)) {
crit_raw &= 0xffffffff;
crit_r1 &= 0xffffffff;
}
/* Critical section when crit == r1 */
crit = (crit_raw == crit_r1);
/* ... and we're in supervisor mode */
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
switch (priority) { switch (priority) {
case BOOK3S_IRQPRIO_DECREMENTER: case BOOK3S_IRQPRIO_DECREMENTER:
deliver = vcpu->arch.shared->msr & MSR_EE; deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
vec = BOOK3S_INTERRUPT_DECREMENTER; vec = BOOK3S_INTERRUPT_DECREMENTER;
break; break;
case BOOK3S_IRQPRIO_EXTERNAL: case BOOK3S_IRQPRIO_EXTERNAL:
deliver = vcpu->arch.shared->msr & MSR_EE; deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit;
vec = BOOK3S_INTERRUPT_EXTERNAL; vec = BOOK3S_INTERRUPT_EXTERNAL;
break; break;
case BOOK3S_IRQPRIO_SYSTEM_RESET: case BOOK3S_IRQPRIO_SYSTEM_RESET:
......
...@@ -147,6 +147,20 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, ...@@ -147,6 +147,20 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
int allowed = 0; int allowed = 0;
ulong uninitialized_var(msr_mask); ulong uninitialized_var(msr_mask);
bool update_esr = false, update_dear = false; bool update_esr = false, update_dear = false;
ulong crit_raw = vcpu->arch.shared->critical;
ulong crit_r1 = kvmppc_get_gpr(vcpu, 1);
bool crit;
/* Truncate crit indicators in 32 bit mode */
if (!(vcpu->arch.shared->msr & MSR_SF)) {
crit_raw &= 0xffffffff;
crit_r1 &= 0xffffffff;
}
/* Critical section when crit == r1 */
crit = (crit_raw == crit_r1);
/* ... and we're in supervisor mode */
crit = crit && !(vcpu->arch.shared->msr & MSR_PR);
switch (priority) { switch (priority) {
case BOOKE_IRQPRIO_DTLB_MISS: case BOOKE_IRQPRIO_DTLB_MISS:
...@@ -181,6 +195,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, ...@@ -181,6 +195,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
case BOOKE_IRQPRIO_DECREMENTER: case BOOKE_IRQPRIO_DECREMENTER:
case BOOKE_IRQPRIO_FIT: case BOOKE_IRQPRIO_FIT:
allowed = vcpu->arch.shared->msr & MSR_EE; allowed = vcpu->arch.shared->msr & MSR_EE;
allowed = allowed && !crit;
msr_mask = MSR_CE|MSR_ME|MSR_DE; msr_mask = MSR_CE|MSR_ME|MSR_DE;
break; break;
case BOOKE_IRQPRIO_DEBUG: case BOOKE_IRQPRIO_DEBUG:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment