Commit 50d0a0f987b83a8dadb1134d834e35ec410392b5

Authored by Gerd Hoffmann
Committed by Avi Kivity
1 parent 1c7b67f757

KVM: Make kvm host use the paravirt clocksource structs

This patch updates the kvm host code to use the pvclock structs.
It also makes the paravirt clock compatible with Xen.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>

Showing 2 changed files with 65 additions and 14 deletions Side-by-side Diff

... ... @@ -492,8 +492,8 @@
492 492 static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
493 493 {
494 494 static int version;
495   - struct kvm_wall_clock wc;
496   - struct timespec wc_ts;
  495 + struct pvclock_wall_clock wc;
  496 + struct timespec now, sys, boot;
497 497  
498 498 if (!wall_clock)
499 499 return;
500 500  
501 501  
... ... @@ -502,17 +502,65 @@
502 502  
503 503 kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
504 504  
505   - wc_ts = current_kernel_time();
506   - wc.wc_sec = wc_ts.tv_sec;
507   - wc.wc_nsec = wc_ts.tv_nsec;
508   - wc.wc_version = version;
  505 + /*
  506 + * The guest calculates current wall clock time by adding
  507 + * system time (updated by kvm_write_guest_time below) to the
  508 + * wall clock specified here. guest system time equals host
  509 + * system time for us, thus we must fill in host boot time here.
  510 + */
  511 + now = current_kernel_time();
  512 + ktime_get_ts(&sys);
  513 + boot = ns_to_timespec(timespec_to_ns(&now) - timespec_to_ns(&sys));
509 514  
  515 + wc.sec = boot.tv_sec;
  516 + wc.nsec = boot.tv_nsec;
  517 + wc.version = version;
  518 +
510 519 kvm_write_guest(kvm, wall_clock, &wc, sizeof(wc));
511 520  
512 521 version++;
513 522 kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
514 523 }
515 524  
  525 +static uint32_t div_frac(uint32_t dividend, uint32_t divisor)
  526 +{
  527 + uint32_t quotient, remainder;
  528 +
  529 + /* Don't try to replace with do_div(), this one calculates
  530 + * "(dividend << 32) / divisor" */
  531 + __asm__ ( "divl %4"
  532 + : "=a" (quotient), "=d" (remainder)
  533 + : "0" (0), "1" (dividend), "r" (divisor) );
  534 + return quotient;
  535 +}
  536 +
  537 +static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *hv_clock)
  538 +{
  539 + uint64_t nsecs = 1000000000LL;
  540 + int32_t shift = 0;
  541 + uint64_t tps64;
  542 + uint32_t tps32;
  543 +
  544 + tps64 = tsc_khz * 1000LL;
  545 + while (tps64 > nsecs*2) {
  546 + tps64 >>= 1;
  547 + shift--;
  548 + }
  549 +
  550 + tps32 = (uint32_t)tps64;
  551 + while (tps32 <= (uint32_t)nsecs) {
  552 + tps32 <<= 1;
  553 + shift++;
  554 + }
  555 +
  556 + hv_clock->tsc_shift = shift;
  557 + hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
  558 +
  559 + pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
  560 + __FUNCTION__, tsc_khz, hv_clock->tsc_shift,
  561 + hv_clock->tsc_to_system_mul);
  562 +}
  563 +
516 564 static void kvm_write_guest_time(struct kvm_vcpu *v)
517 565 {
518 566 struct timespec ts;
... ... @@ -523,6 +571,11 @@
523 571 if ((!vcpu->time_page))
524 572 return;
525 573  
  574 + if (unlikely(vcpu->hv_clock_tsc_khz != tsc_khz)) {
  575 + kvm_set_time_scale(tsc_khz, &vcpu->hv_clock);
  576 + vcpu->hv_clock_tsc_khz = tsc_khz;
  577 + }
  578 +
526 579 /* Keep irq disabled to prevent changes to the clock */
527 580 local_irq_save(flags);
528 581 kvm_get_msr(v, MSR_IA32_TIME_STAMP_COUNTER,
529 582  
530 583  
... ... @@ -537,14 +590,14 @@
537 590 /*
538 591 * The interface expects us to write an even number signaling that the
539 592 * update is finished. Since the guest won't see the intermediate
540   - * state, we just write "2" at the end
  593 + * state, we just increase by 2 at the end.
541 594 */
542   - vcpu->hv_clock.version = 2;
  595 + vcpu->hv_clock.version += 2;
543 596  
544 597 shared_kaddr = kmap_atomic(vcpu->time_page, KM_USER0);
545 598  
546 599 memcpy(shared_kaddr + vcpu->time_offset, &vcpu->hv_clock,
547   - sizeof(vcpu->hv_clock));
  600 + sizeof(vcpu->hv_clock));
548 601  
549 602 kunmap_atomic(shared_kaddr, KM_USER0);
550 603  
... ... @@ -598,10 +651,6 @@
598 651  
599 652 /* ...but clean it before doing the actual write */
600 653 vcpu->arch.time_offset = data & ~(PAGE_MASK | 1);
601   -
602   - vcpu->arch.hv_clock.tsc_to_system_mul =
603   - clocksource_khz2mult(tsc_khz, 22);
604   - vcpu->arch.hv_clock.tsc_shift = 22;
605 654  
606 655 down_read(&current->mm->mmap_sem);
607 656 vcpu->arch.time_page =
include/asm-x86/kvm_host.h
... ... @@ -18,6 +18,7 @@
18 18 #include <linux/kvm_para.h>
19 19 #include <linux/kvm_types.h>
20 20  
  21 +#include <asm/pvclock-abi.h>
21 22 #include <asm/desc.h>
22 23  
23 24 #define KVM_MAX_VCPUS 16
... ... @@ -282,7 +283,8 @@
282 283 struct x86_emulate_ctxt emulate_ctxt;
283 284  
284 285 gpa_t time;
285   - struct kvm_vcpu_time_info hv_clock;
  286 + struct pvclock_vcpu_time_info hv_clock;
  287 + unsigned int hv_clock_tsc_khz;
286 288 unsigned int time_offset;
287 289 struct page *time_page;
288 290 };