Hi Marek, On 6/28/19 2:09 PM, Marek Szyprowski wrote: > Dear All, > > On 2019-06-21 11:52, Vincenzo Frascino wrote: >> To take advantage of the commonly defined vdso interface for >> gettimeofday the architectural code requires an adaptation. >> >> Re-implement the gettimeofday vdso in C in order to use lib/vdso. >> >> With the new implementation arm64 gains support for CLOCK_BOOTTIME >> and CLOCK_TAI. >> >> Cc: Catalin Marinas <catalin.marinas@xxxxxxx> >> Cc: Will Deacon <will.deacon@xxxxxxx> >> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@xxxxxxx> >> Tested-by: Shijith Thotton <sthotton@xxxxxxxxxxx> >> Tested-by: Andre Przywara <andre.przywara@xxxxxxx> >> Signed-off-by: Catalin Marinas <catalin.marinas@xxxxxxx> > > This patch causes serious regression on Samsung Exynos5433 SoC based > TM2(e) boards. The time in userspace is always set to begin of the epoch: > > # date 062813152019 > Fri Jun 28 13:15:00 UTC 2019 > # date > Thu Jan 1 00:00:00 UTC 1970 > # date > Thu Jan 1 00:00:00 UTC 1970 > > I've noticed that since the patch landed in Linux next-20190625 and > bisect indeed pointed to this patch. > Thank you for reporting this, seems that the next that you posted is missing some fixes for arm64. Could you please try the tree below? git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso Let us know if the functionality is restored. Otherwise the issue will require further investigation. >> --- >> arch/arm64/Kconfig | 2 + >> arch/arm64/include/asm/vdso/gettimeofday.h | 86 ++++++ >> arch/arm64/include/asm/vdso/vsyscall.h | 53 ++++ >> arch/arm64/include/asm/vdso_datapage.h | 48 --- >> arch/arm64/kernel/asm-offsets.c | 33 +- >> arch/arm64/kernel/vdso.c | 51 +--- >> arch/arm64/kernel/vdso/Makefile | 34 ++- >> arch/arm64/kernel/vdso/gettimeofday.S | 334 --------------------- >> arch/arm64/kernel/vdso/vgettimeofday.c | 28 ++ >> 9 files changed, 223 insertions(+), 446 deletions(-) >> create mode 100644 arch/arm64/include/asm/vdso/gettimeofday.h >> create mode 100644 arch/arm64/include/asm/vdso/vsyscall.h >> delete mode 100644 arch/arm64/include/asm/vdso_datapage.h >> delete mode 100644 arch/arm64/kernel/vdso/gettimeofday.S >> create mode 100644 arch/arm64/kernel/vdso/vgettimeofday.c >> >> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig >> index 697ea0510729..952c9f8cf3b8 100644 >> --- a/arch/arm64/Kconfig >> +++ b/arch/arm64/Kconfig >> @@ -107,6 +107,7 @@ config ARM64 >> select GENERIC_STRNCPY_FROM_USER >> select GENERIC_STRNLEN_USER >> select GENERIC_TIME_VSYSCALL >> + select GENERIC_GETTIMEOFDAY >> select HANDLE_DOMAIN_IRQ >> select HARDIRQS_SW_RESEND >> select HAVE_PCI >> @@ -160,6 +161,7 @@ config ARM64 >> select HAVE_SYSCALL_TRACEPOINTS >> select HAVE_KPROBES >> select HAVE_KRETPROBES >> + select HAVE_GENERIC_VDSO >> select IOMMU_DMA if IOMMU_SUPPORT >> select IRQ_DOMAIN >> select IRQ_FORCED_THREADING >> diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h >> new file mode 100644 >> index 000000000000..bc3cb6738051 >> --- /dev/null >> +++ b/arch/arm64/include/asm/vdso/gettimeofday.h >> @@ -0,0 +1,86 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +/* >> + * Copyright (C) 2018 ARM Limited >> + */ >> +#ifndef __ASM_VDSO_GETTIMEOFDAY_H >> +#define __ASM_VDSO_GETTIMEOFDAY_H >> + >> +#ifndef __ASSEMBLY__ >> + >> +#include <asm/unistd.h> >> +#include <uapi/linux/time.h> >> + >> +#define VDSO_HAS_CLOCK_GETRES 1 >> + >> +static __always_inline int gettimeofday_fallback( >> + struct __kernel_old_timeval *_tv, >> + struct timezone *_tz) >> +{ >> + register struct timezone *tz asm("x1") = _tz; >> + register struct __kernel_old_timeval *tv asm("x0") = _tv; >> + register long ret asm ("x0"); >> + register long nr asm("x8") = __NR_gettimeofday; >> + >> + asm volatile( >> + " svc #0\n" >> + : "=r" (ret) >> + : "r" (tv), "r" (tz), "r" (nr) >> + : "memory"); >> + >> + return ret; >> +} >> + >> +static __always_inline long clock_gettime_fallback( >> + clockid_t _clkid, >> + struct __kernel_timespec *_ts) >> +{ >> + register struct __kernel_timespec *ts asm("x1") = _ts; >> + register clockid_t clkid asm("x0") = _clkid; >> + register long ret asm ("x0"); >> + register long nr asm("x8") = __NR_clock_gettime; >> + >> + asm volatile( >> + " svc #0\n" >> + : "=r" (ret) >> + : "r" (clkid), "r" (ts), "r" (nr) >> + : "memory"); >> + >> + return ret; >> +} >> + >> +static __always_inline int clock_getres_fallback( >> + clockid_t _clkid, >> + struct __kernel_timespec *_ts) >> +{ >> + register struct __kernel_timespec *ts asm("x1") = _ts; >> + register clockid_t clkid asm("x0") = _clkid; >> + register long ret asm ("x0"); >> + register long nr asm("x8") = __NR_clock_getres; >> + >> + asm volatile( >> + " svc #0\n" >> + : "=r" (ret) >> + : "r" (clkid), "r" (ts), "r" (nr) >> + : "memory"); >> + >> + return ret; >> +} >> + >> +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) >> +{ >> + u64 res; >> + >> + asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory"); >> + >> + return res; >> +} >> + >> +static __always_inline >> +const struct vdso_data *__arch_get_vdso_data(void) >> +{ >> + return _vdso_data; >> +} >> + >> +#endif /* !__ASSEMBLY__ */ >> + >> +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ >> diff --git a/arch/arm64/include/asm/vdso/vsyscall.h b/arch/arm64/include/asm/vdso/vsyscall.h >> new file mode 100644 >> index 000000000000..0c731bfc7c8c >> --- /dev/null >> +++ b/arch/arm64/include/asm/vdso/vsyscall.h >> @@ -0,0 +1,53 @@ >> +/* SPDX-License-Identifier: GPL-2.0 */ >> +#ifndef __ASM_VDSO_VSYSCALL_H >> +#define __ASM_VDSO_VSYSCALL_H >> + >> +#ifndef __ASSEMBLY__ >> + >> +#include <linux/timekeeper_internal.h> >> +#include <vdso/datapage.h> >> + >> +#define VDSO_PRECISION_MASK ~(0xFF00ULL<<48) >> + >> +extern struct vdso_data *vdso_data; >> + >> +/* >> + * Update the vDSO data page to keep in sync with kernel timekeeping. >> + */ >> +static __always_inline >> +struct vdso_data *__arm64_get_k_vdso_data(void) >> +{ >> + return vdso_data; >> +} >> +#define __arch_get_k_vdso_data __arm64_get_k_vdso_data >> + >> +static __always_inline >> +int __arm64_get_clock_mode(struct timekeeper *tk) >> +{ >> + u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct; >> + >> + return use_syscall; >> +} >> +#define __arch_get_clock_mode __arm64_get_clock_mode >> + >> +static __always_inline >> +int __arm64_use_vsyscall(struct vdso_data *vdata) >> +{ >> + return !vdata[CS_HRES_COARSE].clock_mode; >> +} >> +#define __arch_use_vsyscall __arm64_use_vsyscall >> + >> +static __always_inline >> +void __arm64_update_vsyscall(struct vdso_data *vdata, struct timekeeper *tk) >> +{ >> + vdata[CS_HRES_COARSE].mask = VDSO_PRECISION_MASK; >> + vdata[CS_RAW].mask = VDSO_PRECISION_MASK; >> +} >> +#define __arch_update_vsyscall __arm64_update_vsyscall >> + >> +/* The asm-generic header needs to be included after the definitions above */ >> +#include <asm-generic/vdso/vsyscall.h> >> + >> +#endif /* !__ASSEMBLY__ */ >> + >> +#endif /* __ASM_VDSO_VSYSCALL_H */ >> diff --git a/arch/arm64/include/asm/vdso_datapage.h b/arch/arm64/include/asm/vdso_datapage.h >> deleted file mode 100644 >> index f89263c8e11a..000000000000 >> --- a/arch/arm64/include/asm/vdso_datapage.h >> +++ /dev/null >> @@ -1,48 +0,0 @@ >> -/* >> - * Copyright (C) 2012 ARM Limited >> - * >> - * This program is free software; you can redistribute it and/or modify >> - * it under the terms of the GNU General Public License version 2 as >> - * published by the Free Software Foundation. >> - * >> - * This program is distributed in the hope that it will be useful, >> - * but WITHOUT ANY WARRANTY; without even the implied warranty of >> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> - * GNU General Public License for more details. >> - * >> - * You should have received a copy of the GNU General Public License >> - * along with this program. If not, see <http://www.gnu.org/licenses/>. >> - */ >> -#ifndef __ASM_VDSO_DATAPAGE_H >> -#define __ASM_VDSO_DATAPAGE_H >> - >> -#ifdef __KERNEL__ >> - >> -#ifndef __ASSEMBLY__ >> - >> -struct vdso_data { >> - __u64 cs_cycle_last; /* Timebase at clocksource init */ >> - __u64 raw_time_sec; /* Raw time */ >> - __u64 raw_time_nsec; >> - __u64 xtime_clock_sec; /* Kernel time */ >> - __u64 xtime_clock_nsec; >> - __u64 xtime_coarse_sec; /* Coarse time */ >> - __u64 xtime_coarse_nsec; >> - __u64 wtm_clock_sec; /* Wall to monotonic time */ >> - __u64 wtm_clock_nsec; >> - __u32 tb_seq_count; /* Timebase sequence counter */ >> - /* cs_* members must be adjacent and in this order (ldp accesses) */ >> - __u32 cs_mono_mult; /* NTP-adjusted clocksource multiplier */ >> - __u32 cs_shift; /* Clocksource shift (mono = raw) */ >> - __u32 cs_raw_mult; /* Raw clocksource multiplier */ >> - __u32 tz_minuteswest; /* Whacky timezone stuff */ >> - __u32 tz_dsttime; >> - __u32 use_syscall; >> - __u32 hrtimer_res; >> -}; >> - >> -#endif /* !__ASSEMBLY__ */ >> - >> -#endif /* __KERNEL__ */ >> - >> -#endif /* __ASM_VDSO_DATAPAGE_H */ >> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c >> index 947e39896e28..9e4b7ccbab2f 100644 >> --- a/arch/arm64/kernel/asm-offsets.c >> +++ b/arch/arm64/kernel/asm-offsets.c >> @@ -25,13 +25,13 @@ >> #include <linux/kvm_host.h> >> #include <linux/preempt.h> >> #include <linux/suspend.h> >> +#include <vdso/datapage.h> >> #include <asm/cpufeature.h> >> #include <asm/fixmap.h> >> #include <asm/thread_info.h> >> #include <asm/memory.h> >> #include <asm/smp_plat.h> >> #include <asm/suspend.h> >> -#include <asm/vdso_datapage.h> >> #include <linux/kbuild.h> >> #include <linux/arm-smccc.h> >> >> @@ -100,17 +100,28 @@ int main(void) >> DEFINE(CLOCK_COARSE_RES, LOW_RES_NSEC); >> DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); >> BLANK(); >> - DEFINE(VDSO_CS_CYCLE_LAST, offsetof(struct vdso_data, cs_cycle_last)); >> - DEFINE(VDSO_RAW_TIME_SEC, offsetof(struct vdso_data, raw_time_sec)); >> - DEFINE(VDSO_XTIME_CLK_SEC, offsetof(struct vdso_data, xtime_clock_sec)); >> - DEFINE(VDSO_XTIME_CRS_SEC, offsetof(struct vdso_data, xtime_coarse_sec)); >> - DEFINE(VDSO_XTIME_CRS_NSEC, offsetof(struct vdso_data, xtime_coarse_nsec)); >> - DEFINE(VDSO_WTM_CLK_SEC, offsetof(struct vdso_data, wtm_clock_sec)); >> - DEFINE(VDSO_TB_SEQ_COUNT, offsetof(struct vdso_data, tb_seq_count)); >> - DEFINE(VDSO_CS_MONO_MULT, offsetof(struct vdso_data, cs_mono_mult)); >> - DEFINE(VDSO_CS_SHIFT, offsetof(struct vdso_data, cs_shift)); >> + DEFINE(VDSO_SEQ, offsetof(struct vdso_data, seq)); >> + DEFINE(VDSO_CLK_MODE, offsetof(struct vdso_data, clock_mode)); >> + DEFINE(VDSO_CYCLE_LAST, offsetof(struct vdso_data, cycle_last)); >> + DEFINE(VDSO_MASK, offsetof(struct vdso_data, mask)); >> + DEFINE(VDSO_MULT, offsetof(struct vdso_data, mult)); >> + DEFINE(VDSO_SHIFT, offsetof(struct vdso_data, shift)); >> + DEFINE(VDSO_REALTIME_SEC, offsetof(struct vdso_data, basetime[CLOCK_REALTIME].sec)); >> + DEFINE(VDSO_REALTIME_NSEC, offsetof(struct vdso_data, basetime[CLOCK_REALTIME].nsec)); >> + DEFINE(VDSO_MONO_SEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC].sec)); >> + DEFINE(VDSO_MONO_NSEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC].nsec)); >> + DEFINE(VDSO_MONO_RAW_SEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC_RAW].sec)); >> + DEFINE(VDSO_MONO_RAW_NSEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC_RAW].nsec)); >> + DEFINE(VDSO_BOOTTIME_SEC, offsetof(struct vdso_data, basetime[CLOCK_BOOTTIME].sec)); >> + DEFINE(VDSO_BOOTTIME_NSEC, offsetof(struct vdso_data, basetime[CLOCK_BOOTTIME].nsec)); >> + DEFINE(VDSO_TAI_SEC, offsetof(struct vdso_data, basetime[CLOCK_TAI].sec)); >> + DEFINE(VDSO_TAI_NSEC, offsetof(struct vdso_data, basetime[CLOCK_TAI].nsec)); >> + DEFINE(VDSO_RT_COARSE_SEC, offsetof(struct vdso_data, basetime[CLOCK_REALTIME_COARSE].sec)); >> + DEFINE(VDSO_RT_COARSE_NSEC, offsetof(struct vdso_data, basetime[CLOCK_REALTIME_COARSE].nsec)); >> + DEFINE(VDSO_MONO_COARSE_SEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC_COARSE].sec)); >> + DEFINE(VDSO_MONO_COARSE_NSEC, offsetof(struct vdso_data, basetime[CLOCK_MONOTONIC_COARSE].nsec)); >> DEFINE(VDSO_TZ_MINWEST, offsetof(struct vdso_data, tz_minuteswest)); >> - DEFINE(VDSO_USE_SYSCALL, offsetof(struct vdso_data, use_syscall)); >> + DEFINE(VDSO_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime)); >> BLANK(); >> DEFINE(TVAL_TV_SEC, offsetof(struct timeval, tv_sec)); >> DEFINE(TSPEC_TV_SEC, offsetof(struct timespec, tv_sec)); >> diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c >> index 8074cbd3a3a8..23c38303a52a 100644 >> --- a/arch/arm64/kernel/vdso.c >> +++ b/arch/arm64/kernel/vdso.c >> @@ -31,11 +31,13 @@ >> #include <linux/slab.h> >> #include <linux/timekeeper_internal.h> >> #include <linux/vmalloc.h> >> +#include <vdso/datapage.h> >> +#include <vdso/helpers.h> >> +#include <vdso/vsyscall.h> >> >> #include <asm/cacheflush.h> >> #include <asm/signal32.h> >> #include <asm/vdso.h> >> -#include <asm/vdso_datapage.h> >> >> extern char vdso_start[], vdso_end[]; >> static unsigned long vdso_pages __ro_after_init; >> @@ -44,10 +46,10 @@ static unsigned long vdso_pages __ro_after_init; >> * The vDSO data page. >> */ >> static union { >> - struct vdso_data data; >> + struct vdso_data data[CS_BASES]; >> u8 page[PAGE_SIZE]; >> } vdso_data_store __page_aligned_data; >> -struct vdso_data *vdso_data = &vdso_data_store.data; >> +struct vdso_data *vdso_data = vdso_data_store.data; >> >> #ifdef CONFIG_COMPAT >> /* >> @@ -280,46 +282,3 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, >> up_write(&mm->mmap_sem); >> return PTR_ERR(ret); >> } >> - >> -/* >> - * Update the vDSO data page to keep in sync with kernel timekeeping. >> - */ >> -void update_vsyscall(struct timekeeper *tk) >> -{ >> - u32 use_syscall = !tk->tkr_mono.clock->archdata.vdso_direct; >> - >> - ++vdso_data->tb_seq_count; >> - smp_wmb(); >> - >> - vdso_data->use_syscall = use_syscall; >> - vdso_data->xtime_coarse_sec = tk->xtime_sec; >> - vdso_data->xtime_coarse_nsec = tk->tkr_mono.xtime_nsec >> >> - tk->tkr_mono.shift; >> - vdso_data->wtm_clock_sec = tk->wall_to_monotonic.tv_sec; >> - vdso_data->wtm_clock_nsec = tk->wall_to_monotonic.tv_nsec; >> - >> - /* Read without the seqlock held by clock_getres() */ >> - WRITE_ONCE(vdso_data->hrtimer_res, hrtimer_resolution); >> - >> - if (!use_syscall) { >> - /* tkr_mono.cycle_last == tkr_raw.cycle_last */ >> - vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; >> - vdso_data->raw_time_sec = tk->raw_sec; >> - vdso_data->raw_time_nsec = tk->tkr_raw.xtime_nsec; >> - vdso_data->xtime_clock_sec = tk->xtime_sec; >> - vdso_data->xtime_clock_nsec = tk->tkr_mono.xtime_nsec; >> - vdso_data->cs_mono_mult = tk->tkr_mono.mult; >> - vdso_data->cs_raw_mult = tk->tkr_raw.mult; >> - /* tkr_mono.shift == tkr_raw.shift */ >> - vdso_data->cs_shift = tk->tkr_mono.shift; >> - } >> - >> - smp_wmb(); >> - ++vdso_data->tb_seq_count; >> -} >> - >> -void update_vsyscall_tz(void) >> -{ >> - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; >> - vdso_data->tz_dsttime = sys_tz.tz_dsttime; >> -} >> diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile >> index fa230ff09aa1..3acfc813e966 100644 >> --- a/arch/arm64/kernel/vdso/Makefile >> +++ b/arch/arm64/kernel/vdso/Makefile >> @@ -6,7 +6,12 @@ >> # Heavily based on the vDSO Makefiles for other archs. >> # >> >> -obj-vdso := gettimeofday.o note.o sigreturn.o >> +# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before >> +# the inclusion of generic Makefile. >> +ARCH_REL_TYPE_ABS := R_AARCH64_JUMP_SLOT|R_AARCH64_GLOB_DAT|R_AARCH64_ABS64 >> +include $(srctree)/lib/vdso/Makefile >> + >> +obj-vdso := vgettimeofday.o note.o sigreturn.o >> >> # Build rules >> targets := $(obj-vdso) vdso.so vdso.so.dbg >> @@ -15,6 +20,24 @@ obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) >> ldflags-y := -shared -nostdlib -soname=linux-vdso.so.1 --hash-style=sysv \ >> --build-id -n -T >> >> +ccflags-y := -fno-common -fno-builtin -fno-stack-protector >> +ccflags-y += -DDISABLE_BRANCH_PROFILING >> + >> +VDSO_LDFLAGS := -Bsymbolic >> + >> +CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os >> +KBUILD_CFLAGS += $(DISABLE_LTO) >> +KASAN_SANITIZE := n >> +UBSAN_SANITIZE := n >> +OBJECT_FILES_NON_STANDARD := y >> +KCOV_INSTRUMENT := n >> + >> +ifeq ($(c-gettimeofday-y),) >> +CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny >> +else >> +CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -include $(c-gettimeofday-y) >> +endif >> + >> # Disable gcov profiling for VDSO code >> GCOV_PROFILE := n >> >> @@ -28,6 +51,7 @@ $(obj)/vdso.o : $(obj)/vdso.so >> # Link rule for the .so file, .lds has to be first >> $(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE >> $(call if_changed,ld) >> + $(call if_changed,vdso_check) >> >> # Strip rule for the .so file >> $(obj)/%.so: OBJCOPYFLAGS := -S >> @@ -42,13 +66,9 @@ quiet_cmd_vdsosym = VDSOSYM $@ >> include/generated/vdso-offsets.h: $(obj)/vdso.so.dbg FORCE >> $(call if_changed,vdsosym) >> >> -# Assembly rules for the .S files >> -$(obj-vdso): %.o: %.S FORCE >> - $(call if_changed_dep,vdsoas) >> - >> # Actual build commands >> -quiet_cmd_vdsoas = VDSOA $@ >> - cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $< >> +quiet_cmd_vdsocc = VDSOCC $@ >> + cmd_vdsocc = $(CC) $(a_flags) $(c_flags) -c -o $@ $< >> >> # Install commands for the unstripped file >> quiet_cmd_vdso_install = INSTALL $@ >> diff --git a/arch/arm64/kernel/vdso/gettimeofday.S b/arch/arm64/kernel/vdso/gettimeofday.S >> deleted file mode 100644 >> index 856fee6d3512..000000000000 >> --- a/arch/arm64/kernel/vdso/gettimeofday.S >> +++ /dev/null >> @@ -1,334 +0,0 @@ >> -/* >> - * Userspace implementations of gettimeofday() and friends. >> - * >> - * Copyright (C) 2012 ARM Limited >> - * >> - * This program is free software; you can redistribute it and/or modify >> - * it under the terms of the GNU General Public License version 2 as >> - * published by the Free Software Foundation. >> - * >> - * This program is distributed in the hope that it will be useful, >> - * but WITHOUT ANY WARRANTY; without even the implied warranty of >> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> - * GNU General Public License for more details. >> - * >> - * You should have received a copy of the GNU General Public License >> - * along with this program. If not, see <http://www.gnu.org/licenses/>. >> - * >> - * Author: Will Deacon <will.deacon@xxxxxxx> >> - */ >> - >> -#include <linux/linkage.h> >> -#include <asm/asm-offsets.h> >> -#include <asm/unistd.h> >> - >> -#define NSEC_PER_SEC_LO16 0xca00 >> -#define NSEC_PER_SEC_HI16 0x3b9a >> - >> -vdso_data .req x6 >> -seqcnt .req w7 >> -w_tmp .req w8 >> -x_tmp .req x8 >> - >> -/* >> - * Conventions for macro arguments: >> - * - An argument is write-only if its name starts with "res". >> - * - All other arguments are read-only, unless otherwise specified. >> - */ >> - >> - .macro seqcnt_acquire >> -9999: ldr seqcnt, [vdso_data, #VDSO_TB_SEQ_COUNT] >> - tbnz seqcnt, #0, 9999b >> - dmb ishld >> - .endm >> - >> - .macro seqcnt_check fail >> - dmb ishld >> - ldr w_tmp, [vdso_data, #VDSO_TB_SEQ_COUNT] >> - cmp w_tmp, seqcnt >> - b.ne \fail >> - .endm >> - >> - .macro syscall_check fail >> - ldr w_tmp, [vdso_data, #VDSO_USE_SYSCALL] >> - cbnz w_tmp, \fail >> - .endm >> - >> - .macro get_nsec_per_sec res >> - mov \res, #NSEC_PER_SEC_LO16 >> - movk \res, #NSEC_PER_SEC_HI16, lsl #16 >> - .endm >> - >> - /* >> - * Returns the clock delta, in nanoseconds left-shifted by the clock >> - * shift. >> - */ >> - .macro get_clock_shifted_nsec res, cycle_last, mult >> - /* Read the virtual counter. */ >> - isb >> - mrs x_tmp, cntvct_el0 >> - /* Calculate cycle delta and convert to ns. */ >> - sub \res, x_tmp, \cycle_last >> - /* We can only guarantee 56 bits of precision. */ >> - movn x_tmp, #0xff00, lsl #48 >> - and \res, x_tmp, \res >> - mul \res, \res, \mult >> - /* >> - * Fake address dependency from the value computed from the counter >> - * register to subsequent data page accesses so that the sequence >> - * locking also orders the read of the counter. >> - */ >> - and x_tmp, \res, xzr >> - add vdso_data, vdso_data, x_tmp >> - .endm >> - >> - /* >> - * Returns in res_{sec,nsec} the REALTIME timespec, based on the >> - * "wall time" (xtime) and the clock_mono delta. >> - */ >> - .macro get_ts_realtime res_sec, res_nsec, \ >> - clock_nsec, xtime_sec, xtime_nsec, nsec_to_sec >> - add \res_nsec, \clock_nsec, \xtime_nsec >> - udiv x_tmp, \res_nsec, \nsec_to_sec >> - add \res_sec, \xtime_sec, x_tmp >> - msub \res_nsec, x_tmp, \nsec_to_sec, \res_nsec >> - .endm >> - >> - /* >> - * Returns in res_{sec,nsec} the timespec based on the clock_raw delta, >> - * used for CLOCK_MONOTONIC_RAW. >> - */ >> - .macro get_ts_clock_raw res_sec, res_nsec, clock_nsec, nsec_to_sec >> - udiv \res_sec, \clock_nsec, \nsec_to_sec >> - msub \res_nsec, \res_sec, \nsec_to_sec, \clock_nsec >> - .endm >> - >> - /* sec and nsec are modified in place. */ >> - .macro add_ts sec, nsec, ts_sec, ts_nsec, nsec_to_sec >> - /* Add timespec. */ >> - add \sec, \sec, \ts_sec >> - add \nsec, \nsec, \ts_nsec >> - >> - /* Normalise the new timespec. */ >> - cmp \nsec, \nsec_to_sec >> - b.lt 9999f >> - sub \nsec, \nsec, \nsec_to_sec >> - add \sec, \sec, #1 >> -9999: >> - cmp \nsec, #0 >> - b.ge 9998f >> - add \nsec, \nsec, \nsec_to_sec >> - sub \sec, \sec, #1 >> -9998: >> - .endm >> - >> - .macro clock_gettime_return, shift=0 >> - .if \shift == 1 >> - lsr x11, x11, x12 >> - .endif >> - stp x10, x11, [x1, #TSPEC_TV_SEC] >> - mov x0, xzr >> - ret >> - .endm >> - >> - .macro jump_slot jumptable, index, label >> - .if (. - \jumptable) != 4 * (\index) >> - .error "Jump slot index mismatch" >> - .endif >> - b \label >> - .endm >> - >> - .text >> - >> -/* int __kernel_gettimeofday(struct timeval *tv, struct timezone *tz); */ >> -ENTRY(__kernel_gettimeofday) >> - .cfi_startproc >> - adr vdso_data, _vdso_data >> - /* If tv is NULL, skip to the timezone code. */ >> - cbz x0, 2f >> - >> - /* Compute the time of day. */ >> -1: seqcnt_acquire >> - syscall_check fail=4f >> - ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST] >> - /* w11 = cs_mono_mult, w12 = cs_shift */ >> - ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT] >> - ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC] >> - >> - get_nsec_per_sec res=x9 >> - lsl x9, x9, x12 >> - >> - get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11 >> - seqcnt_check fail=1b >> - get_ts_realtime res_sec=x10, res_nsec=x11, \ >> - clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9 >> - >> - /* Convert ns to us. */ >> - mov x13, #1000 >> - lsl x13, x13, x12 >> - udiv x11, x11, x13 >> - stp x10, x11, [x0, #TVAL_TV_SEC] >> -2: >> - /* If tz is NULL, return 0. */ >> - cbz x1, 3f >> - ldp w4, w5, [vdso_data, #VDSO_TZ_MINWEST] >> - stp w4, w5, [x1, #TZ_MINWEST] >> -3: >> - mov x0, xzr >> - ret >> -4: >> - /* Syscall fallback. */ >> - mov x8, #__NR_gettimeofday >> - svc #0 >> - ret >> - .cfi_endproc >> -ENDPROC(__kernel_gettimeofday) >> - >> -#define JUMPSLOT_MAX CLOCK_MONOTONIC_COARSE >> - >> -/* int __kernel_clock_gettime(clockid_t clock_id, struct timespec *tp); */ >> -ENTRY(__kernel_clock_gettime) >> - .cfi_startproc >> - cmp w0, #JUMPSLOT_MAX >> - b.hi syscall >> - adr vdso_data, _vdso_data >> - adr x_tmp, jumptable >> - add x_tmp, x_tmp, w0, uxtw #2 >> - br x_tmp >> - >> - ALIGN >> -jumptable: >> - jump_slot jumptable, CLOCK_REALTIME, realtime >> - jump_slot jumptable, CLOCK_MONOTONIC, monotonic >> - b syscall >> - b syscall >> - jump_slot jumptable, CLOCK_MONOTONIC_RAW, monotonic_raw >> - jump_slot jumptable, CLOCK_REALTIME_COARSE, realtime_coarse >> - jump_slot jumptable, CLOCK_MONOTONIC_COARSE, monotonic_coarse >> - >> - .if (. - jumptable) != 4 * (JUMPSLOT_MAX + 1) >> - .error "Wrong jumptable size" >> - .endif >> - >> - ALIGN >> -realtime: >> - seqcnt_acquire >> - syscall_check fail=syscall >> - ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST] >> - /* w11 = cs_mono_mult, w12 = cs_shift */ >> - ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT] >> - ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC] >> - >> - /* All computations are done with left-shifted nsecs. */ >> - get_nsec_per_sec res=x9 >> - lsl x9, x9, x12 >> - >> - get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11 >> - seqcnt_check fail=realtime >> - get_ts_realtime res_sec=x10, res_nsec=x11, \ >> - clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9 >> - clock_gettime_return, shift=1 >> - >> - ALIGN >> -monotonic: >> - seqcnt_acquire >> - syscall_check fail=syscall >> - ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST] >> - /* w11 = cs_mono_mult, w12 = cs_shift */ >> - ldp w11, w12, [vdso_data, #VDSO_CS_MONO_MULT] >> - ldp x13, x14, [vdso_data, #VDSO_XTIME_CLK_SEC] >> - ldp x3, x4, [vdso_data, #VDSO_WTM_CLK_SEC] >> - >> - /* All computations are done with left-shifted nsecs. */ >> - lsl x4, x4, x12 >> - get_nsec_per_sec res=x9 >> - lsl x9, x9, x12 >> - >> - get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11 >> - seqcnt_check fail=monotonic >> - get_ts_realtime res_sec=x10, res_nsec=x11, \ >> - clock_nsec=x15, xtime_sec=x13, xtime_nsec=x14, nsec_to_sec=x9 >> - >> - add_ts sec=x10, nsec=x11, ts_sec=x3, ts_nsec=x4, nsec_to_sec=x9 >> - clock_gettime_return, shift=1 >> - >> - ALIGN >> -monotonic_raw: >> - seqcnt_acquire >> - syscall_check fail=syscall >> - ldr x10, [vdso_data, #VDSO_CS_CYCLE_LAST] >> - /* w11 = cs_raw_mult, w12 = cs_shift */ >> - ldp w12, w11, [vdso_data, #VDSO_CS_SHIFT] >> - ldp x13, x14, [vdso_data, #VDSO_RAW_TIME_SEC] >> - >> - /* All computations are done with left-shifted nsecs. */ >> - get_nsec_per_sec res=x9 >> - lsl x9, x9, x12 >> - >> - get_clock_shifted_nsec res=x15, cycle_last=x10, mult=x11 >> - seqcnt_check fail=monotonic_raw >> - get_ts_clock_raw res_sec=x10, res_nsec=x11, \ >> - clock_nsec=x15, nsec_to_sec=x9 >> - >> - add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9 >> - clock_gettime_return, shift=1 >> - >> - ALIGN >> -realtime_coarse: >> - seqcnt_acquire >> - ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC] >> - seqcnt_check fail=realtime_coarse >> - clock_gettime_return >> - >> - ALIGN >> -monotonic_coarse: >> - seqcnt_acquire >> - ldp x10, x11, [vdso_data, #VDSO_XTIME_CRS_SEC] >> - ldp x13, x14, [vdso_data, #VDSO_WTM_CLK_SEC] >> - seqcnt_check fail=monotonic_coarse >> - >> - /* Computations are done in (non-shifted) nsecs. */ >> - get_nsec_per_sec res=x9 >> - add_ts sec=x10, nsec=x11, ts_sec=x13, ts_nsec=x14, nsec_to_sec=x9 >> - clock_gettime_return >> - >> - ALIGN >> -syscall: /* Syscall fallback. */ >> - mov x8, #__NR_clock_gettime >> - svc #0 >> - ret >> - .cfi_endproc >> -ENDPROC(__kernel_clock_gettime) >> - >> -/* int __kernel_clock_getres(clockid_t clock_id, struct timespec *res); */ >> -ENTRY(__kernel_clock_getres) >> - .cfi_startproc >> - cmp w0, #CLOCK_REALTIME >> - ccmp w0, #CLOCK_MONOTONIC, #0x4, ne >> - ccmp w0, #CLOCK_MONOTONIC_RAW, #0x4, ne >> - b.ne 1f >> - >> - adr vdso_data, _vdso_data >> - ldr w2, [vdso_data, #CLOCK_REALTIME_RES] >> - b 2f >> -1: >> - cmp w0, #CLOCK_REALTIME_COARSE >> - ccmp w0, #CLOCK_MONOTONIC_COARSE, #0x4, ne >> - b.ne 4f >> - ldr x2, 5f >> -2: >> - cbz x1, 3f >> - stp xzr, x2, [x1] >> - >> -3: /* res == NULL. */ >> - mov w0, wzr >> - ret >> - >> -4: /* Syscall fallback. */ >> - mov x8, #__NR_clock_getres >> - svc #0 >> - ret >> -5: >> - .quad CLOCK_COARSE_RES >> - .cfi_endproc >> -ENDPROC(__kernel_clock_getres) >> diff --git a/arch/arm64/kernel/vdso/vgettimeofday.c b/arch/arm64/kernel/vdso/vgettimeofday.c >> new file mode 100644 >> index 000000000000..3c58f19dbdf4 >> --- /dev/null >> +++ b/arch/arm64/kernel/vdso/vgettimeofday.c >> @@ -0,0 +1,28 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * ARM64 userspace implementations of gettimeofday() and similar. >> + * >> + * Copyright (C) 2018 ARM Limited >> + * >> + */ >> +#include <linux/time.h> >> +#include <linux/types.h> >> + >> +int __kernel_clock_gettime(clockid_t clock, >> + struct __kernel_timespec *ts) >> +{ >> + return __cvdso_clock_gettime(clock, ts); >> +} >> + >> +int __kernel_gettimeofday(struct __kernel_old_timeval *tv, >> + struct timezone *tz) >> +{ >> + return __cvdso_gettimeofday(tv, tz); >> +} >> + >> +int __kernel_clock_getres(clockid_t clock_id, >> + struct __kernel_timespec *res) >> +{ >> + return __cvdso_clock_getres(clock_id, res); >> +} >> + > > Best regards > -- Regards, Vincenzo