RE: [PATCH v6 18/19] x86: Add support for generic vDSO

From: Michael Kelley
Date: Thu May 30 2019 - 11:44:56 EST


From: Vincenzo Frascino <vincenzo.frascino@xxxxxxx> On Thursday, May 30, 2019 7:16 AM
>
> The x86 vDSO library requires some adaptations to take advantage of the
> newly introduced generic vDSO library.
>
> Introduce the following changes:
> - Modification of vdso.c to be compliant with the common vdso datapage
> - Use of lib/vdso for gettimeofday
>
> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@xxxxxxx>
>
>
> diff --git a/arch/x86/include/asm/mshyperv-tsc.h b/arch/x86/include/asm/mshyperv-tsc.h
> new file mode 100644
> index 000000000000..99c98ccea0bf
> --- /dev/null
> +++ b/arch/x86/include/asm/mshyperv-tsc.h
> @@ -0,0 +1,76 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_MSHYPER_TSCPAGE_H
> +#define _ASM_X86_MSHYPER_TSCPAGE_H
> +
> +#include <asm/hyperv-tlfs.h>
> +
> +#ifdef CONFIG_HYPERV_TSCPAGE
> +struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
> +static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
> + u64 *cur_tsc)
> +{
> + u64 scale, offset;
> + u32 sequence;
> +
> + /*
> + * The protocol for reading Hyper-V TSC page is specified in Hypervisor
> + * Top-Level Functional Specification ver. 3.0 and above. To get the
> + * reference time we must do the following:
> + * - READ ReferenceTscSequence
> + * A special '0' value indicates the time source is unreliable and we
> + * need to use something else. The currently published specification
> + * versions (up to 4.0b) contain a mistake and wrongly claim '-1'
> + * instead of '0' as the special value, see commit c35b82ef0294.
> + * - ReferenceTime =
> + * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset
> + * - READ ReferenceTscSequence again. In case its value has changed
> + * since our first reading we need to discard ReferenceTime and repeat
> + * the whole sequence as the hypervisor was updating the page in
> + * between.
> + */
> + do {
> + sequence = READ_ONCE(tsc_pg->tsc_sequence);
> + if (!sequence)
> + return U64_MAX;
> + /*
> + * Make sure we read sequence before we read other values from
> + * TSC page.
> + */
> + smp_rmb();
> +
> + scale = READ_ONCE(tsc_pg->tsc_scale);
> + offset = READ_ONCE(tsc_pg->tsc_offset);
> + *cur_tsc = rdtsc_ordered();
> +
> + /*
> + * Make sure we read sequence after we read all other values
> + * from TSC page.
> + */
> + smp_rmb();
> +
> + } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
> +
> + return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset;
> +}
> +
> +static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
> +{
> + u64 cur_tsc;
> +
> + return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc);
> +}
> +
> +#else
> +static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
> +{
> + return NULL;
> +}
> +
> +static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
> + u64 *cur_tsc)
> +{
> + BUG();
> + return U64_MAX;
> +}
> +#endif
> +#endif
> diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
> index cc60e617931c..db095a992f3e 100644
> --- a/arch/x86/include/asm/mshyperv.h
> +++ b/arch/x86/include/asm/mshyperv.h
> @@ -7,6 +7,7 @@
> #include <linux/nmi.h>
> #include <asm/io.h>
> #include <asm/hyperv-tlfs.h>
> +#include <asm/mshyperv-tsc.h>
> #include <asm/nospec-branch.h>
>
> #define VP_INVAL U32_MAX
> @@ -387,73 +388,4 @@ static inline int hyperv_flush_guest_mapping_range(u64 as,
> }
> #endif /* CONFIG_HYPERV */
>
> -#ifdef CONFIG_HYPERV_TSCPAGE
> -struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
> -static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
> - u64 *cur_tsc)
> -{
> - u64 scale, offset;
> - u32 sequence;
> -
> - /*
> - * The protocol for reading Hyper-V TSC page is specified in Hypervisor
> - * Top-Level Functional Specification ver. 3.0 and above. To get the
> - * reference time we must do the following:
> - * - READ ReferenceTscSequence
> - * A special '0' value indicates the time source is unreliable and we
> - * need to use something else. The currently published specification
> - * versions (up to 4.0b) contain a mistake and wrongly claim '-1'
> - * instead of '0' as the special value, see commit c35b82ef0294.
> - * - ReferenceTime =
> - * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset
> - * - READ ReferenceTscSequence again. In case its value has changed
> - * since our first reading we need to discard ReferenceTime and repeat
> - * the whole sequence as the hypervisor was updating the page in
> - * between.
> - */
> - do {
> - sequence = READ_ONCE(tsc_pg->tsc_sequence);
> - if (!sequence)
> - return U64_MAX;
> - /*
> - * Make sure we read sequence before we read other values from
> - * TSC page.
> - */
> - smp_rmb();
> -
> - scale = READ_ONCE(tsc_pg->tsc_scale);
> - offset = READ_ONCE(tsc_pg->tsc_offset);
> - *cur_tsc = rdtsc_ordered();
> -
> - /*
> - * Make sure we read sequence after we read all other values
> - * from TSC page.
> - */
> - smp_rmb();
> -
> - } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
> -
> - return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset;
> -}
> -
> -static inline u64 hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
> -{
> - u64 cur_tsc;
> -
> - return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc);
> -}
> -
> -#else
> -static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
> -{
> - return NULL;
> -}
> -
> -static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
> - u64 *cur_tsc)
> -{
> - BUG();
> - return U64_MAX;
> -}
> -#endif
> #endif

Vincenzo -- these changes for Hyper-V are a subset of a larger patch set
I have that moves all of the Hyper-V clock/timer code into a separate
clocksource driver in drivers/clocksource, with an include file in
includes/clocksource. That new include file should be able to work
instead of your new mshyperv-tsc.h. It also has the benefit of being
ISA neutral, so it will work with my in-progress patch set to support
Linux on Hyper-V on ARM64. See https://lkml.org/lkml/2019/5/27/231
for the new clocksource driver patch set.

Michael