aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kvm
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-05-29 05:16:37 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-05-30 07:02:45 -0400
commitf82393426afb7c82f7618b3b4e440d8dd2b40c08 (patch)
treefdbaec36165ae0545c8561acf7d56cd09454faef /arch/mips/kvm
parenteda3d33c685ff62524500681249e4c8e2e8dbb8c (diff)
MIPS: KVM: Add master disable count interface
Expose two new virtual registers to userland via the KVM_{GET,SET}_ONE_REG ioctls. KVM_REG_MIPS_COUNT_CTL is for timer configuration fields and just contains a master disable count bit. This can be used by userland to freeze the timer in order to read a consistent state from the timer count value and timer interrupt pending bit. This cannot be done with the CP0_Cause.DC bit because the timer interrupt pending bit (TI) is also in CP0_Cause so it would be impossible to stop the timer without also risking a race with an hrtimer interrupt and having to explicitly check whether an interrupt should have occurred. When the timer is re-enabled it resumes without losing time, i.e. the CP0_Count value jumps to what it would have been had the timer not been disabled, which would also be impossible to do from userland with CP0_Cause.DC. The timer interrupt also cannot be lost, i.e. if a timer interrupt would have occurred had the timer not been disabled it is queued when the timer is re-enabled. This works by storing the nanosecond monotonic time when the master disable is set, and using it for various operations instead of the current monotonic time (e.g. when recalculating the bias when the CP0_Count is set), until the master disable is cleared again, i.e. the timer state is read/written as it would have been at that time. This state is exposed to userland via the read-only KVM_REG_MIPS_COUNT_RESUME virtual register so that userland can determine the exact time the master disable took effect. This should allow userland to atomically save the state of the timer, and later restore it. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Gleb Natapov <gleb@kernel.org> Cc: kvm@vger.kernel.org Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: David Daney <david.daney@cavium.com> Cc: Sanjay Lal <sanjayl@kymasys.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/mips/kvm')
-rw-r--r--arch/mips/kvm/kvm_mips.c9
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c132
-rw-r--r--arch/mips/kvm/kvm_trap_emul.c15
3 files changed, 142 insertions, 14 deletions
diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c
index fc5e44d827fc..a2d5d4243f51 100644
--- a/arch/mips/kvm/kvm_mips.c
+++ b/arch/mips/kvm/kvm_mips.c
@@ -542,7 +542,10 @@ static u64 kvm_mips_get_one_regs[] = {
542 KVM_REG_MIPS_CP0_CONFIG2, 542 KVM_REG_MIPS_CP0_CONFIG2,
543 KVM_REG_MIPS_CP0_CONFIG3, 543 KVM_REG_MIPS_CP0_CONFIG3,
544 KVM_REG_MIPS_CP0_CONFIG7, 544 KVM_REG_MIPS_CP0_CONFIG7,
545 KVM_REG_MIPS_CP0_ERROREPC 545 KVM_REG_MIPS_CP0_ERROREPC,
546
547 KVM_REG_MIPS_COUNT_CTL,
548 KVM_REG_MIPS_COUNT_RESUME,
546}; 549};
547 550
548static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, 551static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
@@ -622,6 +625,8 @@ static int kvm_mips_get_reg(struct kvm_vcpu *vcpu,
622 break; 625 break;
623 /* registers to be handled specially */ 626 /* registers to be handled specially */
624 case KVM_REG_MIPS_CP0_COUNT: 627 case KVM_REG_MIPS_CP0_COUNT:
628 case KVM_REG_MIPS_COUNT_CTL:
629 case KVM_REG_MIPS_COUNT_RESUME:
625 ret = kvm_mips_callbacks->get_one_reg(vcpu, reg, &v); 630 ret = kvm_mips_callbacks->get_one_reg(vcpu, reg, &v);
626 if (ret) 631 if (ret)
627 return ret; 632 return ret;
@@ -717,6 +722,8 @@ static int kvm_mips_set_reg(struct kvm_vcpu *vcpu,
717 case KVM_REG_MIPS_CP0_COUNT: 722 case KVM_REG_MIPS_CP0_COUNT:
718 case KVM_REG_MIPS_CP0_COMPARE: 723 case KVM_REG_MIPS_CP0_COMPARE:
719 case KVM_REG_MIPS_CP0_CAUSE: 724 case KVM_REG_MIPS_CP0_CAUSE:
725 case KVM_REG_MIPS_COUNT_CTL:
726 case KVM_REG_MIPS_COUNT_RESUME:
720 return kvm_mips_callbacks->set_one_reg(vcpu, reg, v); 727 return kvm_mips_callbacks->set_one_reg(vcpu, reg, v);
721 default: 728 default:
722 return -EINVAL; 729 return -EINVAL;
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c
index 088c25d73a11..65c8dea6d1f5 100644
--- a/arch/mips/kvm/kvm_mips_emul.c
+++ b/arch/mips/kvm/kvm_mips_emul.c
@@ -233,14 +233,15 @@ enum emulation_result update_pc(struct kvm_vcpu *vcpu, uint32_t cause)
233 * kvm_mips_count_disabled() - Find whether the CP0_Count timer is disabled. 233 * kvm_mips_count_disabled() - Find whether the CP0_Count timer is disabled.
234 * @vcpu: Virtual CPU. 234 * @vcpu: Virtual CPU.
235 * 235 *
236 * Returns: 1 if the CP0_Count timer is disabled by the guest CP0_Cause.DC 236 * Returns: 1 if the CP0_Count timer is disabled by either the guest
237 * bit. 237 * CP0_Cause.DC bit or the count_ctl.DC bit.
238 * 0 otherwise (in which case CP0_Count timer is running). 238 * 0 otherwise (in which case CP0_Count timer is running).
239 */ 239 */
240static inline int kvm_mips_count_disabled(struct kvm_vcpu *vcpu) 240static inline int kvm_mips_count_disabled(struct kvm_vcpu *vcpu)
241{ 241{
242 struct mips_coproc *cop0 = vcpu->arch.cop0; 242 struct mips_coproc *cop0 = vcpu->arch.cop0;
243 return kvm_read_c0_guest_cause(cop0) & CAUSEF_DC; 243 return (vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC) ||
244 (kvm_read_c0_guest_cause(cop0) & CAUSEF_DC);
244} 245}
245 246
246/** 247/**
@@ -280,6 +281,24 @@ static uint32_t kvm_mips_ktime_to_count(struct kvm_vcpu *vcpu, ktime_t now)
280} 281}
281 282
282/** 283/**
284 * kvm_mips_count_time() - Get effective current time.
285 * @vcpu: Virtual CPU.
286 *
287 * Get effective monotonic ktime. This is usually a straightforward ktime_get(),
288 * except when the master disable bit is set in count_ctl, in which case it is
289 * count_resume, i.e. the time that the count was disabled.
290 *
291 * Returns: Effective monotonic ktime for CP0_Count.
292 */
293static inline ktime_t kvm_mips_count_time(struct kvm_vcpu *vcpu)
294{
295 if (unlikely(vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC))
296 return vcpu->arch.count_resume;
297
298 return ktime_get();
299}
300
301/**
283 * kvm_mips_read_count_running() - Read the current count value as if running. 302 * kvm_mips_read_count_running() - Read the current count value as if running.
284 * @vcpu: Virtual CPU. 303 * @vcpu: Virtual CPU.
285 * @now: Kernel time to read CP0_Count at. 304 * @now: Kernel time to read CP0_Count at.
@@ -448,7 +467,7 @@ void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count)
448 ktime_t now; 467 ktime_t now;
449 468
450 /* Calculate bias */ 469 /* Calculate bias */
451 now = ktime_get(); 470 now = kvm_mips_count_time(vcpu);
452 vcpu->arch.count_bias = count - kvm_mips_ktime_to_count(vcpu, now); 471 vcpu->arch.count_bias = count - kvm_mips_ktime_to_count(vcpu, now);
453 472
454 if (kvm_mips_count_disabled(vcpu)) 473 if (kvm_mips_count_disabled(vcpu))
@@ -508,8 +527,8 @@ void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare)
508 * Disable the CP0_Count timer. A timer interrupt on or before the final stop 527 * Disable the CP0_Count timer. A timer interrupt on or before the final stop
509 * time will be handled but not after. 528 * time will be handled but not after.
510 * 529 *
511 * Assumes CP0_Count was previously enabled but now Guest.CP0_Cause.DC has been 530 * Assumes CP0_Count was previously enabled but now Guest.CP0_Cause.DC or
512 * set (count disabled). 531 * count_ctl.DC has been set (count disabled).
513 * 532 *
514 * Returns: The time that the timer was stopped. 533 * Returns: The time that the timer was stopped.
515 */ 534 */
@@ -535,7 +554,8 @@ static ktime_t kvm_mips_count_disable(struct kvm_vcpu *vcpu)
535 * @vcpu: Virtual CPU. 554 * @vcpu: Virtual CPU.
536 * 555 *
537 * Disable the CP0_Count timer and set CP0_Cause.DC. A timer interrupt on or 556 * Disable the CP0_Count timer and set CP0_Cause.DC. A timer interrupt on or
538 * before the final stop time will be handled, but not after. 557 * before the final stop time will be handled if the timer isn't disabled by
558 * count_ctl.DC, but not after.
539 * 559 *
540 * Assumes CP0_Cause.DC is clear (count enabled). 560 * Assumes CP0_Cause.DC is clear (count enabled).
541 */ 561 */
@@ -544,7 +564,8 @@ void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu)
544 struct mips_coproc *cop0 = vcpu->arch.cop0; 564 struct mips_coproc *cop0 = vcpu->arch.cop0;
545 565
546 kvm_set_c0_guest_cause(cop0, CAUSEF_DC); 566 kvm_set_c0_guest_cause(cop0, CAUSEF_DC);
547 kvm_mips_count_disable(vcpu); 567 if (!(vcpu->arch.count_ctl & KVM_REG_MIPS_COUNT_CTL_DC))
568 kvm_mips_count_disable(vcpu);
548} 569}
549 570
550/** 571/**
@@ -552,9 +573,9 @@ void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu)
552 * @vcpu: Virtual CPU. 573 * @vcpu: Virtual CPU.
553 * 574 *
554 * Enable the CP0_Count timer and clear CP0_Cause.DC. A timer interrupt after 575 * Enable the CP0_Count timer and clear CP0_Cause.DC. A timer interrupt after
555 * the start time will be handled, potentially before even returning, so the 576 * the start time will be handled if the timer isn't disabled by count_ctl.DC,
556 * caller should be careful with ordering of CP0_Cause modifications so as not 577 * potentially before even returning, so the caller should be careful with
557 * to lose it. 578 * ordering of CP0_Cause modifications so as not to lose it.
558 * 579 *
559 * Assumes CP0_Cause.DC is set (count disabled). 580 * Assumes CP0_Cause.DC is set (count disabled).
560 */ 581 */
@@ -567,13 +588,100 @@ void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu)
567 588
568 /* 589 /*
569 * Set the dynamic count to match the static count. 590 * Set the dynamic count to match the static count.
570 * This starts the hrtimer. 591 * This starts the hrtimer if count_ctl.DC allows it.
592 * Otherwise it conveniently updates the biases.
571 */ 593 */
572 count = kvm_read_c0_guest_count(cop0); 594 count = kvm_read_c0_guest_count(cop0);
573 kvm_mips_write_count(vcpu, count); 595 kvm_mips_write_count(vcpu, count);
574} 596}
575 597
576/** 598/**
599 * kvm_mips_set_count_ctl() - Update the count control KVM register.
600 * @vcpu: Virtual CPU.
601 * @count_ctl: Count control register new value.
602 *
603 * Set the count control KVM register. The timer is updated accordingly.
604 *
605 * Returns: -EINVAL if reserved bits are set.
606 * 0 on success.
607 */
608int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl)
609{
610 struct mips_coproc *cop0 = vcpu->arch.cop0;
611 s64 changed = count_ctl ^ vcpu->arch.count_ctl;
612 s64 delta;
613 ktime_t expire, now;
614 uint32_t count, compare;
615
616 /* Only allow defined bits to be changed */
617 if (changed & ~(s64)(KVM_REG_MIPS_COUNT_CTL_DC))
618 return -EINVAL;
619
620 /* Apply new value */
621 vcpu->arch.count_ctl = count_ctl;
622
623 /* Master CP0_Count disable */
624 if (changed & KVM_REG_MIPS_COUNT_CTL_DC) {
625 /* Is CP0_Cause.DC already disabling CP0_Count? */
626 if (kvm_read_c0_guest_cause(cop0) & CAUSEF_DC) {
627 if (count_ctl & KVM_REG_MIPS_COUNT_CTL_DC)
628 /* Just record the current time */
629 vcpu->arch.count_resume = ktime_get();
630 } else if (count_ctl & KVM_REG_MIPS_COUNT_CTL_DC) {
631 /* disable timer and record current time */
632 vcpu->arch.count_resume = kvm_mips_count_disable(vcpu);
633 } else {
634 /*
635 * Calculate timeout relative to static count at resume
636 * time (wrap 0 to 2^32).
637 */
638 count = kvm_read_c0_guest_count(cop0);
639 compare = kvm_read_c0_guest_compare(cop0);
640 delta = (u64)(uint32_t)(compare - count - 1) + 1;
641 delta = div_u64(delta * NSEC_PER_SEC,
642 vcpu->arch.count_hz);
643 expire = ktime_add_ns(vcpu->arch.count_resume, delta);
644
645 /* Handle pending interrupt */
646 now = ktime_get();
647 if (ktime_compare(now, expire) >= 0)
648 /* Nothing should be waiting on the timeout */
649 kvm_mips_callbacks->queue_timer_int(vcpu);
650
651 /* Resume hrtimer without changing bias */
652 count = kvm_mips_read_count_running(vcpu, now);
653 kvm_mips_resume_hrtimer(vcpu, now, count);
654 }
655 }
656
657 return 0;
658}
659
660/**
661 * kvm_mips_set_count_resume() - Update the count resume KVM register.
662 * @vcpu: Virtual CPU.
663 * @count_resume: Count resume register new value.
664 *
665 * Set the count resume KVM register.
666 *
667 * Returns: -EINVAL if out of valid range (0..now).
668 * 0 on success.
669 */
670int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume)
671{
672 /*
673 * It doesn't make sense for the resume time to be in the future, as it
674 * would be possible for the next interrupt to be more than a full
675 * period in the future.
676 */
677 if (count_resume < 0 || count_resume > ktime_to_ns(ktime_get()))
678 return -EINVAL;
679
680 vcpu->arch.count_resume = ns_to_ktime(count_resume);
681 return 0;
682}
683
684/**
577 * kvm_mips_count_timeout() - Push timer forward on timeout. 685 * kvm_mips_count_timeout() - Push timer forward on timeout.
578 * @vcpu: Virtual CPU. 686 * @vcpu: Virtual CPU.
579 * 687 *
diff --git a/arch/mips/kvm/kvm_trap_emul.c b/arch/mips/kvm/kvm_trap_emul.c
index 9908f2b0ff46..854502bcc749 100644
--- a/arch/mips/kvm/kvm_trap_emul.c
+++ b/arch/mips/kvm/kvm_trap_emul.c
@@ -409,6 +409,12 @@ static int kvm_trap_emul_get_one_reg(struct kvm_vcpu *vcpu,
409 case KVM_REG_MIPS_CP0_COUNT: 409 case KVM_REG_MIPS_CP0_COUNT:
410 *v = kvm_mips_read_count(vcpu); 410 *v = kvm_mips_read_count(vcpu);
411 break; 411 break;
412 case KVM_REG_MIPS_COUNT_CTL:
413 *v = vcpu->arch.count_ctl;
414 break;
415 case KVM_REG_MIPS_COUNT_RESUME:
416 *v = ktime_to_ns(vcpu->arch.count_resume);
417 break;
412 default: 418 default:
413 return -EINVAL; 419 return -EINVAL;
414 } 420 }
@@ -420,6 +426,7 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
420 s64 v) 426 s64 v)
421{ 427{
422 struct mips_coproc *cop0 = vcpu->arch.cop0; 428 struct mips_coproc *cop0 = vcpu->arch.cop0;
429 int ret = 0;
423 430
424 switch (reg->id) { 431 switch (reg->id) {
425 case KVM_REG_MIPS_CP0_COUNT: 432 case KVM_REG_MIPS_CP0_COUNT:
@@ -448,10 +455,16 @@ static int kvm_trap_emul_set_one_reg(struct kvm_vcpu *vcpu,
448 kvm_write_c0_guest_cause(cop0, v); 455 kvm_write_c0_guest_cause(cop0, v);
449 } 456 }
450 break; 457 break;
458 case KVM_REG_MIPS_COUNT_CTL:
459 ret = kvm_mips_set_count_ctl(vcpu, v);
460 break;
461 case KVM_REG_MIPS_COUNT_RESUME:
462 ret = kvm_mips_set_count_resume(vcpu, v);
463 break;
451 default: 464 default:
452 return -EINVAL; 465 return -EINVAL;
453 } 466 }
454 return 0; 467 return ret;
455} 468}
456 469
457static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { 470static struct kvm_mips_callbacks kvm_trap_emul_callbacks = {