Merge tag 'for-linus-4.15-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / arch / x86 / kernel / kvmclock.c
index 538738047ff5cb6d5a59bb927cd9fd254cce40f0..8b26c9e01cc4e26005f383fdeb7cf21442cb1814 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/sched/clock.h>
 
+#include <asm/mem_encrypt.h>
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
 #include <asm/kvmclock.h>
@@ -45,7 +46,7 @@ early_param("no-kvmclock", parse_no_kvmclock);
 
 /* The hypervisor will put information about time periodically here */
 static struct pvclock_vsyscall_time_info *hv_clock;
-static struct pvclock_wall_clock wall_clock;
+static struct pvclock_wall_clock *wall_clock;
 
 /*
  * The wallclock is the time of day when we booted. Since then, some time may
@@ -58,22 +59,22 @@ static void kvm_get_wallclock(struct timespec *now)
        int low, high;
        int cpu;
 
-       low = (int)__pa_symbol(&wall_clock);
-       high = ((u64)__pa_symbol(&wall_clock) >> 32);
+       low = (int)slow_virt_to_phys(wall_clock);
+       high = ((u64)slow_virt_to_phys(wall_clock) >> 32);
 
        native_write_msr(msr_kvm_wall_clock, low, high);
 
        cpu = get_cpu();
 
        vcpu_time = &hv_clock[cpu].pvti;
-       pvclock_read_wallclock(&wall_clock, vcpu_time, now);
+       pvclock_read_wallclock(wall_clock, vcpu_time, now);
 
        put_cpu();
 }
 
 static int kvm_set_wallclock(const struct timespec *now)
 {
-       return -1;
+       return -ENODEV;
 }
 
 static u64 kvm_clock_read(void)
@@ -243,11 +244,39 @@ static void kvm_shutdown(void)
        native_machine_shutdown();
 }
 
+static phys_addr_t __init kvm_memblock_alloc(phys_addr_t size,
+                                            phys_addr_t align)
+{
+       phys_addr_t mem;
+
+       mem = memblock_alloc(size, align);
+       if (!mem)
+               return 0;
+
+       if (sev_active()) {
+               if (early_set_memory_decrypted((unsigned long)__va(mem), size))
+                       goto e_free;
+       }
+
+       return mem;
+e_free:
+       memblock_free(mem, size);
+       return 0;
+}
+
+static void __init kvm_memblock_free(phys_addr_t addr, phys_addr_t size)
+{
+       if (sev_active())
+               early_set_memory_encrypted((unsigned long)__va(addr), size);
+
+       memblock_free(addr, size);
+}
+
 void __init kvmclock_init(void)
 {
        struct pvclock_vcpu_time_info *vcpu_time;
-       unsigned long mem;
-       int size, cpu;
+       unsigned long mem, mem_wall_clock;
+       int size, cpu, wall_clock_size;
        u8 flags;
 
        size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
@@ -261,21 +290,35 @@ void __init kvmclock_init(void)
        } else if (!(kvmclock && kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)))
                return;
 
-       printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
-               msr_kvm_system_time, msr_kvm_wall_clock);
+       wall_clock_size = PAGE_ALIGN(sizeof(struct pvclock_wall_clock));
+       mem_wall_clock = kvm_memblock_alloc(wall_clock_size, PAGE_SIZE);
+       if (!mem_wall_clock)
+               return;
 
-       mem = memblock_alloc(size, PAGE_SIZE);
-       if (!mem)
+       wall_clock = __va(mem_wall_clock);
+       memset(wall_clock, 0, wall_clock_size);
+
+       mem = kvm_memblock_alloc(size, PAGE_SIZE);
+       if (!mem) {
+               kvm_memblock_free(mem_wall_clock, wall_clock_size);
+               wall_clock = NULL;
                return;
+       }
+
        hv_clock = __va(mem);
        memset(hv_clock, 0, size);
 
        if (kvm_register_clock("primary cpu clock")) {
                hv_clock = NULL;
-               memblock_free(mem, size);
+               kvm_memblock_free(mem, size);
+               kvm_memblock_free(mem_wall_clock, wall_clock_size);
+               wall_clock = NULL;
                return;
        }
 
+       printk(KERN_INFO "kvm-clock: Using msrs %x and %x",
+               msr_kvm_system_time, msr_kvm_wall_clock);
+
        if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
                pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);