|
@@ -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;
|
|
|
|
|
|
struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
|
|
|
{
|
|
@@ -64,15 +65,15 @@ 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();
|
|
|
}
|
|
@@ -249,11 +250,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);
|
|
@@ -267,21 +296,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);
|
|
|
|