From 3ebeecf060bcd76d2741623a3cd40afc7183d622 Mon Sep 17 00:00:00 2001 From: Qi Yadong Date: Wed, 18 Sep 2019 10:58:09 +0800 Subject: [PATCH] hv: save/restore TSC in host's suspend/resume path TSC would be reset to 0 when enter suspend state on some platform. This will fail the secure timer checking in secure world because secure world leverage the TSC as source of secure timer which should be increased monotonously. This patch save/restore TSC in host suspend/resume path to guarantee the mono increasing TSC. Note: There should no timer setup before TSC resumed. Tracked-On: #3697 Signed-off-by: Qi Yadong Reviewed-by: Yin Fengwei Acked-by: Eddie Dong --- hypervisor/arch/x86/pm.c | 23 ++++++++++++++++++++++- hypervisor/include/arch/x86/per_cpu.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) 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];