diff options
| -rw-r--r-- | arch/mips/include/asm/kvm_host.h | 6 | ||||
| -rw-r--r-- | arch/mips/include/uapi/asm/kvm.h | 28 | ||||
| -rw-r--r-- | arch/mips/kvm/kvm_mips.c | 9 | ||||
| -rw-r--r-- | arch/mips/kvm/kvm_mips_emul.c | 132 | ||||
| -rw-r--r-- | arch/mips/kvm/kvm_trap_emul.c | 15 |
5 files changed, 176 insertions, 14 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 75ed94aeefe7..1deeaecbe73e 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h | |||
| @@ -405,12 +405,16 @@ struct kvm_vcpu_arch { | |||
| 405 | u32 io_gpr; /* GPR used as IO source/target */ | 405 | u32 io_gpr; /* GPR used as IO source/target */ |
| 406 | 406 | ||
| 407 | struct hrtimer comparecount_timer; | 407 | struct hrtimer comparecount_timer; |
| 408 | /* Count timer control KVM register */ | ||
| 409 | uint32_t count_ctl; | ||
| 408 | /* Count bias from the raw time */ | 410 | /* Count bias from the raw time */ |
| 409 | uint32_t count_bias; | 411 | uint32_t count_bias; |
| 410 | /* Frequency of timer in Hz */ | 412 | /* Frequency of timer in Hz */ |
| 411 | uint32_t count_hz; | 413 | uint32_t count_hz; |
| 412 | /* Dynamic nanosecond bias (multiple of count_period) to avoid overflow */ | 414 | /* Dynamic nanosecond bias (multiple of count_period) to avoid overflow */ |
| 413 | s64 count_dyn_bias; | 415 | s64 count_dyn_bias; |
| 416 | /* Resume time */ | ||
| 417 | ktime_t count_resume; | ||
| 414 | /* Period of timer tick in ns */ | 418 | /* Period of timer tick in ns */ |
| 415 | u64 count_period; | 419 | u64 count_period; |
| 416 | 420 | ||
| @@ -714,6 +718,8 @@ uint32_t kvm_mips_read_count(struct kvm_vcpu *vcpu); | |||
| 714 | void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count); | 718 | void kvm_mips_write_count(struct kvm_vcpu *vcpu, uint32_t count); |
| 715 | void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare); | 719 | void kvm_mips_write_compare(struct kvm_vcpu *vcpu, uint32_t compare); |
| 716 | void kvm_mips_init_count(struct kvm_vcpu *vcpu); | 720 | void kvm_mips_init_count(struct kvm_vcpu *vcpu); |
| 721 | int kvm_mips_set_count_ctl(struct kvm_vcpu *vcpu, s64 count_ctl); | ||
| 722 | int kvm_mips_set_count_resume(struct kvm_vcpu *vcpu, s64 count_resume); | ||
| 717 | void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu); | 723 | void kvm_mips_count_enable_cause(struct kvm_vcpu *vcpu); |
| 718 | void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu); | 724 | void kvm_mips_count_disable_cause(struct kvm_vcpu *vcpu); |
| 719 | enum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu); | 725 | enum hrtimer_restart kvm_mips_count_timeout(struct kvm_vcpu *vcpu); |
diff --git a/arch/mips/include/uapi/asm/kvm.h b/arch/mips/include/uapi/asm/kvm.h index f09ff5ae2059..f859fbada1f7 100644 --- a/arch/mips/include/uapi/asm/kvm.h +++ b/arch/mips/include/uapi/asm/kvm.h | |||
| @@ -106,6 +106,34 @@ struct kvm_fpu { | |||
| 106 | #define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33) | 106 | #define KVM_REG_MIPS_LO (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 33) |
| 107 | #define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34) | 107 | #define KVM_REG_MIPS_PC (KVM_REG_MIPS | KVM_REG_SIZE_U64 | 34) |
| 108 | 108 | ||
| 109 | /* KVM specific control registers */ | ||
| 110 | |||
| 111 | /* | ||
| 112 | * CP0_Count control | ||
| 113 | * DC: Set 0: Master disable CP0_Count and set COUNT_RESUME to now | ||
| 114 | * Set 1: Master re-enable CP0_Count with unchanged bias, handling timer | ||
| 115 | * interrupts since COUNT_RESUME | ||
| 116 | * This can be used to freeze the timer to get a consistent snapshot of | ||
| 117 | * the CP0_Count and timer interrupt pending state, while also resuming | ||
| 118 | * safely without losing time or guest timer interrupts. | ||
| 119 | * Other: Reserved, do not change. | ||
| 120 | */ | ||
| 121 | #define KVM_REG_MIPS_COUNT_CTL (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ | ||
| 122 | 0x20000 | 0) | ||
| 123 | #define KVM_REG_MIPS_COUNT_CTL_DC 0x00000001 | ||
| 124 | |||
| 125 | /* | ||
| 126 | * CP0_Count resume monotonic nanoseconds | ||
| 127 | * The monotonic nanosecond time of the last set of COUNT_CTL.DC (master | ||
| 128 | * disable). Any reads and writes of Count related registers while | ||
| 129 | * COUNT_CTL.DC=1 will appear to occur at this time. When COUNT_CTL.DC is | ||
| 130 | * cleared again (master enable) any timer interrupts since this time will be | ||
| 131 | * emulated. | ||
| 132 | * Modifications to times in the future are rejected. | ||
| 133 | */ | ||
| 134 | #define KVM_REG_MIPS_COUNT_RESUME (KVM_REG_MIPS | KVM_REG_SIZE_U64 | \ | ||
| 135 | 0x20000 | 1) | ||
| 136 | |||
| 109 | /* | 137 | /* |
| 110 | * KVM MIPS specific structures and definitions | 138 | * KVM MIPS specific structures and definitions |
| 111 | * | 139 | * |
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 | ||
| 548 | static int kvm_mips_get_reg(struct kvm_vcpu *vcpu, | 551 | static 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 | */ |
| 240 | static inline int kvm_mips_count_disabled(struct kvm_vcpu *vcpu) | 240 | static 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 | */ | ||
| 293 | static 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 | */ | ||
| 608 | int 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 | */ | ||
| 670 | int 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 | ||
| 457 | static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { | 470 | static struct kvm_mips_callbacks kvm_trap_emul_callbacks = { |
