Skip to content

Commit 09712b0

Browse files
authored
drivers: hv: mshv_vtl: Implement restore partition time IOCTL
Hyper-V supports a restore partition time hypercall that resets the TSC to provided values. This call is typically made by a Windows guest when restoring from hibernate. The paravisor needs to support this call in order to allow the guest to be able to successfully perform the operation. Since the reference time is being changed, clocks need to be updated to maintain consistent foward progress.
2 parents 97a9e14 + a9567a0 commit 09712b0

5 files changed

Lines changed: 82 additions & 2 deletions

File tree

arch/x86/include/asm/mshyperv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ void hyperv_setup_mmu_ops(void);
241241
void set_hv_tscchange_cb(void (*cb)(void));
242242
void clear_hv_tscchange_cb(void);
243243
void hyperv_stop_tsc_emulation(void);
244+
void hv_save_sched_clock_state(void);
245+
void hv_restore_sched_clock_state(void);
244246
int hyperv_flush_guest_mapping(u64 as);
245247
int hyperv_flush_guest_mapping_range(u64 as,
246248
hyperv_fill_flush_list_func fill_func, void *data);

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,13 @@ static void restore_hv_clock_tsc_state(void)
266266
* suspend-resume and the offset used to measure time needs to be
267267
* corrected, post resume.
268268
*/
269-
static void hv_save_sched_clock_state(void)
269+
void hv_save_sched_clock_state(void)
270270
{
271271
old_save_sched_clock_state();
272272
save_hv_clock_tsc_state();
273273
}
274274

275-
static void hv_restore_sched_clock_state(void)
275+
void hv_restore_sched_clock_state(void)
276276
{
277277
restore_hv_clock_tsc_state();
278278
old_restore_sched_clock_state();

drivers/hv/mshv_vtl_main.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#ifdef CONFIG_X86_64
3434
#include <linux/cleanup.h>
35+
#include <linux/stop_machine.h>
3536

3637
#include <asm/apic.h>
3738
#include <uapi/asm/mtrr.h>
@@ -42,6 +43,7 @@
4243
#include <asm/vmx.h>
4344

4445
#include "../../kernel/fpu/legacy.h"
46+
#include "../../kernel/time/timekeeping.h"
4547

4648
#endif
4749

@@ -865,6 +867,55 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg)
865867
return 0;
866868
}
867869

870+
#ifdef CONFIG_X86_64
871+
static int restore_partition_time_with_cpus_stopped(void *data)
872+
{
873+
struct mshv_partition_time *partition_time = data;
874+
struct hv_input_restore_partition_time *input;
875+
int result = 0;
876+
u64 status;
877+
878+
/* Save current clock state. Other CPUs are waiting in stop code, so no locks are taken. */
879+
sched_clock_suspend();
880+
timekeeping_suspend();
881+
hv_save_sched_clock_state();
882+
883+
/* Interrupts are disabled. Make the hypercall to update the TSC. */
884+
input = *this_cpu_ptr(hyperv_pcpu_input_arg);
885+
input->partition_id = HV_PARTITION_ID_SELF;
886+
input->tsc_sequence = partition_time->tsc_sequence;
887+
input->reserved = 0;
888+
input->reference_time_in_100_ns = partition_time->reference_time_in_100_ns;
889+
input->tsc = partition_time->tsc;
890+
status = hv_do_hypercall(HVCALL_RESTORE_PARTITION_TIME, input, NULL);
891+
if (!hv_result_success(status)) {
892+
pr_err("HVCALL_RESTORE_PARTITION_TIME failed with %#llx\n", status);
893+
result = -EINVAL;
894+
}
895+
896+
/* Restore clock state using current TSC value. */
897+
hv_restore_sched_clock_state();
898+
timekeeping_resume();
899+
sched_clock_resume();
900+
901+
return result;
902+
}
903+
904+
static int mshv_restore_partition_time(void __user *arg)
905+
{
906+
struct mshv_partition_time partition_time;
907+
int ret;
908+
909+
if (copy_from_user(&partition_time, arg, sizeof(partition_time)))
910+
return -EFAULT;
911+
912+
/* Stop other CPUs, using the current one to restore partition time. */
913+
ret = stop_machine(restore_partition_time_with_cpus_stopped, &partition_time,
914+
cpumask_of(raw_smp_processor_id()));
915+
return ret;
916+
}
917+
#endif
918+
868919
static void mshv_vtl_cancel(int cpu)
869920
{
870921
int here = get_cpu();
@@ -2596,6 +2647,13 @@ mshv_vtl_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
25962647
case MSHV_VTL_ADD_VTL0_MEMORY:
25972648
ret = mshv_vtl_ioctl_add_vtl0_mem(vtl, (void __user *)arg);
25982649
break;
2650+
2651+
#if defined(CONFIG_X86_64)
2652+
case MSHV_RESTORE_PARTITION_TIME:
2653+
ret = mshv_restore_partition_time((void __user *)arg);
2654+
break;
2655+
#endif
2656+
25992657
#if defined(CONFIG_X86_64) && defined(CONFIG_INTEL_TDX_GUEST)
26002658
case MSHV_VTL_TDCALL:
26012659
ret = mshv_vtl_ioctl_tdcall((void __user *)arg);

include/uapi/hyperv/hvgdk_mini.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ union hv_hypervisor_version_info {
261261
#define HVCALL_GET_VP_CPUID_VALUES 0x00f4
262262
#define HVCALL_START_VP 0x0099
263263
#define HVCALL_GET_VP_INDEX_FROM_APIC_ID 0x009a
264+
#define HVCALL_RESTORE_PARTITION_TIME 0x0103
265+
264266

265267
/*
266268
* Some macros - i.e. GENMASK_ULL and BIT_ULL - are not currently supported by
@@ -1310,4 +1312,14 @@ struct hv_input_install_intercept {
13101312
union hv_intercept_parameters intercept_parameter;
13111313
} __packed;
13121314

1315+
#if defined(__x86_64__)
1316+
struct hv_input_restore_partition_time {
1317+
__u64 partition_id;
1318+
__u32 tsc_sequence;
1319+
__u32 reserved;
1320+
__u64 reference_time_in_100_ns;
1321+
__u64 tsc;
1322+
} __packed;
1323+
#endif
1324+
13131325
#endif /* _UAPI_HV_HVGDK_MINI_H */

include/uapi/linux/mshv.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,13 @@ struct mshv_map_device_intr {
306306
__u8 padding[7];
307307
} __packed;
308308

309+
struct mshv_partition_time {
310+
__u32 tsc_sequence;
311+
__u32 reserved;
312+
__u64 reference_time_in_100_ns;
313+
__u64 tsc;
314+
} __packed;
315+
309316
#define MSHV_KICK_CPUS_FLAG_WAIT_FOR_CPUS (1 << 0)
310317
#define MSHV_KICK_CPUS_FLAG_CANCEL_CPU_RUN (1 << 1)
311318

@@ -371,6 +378,7 @@ struct mshv_map_device_intr {
371378
struct mshv_map_device_intr)
372379

373380
/* For x86-64 only */
381+
#define MSHV_RESTORE_PARTITION_TIME _IOW(MSHV_IOCTL, 0x13, struct mshv_partition_time)
374382
#define MSHV_VTL_GUEST_VSM_VMSA_PFN _IOWR(MSHV_IOCTL, 0x34, __u64)
375383

376384
/* For x86-64 SEV-SNP only */

0 commit comments

Comments
 (0)