Skip to content

Commit 72e3244

Browse files
mrutland-armbonzini
authored andcommitted
kvm/mips: rework guest entry logic
In kvm_arch_vcpu_ioctl_run() we use guest_enter_irqoff() and guest_exit_irqoff() directly, with interrupts masked between these. As we don't handle any timer ticks during this window, we will not account time spent within the guest as guest time, which is unfortunate. Additionally, we do not inform lockdep or tracing that interrupts will be enabled during guest execution, which caan lead to misleading traces and warnings that interrupts have been enabled for overly-long periods. This patch fixes these issues by using the new timing and context entry/exit helpers to ensure that interrupts are handled during guest vtime but with RCU watching, with a sequence: guest_timing_enter_irqoff(); guest_state_enter_irqoff(); < run the vcpu > guest_state_exit_irqoff(); < take any pending IRQs > guest_timing_exit_irqoff(); In addition, as guest exits during the "run the vcpu" step are handled by kvm_mips_handle_exit(), a wrapper function is added which ensures that such exists are handled with a sequence: guest_state_exit_irqoff(); < handle the exit > guest_state_enter_irqoff(); This means that exits which stop the vCPU running will have a redundant guest_state_enter_irqoff() .. guest_state_exit_irqoff() sequence, which can be addressed with future rework. Since instrumentation may make use of RCU, we must also ensure that no instrumented code is run during the EQS. I've split out the critical section into a new kvm_mips_enter_exit_vcpu() helper which is marked noinstr. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> Cc: Frederic Weisbecker <frederic@kernel.org> Cc: Huacai Chen <chenhuacai@kernel.org> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Paul E. McKenney <paulmck@kernel.org> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Message-Id: <20220201132926.3301912-6-mark.rutland@arm.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent ef9989a commit 72e3244

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

arch/mips/kvm/mips.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,24 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
414414
return -ENOIOCTLCMD;
415415
}
416416

417+
/*
418+
* Actually run the vCPU, entering an RCU extended quiescent state (EQS) while
419+
* the vCPU is running.
420+
*
421+
* This must be noinstr as instrumentation may make use of RCU, and this is not
422+
* safe during the EQS.
423+
*/
424+
static int noinstr kvm_mips_vcpu_enter_exit(struct kvm_vcpu *vcpu)
425+
{
426+
int ret;
427+
428+
guest_state_enter_irqoff();
429+
ret = kvm_mips_callbacks->vcpu_run(vcpu);
430+
guest_state_exit_irqoff();
431+
432+
return ret;
433+
}
434+
417435
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
418436
{
419437
int r = -EINTR;
@@ -434,7 +452,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
434452
lose_fpu(1);
435453

436454
local_irq_disable();
437-
guest_enter_irqoff();
455+
guest_timing_enter_irqoff();
438456
trace_kvm_enter(vcpu);
439457

440458
/*
@@ -445,10 +463,23 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
445463
*/
446464
smp_store_mb(vcpu->mode, IN_GUEST_MODE);
447465

448-
r = kvm_mips_callbacks->vcpu_run(vcpu);
466+
r = kvm_mips_vcpu_enter_exit(vcpu);
467+
468+
/*
469+
* We must ensure that any pending interrupts are taken before
470+
* we exit guest timing so that timer ticks are accounted as
471+
* guest time. Transiently unmask interrupts so that any
472+
* pending interrupts are taken.
473+
*
474+
* TODO: is there a barrier which ensures that pending interrupts are
475+
* recognised? Currently this just hopes that the CPU takes any pending
476+
* interrupts between the enable and disable.
477+
*/
478+
local_irq_enable();
479+
local_irq_disable();
449480

450481
trace_kvm_out(vcpu);
451-
guest_exit_irqoff();
482+
guest_timing_exit_irqoff();
452483
local_irq_enable();
453484

454485
out:
@@ -1168,7 +1199,7 @@ static void kvm_mips_set_c0_status(void)
11681199
/*
11691200
* Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
11701201
*/
1171-
int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
1202+
static int __kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
11721203
{
11731204
struct kvm_run *run = vcpu->run;
11741205
u32 cause = vcpu->arch.host_cp0_cause;
@@ -1357,6 +1388,17 @@ int kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
13571388
return ret;
13581389
}
13591390

1391+
int noinstr kvm_mips_handle_exit(struct kvm_vcpu *vcpu)
1392+
{
1393+
int ret;
1394+
1395+
guest_state_exit_irqoff();
1396+
ret = __kvm_mips_handle_exit(vcpu);
1397+
guest_state_enter_irqoff();
1398+
1399+
return ret;
1400+
}
1401+
13601402
/* Enable FPU for guest and restore context */
13611403
void kvm_own_fpu(struct kvm_vcpu *vcpu)
13621404
{

0 commit comments

Comments
 (0)