diff --git a/hypervisor/arch/x86/pm.c b/hypervisor/arch/x86/pm.c index 1f6b1db5e..bbce3c895 100644 --- a/hypervisor/arch/x86/pm.c +++ b/hypervisor/arch/x86/pm.c @@ -153,6 +153,16 @@ void host_enter_s5(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_ do_acpi_sx(sstate_data, pm1a_cnt_val, pm1b_cnt_val); } +static void suspend_tsc(__unused void *data) +{ + per_cpu(tsc_suspend, get_pcpu_id()) = rdtsc(); +} + +static void resume_tsc(__unused void *data) +{ + msr_write(MSR_IA32_TIME_STAMP_COUNTER, per_cpu(tsc_suspend, get_pcpu_id())); +} + void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val) { uint64_t pmain_entry_saved; @@ -163,6 +173,10 @@ void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_ *(sstate_data->wake_vector_32) = (uint32_t)get_trampoline_start16_paddr(); clac(); + + /* Save TSC on all PCPU */ + smp_call_function(get_active_pcpu_bitmap(), suspend_tsc, NULL); + /* offline all APs */ stop_pcpus(); @@ -190,7 +204,6 @@ void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_ resume_lapic(); resume_iommu(); resume_ioapic(); - resume_console(); vmx_on(); CPU_IRQ_ENABLE(); @@ -204,6 +217,14 @@ void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_ if (!start_pcpus(AP_MASK)) { panic("Failed to start all APs!"); } + + /* Restore TSC on all PCPU + * Caution: There should no timer setup before TSC resumed. + */ + smp_call_function(get_active_pcpu_bitmap(), resume_tsc, NULL); + + /* console must be resumed after TSC restored since it will setup timer base on TSC */ + resume_console(); } void reset_host(void) diff --git a/hypervisor/include/arch/x86/per_cpu.h b/hypervisor/include/arch/x86/per_cpu.h index dbf330c82..c6ca63214 100644 --- a/hypervisor/include/arch/x86/per_cpu.h +++ b/hypervisor/include/arch/x86/per_cpu.h @@ -56,6 +56,7 @@ struct per_cpu_region { struct profiling_info_wrapper profiling_info; #endif uint16_t shutdown_vm_id; + uint64_t tsc_suspend; } __aligned(PAGE_SIZE); /* per_cpu_region size aligned with PAGE_SIZE */ extern struct per_cpu_region per_cpu_data[CONFIG_MAX_PCPU_NUM];