Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90b20432 authored by Vitaly Kuznetsov's avatar Vitaly Kuznetsov Committed by Thomas Gleixner
Browse files

x86/vdso: Add VCLOCK_HVCLOCK vDSO clock read method



Hyper-V TSC page clocksource is suitable for vDSO, however, the protocol
defined by the hypervisor is different from VCLOCK_PVCLOCK. Implement the
required support by adding hvclock_page VVAR.

Signed-off-by: default avatarVitaly Kuznetsov <vkuznets@redhat.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Dexuan Cui <decui@microsoft.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: devel@linuxdriverproject.org
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: virtualization@lists.linux-foundation.org
Link: http://lkml.kernel.org/r/20170303132142.25595-4-vkuznets@redhat.com


Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 0733379b
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <asm/unistd.h>
#include <asm/msr.h>
#include <asm/pvclock.h>
#include <asm/mshyperv.h>
#include <linux/math64.h>
#include <linux/time.h>
#include <linux/kernel.h>
@@ -32,6 +33,11 @@ extern u8 pvclock_page
	__attribute__((visibility("hidden")));
#endif

#ifdef CONFIG_HYPERV_TSCPAGE
extern u8 hvclock_page
	__attribute__((visibility("hidden")));
#endif

#ifndef BUILD_VDSO32

notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
@@ -141,6 +147,20 @@ static notrace u64 vread_pvclock(int *mode)
	return last;
}
#endif
#ifdef CONFIG_HYPERV_TSCPAGE
static notrace u64 vread_hvclock(int *mode)
{
	const struct ms_hyperv_tsc_page *tsc_pg =
		(const struct ms_hyperv_tsc_page *)&hvclock_page;
	u64 current_tick = hv_read_tsc_page(tsc_pg);

	if (current_tick != U64_MAX)
		return current_tick;

	*mode = VCLOCK_NONE;
	return 0;
}
#endif

notrace static u64 vread_tsc(void)
{
@@ -172,6 +192,10 @@ notrace static inline u64 vgetsns(int *mode)
#ifdef CONFIG_PARAVIRT_CLOCK
	else if (gtod->vclock_mode == VCLOCK_PVCLOCK)
		cycles = vread_pvclock(mode);
#endif
#ifdef CONFIG_HYPERV_TSCPAGE
	else if (gtod->vclock_mode == VCLOCK_HVCLOCK)
		cycles = vread_hvclock(mode);
#endif
	else
		return 0;
+2 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ SECTIONS
	 * segment.
	 */

	vvar_start = . - 2 * PAGE_SIZE;
	vvar_start = . - 3 * PAGE_SIZE;
	vvar_page = vvar_start;

	/* Place all vvars at the offsets in asm/vvar.h. */
@@ -36,6 +36,7 @@ SECTIONS
#undef EMIT_VVAR

	pvclock_page = vvar_start + PAGE_SIZE;
	hvclock_page = vvar_start + 2 * PAGE_SIZE;

	. = SIZEOF_HEADERS;

+3 −0
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ enum {
	sym_vvar_page,
	sym_hpet_page,
	sym_pvclock_page,
	sym_hvclock_page,
	sym_VDSO_FAKE_SECTION_TABLE_START,
	sym_VDSO_FAKE_SECTION_TABLE_END,
};
@@ -82,6 +83,7 @@ const int special_pages[] = {
	sym_vvar_page,
	sym_hpet_page,
	sym_pvclock_page,
	sym_hvclock_page,
};

struct vdso_sym {
@@ -94,6 +96,7 @@ struct vdso_sym required_syms[] = {
	[sym_vvar_page] = {"vvar_page", true},
	[sym_hpet_page] = {"hpet_page", true},
	[sym_pvclock_page] = {"pvclock_page", true},
	[sym_hvclock_page] = {"hvclock_page", true},
	[sym_VDSO_FAKE_SECTION_TABLE_START] = {
		"VDSO_FAKE_SECTION_TABLE_START", false
	},
+7 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <asm/page.h>
#include <asm/desc.h>
#include <asm/cpufeature.h>
#include <asm/mshyperv.h>

#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso64_enabled = 1;
@@ -121,6 +122,12 @@ static int vvar_fault(const struct vm_special_mapping *sm,
				vmf->address,
				__pa(pvti) >> PAGE_SHIFT);
		}
	} else if (sym_offset == image->sym_hvclock_page) {
		struct ms_hyperv_tsc_page *tsc_pg = hv_get_tsc_page();

		if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK))
			ret = vm_insert_pfn(vma, vmf->address,
					    vmalloc_to_pfn(tsc_pg));
	}

	if (ret == 0 || ret == -EBUSY)
+3 −0
Original line number Diff line number Diff line
@@ -132,6 +132,9 @@ void hyperv_init(void)
		tsc_msr.guest_physical_address = vmalloc_to_pfn(tsc_pg);

		wrmsrl(HV_X64_MSR_REFERENCE_TSC, tsc_msr.as_uint64);

		hyperv_cs_tsc.archdata.vclock_mode = VCLOCK_HVCLOCK;

		clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100);
		return;
	}
Loading