|
32 | 32 |
|
33 | 33 | #ifdef CONFIG_X86_64 |
34 | 34 | #include <linux/cleanup.h> |
| 35 | +#include <linux/stop_machine.h> |
35 | 36 |
|
36 | 37 | #include <asm/apic.h> |
37 | 38 | #include <uapi/asm/mtrr.h> |
|
42 | 43 | #include <asm/vmx.h> |
43 | 44 |
|
44 | 45 | #include "../../kernel/fpu/legacy.h" |
| 46 | +#include "../../kernel/time/timekeeping.h" |
45 | 47 |
|
46 | 48 | #endif |
47 | 49 |
|
@@ -865,6 +867,55 @@ static int mshv_vtl_ioctl_add_vtl0_mem(struct mshv_vtl *vtl, void __user *arg) |
865 | 867 | return 0; |
866 | 868 | } |
867 | 869 |
|
| 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 | + |
868 | 919 | static void mshv_vtl_cancel(int cpu) |
869 | 920 | { |
870 | 921 | int here = get_cpu(); |
@@ -2596,6 +2647,13 @@ mshv_vtl_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) |
2596 | 2647 | case MSHV_VTL_ADD_VTL0_MEMORY: |
2597 | 2648 | ret = mshv_vtl_ioctl_add_vtl0_mem(vtl, (void __user *)arg); |
2598 | 2649 | 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 | + |
2599 | 2657 | #if defined(CONFIG_X86_64) && defined(CONFIG_INTEL_TDX_GUEST) |
2600 | 2658 | case MSHV_VTL_TDCALL: |
2601 | 2659 | ret = mshv_vtl_ioctl_tdcall((void __user *)arg); |
|
0 commit comments