vDSO (virtual dynamic shared object) is a mechanism that the Linux kernel provides as an alternative to system calls to reduce where possible the costs in terms of cycles. This is possible because certain syscalls like gettimeofday() do not write any data and return one or more values that are stored in the kernel, which makes relatively safe calling them directly as a library function.
Even if the mechanism is pretty much standard, every architecture in the last few years ended up implementing their own vDSO library in the architectural code.
The purpose of this patch-set is to identify the commonalities in between the architectures and try to consolidate the common code paths, starting with gettimeofday().
This implementation contains the following design choices: * Every architecture defines the arch specific code in an header in "asm/vdso/". * The generic implementation includes the arch specific one and lives in "lib/vdso". * The arch specific code for gettimeofday lives in "<arch path>/vdso/gettimeofday.c" and includes the generic code only. * The generic implementation of update_vsyscall and update_vsyscall_tz lives in kernel/vdso and provide the bindings that can be implemented by each architecture. * Each architecture provides its implementation of the bindings in "asm/vdso/vsyscall.h". * This approach allows to consolidate the common code in a single place with the benefit of avoiding code duplication.
This implementation contains the portings to the common library for: arm64, compat mode for arm64, arm, mips, x86_64, x32, compat mode for x86_64 and i386.
The mips porting has been tested on qemu for mips32el. A configuration to repeat the tests can be found at [4].
The x86_64 porting has been tested on an Intel Xeon 5120T based machine running Ubuntu 18.04 and using the Ubuntu provided defconfig.
The i386 porting has been tested on qemu using the i386_defconfig configuration.
Last but not least from this porting arm64, compat arm64, arm and mips gain the support for: * CLOCK_BOOTTIME that can be useful in certain scenarios since it keeps track of the time during sleep as well. * CLOCK_TAI that is like CLOCK_REALTIME, but uses the International Atomic Time (TAI) reference instead of UTC to avoid jumping on leap second updates. for both clock_gettime and clock_getres.
The porting has been validated using the vdsotest test-suite [1] extended to cover all the clock ids [2].
A new test has been added to the linux kselftest in order to validate the newly added library.
The porting has been benchmarked and the performance results are provided as part of this cover letter.
To simplify the testing, a copy of the patchset on top of a recent linux tree can be found at [3] and [4].
The v7 of this patchseries has been rebased on [5].
[1] https://github.com/nathanlynch/vdsotest [2] https://github.com/fvincenzo/vdsotest [3] git://linux-arm.org/linux-vf.git vdso/v7 [4] git://linux-arm.org/linux-vf.git vdso-mips/v7 [5] git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux.git hyperv-next
Changes: -------- v7: - Rebased on [5] (5.2-rc3). - Added performance numbers for arm64 provided by Shijith Thotton. - Aimed at 1:1 replacement for pre-exisiting vDSO libraries. - Provided separate patches for newly added API. - Addressed review comments. v6: - Rebased on 5.2-rc2. - Added performance numbers. - Removed vdso_types.h. - Unified update_vsyscall and update_vsyscall_tz. - Reworked the kselftest included in this patchset. - Addressed review comments. v5: - Rebased on 5.0-rc7. - Added x86_64, compat mode for x86_64 and i386 portings. - Extended vDSO kselftest. - Addressed review comments. v4: - Rebased on 5.0-rc2. - Addressed review comments. - Disabled compat vdso on arm64 when the kernel is compiled with clang. v3: - Ported the latest fixes and optimizations done on the x86 architecture to the generic library. - Addressed review comments. - Improved the documentation of the interfaces. - Changed the HAVE_ARCH_TIMER config option to a more generic HAVE_HW_COUNTER. v2: - Added -ffixed-x18 to arm64 - Repleced occurrences of timeval and timespec - Modified datapage.h to be compliant with y2038 on all the architectures - Removed __u_vdso type
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Cc: Arnd Bergmann arnd@arndb.de Cc: Russell King linux@armlinux.org.uk Cc: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Cc: Daniel Lezcano daniel.lezcano@linaro.org Cc: Thomas Gleixner tglx@linutronix.de Cc: Mark Salyzyn salyzyn@android.com Cc: Peter Collingbourne pcc@google.com Cc: Shuah Khan shuah@kernel.org Cc: Dmitry Safonov 0x7f454c46@gmail.com Cc: Rasmus Villemoes linux@rasmusvillemoes.dk Cc: Huw Davies huw@codeweavers.com Cc: Shijith Thotton sthotton@marvell.com Cc: Andre Przywara andre.przywara@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
Performance Numbers: Linux 5.2.0-rc2 - Xeon Gold 5120T ======================================================
Unified vDSO: -------------
clock-gettime-monotonic: syscall: 342 nsec/call clock-gettime-monotonic: libc: 25 nsec/call clock-gettime-monotonic: vdso: 24 nsec/call clock-getres-monotonic: syscall: 296 nsec/call clock-getres-monotonic: libc: 296 nsec/call clock-getres-monotonic: vdso: 3 nsec/call clock-gettime-monotonic-coarse: syscall: 294 nsec/call clock-gettime-monotonic-coarse: libc: 5 nsec/call clock-gettime-monotonic-coarse: vdso: 5 nsec/call clock-getres-monotonic-coarse: syscall: 295 nsec/call clock-getres-monotonic-coarse: libc: 292 nsec/call clock-getres-monotonic-coarse: vdso: 5 nsec/call clock-gettime-monotonic-raw: syscall: 343 nsec/call clock-gettime-monotonic-raw: libc: 25 nsec/call clock-gettime-monotonic-raw: vdso: 23 nsec/call clock-getres-monotonic-raw: syscall: 290 nsec/call clock-getres-monotonic-raw: libc: 290 nsec/call clock-getres-monotonic-raw: vdso: 4 nsec/call clock-gettime-tai: syscall: 332 nsec/call clock-gettime-tai: libc: 24 nsec/call clock-gettime-tai: vdso: 23 nsec/call clock-getres-tai: syscall: 288 nsec/call clock-getres-tai: libc: 288 nsec/call clock-getres-tai: vdso: 3 nsec/call clock-gettime-boottime: syscall: 342 nsec/call clock-gettime-boottime: libc: 24 nsec/call clock-gettime-boottime: vdso: 23 nsec/call clock-getres-boottime: syscall: 284 nsec/call clock-getres-boottime: libc: 291 nsec/call clock-getres-boottime: vdso: 3 nsec/call clock-gettime-realtime: syscall: 337 nsec/call clock-gettime-realtime: libc: 24 nsec/call clock-gettime-realtime: vdso: 23 nsec/call clock-getres-realtime: syscall: 287 nsec/call clock-getres-realtime: libc: 284 nsec/call clock-getres-realtime: vdso: 3 nsec/call clock-gettime-realtime-coarse: syscall: 307 nsec/call clock-gettime-realtime-coarse: libc: 4 nsec/call clock-gettime-realtime-coarse: vdso: 4 nsec/call clock-getres-realtime-coarse: syscall: 294 nsec/call clock-getres-realtime-coarse: libc: 291 nsec/call clock-getres-realtime-coarse: vdso: 4 nsec/call getcpu: syscall: 246 nsec/call getcpu: libc: 14 nsec/call getcpu: vdso: 11 nsec/call gettimeofday: syscall: 293 nsec/call gettimeofday: libc: 26 nsec/call gettimeofday: vdso: 25 nsec/call
Stock Kernel: -------------
clock-gettime-monotonic: syscall: 338 nsec/call clock-gettime-monotonic: libc: 24 nsec/call clock-gettime-monotonic: vdso: 23 nsec/call clock-getres-monotonic: syscall: 291 nsec/call clock-getres-monotonic: libc: 304 nsec/call clock-getres-monotonic: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-monotonic-coarse: syscall: 297 nsec/call clock-gettime-monotonic-coarse: libc: 5 nsec/call clock-gettime-monotonic-coarse: vdso: 4 nsec/call clock-getres-monotonic-coarse: syscall: 281 nsec/call clock-getres-monotonic-coarse: libc: 286 nsec/call clock-getres-monotonic-coarse: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-monotonic-raw: syscall: 336 nsec/call clock-gettime-monotonic-raw: libc: 340 nsec/call clock-gettime-monotonic-raw: vdso: 346 nsec/call clock-getres-monotonic-raw: syscall: 297 nsec/call clock-getres-monotonic-raw: libc: 301 nsec/call clock-getres-monotonic-raw: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-tai: syscall: 351 nsec/call clock-gettime-tai: libc: 24 nsec/call clock-gettime-tai: vdso: 23 nsec/call clock-getres-tai: syscall: 298 nsec/call clock-getres-tai: libc: 290 nsec/call clock-getres-tai: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-boottime: syscall: 342 nsec/call clock-gettime-boottime: libc: 347 nsec/call clock-gettime-boottime: vdso: 355 nsec/call clock-getres-boottime: syscall: 296 nsec/call clock-getres-boottime: libc: 295 nsec/call clock-getres-boottime: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-realtime: syscall: 346 nsec/call clock-gettime-realtime: libc: 24 nsec/call clock-gettime-realtime: vdso: 22 nsec/call clock-getres-realtime: syscall: 295 nsec/call clock-getres-realtime: libc: 291 nsec/call clock-getres-realtime: vdso: not tested Note: vDSO version of clock_getres not found clock-gettime-realtime-coarse: syscall: 292 nsec/call clock-gettime-realtime-coarse: libc: 5 nsec/call clock-gettime-realtime-coarse: vdso: 4 nsec/call clock-getres-realtime-coarse: syscall: 300 nsec/call clock-getres-realtime-coarse: libc: 301 nsec/call clock-getres-realtime-coarse: vdso: not tested Note: vDSO version of clock_getres not found getcpu: syscall: 252 nsec/call getcpu: libc: 14 nsec/call getcpu: vdso: 11 nsec/call gettimeofday: syscall: 293 nsec/call gettimeofday: libc: 24 nsec/call gettimeofday: vdso: 25 nsec/call
Performance Numbers: Linux 5.2.0-rc2 - ThunderX2 (arm64) ========================================================
Provided by: Shijith Thotton sthotton@marvell.com
Unified vDSO: -------------
clock-gettime-monotonic: syscall: 346 nsec/call clock-gettime-monotonic: libc: 38 nsec/call clock-gettime-monotonic: vdso: 36 nsec/call clock-getres-monotonic: syscall: 262 nsec/call clock-getres-monotonic: libc: 6 nsec/call clock-getres-monotonic: vdso: 5 nsec/call clock-gettime-monotonic-coarse: syscall: 296 nsec/call clock-gettime-monotonic-coarse: libc: 39 nsec/call clock-gettime-monotonic-coarse: vdso: 38 nsec/call clock-getres-monotonic-coarse: syscall: 260 nsec/call clock-getres-monotonic-coarse: libc: 8 nsec/call clock-getres-monotonic-coarse: vdso: 5 nsec/call clock-gettime-monotonic-raw: syscall: 345 nsec/call clock-gettime-monotonic-raw: libc: 35 nsec/call clock-gettime-monotonic-raw: vdso: 34 nsec/call clock-getres-monotonic-raw: syscall: 261 nsec/call clock-getres-monotonic-raw: libc: 7 nsec/call clock-getres-monotonic-raw: vdso: 5 nsec/call clock-gettime-tai: syscall: 357 nsec/call clock-gettime-tai: libc: 38 nsec/call clock-gettime-tai: vdso: 36 nsec/call clock-getres-tai: syscall: 257 nsec/call clock-getres-tai: libc: 7 nsec/call clock-getres-tai: vdso: 5 nsec/call clock-gettime-boottime: syscall: 356 nsec/call clock-gettime-boottime: libc: 38 nsec/call clock-gettime-boottime: vdso: 36 nsec/call clock-getres-boottime: syscall: 257 nsec/call clock-getres-boottime: libc: 6 nsec/call clock-getres-boottime: vdso: 5 nsec/call clock-gettime-realtime: syscall: 345 nsec/call clock-gettime-realtime: libc: 38 nsec/call clock-gettime-realtime: vdso: 36 nsec/call clock-getres-realtime: syscall: 257 nsec/call clock-getres-realtime: libc: 7 nsec/call clock-getres-realtime: vdso: 5 nsec/call clock-gettime-realtime-coarse: syscall: 295 nsec/call clock-gettime-realtime-coarse: libc: 39 nsec/call clock-gettime-realtime-coarse: vdso: 38 nsec/call clock-getres-realtime-coarse: syscall: 260 nsec/call clock-getres-realtime-coarse: libc: 8 nsec/call clock-getres-realtime-coarse: vdso: 5 nsec/call getcpu: syscall: 244 nsec/call getcpu: libc: 247 nsec/call getcpu: vdso: not tested Note: vDSO version of getcpu not found gettimeofday: syscall: 383 nsec/call gettimeofday: libc: 39 nsec/call gettimeofday: vdso: 35 nsec/call
Stock Kernel: -------------
clock-gettime-monotonic: syscall: 344 nsec/call clock-gettime-monotonic: libc: 74 nsec/call clock-gettime-monotonic: vdso: 73 nsec/call clock-getres-monotonic: syscall: 258 nsec/call clock-getres-monotonic: libc: 6 nsec/call clock-getres-monotonic: vdso: 4 nsec/call clock-gettime-monotonic-coarse: syscall: 300 nsec/call clock-gettime-monotonic-coarse: libc: 36 nsec/call clock-gettime-monotonic-coarse: vdso: 34 nsec/call clock-getres-monotonic-coarse: syscall: 261 nsec/call clock-getres-monotonic-coarse: libc: 6 nsec/call clock-getres-monotonic-coarse: vdso: 4 nsec/call clock-gettime-monotonic-raw: syscall: 346 nsec/call clock-gettime-monotonic-raw: libc: 74 nsec/call clock-gettime-monotonic-raw: vdso: 72 nsec/call clock-getres-monotonic-raw: syscall: 254 nsec/call clock-getres-monotonic-raw: libc: 6 nsec/call clock-getres-monotonic-raw: vdso: 4 nsec/call clock-gettime-tai: syscall: 345 nsec/call clock-gettime-tai: libc: 361 nsec/call clock-gettime-tai: vdso: 359 nsec/call clock-getres-tai: syscall: 259 nsec/call clock-getres-tai: libc: 262 nsec/call clock-getres-tai: vdso: 258 nsec/call clock-gettime-boottime: syscall: 353 nsec/call clock-gettime-boottime: libc: 365 nsec/call clock-gettime-boottime: vdso: 362 nsec/call clock-getres-boottime: syscall: 260 nsec/call clock-getres-boottime: libc: 267 nsec/call clock-getres-boottime: vdso: 259 nsec/call clock-gettime-realtime: syscall: 344 nsec/call clock-gettime-realtime: libc: 73 nsec/call clock-gettime-realtime: vdso: 72 nsec/call clock-getres-realtime: syscall: 255 nsec/call clock-getres-realtime: libc: 7 nsec/call clock-getres-realtime: vdso: 4 nsec/call clock-gettime-realtime-coarse: syscall: 296 nsec/call clock-gettime-realtime-coarse: libc: 35 nsec/call clock-gettime-realtime-coarse: vdso: 33 nsec/call clock-getres-realtime-coarse: syscall: 258 nsec/call clock-getres-realtime-coarse: libc: 6 nsec/call clock-getres-realtime-coarse: vdso: 4 nsec/call getcpu: syscall: 237 nsec/call getcpu: libc: 242 nsec/call getcpu: vdso: not tested Note: vDSO version of getcpu not found gettimeofday: syscall: 378 nsec/call gettimeofday: libc: 73 nsec/call gettimeofday: vdso: 70 nsec/call
Peter Collingbourne (1): arm64: Build vDSO with -ffixed-x18
Vincenzo Frascino (24): kernel: Standardize vdso_datapage kernel: Define gettimeofday vdso common code kernel: Unify update_vsyscall implementation arm64: Substitute gettimeofday with C implementation arm64: compat: Add missing syscall numbers arm64: compat: Expose signal related structures arm64: compat: Generate asm offsets for signals lib: vdso: Add compat support arm64: compat: Add vDSO arm64: Refactor vDSO code arm64: compat: vDSO setup for compat layer arm64: elf: vDSO code page discovery arm64: compat: Get sigreturn trampolines from vDSO arm64: Add vDSO compat support arm: Add support for generic vDSO arm: Add clock_getres entry point arm: Add clock_gettime64 entry point mips: Add support for generic vDSO mips: Add clock_getres entry point mips: Add clock_gettime64 entry point x86: Add support for generic vDSO x86: Add clock_getres entry point x86: Add clock_gettime64 entry point kselftest: Extend vDSO selftest
arch/arm/Kconfig | 3 + arch/arm/include/asm/vdso/gettimeofday.h | 94 +++++ arch/arm/include/asm/vdso/vsyscall.h | 71 ++++ arch/arm/include/asm/vdso_datapage.h | 29 +- arch/arm/kernel/vdso.c | 87 +---- arch/arm/vdso/Makefile | 13 +- arch/arm/vdso/note.c | 15 + arch/arm/vdso/vdso.lds.S | 2 + arch/arm/vdso/vgettimeofday.c | 256 +------------ arch/arm64/Kconfig | 3 + arch/arm64/Makefile | 23 +- arch/arm64/include/asm/elf.h | 14 + arch/arm64/include/asm/signal32.h | 46 +++ arch/arm64/include/asm/unistd.h | 5 + arch/arm64/include/asm/vdso.h | 3 + arch/arm64/include/asm/vdso/compat_barrier.h | 51 +++ .../include/asm/vdso/compat_gettimeofday.h | 110 ++++++ 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/Makefile | 6 +- arch/arm64/kernel/asm-offsets.c | 39 +- arch/arm64/kernel/signal32.c | 72 ++-- arch/arm64/kernel/vdso.c | 356 ++++++++++++------ arch/arm64/kernel/vdso/Makefile | 34 +- arch/arm64/kernel/vdso/gettimeofday.S | 334 ---------------- arch/arm64/kernel/vdso/vgettimeofday.c | 28 ++ arch/arm64/kernel/vdso32/.gitignore | 2 + arch/arm64/kernel/vdso32/Makefile | 186 +++++++++ arch/arm64/kernel/vdso32/note.c | 15 + arch/arm64/kernel/vdso32/sigreturn.S | 62 +++ arch/arm64/kernel/vdso32/vdso.S | 19 + arch/arm64/kernel/vdso32/vdso.lds.S | 82 ++++ arch/arm64/kernel/vdso32/vgettimeofday.c | 59 +++ arch/mips/Kconfig | 2 + arch/mips/include/asm/vdso.h | 78 +--- arch/mips/include/asm/vdso/gettimeofday.h | 177 +++++++++ arch/mips/{ => include/asm}/vdso/vdso.h | 6 +- arch/mips/include/asm/vdso/vsyscall.h | 43 +++ arch/mips/kernel/vdso.c | 37 +- arch/mips/vdso/Makefile | 27 +- arch/mips/vdso/elf.S | 2 +- arch/mips/vdso/sigreturn.S | 2 +- arch/mips/vdso/vdso.lds.S | 4 + arch/mips/vdso/vgettimeofday.c | 58 +++ arch/x86/Kconfig | 3 + arch/x86/entry/vdso/Makefile | 9 + arch/x86/entry/vdso/vclock_gettime.c | 249 +++--------- arch/x86/entry/vdso/vdso.lds.S | 2 + arch/x86/entry/vdso/vdso32/vdso32.lds.S | 2 + arch/x86/entry/vdso/vdsox32.lds.S | 1 + arch/x86/entry/vsyscall/Makefile | 2 - arch/x86/entry/vsyscall/vsyscall_gtod.c | 83 ---- arch/x86/include/asm/pvclock.h | 2 +- arch/x86/include/asm/vdso/gettimeofday.h | 205 ++++++++++ arch/x86/include/asm/vdso/vsyscall.h | 44 +++ arch/x86/include/asm/vgtod.h | 75 +--- arch/x86/include/asm/vvar.h | 7 +- arch/x86/kernel/pvclock.c | 1 + include/asm-generic/vdso/vsyscall.h | 56 +++ include/linux/hrtimer.h | 15 +- include/linux/hrtimer_defs.h | 25 ++ include/linux/timekeeper_internal.h | 9 + include/vdso/datapage.h | 93 +++++ include/vdso/helpers.h | 56 +++ include/vdso/vsyscall.h | 11 + kernel/Makefile | 1 + kernel/vdso/Makefile | 2 + kernel/vdso/vsyscall.c | 131 +++++++ lib/Kconfig | 5 + lib/vdso/Kconfig | 36 ++ lib/vdso/Makefile | 22 ++ lib/vdso/gettimeofday.c | 231 ++++++++++++ tools/testing/selftests/vDSO/Makefile | 2 + tools/testing/selftests/vDSO/vdso_config.h | 90 +++++ tools/testing/selftests/vDSO/vdso_full_test.c | 244 ++++++++++++ 76 files changed, 3044 insertions(+), 1412 deletions(-) create mode 100644 arch/arm/include/asm/vdso/gettimeofday.h create mode 100644 arch/arm/include/asm/vdso/vsyscall.h create mode 100644 arch/arm/vdso/note.c create mode 100644 arch/arm64/include/asm/vdso/compat_barrier.h create mode 100644 arch/arm64/include/asm/vdso/compat_gettimeofday.h 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 create mode 100644 arch/arm64/kernel/vdso32/.gitignore create mode 100644 arch/arm64/kernel/vdso32/Makefile create mode 100644 arch/arm64/kernel/vdso32/note.c create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S create mode 100644 arch/arm64/kernel/vdso32/vdso.S create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c create mode 100644 arch/mips/include/asm/vdso/gettimeofday.h rename arch/mips/{ => include/asm}/vdso/vdso.h (89%) create mode 100644 arch/mips/include/asm/vdso/vsyscall.h create mode 100644 arch/mips/vdso/vgettimeofday.c delete mode 100644 arch/x86/entry/vsyscall/vsyscall_gtod.c create mode 100644 arch/x86/include/asm/vdso/gettimeofday.h create mode 100644 arch/x86/include/asm/vdso/vsyscall.h create mode 100644 include/asm-generic/vdso/vsyscall.h create mode 100644 include/linux/hrtimer_defs.h create mode 100644 include/vdso/datapage.h create mode 100644 include/vdso/helpers.h create mode 100644 include/vdso/vsyscall.h create mode 100644 kernel/vdso/Makefile create mode 100644 kernel/vdso/vsyscall.c create mode 100644 lib/vdso/Kconfig create mode 100644 lib/vdso/Makefile create mode 100644 lib/vdso/gettimeofday.c create mode 100644 tools/testing/selftests/vDSO/vdso_config.h create mode 100644 tools/testing/selftests/vDSO/vdso_full_test.c
In an effort to unify the common code for managing the vdso library in between all the architectures that support it, this patch tries to provide a common format for the vdso datapage.
As a result of this, this patch generalized the data structures in vgtod.h from x86 private includes to general includes (include/vdso).
Cc: Arnd Bergmann arnd@arndb.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- include/vdso/datapage.h | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 include/vdso/datapage.h
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h new file mode 100644 index 000000000000..770f40254b08 --- /dev/null +++ b/include/vdso/datapage.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_DATAPAGE_H +#define __VDSO_DATAPAGE_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +#include <linux/bits.h> +#include <linux/time.h> +#include <linux/types.h> + +#define VDSO_BASES (CLOCK_TAI + 1) +#define VDSO_HRES (BIT(CLOCK_REALTIME) | \ + BIT(CLOCK_MONOTONIC) | \ + BIT(CLOCK_BOOTTIME) | \ + BIT(CLOCK_TAI)) +#define VDSO_COARSE (BIT(CLOCK_REALTIME_COARSE) | \ + BIT(CLOCK_MONOTONIC_COARSE)) +#define VDSO_RAW (BIT(CLOCK_MONOTONIC_RAW)) + +#define CS_HRES_COARSE 0 +#define CS_RAW 1 +#define CS_BASES (CS_RAW + 1) + +/** + * struct vdso_timestamp - basetime per clock_id + * @sec: seconds + * @nsec: nanoseconds + * + * There is one vdso_timestamp object in vvar for each vDSO-accelerated + * clock_id. For high-resolution clocks, this encodes the time + * corresponding to vdso_data.cycle_last. For coarse clocks this encodes + * the actual time. + * + * To be noticed that for highres clocks nsec is left-shifted by + * vdso_data.cs[x].shift. + */ +struct vdso_timestamp { + u64 sec; + u64 nsec; +}; + +/** + * struct vdso_data - vdso datapage representation + * @seq: timebase sequence counter + * @clock_mode: clock mode + * @cycle_last: timebase at clocksource init + * @mask: clocksource mask + * @mult: clocksource multiplier + * @shift: clocksource shift + * @basetime[clock_id]: basetime per clock_id + * @tz_minuteswest: minutes west of Greenwich + * @tz_dsttime: type of DST correction + * @hrtimer_res: hrtimer resolution + * @__unused: unused + * + * vdso_data will be accessed by 64 bit and compat code at the same time + * so we should be careful before modifying this structure. + */ +struct vdso_data { + u32 seq; + + s32 clock_mode; + u64 cycle_last; + u64 mask; + u32 mult; + u32 shift; + + struct vdso_timestamp basetime[VDSO_BASES]; + + s32 tz_minuteswest; + s32 tz_dsttime; + u32 hrtimer_res; + u32 __unused; +}; + +/* + * We use the hidden visibility to prevent the compiler from generating a GOT + * relocation. Not only is going through a GOT useless (the entry couldn't and + * must not be overridden by another library), it does not even work: the linker + * cannot generate an absolute address to the data page. + * + * With the hidden visibility, the compiler simply generates a PC-relative + * relocation, and this is what we need. + */ +extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden"))); + +#endif /* !__ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* __VDSO_DATAPAGE_H */
On Fri, Jun 21, 2019 at 10:52:28AM +0100, Vincenzo Frascino wrote:
In an effort to unify the common code for managing the vdso library in between all the architectures that support it, this patch tries to provide a common format for the vdso datapage.
As a result of this, this patch generalized the data structures in vgtod.h from x86 private includes to general includes (include/vdso).
Cc: Arnd Bergmann arnd@arndb.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
Minor clean-up patch (on top of the tip timers/vdso branch):
------------8<------------------------------
From 2e09fa6fca341b3ec7ecaf0b67a313a167bb4ff2 Mon Sep 17 00:00:00 2001
From: Catalin Marinas catalin.marinas@arm.com Date: Mon, 24 Jun 2019 12:19:23 +0100 Subject: [PATCH] vdso: Remove superfluous #ifdef __KERNEL__ in vdso/datapage.h
With the move to UAPI headers, such #ifdefs are no longer necessary.
Fixes: 361f8aee9b09 ("vdso: Define standardized vdso_datapage") Signed-off-by: Catalin Marinas catalin.marinas@arm.com --- include/vdso/datapage.h | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/include/vdso/datapage.h b/include/vdso/datapage.h index e6eb36c3d54f..2e302c0f41f7 100644 --- a/include/vdso/datapage.h +++ b/include/vdso/datapage.h @@ -2,8 +2,6 @@ #ifndef __VDSO_DATAPAGE_H #define __VDSO_DATAPAGE_H
-#ifdef __KERNEL__ - #ifndef __ASSEMBLY__
#include <linux/bits.h> @@ -88,6 +86,4 @@ extern struct vdso_data _vdso_data[CS_BASES] __attribute__((visibility("hidden")
#endif /* !__ASSEMBLY__ */
-#endif /* __KERNEL__ */ - #endif /* __VDSO_DATAPAGE_H */
In the last few years we have seen an explosion in vdso implementations that mostly share similar code.
Try to unify the gettimeofday vdso implementation introducing lib/vdso. The code contained in this library can ideally be reused by all the architectures avoiding, where possible, code duplication.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- include/linux/hrtimer.h | 15 +-- include/linux/hrtimer_defs.h | 25 ++++ include/vdso/helpers.h | 56 +++++++++ lib/Kconfig | 5 + lib/vdso/Kconfig | 36 ++++++ lib/vdso/Makefile | 22 ++++ lib/vdso/gettimeofday.c | 227 +++++++++++++++++++++++++++++++++++ 7 files changed, 372 insertions(+), 14 deletions(-) create mode 100644 include/linux/hrtimer_defs.h create mode 100644 include/vdso/helpers.h create mode 100644 lib/vdso/Kconfig create mode 100644 lib/vdso/Makefile create mode 100644 lib/vdso/gettimeofday.c
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h index 2e8957eac4d4..c922ce02e2e6 100644 --- a/include/linux/hrtimer.h +++ b/include/linux/hrtimer.h @@ -12,6 +12,7 @@ #ifndef _LINUX_HRTIMER_H #define _LINUX_HRTIMER_H
+#include <linux/hrtimer_defs.h> #include <linux/rbtree.h> #include <linux/ktime.h> #include <linux/init.h> @@ -298,26 +299,12 @@ struct clock_event_device;
extern void hrtimer_interrupt(struct clock_event_device *dev);
-/* - * The resolution of the clocks. The resolution value is returned in - * the clock_getres() system call to give application programmers an - * idea of the (in)accuracy of timers. Timer values are rounded up to - * this resolution values. - */ -# define HIGH_RES_NSEC 1 -# define KTIME_HIGH_RES (HIGH_RES_NSEC) -# define MONOTONIC_RES_NSEC HIGH_RES_NSEC -# define KTIME_MONOTONIC_RES KTIME_HIGH_RES - extern void clock_was_set_delayed(void);
extern unsigned int hrtimer_resolution;
#else
-# define MONOTONIC_RES_NSEC LOW_RES_NSEC -# define KTIME_MONOTONIC_RES KTIME_LOW_RES - #define hrtimer_resolution (unsigned int)LOW_RES_NSEC
static inline void clock_was_set_delayed(void) { } diff --git a/include/linux/hrtimer_defs.h b/include/linux/hrtimer_defs.h new file mode 100644 index 000000000000..7179bfc04115 --- /dev/null +++ b/include/linux/hrtimer_defs.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_HRTIMER_DEFS_H +#define _LINUX_HRTIMER_DEFS_H + +#ifdef CONFIG_HIGH_RES_TIMERS + +/* + * The resolution of the clocks. The resolution value is returned in + * the clock_getres() system call to give application programmers an + * idea of the (in)accuracy of timers. Timer values are rounded up to + * this resolution values. + */ +# define HIGH_RES_NSEC 1 +# define KTIME_HIGH_RES (HIGH_RES_NSEC) +# define MONOTONIC_RES_NSEC HIGH_RES_NSEC +# define KTIME_MONOTONIC_RES KTIME_HIGH_RES + +#else + +# define MONOTONIC_RES_NSEC LOW_RES_NSEC +# define KTIME_MONOTONIC_RES KTIME_LOW_RES + +#endif + +#endif diff --git a/include/vdso/helpers.h b/include/vdso/helpers.h new file mode 100644 index 000000000000..01641dbb68ef --- /dev/null +++ b/include/vdso/helpers.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_HELPERS_H +#define __VDSO_HELPERS_H + +#ifndef __ASSEMBLY__ + +#include <vdso/datapage.h> + +static __always_inline u32 vdso_read_begin(const struct vdso_data *vd) +{ + u32 seq; + + while ((seq = READ_ONCE(vd->seq)) & 1) + cpu_relax(); + + smp_rmb(); + return seq; +} + +static __always_inline u32 vdso_read_retry(const struct vdso_data *vd, + u32 start) +{ + u32 seq; + + smp_rmb(); + seq = READ_ONCE(vd->seq); + return seq != start; +} + +static __always_inline void vdso_write_begin(struct vdso_data *vd) +{ + /* + * WRITE_ONCE it is required otherwise the compiler can validly tear + * updates to vd[x].seq and it is possible that the value seen by the + * reader it is inconsistent. + */ + WRITE_ONCE(vd[CS_HRES_COARSE].seq, vd[CS_HRES_COARSE].seq + 1); + WRITE_ONCE(vd[CS_RAW].seq, vd[CS_RAW].seq + 1); + smp_wmb(); +} + +static __always_inline void vdso_write_end(struct vdso_data *vd) +{ + smp_wmb(); + /* + * WRITE_ONCE it is required otherwise the compiler can validly tear + * updates to vd[x].seq and it is possible that the value seen by the + * reader it is inconsistent. + */ + WRITE_ONCE(vd[CS_HRES_COARSE].seq, vd[CS_HRES_COARSE].seq + 1); + WRITE_ONCE(vd[CS_RAW].seq, vd[CS_RAW].seq + 1); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __VDSO_HELPERS_H */ diff --git a/lib/Kconfig b/lib/Kconfig index 90623a0e1942..8c8eefc5e54c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -576,6 +576,11 @@ config OID_REGISTRY config UCS2_STRING tristate
+# +# generic vdso +# +source "lib/vdso/Kconfig" + source "lib/fonts/Kconfig"
config SG_SPLIT diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig new file mode 100644 index 000000000000..cc00364bd2c2 --- /dev/null +++ b/lib/vdso/Kconfig @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 + +config HAVE_GENERIC_VDSO + bool + +if HAVE_GENERIC_VDSO + +config GENERIC_GETTIMEOFDAY + bool + help + This is a generic implementation of gettimeofday vdso. + Each architecture that enables this feature has to + provide the fallback implementation. + +config GENERIC_VDSO_32 + bool + depends on GENERIC_GETTIMEOFDAY && !64BIT + help + This config option helps to avoid possible performance issues + in 32 bit only architectures. + +config GENERIC_COMPAT_VDSO + bool + help + This config option enables the compat VDSO layer. + +config CROSS_COMPILE_COMPAT_VDSO + string "32 bit Toolchain prefix for compat vDSO" + default "" + depends on GENERIC_COMPAT_VDSO + help + Defines the cross-compiler prefix for compiling compat vDSO. + If a 64 bit compiler (i.e. x86_64) can compile the VDSO for + 32 bit, it does not need to define this parameter. + +endif diff --git a/lib/vdso/Makefile b/lib/vdso/Makefile new file mode 100644 index 000000000000..c415a685d61b --- /dev/null +++ b/lib/vdso/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 + +GENERIC_VDSO_MK_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +GENERIC_VDSO_DIR := $(dir $(GENERIC_VDSO_MK_PATH)) + +c-gettimeofday-$(CONFIG_GENERIC_GETTIMEOFDAY) := $(addprefix $(GENERIC_VDSO_DIR), gettimeofday.c) + +# This cmd checks that the vdso library does not contain absolute relocation +# It has to be called after the linking of the vdso library and requires it +# as a parameter. +# +# $(ARCH_REL_TYPE_ABS) is defined in the arch specific makefile and corresponds +# to the absolute relocation types printed by "objdump -R" and accepted by the +# dynamic linker. +ifndef ARCH_REL_TYPE_ABS +$(error ARCH_REL_TYPE_ABS is not set) +endif + +quiet_cmd_vdso_check = VDSOCHK $@ + cmd_vdso_check = if $(OBJDUMP) -R $@ | egrep -h "$(ARCH_REL_TYPE_ABS)"; \ + then (echo >&2 "$@: dynamic relocations are not supported"; \ + rm -f $@; /bin/false); fi diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c new file mode 100644 index 000000000000..473e2dda0220 --- /dev/null +++ b/lib/vdso/gettimeofday.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Generic userspace implementations of gettimeofday() and similar. + */ +#include <linux/compiler.h> +#include <linux/math64.h> +#include <linux/time.h> +#include <linux/kernel.h> +#include <linux/ktime.h> +#include <linux/hrtimer_defs.h> +#include <vdso/datapage.h> +#include <vdso/helpers.h> + +/* + * The generic vDSO implementation requires that gettimeofday.h + * provides: + * - __arch_get_vdso_data(): to get the vdso datapage. + * - __arch_get_hw_counter(): to get the hw counter based on the + * clock_mode. + * - gettimeofday_fallback(): fallback for gettimeofday. + * - clock_gettime_fallback(): fallback for clock_gettime. + * - clock_getres_fallback(): fallback for clock_getres. + */ +#include <asm/vdso/gettimeofday.h> + +static int do_hres(const struct vdso_data *vd, + clockid_t clk, + struct __kernel_timespec *ts) +{ + const struct vdso_timestamp *vdso_ts = &vd->basetime[clk]; + u64 cycles, last, sec, ns; + u32 seq; + + do { + seq = vdso_read_begin(vd); + cycles = __arch_get_hw_counter(vd->clock_mode) & + vd->mask; + ns = vdso_ts->nsec; + last = vd->cycle_last; + if (unlikely((s64)cycles < 0)) + return clock_gettime_fallback(clk, ts); + if (cycles > last) + ns += (cycles - last) * vd->mult; + ns >>= vd->shift; + sec = vdso_ts->sec; + } while (unlikely(vdso_read_retry(vd, seq))); + + /* + * Do this outside the loop: a race inside the loop could result + * in __iter_div_u64_rem() being extremely slow. + */ + ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); + ts->tv_nsec = ns; + + return 0; +} + +static void do_coarse(const struct vdso_data *vd, + clockid_t clk, + struct __kernel_timespec *ts) +{ + const struct vdso_timestamp *vdso_ts = &vd->basetime[clk]; + u32 seq; + + do { + seq = vdso_read_begin(vd); + ts->tv_sec = vdso_ts->sec; + ts->tv_nsec = vdso_ts->nsec; + } while (unlikely(vdso_read_retry(vd, seq))); +} + +static __maybe_unused int +__cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + u32 msk; + + /* Check for negative values or invalid clocks */ + if (unlikely((u32) clock >= MAX_CLOCKS)) + goto fallback; + + /* + * Convert the clockid to a bitmask and use it to check which + * clocks are handled in the VDSO directly. + */ + msk = 1U << clock; + if (likely(msk & VDSO_HRES)) { + return do_hres(&vd[CS_HRES_COARSE], clock, ts); + } else if (msk & VDSO_COARSE) { + do_coarse(&vd[CS_HRES_COARSE], clock, ts); + return 0; + } else if (msk & VDSO_RAW) { + return do_hres(&vd[CS_RAW], clock, ts); + } + +fallback: + return clock_gettime_fallback(clock, ts); +} + +static __maybe_unused int +__cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) +{ + struct __kernel_timespec ts; + int ret; + + if (res == NULL) + goto fallback; + + ret = __cvdso_clock_gettime(clock, &ts); + + if (ret == 0) { + res->tv_sec = ts.tv_sec; + res->tv_nsec = ts.tv_nsec; + } + + return ret; + +fallback: + return clock_gettime_fallback(clock, (struct __kernel_timespec *)res); +} + +static __maybe_unused int +__cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + + if (likely(tv != NULL)) { + struct __kernel_timespec ts; + + if (do_hres(&vd[CS_HRES_COARSE], CLOCK_REALTIME, &ts)) + return gettimeofday_fallback(tv, tz); + + tv->tv_sec = ts.tv_sec; + tv->tv_usec = (u32)ts.tv_nsec / NSEC_PER_USEC; + } + + if (unlikely(tz != NULL)) { + tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest; + tz->tz_dsttime = vd[CS_HRES_COARSE].tz_dsttime; + } + + return 0; +} + +#ifdef VDSO_HAS_TIME +static __maybe_unused time_t __cvdso_time(time_t *time) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + time_t t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec); + + if (time) + *time = t; + + return t; +} +#endif /* VDSO_HAS_TIME */ + +#ifdef VDSO_HAS_CLOCK_GETRES +static __maybe_unused +int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + u64 ns; + u32 msk; + u64 hrtimer_res = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res); + + /* Check for negative values or invalid clocks */ + if (unlikely((u32) clock >= MAX_CLOCKS)) + goto fallback; + + /* + * Convert the clockid to a bitmask and use it to check which + * clocks are handled in the VDSO directly. + */ + msk = 1U << clock; + if (msk & VDSO_HRES) { + /* + * Preserves the behaviour of posix_get_hrtimer_res(). + */ + ns = hrtimer_res; + } else if (msk & VDSO_COARSE) { + /* + * Preserves the behaviour of posix_get_coarse_res(). + */ + ns = LOW_RES_NSEC; + } else if (msk & VDSO_RAW) { + /* + * Preserves the behaviour of posix_get_hrtimer_res(). + */ + ns = hrtimer_res; + } else { + goto fallback; + } + + if (res) { + res->tv_sec = 0; + res->tv_nsec = ns; + } + + return 0; + +fallback: + return clock_getres_fallback(clock, res); +} + +static __maybe_unused int +__cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) +{ + struct __kernel_timespec ts; + int ret; + + if (res == NULL) + goto fallback; + + ret = __cvdso_clock_getres(clock, &ts); + + if (ret == 0) { + res->tv_sec = ts.tv_sec; + res->tv_nsec = ts.tv_nsec; + } + + return ret; + +fallback: + return clock_getres_fallback(clock, (struct __kernel_timespec *)res); +} +#endif /* VDSO_HAS_CLOCK_GETRES */
With the definition of the unified vDSO library the implementations of update_vsyscall and update_vsyscall_tz became quite similar across architectures.
Define a unified implementation of these two functions in kernel/vdso and provide the bindings that can be implemented by every architecture that takes advantage of the unified vDSO library.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- include/asm-generic/vdso/vsyscall.h | 56 ++++++++++++ include/linux/timekeeper_internal.h | 9 ++ include/vdso/vsyscall.h | 11 +++ kernel/Makefile | 1 + kernel/vdso/Makefile | 2 + kernel/vdso/vsyscall.c | 131 ++++++++++++++++++++++++++++ 6 files changed, 210 insertions(+) create mode 100644 include/asm-generic/vdso/vsyscall.h create mode 100644 include/vdso/vsyscall.h create mode 100644 kernel/vdso/Makefile create mode 100644 kernel/vdso/vsyscall.c
diff --git a/include/asm-generic/vdso/vsyscall.h b/include/asm-generic/vdso/vsyscall.h new file mode 100644 index 000000000000..9a4b9fbcc9b6 --- /dev/null +++ b/include/asm-generic/vdso/vsyscall.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_GENERIC_VSYSCALL_H +#define __ASM_GENERIC_VSYSCALL_H + +#ifndef __ASSEMBLY__ + +#ifndef __arch_get_k_vdso_data +static __always_inline +struct vdso_data *__arch_get_k_vdso_data(void) +{ + return NULL; +} +#endif /* __arch_get_k_vdso_data */ + +#ifndef __arch_update_vdso_data +static __always_inline +int __arch_update_vdso_data(void) +{ + return 0; +} +#endif /* __arch_update_vdso_data */ + +#ifndef __arch_get_clock_mode +static __always_inline +int __arch_get_clock_mode(struct timekeeper *tk) +{ + return 0; +} +#endif /* __arch_get_clock_mode */ + +#ifndef __arch_use_vsyscall +static __always_inline +int __arch_use_vsyscall(struct vdso_data *vdata) +{ + return 1; +} +#endif /* __arch_use_vsyscall */ + +#ifndef __arch_update_vsyscall +static __always_inline +void __arch_update_vsyscall(struct vdso_data *vdata, + struct timekeeper *tk) +{ +} +#endif /* __arch_update_vsyscall */ + +#ifndef __arch_sync_vdso_data +static __always_inline +void __arch_sync_vdso_data(struct vdso_data *vdata) +{ +} +#endif /* __arch_sync_vdso_data */ + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_GENERIC_VSYSCALL_H */ diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h index 7acb953298a7..8177e75a71eb 100644 --- a/include/linux/timekeeper_internal.h +++ b/include/linux/timekeeper_internal.h @@ -135,9 +135,18 @@ struct timekeeper {
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
+#ifdef CONFIG_HAVE_GENERIC_VDSO + +void update_vsyscall(struct timekeeper *tk); +void update_vsyscall_tz(void); + +#else + extern void update_vsyscall(struct timekeeper *tk); extern void update_vsyscall_tz(void);
+#endif /* CONFIG_HAVE_GENERIC_VDSO */ + #else
static inline void update_vsyscall(struct timekeeper *tk) diff --git a/include/vdso/vsyscall.h b/include/vdso/vsyscall.h new file mode 100644 index 000000000000..2c6134e0c23d --- /dev/null +++ b/include/vdso/vsyscall.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __VDSO_VSYSCALL_H +#define __VDSO_VSYSCALL_H + +#ifndef __ASSEMBLY__ + +#include <asm/vdso/vsyscall.h> + +#endif /* !__ASSEMBLY__ */ + +#endif /* __VDSO_VSYSCALL_H */ diff --git a/kernel/Makefile b/kernel/Makefile index 33824f0385b3..56a98ebb7772 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o obj-$(CONFIG_FREEZER) += freezer.o obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_HAVE_GENERIC_VDSO) += vdso/ obj-y += time/ obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o diff --git a/kernel/vdso/Makefile b/kernel/vdso/Makefile new file mode 100644 index 000000000000..ad0d3b1a475c --- /dev/null +++ b/kernel/vdso/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_HAVE_GENERIC_VDSO) += vsyscall.o diff --git a/kernel/vdso/vsyscall.c b/kernel/vdso/vsyscall.c new file mode 100644 index 000000000000..d1e8074e3d10 --- /dev/null +++ b/kernel/vdso/vsyscall.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 ARM Ltd. + * + * Generic implementation of update_vsyscall and update_vsyscall_tz. + */ + +#include <linux/hrtimer.h> +#include <linux/timekeeper_internal.h> +#include <vdso/datapage.h> +#include <vdso/helpers.h> +#include <vdso/vsyscall.h> + +static inline void update_vdso_data(struct vdso_data *vdata, + struct timekeeper *tk) +{ + struct vdso_timestamp *vdso_ts; + u64 nsec; + + vdata[CS_HRES_COARSE].cycle_last = tk->tkr_mono.cycle_last; + vdata[CS_HRES_COARSE].mask = tk->tkr_mono.mask; + vdata[CS_HRES_COARSE].mult = tk->tkr_mono.mult; + vdata[CS_HRES_COARSE].shift = tk->tkr_mono.shift; + vdata[CS_RAW].cycle_last = tk->tkr_raw.cycle_last; + vdata[CS_RAW].mask = tk->tkr_raw.mask; + vdata[CS_RAW].mult = tk->tkr_raw.mult; + vdata[CS_RAW].shift = tk->tkr_raw.shift; + + /* CLOCK_REALTIME */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME]; + vdso_ts->sec = tk->xtime_sec; + vdso_ts->nsec = tk->tkr_mono.xtime_nsec; + + /* CLOCK_MONOTONIC */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC]; + vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; + + nsec = tk->tkr_mono.xtime_nsec; + nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift); + while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { + nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift); + vdso_ts->sec++; + } + vdso_ts->nsec = nsec; + + /* CLOCK_MONOTONIC_RAW */ + vdso_ts = &vdata[CS_RAW].basetime[CLOCK_MONOTONIC_RAW]; + vdso_ts->sec = tk->raw_sec; + vdso_ts->nsec = tk->tkr_raw.xtime_nsec; + + /* CLOCK_BOOTTIME */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_BOOTTIME]; + vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; + nsec = tk->tkr_mono.xtime_nsec; + nsec += ((u64)(tk->wall_to_monotonic.tv_nsec + + ktime_to_ns(tk->offs_boot)) << tk->tkr_mono.shift); + while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { + nsec -= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift); + vdso_ts->sec++; + } + vdso_ts->nsec = nsec; + + /* CLOCK_TAI */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_TAI]; + vdso_ts->sec = tk->xtime_sec + (s64)tk->tai_offset; + vdso_ts->nsec = tk->tkr_mono.xtime_nsec; + + /* + * Read without the seqlock held by clock_getres(). + * Note: No need to have a second copy. + */ + WRITE_ONCE(vdata[CS_HRES_COARSE].hrtimer_res, hrtimer_resolution); +} + +void update_vsyscall(struct timekeeper *tk) +{ + struct vdso_data *vdata = __arch_get_k_vdso_data(); + struct vdso_timestamp *vdso_ts; + u64 nsec; + + if (__arch_update_vdso_data()) { + /* + * Some architectures might want to skip the update of the + * data page. + */ + return; + } + + /* copy vsyscall data */ + vdso_write_begin(vdata); + + vdata[CS_HRES_COARSE].clock_mode = __arch_get_clock_mode(tk); + vdata[CS_RAW].clock_mode = __arch_get_clock_mode(tk); + + /* CLOCK_REALTIME_COARSE */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME_COARSE]; + vdso_ts->sec = tk->xtime_sec; + vdso_ts->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift; + + /* CLOCK_MONOTONIC_COARSE */ + vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_MONOTONIC_COARSE]; + vdso_ts->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; + nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift; + nsec = nsec + tk->wall_to_monotonic.tv_nsec; + while (nsec >= NSEC_PER_SEC) { + nsec = nsec - NSEC_PER_SEC; + vdso_ts->sec++; + } + vdso_ts->nsec = nsec; + + if (__arch_use_vsyscall(vdata)) + update_vdso_data(vdata, tk); + + __arch_update_vsyscall(vdata, tk); + + vdso_write_end(vdata); + + __arch_sync_vdso_data(vdata); +} + +void update_vsyscall_tz(void) +{ + struct vdso_data *vdata = __arch_get_k_vdso_data(); + + if (__arch_use_vsyscall(vdata)) { + vdata[CS_HRES_COARSE].tz_minuteswest = sys_tz.tz_minuteswest; + vdata[CS_HRES_COARSE].tz_dsttime = sys_tz.tz_dsttime; + } + + __arch_sync_vdso_data(vdata); +}
On Fri, Jun 21, 2019 at 10:52:30AM +0100, Vincenzo Frascino wrote:
diff --git a/kernel/vdso/vsyscall.c b/kernel/vdso/vsyscall.c new file mode 100644 index 000000000000..d1e8074e3d10 --- /dev/null +++ b/kernel/vdso/vsyscall.c +static inline void update_vdso_data(struct vdso_data *vdata,
struct timekeeper *tk)
+{
- struct vdso_timestamp *vdso_ts;
- u64 nsec;
- vdata[CS_HRES_COARSE].cycle_last = tk->tkr_mono.cycle_last;
- vdata[CS_HRES_COARSE].mask = tk->tkr_mono.mask;
- vdata[CS_HRES_COARSE].mult = tk->tkr_mono.mult;
- vdata[CS_HRES_COARSE].shift = tk->tkr_mono.shift;
- vdata[CS_RAW].cycle_last = tk->tkr_raw.cycle_last;
- vdata[CS_RAW].mask = tk->tkr_raw.mask;
- vdata[CS_RAW].mult = tk->tkr_raw.mult;
- vdata[CS_RAW].shift = tk->tkr_raw.shift;
- /* CLOCK_REALTIME */
- vdso_ts = &vdata[CS_HRES_COARSE].basetime[CLOCK_REALTIME];
There's an extraneous space after the '='. Hopefully Thomas can fix this up if this patchset is otherwise ok.
- vdso_ts->sec = tk->xtime_sec;
- vdso_ts->nsec = tk->tkr_mono.xtime_nsec;
Huw.
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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- 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@arm.com - */ - -#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); +} +
Hi Vincenzo,
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
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 ++
I'm concerned about an apparent semantic change introduced by your patch:
+static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) +{
- u64 res;
- asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory");
- return res;
+}
vs:
- .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
It looks like you're dropping both the preceding ISB (allowing the counter value to be speculated) and also the subsequent dependency (allowing the seq lock to be speculated). If I've missed them, apologies, but I couldn't spot them elsewhere in this patch.
__arch_get_hw_counter should probably be identical to __arch_counter_get_cntvct to avoid these problems. I guess we don't need to care about the case where the counter is unstable, since we'll just disable the vDSO altogether on such systems?
Will
On 24/06/2019 14:36, Will Deacon wrote:
Hi Vincenzo,
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
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 ++
I'm concerned about an apparent semantic change introduced by your patch:
+static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) +{
- u64 res;
- asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory");
- return res;
+}
vs:
- .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
It looks like you're dropping both the preceding ISB (allowing the counter value to be speculated) and also the subsequent dependency (allowing the seq lock to be speculated). If I've missed them, apologies, but I couldn't spot them elsewhere in this patch.
__arch_get_hw_counter should probably be identical to __arch_counter_get_cntvct to avoid these problems. I guess we don't need to care about the case where the counter is unstable, since we'll just disable the vDSO altogether on such systems?
Oops, I forgot to mirror your patch that introduces this change. I will post a fix in reply to this email.
Will
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- lib/vdso/gettimeofday.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index ef28cc5d7bff..ee1221ba1d32 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -35,12 +35,12 @@ static int do_hres(const struct vdso_data *vd, clockid_t clk,
do { seq = vdso_read_begin(vd); - cycles = __arch_get_hw_counter(vd->clock_mode) & - vd->mask; + cycles = __arch_get_hw_counter(vd->clock_mode); ns = vdso_ts->nsec; last = vd->cycle_last; if (unlikely((s64)cycles < 0)) return clock_gettime_fallback(clk, ts); + cycles &= vd->mask; if (cycles > last) ns += (cycles - last) * vd->mult; ns >>= vd->shift;
Provide the following fixes for the __arch_get_hw_counter() implementation on arm64: - Fallback on syscall when an unstable counter is detected. - Introduce isb()s before and after the counter read to avoid speculation of the counter value and of the seq lock respectively. The second isb() is a temporary solution that will be revisited in 5.3-rc1.
These fixes restore the semantics that __arch_counter_get_cntvct() had on arm64.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm64/include/asm/vdso/gettimeofday.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/arch/arm64/include/asm/vdso/gettimeofday.h b/arch/arm64/include/asm/vdso/gettimeofday.h index 447ef417de45..b08f476b72b4 100644 --- a/arch/arm64/include/asm/vdso/gettimeofday.h +++ b/arch/arm64/include/asm/vdso/gettimeofday.h @@ -10,6 +10,8 @@ #include <asm/unistd.h> #include <uapi/linux/time.h>
+#define __VDSO_USE_SYSCALL ULLONG_MAX + #define VDSO_HAS_CLOCK_GETRES 1
static __always_inline @@ -68,7 +70,24 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) { u64 res;
+ /* + * clock_mode == 0 implies that vDSO are enabled otherwise + * fallback on syscall. + */ + if (clock_mode) + return __VDSO_USE_SYSCALL; + + /* + * This isb() is required to prevent that the counter value + * is speculated. + */ + isb(); asm volatile("mrs %0, cntvct_el0" : "=r" (res) :: "memory"); + /* + * This isb() is required to prevent that the seq lock is + * speculated.# + */ + isb();
return res; }
Provide the following fixes for the __arch_get_hw_counter() implementation on arm64: - Fallback on syscall when an unstable counter is detected. - Introduce isb()s before and after the counter read to avoid speculation of the counter value and of the seq lock respectively. The second isb() is a temporary solution that will be revisited in 5.3-rc1.
These fixes restore the semantics that __arch_counter_get_cntvct() had on arm64.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- .../include/asm/vdso/compat_gettimeofday.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h index 93dbd935b66d..f4812777f5c5 100644 --- a/arch/arm64/include/asm/vdso/compat_gettimeofday.h +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -12,6 +12,8 @@
#include <asm/vdso/compat_barrier.h>
+#define __VDSO_USE_SYSCALL ULLONG_MAX + #define VDSO_HAS_CLOCK_GETRES 1
static __always_inline @@ -74,8 +76,24 @@ static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) { u64 res;
+ /* + * clock_mode == 0 implies that vDSO are enabled otherwise + * fallback on syscall. + */ + if (clock_mode) + return __VDSO_USE_SYSCALL; + + /* + * This isb() is required to prevent that the counter value + * is speculated. + */ isb(); asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res)); + /* + * This isb() is required to prevent that the seq lock is + * speculated. + */ + isb();
return res; }
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
CC+ Andy
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
As we talked about that already yesterday, I tested this on a couple of machines and as expected the outcome is uarch dependent. Minimal deviations to both sides and some machines do not show any change at all. I doubt it's possible to come up with a solution which makes all uarchs go faster magically.
Though, thinking about it, we could remove the mask operation completely on X86. /me runs tests
Thanks,
tglx
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
lib/vdso/gettimeofday.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index ef28cc5d7bff..ee1221ba1d32 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -35,12 +35,12 @@ static int do_hres(const struct vdso_data *vd, clockid_t clk, do { seq = vdso_read_begin(vd);
cycles = __arch_get_hw_counter(vd->clock_mode) &
vd->mask;
ns = vdso_ts->nsec; last = vd->cycle_last; if (unlikely((s64)cycles < 0)) return clock_gettime_fallback(clk, ts);cycles = __arch_get_hw_counter(vd->clock_mode);
if (cycles > last) ns += (cycles - last) * vd->mult; ns >>= vd->shift;cycles &= vd->mask;
-- 2.22.0
On Tue, 25 Jun 2019, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
CC+ Andy
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
As we talked about that already yesterday, I tested this on a couple of machines and as expected the outcome is uarch dependent. Minimal deviations to both sides and some machines do not show any change at all. I doubt it's possible to come up with a solution which makes all uarchs go faster magically.
Though, thinking about it, we could remove the mask operation completely on X86. /me runs tests
Unsurprisingly the results vary. Two uarchs do not care, but they did not care about moving the mask either. The other two gain performance and the last one falls back to the state before moving the mask. So in general it looks like a worthwhile optimization.
Thanks,
tglx
On Tue, Jun 25, 2019 at 11:27 AM Thomas Gleixner tglx@linutronix.de wrote:
On Tue, 25 Jun 2019, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
CC+ Andy
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
As we talked about that already yesterday, I tested this on a couple of machines and as expected the outcome is uarch dependent. Minimal deviations to both sides and some machines do not show any change at all. I doubt it's possible to come up with a solution which makes all uarchs go faster magically.
Though, thinking about it, we could remove the mask operation completely on X86. /me runs tests
Unsurprisingly the results vary. Two uarchs do not care, but they did not care about moving the mask either. The other two gain performance and the last one falls back to the state before moving the mask. So in general it looks like a worthwhile optimization.
At one point, I contemplated a different approach: have the "get the counter" routine return 0 and then do if (unlikely(cycles <= last)) goto fallback. This will remove one branch from the hot path. I got dubious results when I tried benchmarking it, probably because the branch in question was always correctly predicted.
On Tue, 25 Jun 2019, Andy Lutomirski wrote:
On Tue, Jun 25, 2019 at 11:27 AM Thomas Gleixner tglx@linutronix.de wrote:
On Tue, 25 Jun 2019, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
CC+ Andy
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
As we talked about that already yesterday, I tested this on a couple of machines and as expected the outcome is uarch dependent. Minimal deviations to both sides and some machines do not show any change at all. I doubt it's possible to come up with a solution which makes all uarchs go faster magically.
Though, thinking about it, we could remove the mask operation completely on X86. /me runs tests
Unsurprisingly the results vary. Two uarchs do not care, but they did not care about moving the mask either. The other two gain performance and the last one falls back to the state before moving the mask. So in general it looks like a worthwhile optimization.
At one point, I contemplated a different approach: have the "get the counter" routine return 0 and then do if (unlikely(cycles <= last)) goto fallback. This will remove one branch from the hot path. I got dubious results when I tried benchmarking it, probably because the branch in question was always correctly predicted.
Just tried and it's the same thing. One drops, one does not care and one gains. Did not test the other two as they are asleep already. There is no universal cure for this I fear. I even tried a uarch optimized build a few days ago which came out worse than the generic one...
The issue in that code path is the fencing of the TSC read. That seems to screw up every uarch in a different way.
If you have no objections I'll queue this change (moving the mask) along with the other two ARM64 ones to unbreak the fallback path for these errata inflicted machines.
Thanks,
tglx
On Tue, 25 Jun 2019, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
But it's actually worse than that:
if (cycles > last) ns += (cycles - last) * vd->mult; ns >>= vd->shift;cycles &= vd->mask;
This is broken for any clocksource which can legitimately wrap around. The core timekeeping does the right thing:
(cycles - last) & mask
That makes sure that a wraparound is correctly handled. With the above the wrap around would be ignored due to
if (cycles > last)
Stupid me. I should have added big fat comments to the x86 vdso why this all works correctly and only correctly for the x86 crud. That was part of squeezing the last cycles out of the vdso.
Sorry for not noticing earlier. Working on a fix.
Thanks,
tglx
Hi Thomas,
On 26/06/2019 07:38, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Thomas Gleixner wrote:
On Tue, 25 Jun 2019, Vincenzo Frascino wrote:
do_hres() in the vDSO generic library masks the hw counter value immediately after reading it.
Postpone the mask application after checking if the syscall fallback is enabled, in order to be able to detect a possible fallback for the architectures that have masks smaller than ULLONG_MAX.
Right. This only worked on x86 because the mask is there ULLONG_MAX for all VDSO capable clocksources, i.e. that ever worked just by chance.
But it's actually worse than that:
if (cycles > last) ns += (cycles - last) * vd->mult; ns >>= vd->shift;cycles &= vd->mask;
This is broken for any clocksource which can legitimately wrap around. The core timekeeping does the right thing:
(cycles - last) & mask
That makes sure that a wraparound is correctly handled. With the above the wrap around would be ignored due to
if (cycles > last)
You are right. Thanks for spotting it.
...
The x86 vdso implementation on which the generic vdso library is based on has subtle (unfortunately undocumented) twists:
1) The code assumes that the clocksource mask is U64_MAX which means that no bits are masked. Which is true for any valid x86 VDSO clocksource. Stupidly it still did the mask operation for no reason and at the wrong place right after reading the clocksource.
2) It contains a sanity check to catch the case where slightly unsynchronized TSC values can be overserved which would cause the delta calculation to make a huge jump. It therefore checks whether the current TSC value is larger than the value on which the current conversion is based on. If it's not larger the base value is used to prevent time jumps.
#1 Is not only stupid for the X86 case because it does the masking for no reason it is also completely wrong for clocksources with a smaller mask which can legitimately wrap around during a conversion period. The core timekeeping code does it correct by applying the mask after the delta calculation:
(now - base) & mask
#2 is equally broken for clocksources which have smaller masks and can wrap around during a conversion period because there the now > base check is just wrong and causes stale time stamps and time going backwards issues.
Unbreak it by:
1) Removing the mask operation from the clocksource read which makes the fallback detection work for all clocksources
2) Replacing the conditional delta calculation with a overrideable inline function.
#2 could reuse clocksource_delta() from the timekeeping code but that results in a significant performance hit for the x86 VSDO. The timekeeping core code must have the non optimized version as it has to operate correctly with clocksources which have smaller masks as well to handle the case where TSC is discarded as timekeeper clocksource and replaced by HPET or pmtimer. For the VDSO there is no replacement clocksource. If TSC is unusable the syscall is enforced which does the right thing.
To accomodate to the needs of various architectures provide an overrideable inline function which defaults to the regular delta calculation with masking:
(now - base) & mask
Override it for x86 with the non-masking and checking version.
This unbreaks the ARM64 syscall fallback operation, allows to use clocksources with arbitrary width and preserves the performance optimization for x86.
Signed-off-by: Thomas Gleixner tglx@linutronix.de --- arch/x86/include/asm/vdso/gettimeofday.h | 27 +++++++++++++++++++++++++++ lib/vdso/gettimeofday.c | 19 +++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-)
--- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -229,6 +229,33 @@ static __always_inline const struct vdso return __vdso_data; }
+/* + * x86 specific delta calculation. + * + * The regular implementation assumes that clocksource reads are globally + * monotonic. The TSC can be slightly off across sockets which can cause + * the regular delta calculation (@cycles - @last) to return a huge time + * jump. + * + * Therefore it needs to be verified that @cycles are greater than + * @last. If not then use @last, which is the base time of the current + * conversion period. + * + * This variant also removes the masking of the subtraction because the + * clocksource mask of all VDSO capable clocksources on x86 is U64_MAX + * which would result in a pointless operation. The compiler cannot + * optimize it away as the mask comes from the vdso data and is not compile + * time constant. + */ +static __always_inline +u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) +{ + if (cycles > last) + return (cycles - last) * mult; + return 0; +} +#define vdso_calc_delta vdso_calc_delta + #endif /* !__ASSEMBLY__ */
#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -26,6 +26,18 @@ #include <asm/vdso/gettimeofday.h> #endif /* ENABLE_COMPAT_VDSO */
+#ifndef vdso_calc_delta +/* + * Default implementation which works for all sane clocksources. That + * obviously excludes x86/TSC. + */ +static __always_inline +u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) +{ + return ((cyles - last) & mask) * mult; +} +#endif + static int do_hres(const struct vdso_data *vd, clockid_t clk, struct __kernel_timespec *ts) { @@ -35,14 +47,13 @@ static int do_hres(const struct vdso_dat
do { seq = vdso_read_begin(vd); - cycles = __arch_get_hw_counter(vd->clock_mode) & - vd->mask; + cycles = __arch_get_hw_counter(vd->clock_mode); ns = vdso_ts->nsec; last = vd->cycle_last; if (unlikely((s64)cycles < 0)) return clock_gettime_fallback(clk, ts); - if (cycles > last) - ns += (cycles - last) * vd->mult; + + ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult); ns >>= vd->shift; sec = vdso_ts->sec; } while (unlikely(vdso_read_retry(vd, seq)));
Hi Thomas,
On 26/06/2019 11:02, Thomas Gleixner wrote:
The x86 vdso implementation on which the generic vdso library is based on has subtle (unfortunately undocumented) twists:
The code assumes that the clocksource mask is U64_MAX which means that no bits are masked. Which is true for any valid x86 VDSO clocksource. Stupidly it still did the mask operation for no reason and at the wrong place right after reading the clocksource.
It contains a sanity check to catch the case where slightly unsynchronized TSC values can be overserved which would cause the delta calculation to make a huge jump. It therefore checks whether the current TSC value is larger than the value on which the current conversion is based on. If it's not larger the base value is used to prevent time jumps.
#1 Is not only stupid for the X86 case because it does the masking for no reason it is also completely wrong for clocksources with a smaller mask which can legitimately wrap around during a conversion period. The core timekeeping code does it correct by applying the mask after the delta calculation:
(now - base) & mask
#2 is equally broken for clocksources which have smaller masks and can wrap around during a conversion period because there the now > base check is just wrong and causes stale time stamps and time going backwards issues.
Unbreak it by:
Removing the mask operation from the clocksource read which makes the fallback detection work for all clocksources
Replacing the conditional delta calculation with a overrideable inline function.
#2 could reuse clocksource_delta() from the timekeeping code but that results in a significant performance hit for the x86 VSDO. The timekeeping core code must have the non optimized version as it has to operate correctly with clocksources which have smaller masks as well to handle the case where TSC is discarded as timekeeper clocksource and replaced by HPET or pmtimer. For the VDSO there is no replacement clocksource. If TSC is unusable the syscall is enforced which does the right thing.
To accomodate to the needs of various architectures provide an overrideable inline function which defaults to the regular delta calculation with masking:
(now - base) & mask
Override it for x86 with the non-masking and checking version.
This unbreaks the ARM64 syscall fallback operation, allows to use clocksources with arbitrary width and preserves the performance optimization for x86.
Signed-off-by: Thomas Gleixner tglx@linutronix.de
A part a typo that leads to compilation errors on non-x86 platforms the rest looks fine by me.
I tested it on arm64 and behaves correctly.
With this:
Reviewed-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/x86/include/asm/vdso/gettimeofday.h | 27 +++++++++++++++++++++++++++ lib/vdso/gettimeofday.c | 19 +++++++++++++++---- 2 files changed, 42 insertions(+), 4 deletions(-)
--- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -229,6 +229,33 @@ static __always_inline const struct vdso return __vdso_data; } +/*
- x86 specific delta calculation.
- The regular implementation assumes that clocksource reads are globally
- monotonic. The TSC can be slightly off across sockets which can cause
- the regular delta calculation (@cycles - @last) to return a huge time
- jump.
- Therefore it needs to be verified that @cycles are greater than
- @last. If not then use @last, which is the base time of the current
- conversion period.
- This variant also removes the masking of the subtraction because the
- clocksource mask of all VDSO capable clocksources on x86 is U64_MAX
- which would result in a pointless operation. The compiler cannot
- optimize it away as the mask comes from the vdso data and is not compile
- time constant.
- */
+static __always_inline +u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) +{
- if (cycles > last)
return (cycles - last) * mult;
- return 0;
+} +#define vdso_calc_delta vdso_calc_delta
#endif /* !__ASSEMBLY__ */ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -26,6 +26,18 @@ #include <asm/vdso/gettimeofday.h> #endif /* ENABLE_COMPAT_VDSO */ +#ifndef vdso_calc_delta +/*
- Default implementation which works for all sane clocksources. That
- obviously excludes x86/TSC.
- */
+static __always_inline +u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) +{
- return ((cyles - last) & mask) * mult;
Typo here:
s/cyles/cycles/
+} +#endif
static int do_hres(const struct vdso_data *vd, clockid_t clk, struct __kernel_timespec *ts) { @@ -35,14 +47,13 @@ static int do_hres(const struct vdso_dat do { seq = vdso_read_begin(vd);
cycles = __arch_get_hw_counter(vd->clock_mode) &
vd->mask;
ns = vdso_ts->nsec; last = vd->cycle_last; if (unlikely((s64)cycles < 0)) return clock_gettime_fallback(clk, ts);cycles = __arch_get_hw_counter(vd->clock_mode);
if (cycles > last)
ns += (cycles - last) * vd->mult;
ns >>= vd->shift; sec = vdso_ts->sec; } while (unlikely(vdso_read_retry(vd, seq)));ns += vdso_calc_delta(cycles, last, vd->mask, vd->mult);
On Fri, Jun 21, 2019 at 10:52:31AM +0100, Vincenzo Frascino wrote:
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));
Now that we are moving this to C, do we actually need the asm-offsets? If not, here's a clean-up patch:
---------------8<--------------------------------------
From 7e818178a8b225b522fe547cf00ba8508d4cdcf0 Mon Sep 17 00:00:00 2001
From: Catalin Marinas catalin.marinas@arm.com Date: Mon, 24 Jun 2019 14:12:48 +0100 Subject: [PATCH] arm64: vdso: Remove unnecessary asm-offsets.c definitions
Since the VDSO code is moving to C from assembly, there is no need to define and maintain the corresponding asm offsets.
Fixes: 28b1a824a4f4 ("arm64: vdso: Substitute gettimeofday() with C implementation") Signed-off-by: Catalin Marinas catalin.marinas@arm.com --- arch/arm64/kernel/asm-offsets.c | 39 --------------------------------- 1 file changed, 39 deletions(-)
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index e6f7409a78a4..214685760e1c 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -14,7 +14,6 @@ #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> @@ -86,44 +85,6 @@ int main(void) BLANK(); DEFINE(PREEMPT_DISABLE_OFFSET, PREEMPT_DISABLE_OFFSET); BLANK(); - DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); - DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); - DEFINE(CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_RAW); - DEFINE(CLOCK_REALTIME_RES, offsetof(struct vdso_data, hrtimer_res)); - DEFINE(CLOCK_REALTIME_COARSE, CLOCK_REALTIME_COARSE); - DEFINE(CLOCK_MONOTONIC_COARSE,CLOCK_MONOTONIC_COARSE); - DEFINE(CLOCK_COARSE_RES, LOW_RES_NSEC); - DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - BLANK(); - 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_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)); - BLANK(); - DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); - DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); - BLANK(); DEFINE(CPU_BOOT_STACK, offsetof(struct secondary_data, stack)); DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); BLANK();
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
[...]
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)
Out of interest, does this need to be __always_inline?
+{
- 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"
Can inlining of this function result in non-trivial expressions being substituted for _tz or _tv?
A function call can clobber register asm vars that are assigned to the caller-save registers or that the PCS uses for function arguments, and the situations where this can happen are poorly defined AFAICT. There's also no reliable way to detect at build time whether the compiler has done this, and no robust way to stop if happening.
(IMHO the compiler is wrong to do this, but it's been that way for ever, and I think I saw GCC 9 show this behaviour recently when I was investigating something related.)
To be safe, it's better to put this out of line, or remove the reg asm() specifiers, mark x0-x18 and lr as clobbered here (so that the compiler doesn't map arguments to them), and put movs in the asm to move things into the right registers. The syscall number can be passed with an "i" constraint. (And yes, this sucks.)
If the code this is inlined in is simple enough though, we can be fairly confident of getting away with it.
[...]
Cheers ---Dave
Hi Dave,
On 25/06/2019 16:33, Dave Martin wrote:
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
[...]
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)
Out of interest, does this need to be __always_inline?
It is a design choice. Philosophically, I prefer to control and reduce the scope of the decisions the compiler has to make in order to not have surprises.
+{
- 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"
Can inlining of this function result in non-trivial expressions being substituted for _tz or _tv?
A function call can clobber register asm vars that are assigned to the caller-save registers or that the PCS uses for function arguments, and the situations where this can happen are poorly defined AFAICT. There's also no reliable way to detect at build time whether the compiler has done this, and no robust way to stop if happening.
(IMHO the compiler is wrong to do this, but it's been that way for ever, and I think I saw GCC 9 show this behaviour recently when I was investigating something related.)
To be safe, it's better to put this out of line, or remove the reg asm() specifiers, mark x0-x18 and lr as clobbered here (so that the compiler doesn't map arguments to them), and put movs in the asm to move things into the right registers. The syscall number can be passed with an "i" constraint. (And yes, this sucks.)
If the code this is inlined in is simple enough though, we can be fairly confident of getting away with it.
I took very seriously what you are mentioning here because I think that robustness of the code comes before than everything especially in the kernel and I carried on some experiments to try to verify if in this case is safe to assume that the compiler is doing the right thing.
Based on my investigation and on previous observations of the generation of the vDSO library, I can conclude that the approach seems safe due to the fact that the usage of this code is very limited, the code itself is simple enough and that gcc would inline this code anyway based on the current compilation options.
The experiment that I did was to define some self-contained code that tries to mimic what you are describing and compile it with 3 different versions of gcc (6.4, 8.1 and 8.3) and in all the tree cases the behavior seems correct.
Code: =====
typedef int ssize_t; typedef int size_t;
static int my_strlen(const char *s) { int i = 0;
while (s[i] == '\0') i++;
return i; }
static inline ssize_t my_syscall(int fd, const void *buf, size_t count) { register ssize_t arg1 asm ("x0") = fd; register const void *arg2 asm ("x1") = buf; register size_t arg3 asm ("x2") = count;
__asm__ volatile ( "mov x8, #64\n" "svc #0\n" : "=&r" (arg1) : "r" (arg2), "r" (arg3) : "x8" );
return arg1; }
void sys_caller(const char *s) { my_syscall(1, s, my_strlen(s)); }
GCC 8.3.0: ==========
main.8.3.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 8.1.0: ==========
main.8.1.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 6.4.0: ==========
main.6.4.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
[...]
Cheers ---Dave
On Wed, Jun 26, 2019 at 02:27:59PM +0100, Vincenzo Frascino wrote:
Hi Dave,
On 25/06/2019 16:33, Dave Martin wrote:
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
[...]
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)
Out of interest, does this need to be __always_inline?
It is a design choice. Philosophically, I prefer to control and reduce the scope of the decisions the compiler has to make in order to not have surprises.
+{
- 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"
Can inlining of this function result in non-trivial expressions being substituted for _tz or _tv?
A function call can clobber register asm vars that are assigned to the caller-save registers or that the PCS uses for function arguments, and the situations where this can happen are poorly defined AFAICT. There's also no reliable way to detect at build time whether the compiler has done this, and no robust way to stop if happening.
(IMHO the compiler is wrong to do this, but it's been that way for ever, and I think I saw GCC 9 show this behaviour recently when I was investigating something related.)
To be safe, it's better to put this out of line, or remove the reg asm() specifiers, mark x0-x18 and lr as clobbered here (so that the compiler doesn't map arguments to them), and put movs in the asm to move things into the right registers. The syscall number can be passed with an "i" constraint. (And yes, this sucks.)
If the code this is inlined in is simple enough though, we can be fairly confident of getting away with it.
I took very seriously what you are mentioning here because I think that robustness of the code comes before than everything especially in the kernel and I carried on some experiments to try to verify if in this case is safe to assume that the compiler is doing the right thing.
Based on my investigation and on previous observations of the generation of the vDSO library, I can conclude that the approach seems safe due to the fact that the usage of this code is very limited, the code itself is simple enough and that gcc would inline this code anyway based on the current compilation options.
I'd caution about "seems safe". A lot of subtly wrong code not only seems safe, but _is_ safe in its original context, in practice. Add some code to the vdso over time though, or tweak the compilation options at some point in the future, or use a different compiler, and things could still go wrong.
(Further comments below.)
The experiment that I did was to define some self-contained code that tries to mimic what you are describing and compile it with 3 different versions of gcc (6.4, 8.1 and 8.3) and in all the tree cases the behavior seems correct.
Code:
typedef int ssize_t; typedef int size_t;
static int my_strlen(const char *s) { int i = 0;
while (s[i] == '\0') i++;
return i; }
static inline ssize_t my_syscall(int fd, const void *buf, size_t count) { register ssize_t arg1 asm ("x0") = fd; register const void *arg2 asm ("x1") = buf; register size_t arg3 asm ("x2") = count;
__asm__ volatile ( "mov x8, #64\n" "svc #0\n" : "=&r" (arg1) : "r" (arg2), "r" (arg3) : "x8" );
return arg1;
}
void sys_caller(const char *s) { my_syscall(1, s, my_strlen(s)); }
GCC 8.3.0:
main.8.3.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 8.1.0:
main.8.1.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 6.4.0:
main.6.4.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
Thanks for having a go at this. If the compiler can show the problematic behaviour, it looks like your could could probably trigger it, and as you observe, it doesn't trigger.
I am sure I have seen it in the past, but today I am struggling to tickle the compiler in the right way. My original reproducer may have involved LTO, but either way I don't still have it :(
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
The case where this behaviour is triggered by inlining an expression that involves a (possibly implicit) function call seems hard to reproduce.
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
Cheers ---Dave
Hi Dave,
thank you for the quick turn around.
On 6/26/19 5:14 PM, Dave Martin wrote:
On Wed, Jun 26, 2019 at 02:27:59PM +0100, Vincenzo Frascino wrote:
Hi Dave,
On 25/06/2019 16:33, Dave Martin wrote:
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
[...]
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)
Out of interest, does this need to be __always_inline?
It is a design choice. Philosophically, I prefer to control and reduce the scope of the decisions the compiler has to make in order to not have surprises.
+{
- 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"
Can inlining of this function result in non-trivial expressions being substituted for _tz or _tv?
A function call can clobber register asm vars that are assigned to the caller-save registers or that the PCS uses for function arguments, and the situations where this can happen are poorly defined AFAICT. There's also no reliable way to detect at build time whether the compiler has done this, and no robust way to stop if happening.
(IMHO the compiler is wrong to do this, but it's been that way for ever, and I think I saw GCC 9 show this behaviour recently when I was investigating something related.)
To be safe, it's better to put this out of line, or remove the reg asm() specifiers, mark x0-x18 and lr as clobbered here (so that the compiler doesn't map arguments to them), and put movs in the asm to move things into the right registers. The syscall number can be passed with an "i" constraint. (And yes, this sucks.)
If the code this is inlined in is simple enough though, we can be fairly confident of getting away with it.
I took very seriously what you are mentioning here because I think that robustness of the code comes before than everything especially in the kernel and I carried on some experiments to try to verify if in this case is safe to assume that the compiler is doing the right thing.
Based on my investigation and on previous observations of the generation of the vDSO library, I can conclude that the approach seems safe due to the fact that the usage of this code is very limited, the code itself is simple enough and that gcc would inline this code anyway based on the current compilation options.
I'd caution about "seems safe". A lot of subtly wrong code not only seems safe, but _is_ safe in its original context, in practice. Add some code to the vdso over time though, or tweak the compilation options at some point in the future, or use a different compiler, and things could still go wrong.
(Further comments below.)
Allow me to provide a clarification on "seems safe" vs "is safe": my approach "seems safe" because I am providing empirical evidence to support my thesis, but I guess we both know that there is no simple way to prove in one way or another that the problem has a complete solution. The proposed problem involves suppositions on potential future code additions and changes of behavior of the compiler that I can't either control or prevent. In other words, I can comment and propose solutions only based on the current status of the things, and it is what my analysis targets, not on what will happen in future.
I will reply point by point below.
The experiment that I did was to define some self-contained code that tries to mimic what you are describing and compile it with 3 different versions of gcc (6.4, 8.1 and 8.3) and in all the tree cases the behavior seems correct.
Code:
typedef int ssize_t; typedef int size_t;
static int my_strlen(const char *s) { int i = 0;
while (s[i] == '\0') i++;
return i; }
static inline ssize_t my_syscall(int fd, const void *buf, size_t count) { register ssize_t arg1 asm ("x0") = fd; register const void *arg2 asm ("x1") = buf; register size_t arg3 asm ("x2") = count;
__asm__ volatile ( "mov x8, #64\n" "svc #0\n" : "=&r" (arg1) : "r" (arg2), "r" (arg3) : "x8" );
return arg1;
}
void sys_caller(const char *s) { my_syscall(1, s, my_strlen(s)); }
GCC 8.3.0:
main.8.3.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 8.1.0:
main.8.1.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 6.4.0:
main.6.4.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
Thanks for having a go at this. If the compiler can show the problematic behaviour, it looks like your could could probably trigger it, and as you observe, it doesn't trigger.
I am sure I have seen it in the past, but today I am struggling to tickle the compiler in the right way. My original reproducer may have involved LTO, but either way I don't still have it :(
vDSO library is a shared object not compiled with LTO as far as I can see, hence if this involved LTO should not applicable in this case.
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
Contextualized to what my vdso fallback functions do, this should not be a concern because in no case a function result is directly set to a variable declared as register.
Since the vdso fallback functions serve a very specific and limited purpose, I do not expect that that code is going to change much in future.
The only thing that can happen is something similar to what I wrote in my example, which as I empirically proved does not trigger the problematic behavior.
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
On this I agree, it is not very clear, but this seems more something to raise with the gcc folks in order to have a more "explicit" description that leaves no room to the interpretation.
...
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
The solution seems ok, thanks for providing it, but IMHO I think we should find a workaround for something that is broken, which, unless I am missing something major, this seems not the case.
Cheers ---Dave
On Wed, Jun 26, 2019 at 08:01:58PM +0100, Vincenzo Frascino wrote:
[...]
On 6/26/19 5:14 PM, Dave Martin wrote:
On Wed, Jun 26, 2019 at 02:27:59PM +0100, Vincenzo Frascino wrote:
Hi Dave,
On 25/06/2019 16:33, Dave Martin wrote:
On Fri, Jun 21, 2019 at 10:52:31AM +0100, 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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com
[...]
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)
Out of interest, does this need to be __always_inline?
It is a design choice. Philosophically, I prefer to control and reduce the scope of the decisions the compiler has to make in order to not have surprises.
+{
- 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"
Can inlining of this function result in non-trivial expressions being substituted for _tz or _tv?
A function call can clobber register asm vars that are assigned to the caller-save registers or that the PCS uses for function arguments, and the situations where this can happen are poorly defined AFAICT. There's also no reliable way to detect at build time whether the compiler has done this, and no robust way to stop if happening.
(IMHO the compiler is wrong to do this, but it's been that way for ever, and I think I saw GCC 9 show this behaviour recently when I was investigating something related.)
To be safe, it's better to put this out of line, or remove the reg asm() specifiers, mark x0-x18 and lr as clobbered here (so that the compiler doesn't map arguments to them), and put movs in the asm to move things into the right registers. The syscall number can be passed with an "i" constraint. (And yes, this sucks.)
If the code this is inlined in is simple enough though, we can be fairly confident of getting away with it.
I took very seriously what you are mentioning here because I think that robustness of the code comes before than everything especially in the kernel and I carried on some experiments to try to verify if in this case is safe to assume that the compiler is doing the right thing.
Based on my investigation and on previous observations of the generation of the vDSO library, I can conclude that the approach seems safe due to the fact that the usage of this code is very limited, the code itself is simple enough and that gcc would inline this code anyway based on the current compilation options.
I'd caution about "seems safe". A lot of subtly wrong code not only seems safe, but _is_ safe in its original context, in practice. Add some code to the vdso over time though, or tweak the compilation options at some point in the future, or use a different compiler, and things could still go wrong.
(Further comments below.)
Allow me to provide a clarification on "seems safe" vs "is safe": my approach "seems safe" because I am providing empirical evidence to support my thesis, but I guess we both know that there is no simple way to prove in one way or another that the problem has a complete solution. The proposed problem involves suppositions on potential future code additions and changes of behavior of the compiler that I can't either control or prevent. In other words, I can comment and propose solutions only based on the current status of the things, and it is what my analysis targets, not on what will happen in future.
I will reply point by point below.
The experiment that I did was to define some self-contained code that tries to mimic what you are describing and compile it with 3 different versions of gcc (6.4, 8.1 and 8.3) and in all the tree cases the behavior seems correct.
Code:
typedef int ssize_t; typedef int size_t;
static int my_strlen(const char *s) { int i = 0;
while (s[i] == '\0') i++;
return i; }
static inline ssize_t my_syscall(int fd, const void *buf, size_t count) { register ssize_t arg1 asm ("x0") = fd; register const void *arg2 asm ("x1") = buf; register size_t arg3 asm ("x2") = count;
__asm__ volatile ( "mov x8, #64\n" "svc #0\n" : "=&r" (arg1) : "r" (arg2), "r" (arg3) : "x8" );
return arg1;
}
void sys_caller(const char *s) { my_syscall(1, s, my_strlen(s)); }
GCC 8.3.0:
main.8.3.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 8.1.0:
main.8.1.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
GCC 6.4.0:
main.6.4.0.o: file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <sys_caller>: 0: 39400001 ldrb w1, [x0] 4: 35000161 cbnz w1, 30 <sys_caller+0x30> 8: d2800023 mov x3, #0x1 // #1 c: d1000404 sub x4, x0, #0x1 10: 2a0303e2 mov w2, w3 14: 91000463 add x3, x3, #0x1 18: 38636881 ldrb w1, [x4, x3] 1c: 34ffffa1 cbz w1, 10 <sys_caller+0x10> 20: aa0003e1 mov x1, x0 24: d2800808 mov x8, #0x40 // #64 28: d4000001 svc #0x0 2c: d65f03c0 ret 30: 52800002 mov w2, #0x0 // #0 34: 17fffffb b 20 <sys_caller+0x20>
Thanks for having a go at this. If the compiler can show the problematic behaviour, it looks like your could could probably trigger it, and as you observe, it doesn't trigger.
I am sure I have seen it in the past, but today I am struggling to tickle the compiler in the right way. My original reproducer may have involved LTO, but either way I don't still have it :(
vDSO library is a shared object not compiled with LTO as far as I can see, hence if this involved LTO should not applicable in this case.
That turned to be a spurious hypothesis on my part -- LTO isn't the smoking gun. (See below.)
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
Contextualized to what my vdso fallback functions do, this should not be a concern because in no case a function result is directly set to a variable declared as register.
Since the vdso fallback functions serve a very specific and limited purpose, I do not expect that that code is going to change much in future.
The only thing that can happen is something similar to what I wrote in my example, which as I empirically proved does not trigger the problematic behavior.
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
On this I agree, it is not very clear, but this seems more something to raise with the gcc folks in order to have a more "explicit" description that leaves no room to the interpretation.
...
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
The solution seems ok, thanks for providing it, but IMHO I think we should find a workaround for something that is broken, which, unless I am missing something major, this seems not the case.
So, after a bit of further experimentation, I found that I could trigger it with implicit function calls on an older compiler. I couldn't show it with explicit function calls (as in your example).
With the following code, inlining if an expression that causes an implicit call to a libgcc helper can trigger this issue, but I had to try an older compiler:
int foo(int x, int y) { register int res asm("r0"); register const int x_ asm("r0") = x; register const int y_ asm("r1") = y;
asm volatile ( "svc #0" : "=r" (res) : "r" (x_), "r" (y_) : "memory" );
return res; }
int bar(int x, int y) { return foo(x, x / y); }
-> (arm-linux-gnueabihf-gcc 9.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b510 push {r4, lr} 6: 4604 mov r4, r0 8: f7ff fffe bl 0 <__aeabi_idiv> c: 4601 mov r1, r0 e: 4620 mov r0, r4 10: df00 svc 0 12: bd10 pop {r4, pc}
-> (arm-linux-gnueabihf-gcc 5.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b508 push {r3, lr} 6: f7ff fffe bl 0 <__aeabi_idiv> a: 4601 mov r1, r0 c: df00 svc 0 e: bd08 pop {r3, pc}
I was struggling to find a way to emit an implicit function call for AArch64, except for 128-bit divide, which would complicate things since uint128_t doesn't fit in a single register anyway.
Maybe this was considered a bug and fixed sometime after GCC 5, but I think the GCC documentation is still quite unclear on the semantics of register asm vars that alias call-clobbered registers in the PCS.
If we can get a promise out of the GCC folks that this will not happen with any future compiler, then maybe we could just require a new enough compiler to be used.
Then of course there is clang.
Cheers ---Dave
Hi Dave,
Overall, I want to thank you for bringing out the topic. It helped me to question some decisions and make sure that we have no holes left in the approach.
[...]
vDSO library is a shared object not compiled with LTO as far as I can see, hence if this involved LTO should not applicable in this case.
That turned to be a spurious hypothesis on my part -- LTO isn't the smoking gun. (See below.)
Ok.
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
Contextualized to what my vdso fallback functions do, this should not be a concern because in no case a function result is directly set to a variable declared as register.
Since the vdso fallback functions serve a very specific and limited purpose, I do not expect that that code is going to change much in future.
The only thing that can happen is something similar to what I wrote in my example, which as I empirically proved does not trigger the problematic behavior.
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
On this I agree, it is not very clear, but this seems more something to raise with the gcc folks in order to have a more "explicit" description that leaves no room to the interpretation.
...
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
The solution seems ok, thanks for providing it, but IMHO I think we should find a workaround for something that is broken, which, unless I am missing something major, this seems not the case.
So, after a bit of further experimentation, I found that I could trigger it with implicit function calls on an older compiler. I couldn't show it with explicit function calls (as in your example).
With the following code, inlining if an expression that causes an implicit call to a libgcc helper can trigger this issue, but I had to try an older compiler:
int foo(int x, int y) { register int res asm("r0"); register const int x_ asm("r0") = x; register const int y_ asm("r1") = y;
asm volatile ( "svc #0" : "=r" (res) : "r" (x_), "r" (y_) : "memory" );
return res; }
int bar(int x, int y) { return foo(x, x / y); }
-> (arm-linux-gnueabihf-gcc 9.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b510 push {r4, lr} 6: 4604 mov r4, r0 8: f7ff fffe bl 0 <__aeabi_idiv> c: 4601 mov r1, r0 e: 4620 mov r0, r4 10: df00 svc 0 12: bd10 pop {r4, pc}
-> (arm-linux-gnueabihf-gcc 5.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b508 push {r3, lr} 6: f7ff fffe bl 0 <__aeabi_idiv> a: 4601 mov r1, r0 c: df00 svc 0 e: bd08 pop {r3, pc}
Thanks for reporting this. I had a go with gcc-5.1 on the vDSO library and seems Ok, but it was worth trying.
For obvious reasons I am not reporting the objdump here :)
I was struggling to find a way to emit an implicit function call for AArch64, except for 128-bit divide, which would complicate things since uint128_t doesn't fit in a single register anyway.
Maybe this was considered a bug and fixed sometime after GCC 5, but I think the GCC documentation is still quite unclear on the semantics of register asm vars that alias call-clobbered registers in the PCS.
If we can get a promise out of the GCC folks that this will not happen with any future compiler, then maybe we could just require a new enough compiler to be used.
On this I fully agree, the compiler should never change an "expected" behavior.
If the issue comes from a gray area in the documentation, we have to address it and have it fixed there.
The minimum version of the compiler from linux-4.19 is 4.6, hence I had to try that the vDSO lib does not break with 5.1 [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
Then of course there is clang.
I could not help myself and I tried clang.8 and clang.7 as well with my example, just to make sure that we are fine even in that case. Please find below the results (pretty identical).
main.clang.7.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
main.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
Commands used:
$ clang -target aarch64-linux-gnueabi main.c -O -c -o main.clang.<x>.o $ llvm-objdump -d main.clang.<x>.o
Cheers ---Dave
On Thu, Jun 27, 2019 at 11:57:36AM +0100, Vincenzo Frascino wrote:
Hi Dave,
Overall, I want to thank you for bringing out the topic. It helped me to question some decisions and make sure that we have no holes left in the approach.
Fair enough.
This is really just a nasty compiler corner-case... the validity of the overall approach isn't affected.
vDSO library is a shared object not compiled with LTO as far as I can see, hence if this involved LTO should not applicable in this case.
That turned to be a spurious hypothesis on my part -- LTO isn't the smoking gun. (See below.)
Ok.
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
Contextualized to what my vdso fallback functions do, this should not be a concern because in no case a function result is directly set to a variable declared as register.
Since the vdso fallback functions serve a very specific and limited purpose, I do not expect that that code is going to change much in future.
The only thing that can happen is something similar to what I wrote in my example, which as I empirically proved does not trigger the problematic behavior.
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
On this I agree, it is not very clear, but this seems more something to raise with the gcc folks in order to have a more "explicit" description that leaves no room to the interpretation.
...
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
The solution seems ok, thanks for providing it, but IMHO I think we should find a workaround for something that is broken, which, unless I am missing something major, this seems not the case.
So, after a bit of further experimentation, I found that I could trigger it with implicit function calls on an older compiler. I couldn't show it with explicit function calls (as in your example).
With the following code, inlining if an expression that causes an implicit call to a libgcc helper can trigger this issue, but I had to try an older compiler:
int foo(int x, int y) { register int res asm("r0"); register const int x_ asm("r0") = x; register const int y_ asm("r1") = y;
asm volatile ( "svc #0" : "=r" (res) : "r" (x_), "r" (y_) : "memory" );
return res; }
int bar(int x, int y) { return foo(x, x / y); }
-> (arm-linux-gnueabihf-gcc 9.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b510 push {r4, lr} 6: 4604 mov r4, r0 8: f7ff fffe bl 0 <__aeabi_idiv> c: 4601 mov r1, r0 e: 4620 mov r0, r4 10: df00 svc 0 12: bd10 pop {r4, pc}
-> (arm-linux-gnueabihf-gcc 5.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b508 push {r3, lr} 6: f7ff fffe bl 0 <__aeabi_idiv> a: 4601 mov r1, r0 c: df00 svc 0 e: bd08 pop {r3, pc}
Thanks for reporting this. I had a go with gcc-5.1 on the vDSO library and seems Ok, but it was worth trying.
For obvious reasons I am not reporting the objdump here :)
I was struggling to find a way to emit an implicit function call for AArch64, except for 128-bit divide, which would complicate things since uint128_t doesn't fit in a single register anyway.
Maybe this was considered a bug and fixed sometime after GCC 5, but I think the GCC documentation is still quite unclear on the semantics of register asm vars that alias call-clobbered registers in the PCS.
If we can get a promise out of the GCC folks that this will not happen with any future compiler, then maybe we could just require a new enough compiler to be used.
On this I fully agree, the compiler should never change an "expected" behavior.
If the issue comes from a gray area in the documentation, we have to address it and have it fixed there.
The minimum version of the compiler from linux-4.19 is 4.6, hence I had to try that the vDSO lib does not break with 5.1 [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
OK
Then of course there is clang.
I could not help myself and I tried clang.8 and clang.7 as well with my example, just to make sure that we are fine even in that case. Please find below the results (pretty identical).
main.clang.7.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
main.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
Commands used:
$ clang -target aarch64-linux-gnueabi main.c -O -c -o main.clang.<x>.o $ llvm-objdump -d main.clang.<x>.o
Actually, I'm not sure this is comparable with the reproducer I quoted in my last reply.
The compiler can see the definition of strlen and fully inlines it. I only ever saw the problem when the compiler emits an out-of-line implicit function call.
What does clang do with my example on 32-bit?
Cheers ---Dave
On 6/27/19 12:27 PM, Dave Martin wrote:
On Thu, Jun 27, 2019 at 11:57:36AM +0100, Vincenzo Frascino wrote:
Hi Dave,
Overall, I want to thank you for bringing out the topic. It helped me to question some decisions and make sure that we have no holes left in the approach.
Fair enough.
This is really just a nasty compiler corner-case... the validity of the overall approach isn't affected.
vDSO library is a shared object not compiled with LTO as far as I can see, hence if this involved LTO should not applicable in this case.
That turned to be a spurious hypothesis on my part -- LTO isn't the smoking gun. (See below.)
Ok.
The classic example of this (triggered directly and not due to inlining) would be something like:
int bar(int, int);
void foo(int x, int y) { register int x_ asm("r0") = x; register int y_ asm("r1") = bar(x, y);
asm volatile ( "svc #0" :: "r" (x_), "r" (y_) : "memory" ); }
->
0000000000000000 <foo>: 0: a9bf7bfd stp x29, x30, [sp, #-16]! 4: 910003fd mov x29, sp 8: 94000000 bl 0 <bar> c: 2a0003e1 mov w1, w0 10: d4000001 svc #0x0 14: a8c17bfd ldp x29, x30, [sp], #16 18: d65f03c0 ret
Contextualized to what my vdso fallback functions do, this should not be a concern because in no case a function result is directly set to a variable declared as register.
Since the vdso fallback functions serve a very specific and limited purpose, I do not expect that that code is going to change much in future.
The only thing that can happen is something similar to what I wrote in my example, which as I empirically proved does not trigger the problematic behavior.
The gcc documentation is vague and ambiguous about precisely whan this can happen and about how to avoid it.
On this I agree, it is not very clear, but this seems more something to raise with the gcc folks in order to have a more "explicit" description that leaves no room to the interpretation.
...
However, the workaround is cheap, and to avoid the chance of subtle intermittent code gen bugs it may be worth it:
void foo(int x, int y) { asm volatile ( "mov x0, %0\n\t" "mov x1, %1\n\t" "svc #0" :: "r" (x), "r" (bar(x, y)) : "r0", "r1", "memory" ); }
->
0000000000000000 <foo>: 0: a9be7bfd stp x29, x30, [sp, #-32]! 4: 910003fd mov x29, sp 8: f9000bf3 str x19, [sp, #16] c: 2a0003f3 mov w19, w0 10: 94000000 bl 0 <bar> 14: 2a0003e2 mov w2, w0 18: aa1303e0 mov x0, x19 1c: aa0203e1 mov x1, x2 20: d4000001 svc #0x0 24: f9400bf3 ldr x19, [sp, #16] 28: a8c27bfd ldp x29, x30, [sp], #32 2c: d65f03c0 ret
What do you think?
The solution seems ok, thanks for providing it, but IMHO I think we should find a workaround for something that is broken, which, unless I am missing something major, this seems not the case.
So, after a bit of further experimentation, I found that I could trigger it with implicit function calls on an older compiler. I couldn't show it with explicit function calls (as in your example).
With the following code, inlining if an expression that causes an implicit call to a libgcc helper can trigger this issue, but I had to try an older compiler:
int foo(int x, int y) { register int res asm("r0"); register const int x_ asm("r0") = x; register const int y_ asm("r1") = y;
asm volatile ( "svc #0" : "=r" (res) : "r" (x_), "r" (y_) : "memory" );
return res; }
int bar(int x, int y) { return foo(x, x / y); }
-> (arm-linux-gnueabihf-gcc 9.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b510 push {r4, lr} 6: 4604 mov r4, r0 8: f7ff fffe bl 0 <__aeabi_idiv> c: 4601 mov r1, r0 e: 4620 mov r0, r4 10: df00 svc 0 12: bd10 pop {r4, pc}
-> (arm-linux-gnueabihf-gcc 5.1 -O2)
00000000 <foo>: 0: df00 svc 0 2: 4770 bx lr
00000004 <bar>: 4: b508 push {r3, lr} 6: f7ff fffe bl 0 <__aeabi_idiv> a: 4601 mov r1, r0 c: df00 svc 0 e: bd08 pop {r3, pc}
Thanks for reporting this. I had a go with gcc-5.1 on the vDSO library and seems Ok, but it was worth trying.
For obvious reasons I am not reporting the objdump here :)
I was struggling to find a way to emit an implicit function call for AArch64, except for 128-bit divide, which would complicate things since uint128_t doesn't fit in a single register anyway.
Maybe this was considered a bug and fixed sometime after GCC 5, but I think the GCC documentation is still quite unclear on the semantics of register asm vars that alias call-clobbered registers in the PCS.
If we can get a promise out of the GCC folks that this will not happen with any future compiler, then maybe we could just require a new enough compiler to be used.
On this I fully agree, the compiler should never change an "expected" behavior.
If the issue comes from a gray area in the documentation, we have to address it and have it fixed there.
The minimum version of the compiler from linux-4.19 is 4.6, hence I had to try that the vDSO lib does not break with 5.1 [1].
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
OK
Then of course there is clang.
I could not help myself and I tried clang.8 and clang.7 as well with my example, just to make sure that we are fine even in that case. Please find below the results (pretty identical).
main.clang.7.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
main.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
Commands used:
$ clang -target aarch64-linux-gnueabi main.c -O -c -o main.clang.<x>.o $ llvm-objdump -d main.clang.<x>.o
Actually, I'm not sure this is comparable with the reproducer I quoted in my last reply.
As explained in my previous email, this is the only case that can realistically happen. vDSO has no dependency on any other library (i.e. libgcc you were mentioning) and we are referring to the fallbacks which fall in this category.
The compiler can see the definition of strlen and fully inlines it. I only ever saw the problem when the compiler emits an out-of-line implicit function call.
What does clang do with my example on 32-bit?
When clang is selected compat vDSOs are currently disabled on arm64, will be introduced with a future patch series.
Anyway since I am curious as well, this is what happens with your example with clang.8 target=arm-linux-gnueabihf:
dave-code.clang.8.o: file format ELF32-arm-little
Disassembly of section .text: 0000000000000000 foo: 0: 00 00 00 ef svc #0 4: 1e ff 2f e1 bx lr
0000000000000008 bar: 8: 10 4c 2d e9 push {r4, r10, r11, lr} c: 08 b0 8d e2 add r11, sp, #8 10: 00 40 a0 e1 mov r4, r0 14: fe ff ff eb bl #-8 <bar+0xc> 18: 00 10 a0 e1 mov r1, r0 1c: 04 00 a0 e1 mov r0, r4 20: 00 00 00 ef svc #0 24: 10 8c bd e8 pop {r4, r10, r11, pc}
Compiled with -O2, -O3, -Os never inlines.
Same thing happens for aarch64-linux-gnueabi:
dave-code.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 foo: 0: e0 03 00 2a mov w0, w0 4: e1 03 01 2a mov w1, w1 8: 01 00 00 d4 svc #0 c: c0 03 5f d6 ret
0000000000000010 bar: 10: 01 0c c1 1a sdiv w1, w0, w1 14: e0 03 00 2a mov w0, w0 18: 01 00 00 d4 svc #0 1c: c0 03 5f d6 ret
Based on this I think we can conclude our investigation.
Cheers ---Dave
linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 27, 2019 at 12:59:07PM +0100, Vincenzo Frascino wrote:
On 6/27/19 12:27 PM, Dave Martin wrote:
On Thu, Jun 27, 2019 at 11:57:36AM +0100, Vincenzo Frascino wrote:
[...]
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
Commands used:
$ clang -target aarch64-linux-gnueabi main.c -O -c -o main.clang.<x>.o $ llvm-objdump -d main.clang.<x>.o
Actually, I'm not sure this is comparable with the reproducer I quoted in my last reply.
As explained in my previous email, this is the only case that can realistically happen. vDSO has no dependency on any other library (i.e. libgcc you were mentioning) and we are referring to the fallbacks which fall in this category.
Outlining could also introduce a local function call where none exists explicitly in the program IIUC.
My point is that the interaction between asm reg vars and machine-level procedure calls is at best ill-defined, and it is largely up to the compiler when to introduce such a call, even without LTO etc.
So we should not be surprised to see variations in behaviour depending on compiler, compiler version and compiler flags.
The compiler can see the definition of strlen and fully inlines it. I only ever saw the problem when the compiler emits an out-of-line implicit function call.
What does clang do with my example on 32-bit?
When clang is selected compat vDSOs are currently disabled on arm64, will be introduced with a future patch series.
Anyway since I am curious as well, this is what happens with your example with clang.8 target=arm-linux-gnueabihf:
dave-code.clang.8.o: file format ELF32-arm-little
Disassembly of section .text: 0000000000000000 foo: 0: 00 00 00 ef svc #0 4: 1e ff 2f e1 bx lr
0000000000000008 bar: 8: 10 4c 2d e9 push {r4, r10, r11, lr} c: 08 b0 8d e2 add r11, sp, #8 10: 00 40 a0 e1 mov r4, r0 14: fe ff ff eb bl #-8 <bar+0xc> 18: 00 10 a0 e1 mov r1, r0 1c: 04 00 a0 e1 mov r0, r4 20: 00 00 00 ef svc #0 24: 10 8c bd e8 pop {r4, r10, r11, pc}
Compiled with -O2, -O3, -Os never inlines.
Looks sane, and is the behaviour we want.
Same thing happens for aarch64-linux-gnueabi:
dave-code.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 foo: 0: e0 03 00 2a mov w0, w0 4: e1 03 01 2a mov w1, w1 8: 01 00 00 d4 svc #0 c: c0 03 5f d6 ret
0000000000000010 bar: 10: 01 0c c1 1a sdiv w1, w0, w1 14: e0 03 00 2a mov w0, w0 18: 01 00 00 d4 svc #0 1c: c0 03 5f d6 ret
Curious, clang seems to be inserting some seemingly redundant moves of its own here, though this shouldn't break anything.
I suspect that clang might require an X-reg holding an int to have its top 32 bits zeroed for passing to an asm, whereas GCC does not. I think this comes under "we should not be surprised to see variations".
GCC 9 does this instead:
0000000000000000 <foo>: 0: d4000001 svc #0x0 4: d65f03c0 ret
0000000000000008 <bar>: 8: 1ac10c01 sdiv w1, w0, w1 c: d4000001 svc #0x0 10: d65f03c0 ret
Based on this I think we can conclude our investigation.
So we use non-reg vars and use the asm clobber list and explicit moves to get things into / out of the right registers?
Cheers ---Dave
Hi Dave,
On 6/27/19 3:38 PM, Dave Martin wrote:
On Thu, Jun 27, 2019 at 12:59:07PM +0100, Vincenzo Frascino wrote:
On 6/27/19 12:27 PM, Dave Martin wrote:
On Thu, Jun 27, 2019 at 11:57:36AM +0100, Vincenzo Frascino wrote:
[...]
Disassembly of section .text: 0000000000000000 show_it: 0: e8 03 1f aa mov x8, xzr 4: 09 68 68 38 ldrb w9, [x0, x8] 8: 08 05 00 91 add x8, x8, #1 c: c9 ff ff 34 cbz w9, #-8 <show_it+0x4> 10: 02 05 00 51 sub w2, w8, #1 14: e1 03 00 aa mov x1, x0 18: 08 08 80 d2 mov x8, #64 1c: 01 00 00 d4 svc #0 20: c0 03 5f d6 ret
Commands used:
$ clang -target aarch64-linux-gnueabi main.c -O -c -o main.clang.<x>.o $ llvm-objdump -d main.clang.<x>.o
Actually, I'm not sure this is comparable with the reproducer I quoted in my last reply.
As explained in my previous email, this is the only case that can realistically happen. vDSO has no dependency on any other library (i.e. libgcc you were mentioning) and we are referring to the fallbacks which fall in this category.
Outlining could also introduce a local function call where none exists explicitly in the program IIUC.
My point is that the interaction between asm reg vars and machine-level procedure calls is at best ill-defined, and it is largely up to the compiler when to introduce such a call, even without LTO etc.
So we should not be surprised to see variations in behaviour depending on compiler, compiler version and compiler flags.
I tested 10 version of the compiler and a part gcc-5.1 that triggers the issue in a specific case and not in the vdso library, I could not find evidence of the problem.
The compiler can see the definition of strlen and fully inlines it. I only ever saw the problem when the compiler emits an out-of-line implicit function call.
What does clang do with my example on 32-bit?
When clang is selected compat vDSOs are currently disabled on arm64, will be introduced with a future patch series.
Anyway since I am curious as well, this is what happens with your example with clang.8 target=arm-linux-gnueabihf:
dave-code.clang.8.o: file format ELF32-arm-little
Disassembly of section .text: 0000000000000000 foo: 0: 00 00 00 ef svc #0 4: 1e ff 2f e1 bx lr
0000000000000008 bar: 8: 10 4c 2d e9 push {r4, r10, r11, lr} c: 08 b0 8d e2 add r11, sp, #8 10: 00 40 a0 e1 mov r4, r0 14: fe ff ff eb bl #-8 <bar+0xc> 18: 00 10 a0 e1 mov r1, r0 1c: 04 00 a0 e1 mov r0, r4 20: 00 00 00 ef svc #0 24: 10 8c bd e8 pop {r4, r10, r11, pc}
Compiled with -O2, -O3, -Os never inlines.
Looks sane, and is the behaviour we want.
Same thing happens for aarch64-linux-gnueabi:
dave-code.clang.8.o: file format ELF64-aarch64-little
Disassembly of section .text: 0000000000000000 foo: 0: e0 03 00 2a mov w0, w0 4: e1 03 01 2a mov w1, w1 8: 01 00 00 d4 svc #0 c: c0 03 5f d6 ret
0000000000000010 bar: 10: 01 0c c1 1a sdiv w1, w0, w1 14: e0 03 00 2a mov w0, w0 18: 01 00 00 d4 svc #0 1c: c0 03 5f d6 ret
Curious, clang seems to be inserting some seemingly redundant moves of its own here, though this shouldn't break anything.
I suspect that clang might require an X-reg holding an int to have its top 32 bits zeroed for passing to an asm, whereas GCC does not. I think this comes under "we should not be surprised to see variations".
GCC 9 does this instead:
0000000000000000 <foo>: 0: d4000001 svc #0x0 4: d65f03c0 ret
0000000000000008 <bar>: 8: 1ac10c01 sdiv w1, w0, w1 c: d4000001 svc #0x0 10: d65f03c0 ret
Based on this I think we can conclude our investigation.
So we use non-reg vars and use the asm clobber list and explicit moves to get things into / out of the right registers?
Since I managed to provide enough evidence, based on the behavior of various versions of the compilers, that the library as it stands is consistent and does not suffer any of the issues you reported I think I will keep my code as is at least for this release, I will revisit it in future if something happens.
If you manage to prove that my library as it stands (no code additions or source modifications) has the issues you mentioned based on some version of the compiler, this changes everything.
Happy to hear from you.
Cheers ---Dave
clang versions previous to 8 do not support -mcmodel=tiny.
Add a check to the vDSO Makefile for arm64 to remove the flag when these versions of the compiler are detected.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Reported-by: Qian Cai cai@lca.pw Tested-by: Qian Cai cai@lca.pw --- arch/arm64/kernel/vdso/Makefile | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index ec81d28aeb5d..5154f50aff2d 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -38,6 +38,11 @@ else CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -include $(c-gettimeofday-y) endif
+# Clang versions less than 8 do not support -mcmodel=tiny +ifeq ($(shell test $(CONFIG_CLANG_VERSION) -lt 80000; echo $$?),0) +CFLAGS_REMOVE_vgettimeofday.o += -mcmodel=tiny +endif + # Disable gcov profiling for VDSO code GCOV_PROFILE := n
clang versions older then 8 do not support -mcmodel=tiny.
Add a check to the vDSO Makefile for arm64 to remove the flag when these versions of the compiler are detected.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Reported-by: Qian Cai cai@lca.pw Tested-by: Qian Cai cai@lca.pw --- arch/arm64/kernel/vdso/Makefile | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index ec81d28aeb5d..4ab863045188 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -38,6 +38,13 @@ else CFLAGS_vgettimeofday.o = -O2 -mcmodel=tiny -include $(c-gettimeofday-y) endif
+# Clang versions less than 8 do not support -mcmodel=tiny +ifeq ($(CONFIG_CC_IS_CLANG), y) + ifeq ($(shell test $(CONFIG_CLANG_VERSION) -lt 80000; echo $$?),0) + CFLAGS_REMOVE_vgettimeofday.o += -mcmodel=tiny + endif +endif + # Disable gcov profiling for VDSO code GCOV_PROFILE := n
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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com
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.
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@arm.com
- */
-#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
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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com
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@arm.com
- */
-#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
Hi Vincenzo,
On 6/28/19 16:32, Vincenzo Frascino wrote:
On 6/28/19 2:09 PM, Marek Szyprowski wrote:
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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com
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.
Marek is already out for holidays, I gave your tree a try but kernel from that branch was failing to boot on TM2(e).
Then I have cherry-picked 5 patches from the branch that seemed to be missing in next-20190628:
28028f3174cf1 (HEAD) MAINTAINERS: Fix Andy's surname and the directory entries of VDSO ec8f8e4bf2206 arm64: vdso: Fix compilation with clang older than 8 721882ebb5729 arm64: compat: Fix __arch_get_hw_counter() implementation 7027fea977a3d arm64: Fix __arch_get_hw_counter() implementation 10b305853fe22 lib/vdso: Make delta calculation work correctly 48568d8c7f479 (tag: next-20190628, linux-next/master) Add linux-next specific files for 20190628
With those 5 additional patches on top of next-20190628 the problem is not observed any more. date, ping, etc. seems to be working well.
# date Fri Jun 28 16:39:22 UTC 2019 # # systemctl stop systemd-timesyncd # # date 062818392019 Fri Jun 28 18:39:00 UTC 2019 # date Fri Jun 28 18:39:01 UTC 2019 # # date 062818432019; date Fri Jun 28 18:43:00 UTC 2019 Fri Jun 28 18:43:00 UTC 2019 # date Fri Jun 28 18:43:04 UTC 2019
-- Regards, Sylwester
Hi Sylwester,
thank you for the quick turn around to my email.
On 6/28/19 5:50 PM, Sylwester Nawrocki wrote:
Hi Vincenzo,
On 6/28/19 16:32, Vincenzo Frascino wrote:
On 6/28/19 2:09 PM, Marek Szyprowski wrote:
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@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com
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.
Marek is already out for holidays, I gave your tree a try but kernel from that branch was failing to boot on TM2(e).
Then I have cherry-picked 5 patches from the branch that seemed to be missing in next-20190628:
28028f3174cf1 (HEAD) MAINTAINERS: Fix Andy's surname and the directory entries of VDSO ec8f8e4bf2206 arm64: vdso: Fix compilation with clang older than 8 721882ebb5729 arm64: compat: Fix __arch_get_hw_counter() implementation 7027fea977a3d arm64: Fix __arch_get_hw_counter() implementation 10b305853fe22 lib/vdso: Make delta calculation work correctly 48568d8c7f479 (tag: next-20190628, linux-next/master) Add linux-next specific files for 20190628
With those 5 additional patches on top of next-20190628 the problem is not observed any more. date, ping, etc. seems to be working well.
# date Fri Jun 28 16:39:22 UTC 2019 # # systemctl stop systemd-timesyncd # # date 062818392019 Fri Jun 28 18:39:00 UTC 2019 # date Fri Jun 28 18:39:01 UTC 2019 # # date 062818432019; date Fri Jun 28 18:43:00 UTC 2019 Fri Jun 28 18:43:00 UTC 2019 # date Fri Jun 28 18:43:04 UTC 2019
This seems ok, thanks for spending some time to test our patches against your board.
If I may, I would like to ask to you one favor, could you please keep an eye on next and once those patches are merged repeat the test?
I want just to make sure that the regression does not reappear.
Have a nice weekend.
-- Regards, Sylwester
Hi Vincenzo,
On 6/29/19 08:58, Vincenzo Frascino wrote:
If I may, I would like to ask to you one favor, could you please keep an eye on next and once those patches are merged repeat the test?
I want just to make sure that the regression does not reappear.
My apologies, I forgot about this for a moment. I repeated the test with next-20190705 tag and couldn't see any regressions.
Hi Sylwester,
On 08/07/2019 13:57, Sylwester Nawrocki wrote:
Hi Vincenzo,
On 6/29/19 08:58, Vincenzo Frascino wrote:
If I may, I would like to ask to you one favor, could you please keep an eye on next and once those patches are merged repeat the test?
I want just to make sure that the regression does not reappear.
My apologies, I forgot about this for a moment. I repeated the test with next-20190705 tag and couldn't see any regressions.
No problem and thank you for the confirmation.
From: Peter Collingbourne pcc@google.com
The vDSO needs to be build with x18 reserved in order to accommodate userspace platform ABIs built on top of Linux that use the register to carry inter-procedural state, as provided for by the AAPCS. An example of such a platform ABI is the one that will be used by an upcoming version of Android.
Although this change is currently a no-op due to the fact that the vDSO is currently implemented in pure assembly on arm64, it is necessary in order to prepare for another change [1] that will add C code to the vDSO.
[1] https://patchwork.kernel.org/patch/10044501/
Signed-off-by: Peter Collingbourne pcc@google.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com Cc: Mark Salyzyn salyzyn@google.com Cc: Will Deacon will.deacon@arm.com Cc: linux-arm-kernel@lists.infradead.org --- arch/arm64/kernel/vdso/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index 3acfc813e966..ec81d28aeb5d 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -20,7 +20,7 @@ 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 := -fno-common -fno-builtin -fno-stack-protector -ffixed-x18 ccflags-y += -DDISABLE_BRANCH_PROFILING
VDSO_LDFLAGS := -Bsymbolic
vDSO requires gettimeofday and clock_gettime syscalls to implement the fallback mechanism.
Add the missing syscall numbers to unistd.h for arm64.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Cc: Arnd Bergmann arnd@arndb.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/include/asm/unistd.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 70e6882853c0..81cc05acccc9 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -33,8 +33,13 @@ #define __NR_compat_exit 1 #define __NR_compat_read 3 #define __NR_compat_write 4 +#define __NR_compat_gettimeofday 78 #define __NR_compat_sigreturn 119 #define __NR_compat_rt_sigreturn 173 +#define __NR_compat_clock_getres 247 +#define __NR_compat_clock_gettime 263 +#define __NR_compat_clock_gettime64 403 +#define __NR_compat_clock_getres_time64 406
/* * The following SVCs are ARM private.
The compat signal data structures are required as part of the compat vDSO implementation in order to provide the unwinding information for the sigreturn trampolines.
Expose the mentioned data structures as part of signal32.h.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/include/asm/signal32.h | 46 +++++++++++++++++++++++++++++++ arch/arm64/kernel/signal32.c | 46 ------------------------------- 2 files changed, 46 insertions(+), 46 deletions(-)
diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h index 58e288aaf0ba..1f05268f4c6d 100644 --- a/arch/arm64/include/asm/signal32.h +++ b/arch/arm64/include/asm/signal32.h @@ -20,6 +20,52 @@ #ifdef CONFIG_COMPAT #include <linux/compat.h>
+struct compat_sigcontext { + /* We always set these two fields to 0 */ + compat_ulong_t trap_no; + compat_ulong_t error_code; + + compat_ulong_t oldmask; + compat_ulong_t arm_r0; + compat_ulong_t arm_r1; + compat_ulong_t arm_r2; + compat_ulong_t arm_r3; + compat_ulong_t arm_r4; + compat_ulong_t arm_r5; + compat_ulong_t arm_r6; + compat_ulong_t arm_r7; + compat_ulong_t arm_r8; + compat_ulong_t arm_r9; + compat_ulong_t arm_r10; + compat_ulong_t arm_fp; + compat_ulong_t arm_ip; + compat_ulong_t arm_sp; + compat_ulong_t arm_lr; + compat_ulong_t arm_pc; + compat_ulong_t arm_cpsr; + compat_ulong_t fault_address; +}; + +struct compat_ucontext { + compat_ulong_t uc_flags; + compat_uptr_t uc_link; + compat_stack_t uc_stack; + struct compat_sigcontext uc_mcontext; + compat_sigset_t uc_sigmask; + int __unused[32 - (sizeof(compat_sigset_t) / sizeof(int))]; + compat_ulong_t uc_regspace[128] __attribute__((__aligned__(8))); +}; + +struct compat_sigframe { + struct compat_ucontext uc; + compat_ulong_t retcode[2]; +}; + +struct compat_rt_sigframe { + struct compat_siginfo info; + struct compat_sigframe sig; +}; + int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set, struct pt_regs *regs); int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set, diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index caea6e25db2a..74e06d8c7c2b 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -30,42 +30,6 @@ #include <linux/uaccess.h> #include <asm/unistd.h>
-struct compat_sigcontext { - /* We always set these two fields to 0 */ - compat_ulong_t trap_no; - compat_ulong_t error_code; - - compat_ulong_t oldmask; - compat_ulong_t arm_r0; - compat_ulong_t arm_r1; - compat_ulong_t arm_r2; - compat_ulong_t arm_r3; - compat_ulong_t arm_r4; - compat_ulong_t arm_r5; - compat_ulong_t arm_r6; - compat_ulong_t arm_r7; - compat_ulong_t arm_r8; - compat_ulong_t arm_r9; - compat_ulong_t arm_r10; - compat_ulong_t arm_fp; - compat_ulong_t arm_ip; - compat_ulong_t arm_sp; - compat_ulong_t arm_lr; - compat_ulong_t arm_pc; - compat_ulong_t arm_cpsr; - compat_ulong_t fault_address; -}; - -struct compat_ucontext { - compat_ulong_t uc_flags; - compat_uptr_t uc_link; - compat_stack_t uc_stack; - struct compat_sigcontext uc_mcontext; - compat_sigset_t uc_sigmask; - int __unused[32 - (sizeof (compat_sigset_t) / sizeof (int))]; - compat_ulong_t uc_regspace[128] __attribute__((__aligned__(8))); -}; - struct compat_vfp_sigframe { compat_ulong_t magic; compat_ulong_t size; @@ -92,16 +56,6 @@ struct compat_aux_sigframe { unsigned long end_magic; } __attribute__((__aligned__(8)));
-struct compat_sigframe { - struct compat_ucontext uc; - compat_ulong_t retcode[2]; -}; - -struct compat_rt_sigframe { - struct compat_siginfo info; - struct compat_sigframe sig; -}; - #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
Update asm-offsets for arm64 to generate the correct offsets for compat signals.
They will be useful for the implementation of the compat sigreturn trampolines in vDSO context.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/kernel/asm-offsets.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 9e4b7ccbab2f..c0d8b9f40022 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -30,6 +30,7 @@ #include <asm/fixmap.h> #include <asm/thread_info.h> #include <asm/memory.h> +#include <asm/signal32.h> #include <asm/smp_plat.h> #include <asm/suspend.h> #include <linux/kbuild.h> @@ -77,6 +78,11 @@ int main(void) DEFINE(S_STACKFRAME, offsetof(struct pt_regs, stackframe)); DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); BLANK(); +#ifdef CONFIG_COMPAT + DEFINE(COMPAT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_sigframe, uc.uc_mcontext.arm_r0)); + DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET, offsetof(struct compat_rt_sigframe, sig.uc.uc_mcontext.arm_r0)); + BLANK(); +#endif DEFINE(MM_CONTEXT_ID, offsetof(struct mm_struct, context.id.counter)); BLANK(); DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));
Some 64 bit architectures have support for 32 bit applications that require a separate version of the vDSOs.
Add support to the generic code for compat fallback functions.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- lib/vdso/gettimeofday.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index 473e2dda0220..fc43f457ed2c 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -21,7 +21,11 @@ * - clock_gettime_fallback(): fallback for clock_gettime. * - clock_getres_fallback(): fallback for clock_getres. */ +#ifdef ENABLE_COMPAT_VDSO +#include <asm/vdso/compat_gettimeofday.h> +#else #include <asm/vdso/gettimeofday.h> +#endif /* ENABLE_COMPAT_VDSO */
static int do_hres(const struct vdso_data *vd, clockid_t clk,
Provide the arm64 compat (AArch32) vDSO in kernel/vdso32 in a similar way to what happens in kernel/vdso.
The compat vDSO leverages on an adaptation of the arm architecture code with few changes: - Use of lib/vdso for gettimeofday - Implementation of syscall based fallback - Introduction of clock_getres for the compat library - Implementation of trampolines - Implementation of elf note
To build the compat vDSO a 32 bit compiler is required and needs to be specified via CONFIG_CROSS_COMPILE_COMPAT_VDSO.
The implementation of the configuration option will be contained in a future patch.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/include/asm/vdso/compat_barrier.h | 51 +++++ .../include/asm/vdso/compat_gettimeofday.h | 110 +++++++++++ arch/arm64/kernel/vdso32/.gitignore | 2 + arch/arm64/kernel/vdso32/Makefile | 186 ++++++++++++++++++ arch/arm64/kernel/vdso32/note.c | 15 ++ arch/arm64/kernel/vdso32/sigreturn.S | 62 ++++++ arch/arm64/kernel/vdso32/vdso.S | 19 ++ arch/arm64/kernel/vdso32/vdso.lds.S | 82 ++++++++ arch/arm64/kernel/vdso32/vgettimeofday.c | 59 ++++++ 9 files changed, 586 insertions(+) create mode 100644 arch/arm64/include/asm/vdso/compat_barrier.h create mode 100644 arch/arm64/include/asm/vdso/compat_gettimeofday.h create mode 100644 arch/arm64/kernel/vdso32/.gitignore create mode 100644 arch/arm64/kernel/vdso32/Makefile create mode 100644 arch/arm64/kernel/vdso32/note.c create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S create mode 100644 arch/arm64/kernel/vdso32/vdso.S create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
diff --git a/arch/arm64/include/asm/vdso/compat_barrier.h b/arch/arm64/include/asm/vdso/compat_barrier.h new file mode 100644 index 000000000000..ea24ea856b07 --- /dev/null +++ b/arch/arm64/include/asm/vdso/compat_barrier.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 ARM Limited + */ +#ifndef __COMPAT_BARRIER_H +#define __COMPAT_BARRIER_H + +#ifndef __ASSEMBLY__ +/* + * Warning: This code is meant to be used with + * ENABLE_COMPAT_VDSO only. + */ +#ifndef ENABLE_COMPAT_VDSO +#error This header is meant to be used with ENABLE_COMPAT_VDSO only +#endif + +#ifdef dmb +#undef dmb +#endif + +#if __LINUX_ARM_ARCH__ >= 7 +#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") +#elif __LINUX_ARM_ARCH__ == 6 +#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ + : : "r" (0) : "memory") +#else +#define dmb(x) __asm__ __volatile__ ("" : : : "memory") +#endif + +#if __LINUX_ARM_ARCH__ >= 8 +#define aarch32_smp_mb() dmb(ish) +#define aarch32_smp_rmb() dmb(ishld) +#define aarch32_smp_wmb() dmb(ishst) +#else +#define aarch32_smp_mb() dmb(ish) +#define aarch32_smp_rmb() aarch32_smp_mb() +#define aarch32_smp_wmb() dmb(ishst) +#endif + + +#undef smp_mb +#undef smp_rmb +#undef smp_wmb + +#define smp_mb() aarch32_smp_mb() +#define smp_rmb() aarch32_smp_rmb() +#define smp_wmb() aarch32_smp_wmb() + +#endif /* !__ASSEMBLY__ */ + +#endif /* __COMPAT_BARRIER_H */ diff --git a/arch/arm64/include/asm/vdso/compat_gettimeofday.h b/arch/arm64/include/asm/vdso/compat_gettimeofday.h new file mode 100644 index 000000000000..7a39c8340936 --- /dev/null +++ b/arch/arm64/include/asm/vdso/compat_gettimeofday.h @@ -0,0 +1,110 @@ +/* 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> + +#include <asm/vdso/compat_barrier.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("r1") = _tz; + register struct __kernel_old_timeval *tv asm("r0") = _tv; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_compat_gettimeofday; + + asm volatile( + " swi #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("r1") = _ts; + register clockid_t clkid asm("r0") = _clkid; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_compat_clock_gettime64; + + asm volatile( + " swi #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("r1") = _ts; + register clockid_t clkid asm("r0") = _clkid; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_compat_clock_getres_time64; + + /* The checks below are required for ABI consistency with arm */ + if ((_clkid >= MAX_CLOCKS) && (_ts == NULL)) + return -EINVAL; + + asm volatile( + " swi #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; + + isb(); + asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (res)); + + return res; +} + +static __always_inline const struct vdso_data *__arch_get_vdso_data(void) +{ + const struct vdso_data *ret; + + /* + * This simply puts &_vdso_data into ret. The reason why we don't use + * `ret = _vdso_data` is that the compiler tends to optimise this in a + * very suboptimal way: instead of keeping &_vdso_data in a register, + * it goes through a relocation almost every time _vdso_data must be + * accessed (even in subfunctions). This is both time and space + * consuming: each relocation uses a word in the code section, and it + * has to be loaded at runtime. + * + * This trick hides the assignment from the compiler. Since it cannot + * track where the pointer comes from, it will only use one relocation + * where __arch_get_vdso_data() is called, and then keep the result in + * a register. + */ + asm volatile("mov %0, %1" : "=r"(ret) : "r"(_vdso_data)); + + return ret; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/arm64/kernel/vdso32/.gitignore b/arch/arm64/kernel/vdso32/.gitignore new file mode 100644 index 000000000000..4fea950fa5ed --- /dev/null +++ b/arch/arm64/kernel/vdso32/.gitignore @@ -0,0 +1,2 @@ +vdso.lds +vdso.so.raw diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile new file mode 100644 index 000000000000..288c14d30b45 --- /dev/null +++ b/arch/arm64/kernel/vdso32/Makefile @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for vdso32 +# + +# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before +# the inclusion of generic Makefile. +ARCH_REL_TYPE_ABS := R_ARM_JUMP_SLOT|R_ARM_GLOB_DAT|R_ARM_ABS32 +include $(srctree)/lib/vdso/Makefile + +COMPATCC := $(CROSS_COMPILE_COMPAT)gcc + +# Same as cc-*option, but using COMPATCC instead of CC +cc32-option = $(call try-run,\ + $(COMPATCC) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) +cc32-disable-warning = $(call try-run,\ + $(COMPATCC) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) +cc32-ldoption = $(call try-run,\ + $(COMPATCC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) + +# We cannot use the global flags to compile the vDSO files, the main reason +# being that the 32-bit compiler may be older than the main (64-bit) compiler +# and therefore may not understand flags set using $(cc-option ...). Besides, +# arch-specific options should be taken from the arm Makefile instead of the +# arm64 one. +# As a result we set our own flags here. + +# From top-level Makefile +# NOSTDINC_FLAGS +VDSO_CPPFLAGS := -nostdinc -isystem $(shell $(COMPATCC) -print-file-name=include) +VDSO_CPPFLAGS += $(LINUXINCLUDE) +VDSO_CPPFLAGS += $(KBUILD_CPPFLAGS) + +# Common C and assembly flags +# From top-level Makefile +VDSO_CAFLAGS := $(VDSO_CPPFLAGS) +VDSO_CAFLAGS += $(call cc32-option,-fno-PIE) +ifdef CONFIG_DEBUG_INFO +VDSO_CAFLAGS += -g +endif +ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(COMPATCC)), y) +VDSO_CAFLAGS += -DCC_HAVE_ASM_GOTO +endif + +# From arm Makefile +VDSO_CAFLAGS += $(call cc32-option,-fno-dwarf2-cfi-asm) +VDSO_CAFLAGS += -mabi=aapcs-linux -mfloat-abi=soft +ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) +VDSO_CAFLAGS += -mbig-endian +else +VDSO_CAFLAGS += -mlittle-endian +endif + +# From arm vDSO Makefile +VDSO_CAFLAGS += -fPIC -fno-builtin -fno-stack-protector +VDSO_CAFLAGS += -DDISABLE_BRANCH_PROFILING + +# Try to compile for ARMv8. If the compiler is too old and doesn't support it, +# fall back to v7. There is no easy way to check for what architecture the code +# is being compiled, so define a macro specifying that (see arch/arm/Makefile). +VDSO_CAFLAGS += $(call cc32-option,-march=armv8-a -D__LINUX_ARM_ARCH__=8,\ + -march=armv7-a -D__LINUX_ARM_ARCH__=7) + +VDSO_CFLAGS := $(VDSO_CAFLAGS) +VDSO_CFLAGS += -DENABLE_COMPAT_VDSO=1 +# KBUILD_CFLAGS from top-level Makefile +VDSO_CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ + -fno-strict-aliasing -fno-common \ + -Werror-implicit-function-declaration \ + -Wno-format-security \ + -std=gnu89 +VDSO_CFLAGS += -O2 +# Some useful compiler-dependent flags from top-level Makefile +VDSO_CFLAGS += $(call cc32-option,-Wdeclaration-after-statement,) +VDSO_CFLAGS += $(call cc32-option,-Wno-pointer-sign) +VDSO_CFLAGS += $(call cc32-option,-fno-strict-overflow) +VDSO_CFLAGS += $(call cc32-option,-Werror=strict-prototypes) +VDSO_CFLAGS += $(call cc32-option,-Werror=date-time) +VDSO_CFLAGS += $(call cc32-option,-Werror=incompatible-pointer-types) + +# The 32-bit compiler does not provide 128-bit integers, which are used in +# some headers that are indirectly included from the vDSO code. +# This hack makes the compiler happy and should trigger a warning/error if +# variables of such type are referenced. +VDSO_CFLAGS += -D__uint128_t='void*' +# Silence some warnings coming from headers that operate on long's +# (on GCC 4.8 or older, there is unfortunately no way to silence this warning) +VDSO_CFLAGS += $(call cc32-disable-warning,shift-count-overflow) +VDSO_CFLAGS += -Wno-int-to-pointer-cast + +VDSO_AFLAGS := $(VDSO_CAFLAGS) +VDSO_AFLAGS += -D__ASSEMBLY__ + +VDSO_LDFLAGS := $(VDSO_CPPFLAGS) +# From arm vDSO Makefile +VDSO_LDFLAGS += -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 +VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 +VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft +VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--hash-style=sysv) +VDSO_LDFLAGS += $(call cc32-ldoption,-Wl$(comma)--build-id) +VDSO_LDFLAGS += $(call cc32-ldoption,-fuse-ld=bfd) + + +# Borrow vdsomunge.c from the arm vDSO +# We have to use a relative path because scripts/Makefile.host prefixes +# $(hostprogs-y) with $(obj) +munge := ../../../arm/vdso/vdsomunge +hostprogs-y := $(munge) + +c-obj-vdso := note.o +c-obj-vdso-gettimeofday := vgettimeofday.o +asm-obj-vdso := sigreturn.o + +ifneq ($(c-gettimeofday-y),) +VDSO_CFLAGS_gettimeofday_o += -include $(c-gettimeofday-y) +endif + +VDSO_CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os + +# Build rules +targets := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw +c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso)) +c-obj-vdso-gettimeofday := $(addprefix $(obj)/, $(c-obj-vdso-gettimeofday)) +asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso)) +obj-vdso := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) + +obj-y += vdso.o +extra-y += vdso.lds +CPPFLAGS_vdso.lds += -P -C -U$(ARCH) + +# Force dependency (vdso.s includes vdso.so through incbin) +$(obj)/vdso.o: $(obj)/vdso.so + +include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE + $(call if_changed,vdsosym) + +# Strip rule for vdso.so +$(obj)/vdso.so: OBJCOPYFLAGS := -S +$(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE + $(call if_changed,objcopy) + +$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/$(munge) FORCE + $(call if_changed,vdsomunge) + +# Link rule for the .so file, .lds has to be first +$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE + $(call if_changed,vdsold) + $(call if_changed,vdso_check) + +# Compilation rules for the vDSO sources +$(c-obj-vdso): %.o: %.c FORCE + $(call if_changed_dep,vdsocc) +$(c-obj-vdso-gettimeofday): %.o: %.c FORCE + $(call if_changed_dep,vdsocc_gettimeofday) +$(asm-obj-vdso): %.o: %.S FORCE + $(call if_changed_dep,vdsoas) + +# Actual build commands +quiet_cmd_vdsold = VDSOL $@ + cmd_vdsold = $(COMPATCC) -Wp,-MD,$(depfile) $(VDSO_LDFLAGS) \ + -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@ +quiet_cmd_vdsocc = VDSOC $@ + cmd_vdsocc = $(COMPATCC) -Wp,-MD,$(depfile) $(VDSO_CFLAGS) -c -o $@ $< +quiet_cmd_vdsocc_gettimeofday = VDSOC_GTD $@ + cmd_vdsocc_gettimeofday = $(COMPATCC) -Wp,-MD,$(depfile) $(VDSO_CFLAGS) $(VDSO_CFLAGS_gettimeofday_o) -c -o $@ $< +quiet_cmd_vdsoas = VDSOA $@ + cmd_vdsoas = $(COMPATCC) -Wp,-MD,$(depfile) $(VDSO_AFLAGS) -c -o $@ $< + +quiet_cmd_vdsomunge = MUNGE $@ + cmd_vdsomunge = $(obj)/$(munge) $< $@ + +# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO) +gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh +quiet_cmd_vdsosym = VDSOSYM $@ +# The AArch64 nm should be able to read an AArch32 binary + cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@ + +# Install commands for the unstripped file +quiet_cmd_vdso_install = INSTALL $@ + cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so + +vdso.so: $(obj)/vdso.so.dbg + @mkdir -p $(MODLIB)/vdso + $(call cmd,vdso_install) + +vdso_install: vdso.so diff --git a/arch/arm64/kernel/vdso32/note.c b/arch/arm64/kernel/vdso32/note.c new file mode 100644 index 000000000000..eff5bf9efb8b --- /dev/null +++ b/arch/arm64/kernel/vdso32/note.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2012-2018 ARM Limited + * + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include <linux/uts.h> +#include <linux/version.h> +#include <linux/elfnote.h> +#include <linux/build-salt.h> + +ELFNOTE32("Linux", 0, LINUX_VERSION_CODE); +BUILD_SALT; diff --git a/arch/arm64/kernel/vdso32/sigreturn.S b/arch/arm64/kernel/vdso32/sigreturn.S new file mode 100644 index 000000000000..1a81277c2d09 --- /dev/null +++ b/arch/arm64/kernel/vdso32/sigreturn.S @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file provides both A32 and T32 versions, in accordance with the + * arm sigreturn code. + * + * Copyright (C) 2018 ARM Limited + */ + +#include <linux/linkage.h> +#include <asm/asm-offsets.h> +#include <asm/unistd.h> + +#define ARM_ENTRY(name) \ + ENTRY(name) + +#define ARM_ENDPROC(name) \ + .type name, %function; \ + END(name) + + .text + + .arm + .fnstart + .save {r0-r15} + .pad #COMPAT_SIGFRAME_REGS_OFFSET + nop +ARM_ENTRY(__kernel_sigreturn_arm) + mov r7, #__NR_compat_sigreturn + svc #0 + .fnend +ARM_ENDPROC(__kernel_sigreturn_arm) + + .fnstart + .save {r0-r15} + .pad #COMPAT_RT_SIGFRAME_REGS_OFFSET + nop +ARM_ENTRY(__kernel_rt_sigreturn_arm) + mov r7, #__NR_compat_rt_sigreturn + svc #0 + .fnend +ARM_ENDPROC(__kernel_rt_sigreturn_arm) + + .thumb + .fnstart + .save {r0-r15} + .pad #COMPAT_SIGFRAME_REGS_OFFSET + nop +ARM_ENTRY(__kernel_sigreturn_thumb) + mov r7, #__NR_compat_sigreturn + svc #0 + .fnend +ARM_ENDPROC(__kernel_sigreturn_thumb) + + .fnstart + .save {r0-r15} + .pad #COMPAT_RT_SIGFRAME_REGS_OFFSET + nop +ARM_ENTRY(__kernel_rt_sigreturn_thumb) + mov r7, #__NR_compat_rt_sigreturn + svc #0 + .fnend +ARM_ENDPROC(__kernel_rt_sigreturn_thumb) diff --git a/arch/arm64/kernel/vdso32/vdso.S b/arch/arm64/kernel/vdso32/vdso.S new file mode 100644 index 000000000000..e72ac7bc4c04 --- /dev/null +++ b/arch/arm64/kernel/vdso32/vdso.S @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 ARM Limited + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <linux/const.h> +#include <asm/page.h> + + .globl vdso32_start, vdso32_end + .section .rodata + .balign PAGE_SIZE +vdso32_start: + .incbin "arch/arm64/kernel/vdso32/vdso.so" + .balign PAGE_SIZE +vdso32_end: + + .previous diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S new file mode 100644 index 000000000000..a3944927eaeb --- /dev/null +++ b/arch/arm64/kernel/vdso32/vdso.lds.S @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Adapted from arm64 version. + * + * GNU linker script for the VDSO library. + * Heavily based on the vDSO linker scripts for other archs. + * + * Copyright (C) 2012-2018 ARM Limited + */ + +#include <linux/const.h> +#include <asm/page.h> +#include <asm/vdso.h> + +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) + +SECTIONS +{ + PROVIDE_HIDDEN(_vdso_data = . - PAGE_SIZE); + . = VDSO_LBASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + .note : { *(.note.*) } :text :note + + .dynamic : { *(.dynamic) } :text :dynamic + + .rodata : { *(.rodata*) } :text + + .text : { *(.text*) } :text =0xe7f001f2 + + .got : { *(.got) } + .rel.plt : { *(.rel.plt) } + + /DISCARD/ : { + *(.note.GNU-stack) + *(.data .data.* .gnu.linkonce.d.* .sdata*) + *(.bss .sbss .dynbss .dynsbss) + } +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ +} + +VERSION +{ + LINUX_2.6 { + global: + __vdso_clock_gettime; + __vdso_gettimeofday; + __vdso_clock_getres; + __kernel_sigreturn_arm; + __kernel_sigreturn_thumb; + __kernel_rt_sigreturn_arm; + __kernel_rt_sigreturn_thumb; + __vdso_clock_gettime64; + local: *; + }; +} + +/* + * Make the sigreturn code visible to the kernel. + */ +VDSO_compat_sigreturn_arm = __kernel_sigreturn_arm; +VDSO_compat_sigreturn_thumb = __kernel_sigreturn_thumb; +VDSO_compat_rt_sigreturn_arm = __kernel_rt_sigreturn_arm; +VDSO_compat_rt_sigreturn_thumb = __kernel_rt_sigreturn_thumb; diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c new file mode 100644 index 000000000000..54fc1c2ce93f --- /dev/null +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM64 compat userspace implementations of gettimeofday() and similar. + * + * Copyright (C) 2018 ARM Limited + * + */ +#include <linux/time.h> +#include <linux/types.h> + +int __vdso_clock_gettime(clockid_t clock, + struct old_timespec32 *ts) +{ + /* The checks below are required for ABI consistency with arm */ + if ((u32)ts >= TASK_SIZE_32) + return -EFAULT; + + return __cvdso_clock_gettime32(clock, ts); +} + +int __vdso_clock_gettime64(clockid_t clock, + struct __kernel_timespec *ts) +{ + /* The checks below are required for ABI consistency with arm */ + if ((u32)ts >= TASK_SIZE_32) + return -EFAULT; + + return __cvdso_clock_gettime(clock, ts); +} + +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) +{ + return __cvdso_gettimeofday(tv, tz); +} + +int __vdso_clock_getres(clockid_t clock_id, + struct old_timespec32 *res) +{ + /* The checks below are required for ABI consistency with arm */ + if ((u32)res >= TASK_SIZE_32) + return -EFAULT; + + return __cvdso_clock_getres_time32(clock_id, res); +} + +/* Avoid unresolved references emitted by GCC */ + +void __aeabi_unwind_cpp_pr0(void) +{ +} + +void __aeabi_unwind_cpp_pr1(void) +{ +} + +void __aeabi_unwind_cpp_pr2(void) +{ +}
On Fri, Jun 21, 2019 at 10:52:37AM +0100, Vincenzo Frascino wrote:
--- /dev/null +++ b/arch/arm64/include/asm/vdso/compat_barrier.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (C) 2018 ARM Limited
- */
+#ifndef __COMPAT_BARRIER_H +#define __COMPAT_BARRIER_H
+#ifndef __ASSEMBLY__ +/*
- Warning: This code is meant to be used with
- ENABLE_COMPAT_VDSO only.
- */
+#ifndef ENABLE_COMPAT_VDSO +#error This header is meant to be used with ENABLE_COMPAT_VDSO only +#endif
+#ifdef dmb +#undef dmb +#endif
+#if __LINUX_ARM_ARCH__ >= 7 +#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") +#elif __LINUX_ARM_ARCH__ == 6 +#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
: : "r" (0) : "memory")
+#else +#define dmb(x) __asm__ __volatile__ ("" : : : "memory") +#endif
We don't need pre-ARMv7 barriers (they've been deprecated and the arm64 kernel actually traps and emulates them by default). Also your Makefile changes never define a __LINUX_ARM_ARCH__ lower than 7. Fix-up below:
------8<-----------------------
From 5655a0313ce7bb731bfed6a19bcfe6b1100b542a Mon Sep 17 00:00:00 2001
From: Catalin Marinas catalin.marinas@arm.com Date: Mon, 24 Jun 2019 12:16:06 +0100 Subject: [PATCH] arm64: compat: No need for pre-ARMv7 barriers on an ARMv8 system
This patch removes the deprecated (pre-ARMv7) compat barriers as they would not be used on an ARMv8 system.
Fixes: a7f71a2c8903 ("arm64: compat: Add vDSO") Signed-off-by: Catalin Marinas catalin.marinas@arm.com --- arch/arm64/include/asm/vdso/compat_barrier.h | 7 ------- 1 file changed, 7 deletions(-)
diff --git a/arch/arm64/include/asm/vdso/compat_barrier.h b/arch/arm64/include/asm/vdso/compat_barrier.h index ea24ea856b07..fb60a88b5ed4 100644 --- a/arch/arm64/include/asm/vdso/compat_barrier.h +++ b/arch/arm64/include/asm/vdso/compat_barrier.h @@ -18,14 +18,7 @@ #undef dmb #endif
-#if __LINUX_ARM_ARCH__ >= 7 #define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory") -#elif __LINUX_ARM_ARCH__ == 6 -#define dmb(x) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \ - : : "r" (0) : "memory") -#else -#define dmb(x) __asm__ __volatile__ ("" : : : "memory") -#endif
#if __LINUX_ARM_ARCH__ >= 8 #define aarch32_smp_mb() dmb(ish)
On Fri, Jun 21, 2019 at 3:18 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Provide the arm64 compat (AArch32) vDSO in kernel/vdso32 in a similar way to what happens in kernel/vdso.
The compat vDSO leverages on an adaptation of the arm architecture code with few changes:
- Use of lib/vdso for gettimeofday
- Implementation of syscall based fallback
- Introduction of clock_getres for the compat library
- Implementation of trampolines
- Implementation of elf note
To build the compat vDSO a 32 bit compiler is required and needs to be specified via CONFIG_CROSS_COMPILE_COMPAT_VDSO.
Hey Vincenzo! Congrats on getting this work merged, I know its been a long effort over a number of years!
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
thanks -john
On Tue, 9 Jul 2019, John Stultz wrote:
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
The obvious question is whether the VDSO is mapped to the 32bit process in that case. It shouldn't...
Thanks,
tglx
On 10/07/2019 07:12, Thomas Gleixner wrote:
On Tue, 9 Jul 2019, John Stultz wrote:
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
The obvious question is whether the VDSO is mapped to the 32bit process in that case. It shouldn't...
Agreed. I am investing if/why this is happening and will post a fix accordingly.
Thanks,
tglx
Hi John,
On Tue, Jul 09, 2019 at 09:02:54PM -0700, John Stultz wrote:
On Fri, Jun 21, 2019 at 3:18 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Provide the arm64 compat (AArch32) vDSO in kernel/vdso32 in a similar way to what happens in kernel/vdso.
The compat vDSO leverages on an adaptation of the arm architecture code with few changes:
- Use of lib/vdso for gettimeofday
- Implementation of syscall based fallback
- Introduction of clock_getres for the compat library
- Implementation of trampolines
- Implementation of elf note
To build the compat vDSO a 32 bit compiler is required and needs to be specified via CONFIG_CROSS_COMPILE_COMPAT_VDSO.
Hey Vincenzo! Congrats on getting this work merged, I know its been a long effort over a number of years!
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
First I've seen of it, although Vincenzo is likely to know better than me. In the meantime, please can you share your .config?
Thanks,
Will
On Wed, 10 Jul 2019, Will Deacon wrote:
On Tue, Jul 09, 2019 at 09:02:54PM -0700, John Stultz wrote:
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
First I've seen of it, although Vincenzo is likely to know better than me. In the meantime, please can you share your .config?
I think the key is: CROSS_COMPILE_COMPAT not defined or empty. And then run 32bit userspace.
Thanks,
tglx
On Wed, Jul 10, 2019 at 10:58:25AM +0200, Thomas Gleixner wrote:
On Wed, 10 Jul 2019, Will Deacon wrote:
On Tue, Jul 09, 2019 at 09:02:54PM -0700, John Stultz wrote:
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
First I've seen of it, although Vincenzo is likely to know better than me. In the meantime, please can you share your .config?
I think the key is: CROSS_COMPILE_COMPAT not defined or empty. And then run 32bit userspace.
The part I was wondering about is whether the vectors page has been disabled at the same time, since I'm fairly sure I've already been running with the above (but I can easily double-check).
Will
Hi John,
On 10/07/2019 05:02, John Stultz wrote:
On Fri, Jun 21, 2019 at 3:18 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Provide the arm64 compat (AArch32) vDSO in kernel/vdso32 in a similar way to what happens in kernel/vdso.
The compat vDSO leverages on an adaptation of the arm architecture code with few changes:
- Use of lib/vdso for gettimeofday
- Implementation of syscall based fallback
- Introduction of clock_getres for the compat library
- Implementation of trampolines
- Implementation of elf note
To build the compat vDSO a 32 bit compiler is required and needs to be specified via CONFIG_CROSS_COMPILE_COMPAT_VDSO.
Hey Vincenzo! Congrats on getting this work merged, I know its been a long effort over a number of years!
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
I do not have Android (bionic/libc) as part of my testing environment hence I never saw this issue. Thanks for reporting it.
I am investigating the problem and will post a fix as soon as it is ready.
As Will suggested, .config would help the debugging and I would like to ask to you to test my fix once it is ready. Is that OK for you?
thanks -john
Hi John,
On 10/07/2019 10:47, Vincenzo Frascino wrote:
Hi John,
On 10/07/2019 05:02, John Stultz wrote:
On Fri, Jun 21, 2019 at 3:18 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Provide the arm64 compat (AArch32) vDSO in kernel/vdso32 in a similar way to what happens in kernel/vdso.
The compat vDSO leverages on an adaptation of the arm architecture code with few changes:
- Use of lib/vdso for gettimeofday
- Implementation of syscall based fallback
- Introduction of clock_getres for the compat library
- Implementation of trampolines
- Implementation of elf note
To build the compat vDSO a 32 bit compiler is required and needs to be specified via CONFIG_CROSS_COMPILE_COMPAT_VDSO.
Hey Vincenzo! Congrats on getting this work merged, I know its been a long effort over a number of years!
Though unfortunately, it seems the arm64 vdso code that just landed is breaking AOSP for me.
I see a lot of the following errors: 01-01 01:22:14.097 755 755 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 755 (cameraserver), pid 755 (cameraserver) 01-01 01:22:14.112 759 759 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 759 (android.hardwar), pid 759 (android.hardwar) 01-01 01:22:14.120 756 756 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3cf2c96c in tid 756 (drmserver), pid 756 (drmserver)
Which go away if I revert the vdso merge that went in via tip/timers.
I tried to bisect things down a bit, but as some later fixes are required (at one point, date was returning the start epoch and never increasing), this hasn't worked too well. But I'm guessing since I see: "CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built", and the system is half working, I'm guessing this is an issue with just the 32bit code failing. While I can try to sort out the proper CROSS_COMPILE_COMPAT in my build environment, I assume userland shouldn't be crashing if that value isn't set.
Any chance this issue has already been raised?
I do not have Android (bionic/libc) as part of my testing environment hence I never saw this issue. Thanks for reporting it.
I am investigating the problem and will post a fix as soon as it is ready.
As Will suggested, .config would help the debugging and I would like to ask to you to test my fix once it is ready. Is that OK for you?
thanks -john
Seems that the problem you are experiencing is caused by an ABI regression for which I provided a fix in [1]. Could you please verify that works for you as well?
[1] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg2046889.html
Please find below the tests that I conducted to verify that when CROSS_COMPILE_COMPAT is not defined or empty the compat vdso library is not exposed.
# cat main-arm32.c
#include <stdio.h> #include <sys/auxv.h>
int main() { uintptr_t vdso = (uintptr_t) getauxval(AT_SYSINFO_EHDR);
printf("AT_SYSINFO_EHDR: %p\n", vdso);
[...]
return 0; }
# file main-arm32 main-arm32: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, with d
When CROSS_COMPILE_COMPAT is _not_ defined: ===========================================
# ./main-arm32 AT_SYSINFO_EHDR: (nil)
Memory Map: -----------
00008000-00010000 rw-p 00000000 00:00 0 00010000-00011000 r-xp 00000000 00:13 24905929 /home/vinfra01/bin/main-arm32 00011000-00020000 rw-p 00000000 00:00 0 00020000-00021000 r--p 00000000 00:13 24905929 /home/vinfra01/bin/main-arm32 00021000-00022000 rw-p 00001000 00:13 24905929 /home/vinfra01/bin/main-arm32 00022000-f773d000 rw-p 00000000 00:00 0 [heap] f773d000-f781f000 r-xp 00000000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f781f000-f782f000 ---p 000e2000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f782f000-f7831000 r--p 000e2000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7831000-f7832000 rw-p 000e4000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7832000-f7835000 rw-p 00000000 00:00 0 f7835000-f784b000 rw-p 00000000 00:00 0 f784b000-f7863000 r-xp 00000000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7863000-f7870000 rw-p 00000000 00:00 0 f7870000-f7872000 rw-p 00000000 00:00 0 f7872000-f7873000 r-xp 00000000 00:00 0 [sigpage] f7873000-f7874000 r--p 00018000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7874000-f7875000 rw-p 00019000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7875000-ff77a000 rw-p 00000000 00:00 0 ff87a000-ff89b000 rw-p 00000000 00:00 0 [stack] ff89b000-ffff0000 rw-p 00000000 00:00 0 ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors] ffff1000-fffff000 rw-p 00000000 00:00 0
vdsotest for compat [2]: ------------------------
Note: vDSO version of clock_gettime not found clock-gettime-monotonic: syscall: 796 nsec/call clock-gettime-monotonic: libc: 816 nsec/call clock-gettime-monotonic: vdso: not tested Note: vDSO version of clock_gettime not found Note: vDSO version of clock_gettime not found Note: vDSO version of clock_getres not found clock-getres-monotonic: syscall: 567 nsec/call clock-getres-monotonic: libc: 581 nsec/call clock-getres-monotonic: vdso: not tested Note: vDSO version of clock_getres not found Note: vDSO version of clock_getres not found Note: vDSO version of clock_gettime not found clock-gettime-monotonic-coarse: syscall: 617 nsec/call clock-gettime-monotonic-coarse: libc: 656 nsec/call clock-gettime-monotonic-coarse: vdso: not tested Note: vDSO version of clock_gettime not found Note: vDSO version of clock_gettime not found Note: vDSO version of clock_getres not found clock-getres-monotonic-coarse: syscall: 591 nsec/call clock-getres-monotonic-coarse: libc: 614 nsec/call clock-getres-monotonic-coarse: vdso: not tested Note: vDSO version of clock_getres not found Note: vDSO version of clock_getres not found Note: vDSO version of clock_gettime not found clock-gettime-realtime: syscall: 819 nsec/call clock-gettime-realtime: libc: 858 nsec/call clock-gettime-realtime: vdso: not tested Note: vDSO version of clock_gettime not found Note: vDSO version of clock_gettime not found Note: vDSO version of clock_getres not found clock-getres-realtime: syscall: 567 nsec/call clock-getres-realtime: libc: 583 nsec/call clock-getres-realtime: vdso: not tested Note: vDSO version of clock_getres not found Note: vDSO version of clock_getres not found Note: vDSO version of clock_gettime not found clock-gettime-realtime-coarse: syscall: 599 nsec/call clock-gettime-realtime-coarse: libc: 638 nsec/call clock-gettime-realtime-coarse: vdso: not tested Note: vDSO version of clock_gettime not found Note: vDSO version of clock_gettime not found Note: vDSO version of clock_getres not found clock-getres-realtime-coarse: syscall: 591 nsec/call clock-getres-realtime-coarse: libc: 610 nsec/call clock-getres-realtime-coarse: vdso: not tested Note: vDSO version of clock_getres not found Note: vDSO version of clock_getres not found Note: vDSO version of getcpu not found getcpu: syscall: 431 nsec/call getcpu: libc: 451 nsec/call getcpu: vdso: not tested Note: vDSO version of getcpu not found Note: vDSO version of getcpu not found Note: vDSO version of gettimeofday not found gettimeofday: syscall: 765 nsec/call gettimeofday: libc: 808 nsec/call gettimeofday: vdso: not tested Note: vDSO version of gettimeofday not found Note: vDSO version of gettimeofday not found
When CROSS_COMPILE_COMPAT is defined: =====================================
# ./main-arm32 AT_SYSINFO_EHDR: 0xf7a67000
Memory map: -----------
00008000-00010000 rw-p 00000000 00:00 0 00010000-00011000 r-xp 00000000 00:13 24905929 /home/vinfra01/bin/main-arm32 00011000-00020000 rw-p 00000000 00:00 0 00020000-00021000 r--p 00000000 00:13 24905929 /home/vinfra01/bin/main-arm32 00021000-00022000 rw-p 00001000 00:13 24905929 /home/vinfra01/bin/main-arm32 00022000-f7932000 rw-p 00000000 00:00 0 [heap] f7932000-f7a14000 r-xp 00000000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7a14000-f7a24000 ---p 000e2000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7a24000-f7a26000 r--p 000e2000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7a26000-f7a27000 rw-p 000e4000 00:13 24906912 /lib/arm-linux-gnueabihf/libc-2.27.so f7a27000-f7a2a000 rw-p 00000000 00:00 0 f7a2a000-f7a40000 rw-p 00000000 00:00 0 f7a40000-f7a58000 r-xp 00000000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7a58000-f7a64000 rw-p 00000000 00:00 0 f7a64000-f7a66000 rw-p 00000000 00:00 0 f7a66000-f7a67000 r--p 00000000 00:00 0 [vvar] f7a67000-f7a68000 r-xp 00000000 00:00 0 [vdso] f7a68000-f7a69000 r--p 00018000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7a69000-f7a6a000 rw-p 00019000 00:13 24906908 /lib/arm-linux-gnueabihf/ld-2.27.so f7a6a000-ff6d8000 rw-p 00000000 00:00 0 ff7d8000-ff7f9000 rw-p 00000000 00:00 0 [stack] ff7f9000-ffff0000 rw-p 00000000 00:00 0 ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors] ffff1000-fffff000 rw-p 00000000 00:00 0
vdsotest for compat [2]: ------------------------
clock-gettime-monotonic: syscall: 700 nsec/call clock-gettime-monotonic: libc: 226 nsec/call clock-gettime-monotonic: vdso: 189 nsec/call clock-getres-monotonic: syscall: 582 nsec/call clock-getres-monotonic: libc: 581 nsec/call clock-getres-monotonic: vdso: 40 nsec/call clock-gettime-monotonic-coarse: syscall: 618 nsec/call clock-gettime-monotonic-coarse: libc: 103 nsec/call clock-gettime-monotonic-coarse: vdso: 85 nsec/call clock-getres-monotonic-coarse: syscall: 602 nsec/call clock-getres-monotonic-coarse: libc: 610 nsec/call clock-getres-monotonic-coarse: vdso: 64 nsec/call clock-gettime-realtime: syscall: 741 nsec/call clock-gettime-realtime: libc: 209 nsec/call clock-gettime-realtime: vdso: 189 nsec/call clock-getres-realtime: syscall: 627 nsec/call clock-getres-realtime: libc: 604 nsec/call clock-getres-realtime: vdso: 41 nsec/call clock-gettime-realtime-coarse: syscall: 640 nsec/call clock-gettime-realtime-coarse: libc: 105 nsec/call clock-gettime-realtime-coarse: vdso: 84 nsec/call clock-getres-realtime-coarse: syscall: 597 nsec/call clock-getres-realtime-coarse: libc: 608 nsec/call clock-getres-realtime-coarse: vdso: 46 nsec/call Note: vDSO version of getcpu not found getcpu: syscall: 492 nsec/call getcpu: libc: 492 nsec/call getcpu: vdso: not tested Note: vDSO version of getcpu not found Note: vDSO version of getcpu not found gettimeofday: syscall: 664 nsec/call gettimeofday: libc: 224 nsec/call gettimeofday: vdso: 185 nsec/call
[2] https://github.com/nathanlynch/vdsotest
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_GENERIC_COMPAT_VDSO and CONFIG_COMPAT_VDSO are enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b7992bb9d414 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#if defined(CONFIG_COMPAT_VDSO) && defined(CONFIG_GENERIC_COMPAT_VDSO) #define COMPAT_ARCH_DLINFO \ do { \ /* \
On Wed, Jul 10, 2019 at 02:04:52PM +0100, Vincenzo Frascino wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_GENERIC_COMPAT_VDSO and CONFIG_COMPAT_VDSO are enabled.
I think you could do a better job in the changelog of explaining what's actually going on here. The problem seems to be that you're advertising the presence of a non-existent vDSO to userspace.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b7992bb9d414 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#if defined(CONFIG_COMPAT_VDSO) && defined(CONFIG_GENERIC_COMPAT_VDSO)
Can't this just be #ifdef CONFIG_COMPAT_VDSO ?
John -- can you give this a whirl, please?
Cheers,
Will
On 10/07/2019 14:25, Will Deacon wrote:
On Wed, Jul 10, 2019 at 02:04:52PM +0100, Vincenzo Frascino wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_GENERIC_COMPAT_VDSO and CONFIG_COMPAT_VDSO are enabled.
I think you could do a better job in the changelog of explaining what's actually going on here. The problem seems to be that you're advertising the presence of a non-existent vDSO to userspace.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b7992bb9d414 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#if defined(CONFIG_COMPAT_VDSO) && defined(CONFIG_GENERIC_COMPAT_VDSO)
Can't this just be #ifdef CONFIG_COMPAT_VDSO ?
Yes, I realized it after I pushed the patch that CONFIG_GENERIC_COMPAT_VDSO can be removed. Posting v2 shortly.
John -- can you give this a whirl, please?
Cheers,
Will
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b618017205a3 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#ifdef CONFIG_COMPAT_VDSO #define COMPAT_ARCH_DLINFO \ do { \ /* \
On Wed, Jul 10, 2019 at 7:01 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This seems to solve it for me! Thanks so much for the quick turnaround on a fix. I really appreciate it!
Tested-by: John Stultz john.stultz@linaro.org
thanks -john
Hi John,
On 10/07/2019 16:44, John Stultz wrote:
On Wed, Jul 10, 2019 at 7:01 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This seems to solve it for me! Thanks so much for the quick turnaround on a fix. I really appreciate it!
Tested-by: John Stultz john.stultz@linaro.org
Thank you for the quick reply, it means I can go home early today ;-)
thanks -john
On Wed, Jul 10, 2019 at 03:01:19PM +0100, Vincenzo Frascino wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b618017205a3 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#ifdef CONFIG_COMPAT_VDSO #define COMPAT_ARCH_DLINFO \ do { \ /* \
Acked-by: Will Deacon will@kernel.org
I can take this at -rc1 via arm64 unless tglx plans to send it during the rest of the merge window. Please let me know.
Will
On Thu, 11 Jul 2019, Will Deacon wrote:
On Wed, Jul 10, 2019 at 03:01:19PM +0100, Vincenzo Frascino wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b618017205a3 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#ifdef CONFIG_COMPAT_VDSO #define COMPAT_ARCH_DLINFO \ do { \ /* \
Acked-by: Will Deacon will@kernel.org
I can take this at -rc1 via arm64 unless tglx plans to send it during the rest of the merge window. Please let me know.
I had no plan to pick it up, but if you want I can route it through timer urgents so it hits Linus tree before rc1.
Thanks,
tglx
On Thu, Jul 11, 2019 at 12:34:27PM +0200, Thomas Gleixner wrote:
On Thu, 11 Jul 2019, Will Deacon wrote:
On Wed, Jul 10, 2019 at 03:01:19PM +0100, Vincenzo Frascino wrote:
Prior to the introduction of Unified vDSO support and compat layer for vDSO on arm64, AT_SYSINFO_EHDR was not defined for compat tasks. In the current implementation, AT_SYSINFO_EHDR is defined even if the compat vdso layer is not built and this causes a regression in the expected behavior of the ABI.
Restore the ABI behavior making sure that AT_SYSINFO_EHDR for compat tasks is defined only when CONFIG_COMPAT_VDSO is enabled.
Reported-by: John Stultz john.stultz@linaro.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
arch/arm64/include/asm/elf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 3c7037c6ba9b..b618017205a3 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -202,7 +202,7 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) -#ifdef CONFIG_GENERIC_COMPAT_VDSO +#ifdef CONFIG_COMPAT_VDSO #define COMPAT_ARCH_DLINFO \ do { \ /* \
Acked-by: Will Deacon will@kernel.org
I can take this at -rc1 via arm64 unless tglx plans to send it during the rest of the merge window. Please let me know.
I had no plan to pick it up, but if you want I can route it through timer urgents so it hits Linus tree before rc1.
I don't think it's urgent, so I'll just queue it along with any other fixes that show up at -rc1.
Cheers,
Will
Most of the code for initializing the vDSOs in arm64 and compat will be in common, hence a refactor of the current code is required to avoid duplication and simplify maintainability.
Refactor vdso.c to simplify the implementation of arm64 vDSO compat (which will be pushed with a future patch).
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/kernel/vdso.c | 215 ++++++++++++++++++++++++++------------- 1 file changed, 144 insertions(+), 71 deletions(-)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index 23c38303a52a..aa1fb25a9fe4 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -40,7 +40,31 @@ #include <asm/vdso.h>
extern char vdso_start[], vdso_end[]; -static unsigned long vdso_pages __ro_after_init; + +/* vdso_lookup arch_index */ +enum arch_vdso_type { + ARM64_VDSO = 0, +}; +#define VDSO_TYPES (ARM64_VDSO + 1) + +struct __vdso_abi { + const char *name; + const char *vdso_code_start; + const char *vdso_code_end; + unsigned long vdso_pages; + /* Data Mapping */ + struct vm_special_mapping *dm; + /* Code Mapping */ + struct vm_special_mapping *cm; +}; + +static struct __vdso_abi vdso_lookup[VDSO_TYPES] __ro_after_init = { + { + .name = "vdso", + .vdso_code_start = vdso_start, + .vdso_code_end = vdso_end, + }, +};
/* * The vDSO data page. @@ -51,10 +75,110 @@ static union { } vdso_data_store __page_aligned_data; struct vdso_data *vdso_data = vdso_data_store.data;
+static int __vdso_remap(enum arch_vdso_type arch_index, + const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + unsigned long new_size = new_vma->vm_end - new_vma->vm_start; + unsigned long vdso_size = vdso_lookup[arch_index].vdso_code_end - + vdso_lookup[arch_index].vdso_code_start; + + if (vdso_size != new_size) + return -EINVAL; + + current->mm->context.vdso = (void *)new_vma->vm_start; + + return 0; +} + +static int __vdso_init(enum arch_vdso_type arch_index) +{ + int i; + struct page **vdso_pagelist; + unsigned long pfn; + + if (memcmp(vdso_lookup[arch_index].vdso_code_start, "\177ELF", 4)) { + pr_err("vDSO is not a valid ELF object!\n"); + return -EINVAL; + } + + vdso_lookup[arch_index].vdso_pages = ( + vdso_lookup[arch_index].vdso_code_end - + vdso_lookup[arch_index].vdso_code_start) >> + PAGE_SHIFT; + + /* Allocate the vDSO pagelist, plus a page for the data. */ + vdso_pagelist = kcalloc(vdso_lookup[arch_index].vdso_pages + 1, + sizeof(struct page *), + GFP_KERNEL); + if (vdso_pagelist == NULL) + return -ENOMEM; + + /* Grab the vDSO data page. */ + vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data)); + + + /* Grab the vDSO code pages. */ + pfn = sym_to_pfn(vdso_lookup[arch_index].vdso_code_start); + + for (i = 0; i < vdso_lookup[arch_index].vdso_pages; i++) + vdso_pagelist[i + 1] = pfn_to_page(pfn + i); + + vdso_lookup[arch_index].dm->pages = &vdso_pagelist[0]; + vdso_lookup[arch_index].cm->pages = &vdso_pagelist[1]; + + return 0; +} + +static int __setup_additional_pages(enum arch_vdso_type arch_index, + struct mm_struct *mm, + struct linux_binprm *bprm, + int uses_interp) +{ + unsigned long vdso_base, vdso_text_len, vdso_mapping_len; + void *ret; + + vdso_text_len = vdso_lookup[arch_index].vdso_pages << PAGE_SHIFT; + /* Be sure to map the data page */ + vdso_mapping_len = vdso_text_len + PAGE_SIZE; + + vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); + if (IS_ERR_VALUE(vdso_base)) { + ret = ERR_PTR(vdso_base); + goto up_fail; + } + + ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE, + VM_READ|VM_MAYREAD, + vdso_lookup[arch_index].dm); + if (IS_ERR(ret)) + goto up_fail; + + vdso_base += PAGE_SIZE; + mm->context.vdso = (void *)vdso_base; + ret = _install_special_mapping(mm, vdso_base, vdso_text_len, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, + vdso_lookup[arch_index].cm); + if (IS_ERR(ret)) + goto up_fail; + + return 0; + +up_fail: + mm->context.vdso = NULL; + return PTR_ERR(ret); +} + #ifdef CONFIG_COMPAT /* * Create and map the vectors page for AArch32 tasks. */ +/* + * aarch32_vdso_pages: + * 0 - kuser helpers + * 1 - sigreturn code + */ #define C_VECTORS 0 #define C_SIGPAGE 1 #define C_PAGES (C_SIGPAGE + 1) @@ -183,18 +307,18 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) static int vdso_mremap(const struct vm_special_mapping *sm, struct vm_area_struct *new_vma) { - unsigned long new_size = new_vma->vm_end - new_vma->vm_start; - unsigned long vdso_size = vdso_end - vdso_start; - - if (vdso_size != new_size) - return -EINVAL; - - current->mm->context.vdso = (void *)new_vma->vm_start; - - return 0; + return __vdso_remap(ARM64_VDSO, sm, new_vma); }
-static struct vm_special_mapping vdso_spec[2] __ro_after_init = { +/* + * aarch64_vdso_pages: + * 0 - vvar + * 1 - vdso + */ +#define A_VVAR 0 +#define A_VDSO 1 +#define A_PAGES (A_VDSO + 1) +static struct vm_special_mapping vdso_spec[A_PAGES] __ro_after_init = { { .name = "[vvar]", }, @@ -206,37 +330,10 @@ static struct vm_special_mapping vdso_spec[2] __ro_after_init = {
static int __init vdso_init(void) { - int i; - struct page **vdso_pagelist; - unsigned long pfn; - - if (memcmp(vdso_start, "\177ELF", 4)) { - pr_err("vDSO is not a valid ELF object!\n"); - return -EINVAL; - } - - vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; - - /* Allocate the vDSO pagelist, plus a page for the data. */ - vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *), - GFP_KERNEL); - if (vdso_pagelist == NULL) - return -ENOMEM; - - /* Grab the vDSO data page. */ - vdso_pagelist[0] = phys_to_page(__pa_symbol(vdso_data)); - + vdso_lookup[ARM64_VDSO].dm = &vdso_spec[A_VVAR]; + vdso_lookup[ARM64_VDSO].cm = &vdso_spec[A_VDSO];
- /* Grab the vDSO code pages. */ - pfn = sym_to_pfn(vdso_start); - - for (i = 0; i < vdso_pages; i++) - vdso_pagelist[i + 1] = pfn_to_page(pfn + i); - - vdso_spec[0].pages = &vdso_pagelist[0]; - vdso_spec[1].pages = &vdso_pagelist[1]; - - return 0; + return __vdso_init(ARM64_VDSO); } arch_initcall(vdso_init);
@@ -244,41 +341,17 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { struct mm_struct *mm = current->mm; - unsigned long vdso_base, vdso_text_len, vdso_mapping_len; - void *ret; - - vdso_text_len = vdso_pages << PAGE_SHIFT; - /* Be sure to map the data page */ - vdso_mapping_len = vdso_text_len + PAGE_SIZE; + int ret;
if (down_write_killable(&mm->mmap_sem)) return -EINTR; - vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0); - if (IS_ERR_VALUE(vdso_base)) { - ret = ERR_PTR(vdso_base); - goto up_fail; - } - ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE, - VM_READ|VM_MAYREAD, - &vdso_spec[0]); - if (IS_ERR(ret)) - goto up_fail; - - vdso_base += PAGE_SIZE; - mm->context.vdso = (void *)vdso_base; - ret = _install_special_mapping(mm, vdso_base, vdso_text_len, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, - &vdso_spec[1]); - if (IS_ERR(ret)) - goto up_fail;
+ ret = __setup_additional_pages(ARM64_VDSO, + mm, + bprm, + uses_interp);
up_write(&mm->mmap_sem); - return 0;
-up_fail: - mm->context.vdso = NULL; - up_write(&mm->mmap_sem); - return PTR_ERR(ret); + return ret; }
If CONFIG_GENERIC_COMPAT_VDSO is enabled, compat vDSO are installed in a compat (32 bit) process instead of sigpage.
Add the necessary code to setup the vDSO required pages.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/kernel/vdso.c | 90 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c index aa1fb25a9fe4..ad3a81b2c7ce 100644 --- a/arch/arm64/kernel/vdso.c +++ b/arch/arm64/kernel/vdso.c @@ -40,12 +40,22 @@ #include <asm/vdso.h>
extern char vdso_start[], vdso_end[]; +#ifdef CONFIG_COMPAT_VDSO +extern char vdso32_start[], vdso32_end[]; +#endif /* CONFIG_COMPAT_VDSO */
/* vdso_lookup arch_index */ enum arch_vdso_type { ARM64_VDSO = 0, +#ifdef CONFIG_COMPAT_VDSO + ARM64_VDSO32 = 1, +#endif /* CONFIG_COMPAT_VDSO */ }; +#ifdef CONFIG_COMPAT_VDSO +#define VDSO_TYPES (ARM64_VDSO32 + 1) +#else #define VDSO_TYPES (ARM64_VDSO + 1) +#endif /* CONFIG_COMPAT_VDSO */
struct __vdso_abi { const char *name; @@ -64,6 +74,13 @@ static struct __vdso_abi vdso_lookup[VDSO_TYPES] __ro_after_init = { .vdso_code_start = vdso_start, .vdso_code_end = vdso_end, }, +#ifdef CONFIG_COMPAT_VDSO + { + .name = "vdso32", + .vdso_code_start = vdso32_start, + .vdso_code_end = vdso32_end, + }, +#endif /* CONFIG_COMPAT_VDSO */ };
/* @@ -174,24 +191,52 @@ static int __setup_additional_pages(enum arch_vdso_type arch_index, /* * Create and map the vectors page for AArch32 tasks. */ +#ifdef CONFIG_COMPAT_VDSO +static int aarch32_vdso_mremap(const struct vm_special_mapping *sm, + struct vm_area_struct *new_vma) +{ + return __vdso_remap(ARM64_VDSO32, sm, new_vma); +} +#endif /* CONFIG_COMPAT_VDSO */ + /* * aarch32_vdso_pages: * 0 - kuser helpers * 1 - sigreturn code + * or (CONFIG_COMPAT_VDSO): + * 0 - kuser helpers + * 1 - vdso data + * 2 - vdso code */ #define C_VECTORS 0 +#ifdef CONFIG_COMPAT_VDSO +#define C_VVAR 1 +#define C_VDSO 2 +#define C_PAGES (C_VDSO + 1) +#else #define C_SIGPAGE 1 #define C_PAGES (C_SIGPAGE + 1) +#endif /* CONFIG_COMPAT_VDSO */ static struct page *aarch32_vdso_pages[C_PAGES] __ro_after_init; -static const struct vm_special_mapping aarch32_vdso_spec[C_PAGES] = { +static struct vm_special_mapping aarch32_vdso_spec[C_PAGES] = { { .name = "[vectors]", /* ABI */ .pages = &aarch32_vdso_pages[C_VECTORS], }, +#ifdef CONFIG_COMPAT_VDSO + { + .name = "[vvar]", + }, + { + .name = "[vdso]", + .mremap = aarch32_vdso_mremap, + }, +#else { .name = "[sigpage]", /* ABI */ .pages = &aarch32_vdso_pages[C_SIGPAGE], }, +#endif /* CONFIG_COMPAT_VDSO */ };
static int aarch32_alloc_kuser_vdso_page(void) @@ -214,7 +259,33 @@ static int aarch32_alloc_kuser_vdso_page(void) return 0; }
-static int __init aarch32_alloc_vdso_pages(void) +#ifdef CONFIG_COMPAT_VDSO +static int __aarch32_alloc_vdso_pages(void) +{ + int ret; + + vdso_lookup[ARM64_VDSO32].dm = &aarch32_vdso_spec[C_VVAR]; + vdso_lookup[ARM64_VDSO32].cm = &aarch32_vdso_spec[C_VDSO]; + + ret = __vdso_init(ARM64_VDSO32); + if (ret) + return ret; + + ret = aarch32_alloc_kuser_vdso_page(); + if (ret) { + unsigned long c_vvar = + (unsigned long)page_to_virt(aarch32_vdso_pages[C_VVAR]); + unsigned long c_vdso = + (unsigned long)page_to_virt(aarch32_vdso_pages[C_VDSO]); + + free_page(c_vvar); + free_page(c_vdso); + } + + return ret; +} +#else +static int __aarch32_alloc_vdso_pages(void) { extern char __aarch32_sigret_code_start[], __aarch32_sigret_code_end[]; int sigret_sz = __aarch32_sigret_code_end - __aarch32_sigret_code_start; @@ -235,6 +306,12 @@ static int __init aarch32_alloc_vdso_pages(void)
return ret; } +#endif /* CONFIG_COMPAT_VDSO */ + +static int __init aarch32_alloc_vdso_pages(void) +{ + return __aarch32_alloc_vdso_pages(); +} arch_initcall(aarch32_alloc_vdso_pages);
static int aarch32_kuser_helpers_setup(struct mm_struct *mm) @@ -256,6 +333,7 @@ static int aarch32_kuser_helpers_setup(struct mm_struct *mm) return PTR_ERR_OR_ZERO(ret); }
+#ifndef CONFIG_COMPAT_VDSO static int aarch32_sigreturn_setup(struct mm_struct *mm) { unsigned long addr; @@ -283,6 +361,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm) out: return PTR_ERR_OR_ZERO(ret); } +#endif /* !CONFIG_COMPAT_VDSO */
int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) { @@ -296,7 +375,14 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) if (ret) goto out;
+#ifdef CONFIG_COMPAT_VDSO + ret = __setup_additional_pages(ARM64_VDSO32, + mm, + bprm, + uses_interp); +#else ret = aarch32_sigreturn_setup(mm); +#endif /* CONFIG_COMPAT_VDSO */
out: up_write(&mm->mmap_sem);
Like in normal vDSOs, when compat vDSOs are enabled the auxiliary vector symbol AT_SYSINFO_EHDR needs to point at the address of the vDSO code, to allow the dynamic linker to find it.
Add the necessary code to the elf arm64 module to make this possible.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/include/asm/elf.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h index 355d120b78cb..34cabaf78011 100644 --- a/arch/arm64/include/asm/elf.h +++ b/arch/arm64/include/asm/elf.h @@ -213,7 +213,21 @@ typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; ({ \ set_thread_flag(TIF_32BIT); \ }) +#ifdef CONFIG_GENERIC_COMPAT_VDSO +#define COMPAT_ARCH_DLINFO \ +do { \ + /* \ + * Note that we use Elf64_Off instead of elf_addr_t because \ + * elf_addr_t in compat is defined as Elf32_Addr and casting \ + * current->mm->context.vdso to it triggers a cast warning of \ + * cast from pointer to integer of different size. \ + */ \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, \ + (Elf64_Off)current->mm->context.vdso); \ +} while (0) +#else #define COMPAT_ARCH_DLINFO +#endif extern int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp); #define compat_arch_setup_additional_pages \
When the compat vDSO is enabled, the sigreturn trampolines are not anymore available through [sigpage] but through [vdso].
Add the relevant code the enable the feature.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/include/asm/vdso.h | 3 +++ arch/arm64/kernel/signal32.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+)
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h index 839ce0031bd5..9b197e5ea759 100644 --- a/arch/arm64/include/asm/vdso.h +++ b/arch/arm64/include/asm/vdso.h @@ -28,6 +28,9 @@ #ifndef __ASSEMBLY__
#include <generated/vdso-offsets.h> +#ifdef CONFIG_COMPAT_VDSO +#include <generated/vdso32-offsets.h> +#endif
#define VDSO_SYMBOL(base, name) \ ({ \ diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index 74e06d8c7c2b..4fca2e1937b2 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -29,6 +29,7 @@ #include <asm/traps.h> #include <linux/uaccess.h> #include <asm/unistd.h> +#include <asm/vdso.h>
struct compat_vfp_sigframe { compat_ulong_t magic; @@ -352,6 +353,30 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka, retcode = ptr_to_compat(ka->sa.sa_restorer); } else { /* Set up sigreturn pointer */ +#ifdef CONFIG_COMPAT_VDSO + void *vdso_base = current->mm->context.vdso; + void *vdso_trampoline; + + if (ka->sa.sa_flags & SA_SIGINFO) { + if (thumb) { + vdso_trampoline = VDSO_SYMBOL(vdso_base, + compat_rt_sigreturn_thumb); + } else { + vdso_trampoline = VDSO_SYMBOL(vdso_base, + compat_rt_sigreturn_arm); + } + } else { + if (thumb) { + vdso_trampoline = VDSO_SYMBOL(vdso_base, + compat_sigreturn_thumb); + } else { + vdso_trampoline = VDSO_SYMBOL(vdso_base, + compat_sigreturn_arm); + } + } + + retcode = ptr_to_compat(vdso_trampoline) + thumb; +#else unsigned int idx = thumb << 1;
if (ka->sa.sa_flags & SA_SIGINFO) @@ -359,6 +384,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
retcode = (unsigned long)current->mm->context.vdso + (idx << 2) + thumb; +#endif }
regs->regs[0] = usig;
Add vDSO compat support to the arm64 building system.
Cc: Catalin Marinas catalin.marinas@arm.com Cc: Will Deacon will.deacon@arm.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Tested-by: Shijith Thotton sthotton@marvell.com Tested-by: Andre Przywara andre.przywara@arm.com --- arch/arm64/Kconfig | 1 + arch/arm64/Makefile | 23 +++++++++++++++++++++-- arch/arm64/kernel/Makefile | 6 +++++- 3 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 952c9f8cf3b8..f5eb592b8579 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -108,6 +108,7 @@ config ARM64 select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL select GENERIC_GETTIMEOFDAY + select GENERIC_COMPAT_VDSO if (!CPU_BIG_ENDIAN && COMPAT) select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_PCI diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index b025304bde46..4db50d4b2476 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -49,9 +49,25 @@ $(warning Detected assembler with broken .inst; disassembly will be unreliable) endif endif
-KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) +ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y) + CROSS_COMPILE_COMPAT ?= $(CONFIG_CROSS_COMPILE_COMPAT_VDSO:"%"=%) + + ifeq ($(CONFIG_CC_IS_CLANG), y) + $(warning CROSS_COMPILE_COMPAT is clang, the compat vDSO will not be built) + else ifeq ($(CROSS_COMPILE_COMPAT),) + $(warning CROSS_COMPILE_COMPAT not defined or empty, the compat vDSO will not be built) + else ifeq ($(shell which $(CROSS_COMPILE_COMPAT)gcc 2> /dev/null),) + $(error $(CROSS_COMPILE_COMPAT)gcc not found, check CROSS_COMPILE_COMPAT) + else + export CROSS_COMPILE_COMPAT + export CONFIG_COMPAT_VDSO := y + compat_vdso := -DCONFIG_COMPAT_VDSO=1 + endif +endif + +KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) $(compat_vdso) KBUILD_CFLAGS += -fno-asynchronous-unwind-tables -KBUILD_AFLAGS += $(lseinstr) $(brokengasinst) +KBUILD_AFLAGS += $(lseinstr) $(brokengasinst) $(compat_vdso)
KBUILD_CFLAGS += $(call cc-option,-mabi=lp64) KBUILD_AFLAGS += $(call cc-option,-mabi=lp64) @@ -163,6 +179,9 @@ ifeq ($(KBUILD_EXTMOD),) prepare: vdso_prepare vdso_prepare: prepare0 $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso include/generated/vdso-offsets.h + $(if $(CONFIG_COMPAT_VDSO),$(Q)$(MAKE) \ + $(build)=arch/arm64/kernel/vdso32 \ + include/generated/vdso32-offsets.h) endif
define archhelp diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 9e7dcb2c31c7..478491f07b4f 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -28,7 +28,10 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE $(call if_changed,objcopy)
obj-$(CONFIG_COMPAT) += sys32.o signal32.o \ - sigreturn32.o sys_compat.o + sys_compat.o +ifneq ($(CONFIG_COMPAT_VDSO), y) +obj-$(CONFIG_COMPAT) += sigreturn32.o +endif obj-$(CONFIG_KUSER_HELPERS) += kuser32.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o obj-$(CONFIG_MODULES) += module.o @@ -62,6 +65,7 @@ obj-$(CONFIG_ARM64_SSBD) += ssbd.o obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o
obj-y += vdso/ probes/ +obj-$(CONFIG_COMPAT_VDSO) += vdso32/ head-y := head.o extra-y += $(head-y) vmlinux.lds
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes: - Modification vdso.c to be compliant with the common vdso datapage - Use of lib/vdso for gettimeofday - Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm/Kconfig | 3 + arch/arm/include/asm/vdso/gettimeofday.h | 74 +++++++ arch/arm/include/asm/vdso/vsyscall.h | 71 +++++++ arch/arm/include/asm/vdso_datapage.h | 29 +-- arch/arm/kernel/vdso.c | 87 +------- arch/arm/vdso/Makefile | 13 +- arch/arm/vdso/note.c | 15 ++ arch/arm/vdso/vgettimeofday.c | 256 +---------------------- 8 files changed, 192 insertions(+), 356 deletions(-) create mode 100644 arch/arm/include/asm/vdso/gettimeofday.h create mode 100644 arch/arm/include/asm/vdso/vsyscall.h create mode 100644 arch/arm/vdso/note.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 8869742a85df..a238fc34e478 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -53,6 +53,8 @@ config ARM select GENERIC_SMP_IDLE_THREAD select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER + select GENERIC_GETTIMEOFDAY + select GENERIC_VDSO_32 select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT @@ -101,6 +103,7 @@ config ARM select HAVE_SYSCALL_TRACEPOINTS select HAVE_UID16 select HAVE_VIRT_CPU_ACCOUNTING_GEN + select HAVE_GENERIC_VDSO if AEABI select IRQ_FORCED_THREADING select MODULES_USE_ELF_REL select NEED_DMA_MAP_STATE diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h new file mode 100644 index 000000000000..30ce4e87dffc --- /dev/null +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -0,0 +1,74 @@ +/* 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/barrier.h> +#include <asm/cp15.h> +#include <asm/unistd.h> +#include <uapi/linux/time.h> + +extern struct vdso_data *__get_datapage(void); + +static __always_inline int gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + register struct timezone *tz asm("r1") = _tz; + register struct __kernel_old_timeval *tv asm("r0") = _tv; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_gettimeofday; + + asm volatile( + " swi #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("r1") = _ts; + register clockid_t clkid asm("r0") = _clkid; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_clock_gettime64; + + asm volatile( + " swi #0\n" + : "=r" (ret) + : "r" (clkid), "r" (ts), "r" (nr) + : "memory"); + + return ret; +} + +static __always_inline u64 __arch_get_hw_counter(int clock_mode) +{ +#ifdef CONFIG_ARM_ARCH_TIMER + u64 cycle_now; + + isb(); + cycle_now = read_sysreg(CNTVCT); + + return cycle_now; +#else + return -EINVAL; /* use fallback */ +#endif +} + +static __always_inline const struct vdso_data *__arch_get_vdso_data(void) +{ + return __get_datapage(); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/arm/include/asm/vdso/vsyscall.h b/arch/arm/include/asm/vdso/vsyscall.h new file mode 100644 index 000000000000..c4166f317071 --- /dev/null +++ b/arch/arm/include/asm/vdso/vsyscall.h @@ -0,0 +1,71 @@ +/* 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> +#include <asm/cacheflush.h> + +extern struct vdso_data *vdso_data; +extern bool cntvct_ok; + +static __always_inline +bool tk_is_cntvct(const struct timekeeper *tk) +{ + if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) + return false; + + if (!tk->tkr_mono.clock->archdata.vdso_direct) + return false; + + return true; +} + +/* + * Update the vDSO data page to keep in sync with kernel timekeeping. + */ +static __always_inline +struct vdso_data *__arm_get_k_vdso_data(void) +{ + return vdso_data; +} +#define __arch_get_k_vdso_data __arm_get_k_vdso_data + +static __always_inline +int __arm_update_vdso_data(void) +{ + return !cntvct_ok; +} +#define __arch_update_vdso_data __arm_update_vdso_data + +static __always_inline +int __arm_get_clock_mode(struct timekeeper *tk) +{ + u32 __tk_is_cntvct = tk_is_cntvct(tk); + + return __tk_is_cntvct; +} +#define __arch_get_clock_mode __arm_get_clock_mode + +static __always_inline +int __arm_use_vsyscall(struct vdso_data *vdata) +{ + return vdata[CS_HRES_COARSE].clock_mode; +} +#define __arch_use_vsyscall __arm_use_vsyscall + +static __always_inline +void __arm_sync_vdso_data(struct vdso_data *vdata) +{ + flush_dcache_page(virt_to_page(vdata)); +} +#define __arch_sync_vdso_data __arm_sync_vdso_data + +/* 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/arm/include/asm/vdso_datapage.h b/arch/arm/include/asm/vdso_datapage.h index 9be259442fca..bfdbbd2b5fe7 100644 --- a/arch/arm/include/asm/vdso_datapage.h +++ b/arch/arm/include/asm/vdso_datapage.h @@ -22,35 +22,12 @@
#ifndef __ASSEMBLY__
+#include <vdso/datapage.h> #include <asm/page.h>
-/* Try to be cache-friendly on systems that don't implement the - * generic timer: fit the unconditionally updated fields in the first - * 32 bytes. - */ -struct vdso_data { - u32 seq_count; /* sequence count - odd during updates */ - u16 tk_is_cntvct; /* fall back to syscall if false */ - u16 cs_shift; /* clocksource shift */ - u32 xtime_coarse_sec; /* coarse time */ - u32 xtime_coarse_nsec; - - u32 wtm_clock_sec; /* wall to monotonic offset */ - u32 wtm_clock_nsec; - u32 xtime_clock_sec; /* CLOCK_REALTIME - seconds */ - u32 cs_mult; /* clocksource multiplier */ - - u64 cs_cycle_last; /* last cycle value */ - u64 cs_mask; /* clocksource mask */ - - u64 xtime_clock_snsec; /* CLOCK_REALTIME sub-ns base */ - u32 tz_minuteswest; /* timezone info for gettimeofday(2) */ - u32 tz_dsttime; -}; - union vdso_data_store { - struct vdso_data data; - u8 page[PAGE_SIZE]; + struct vdso_data data[CS_BASES]; + u8 page[PAGE_SIZE]; };
#endif /* !__ASSEMBLY__ */ diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c index f4dd7f9663c1..9a9cea8b333d 100644 --- a/arch/arm/kernel/vdso.c +++ b/arch/arm/kernel/vdso.c @@ -34,6 +34,8 @@ #include <asm/vdso.h> #include <asm/vdso_datapage.h> #include <clocksource/arm_arch_timer.h> +#include <vdso/helpers.h> +#include <vdso/vsyscall.h>
#define MAX_SYMNAME 64
@@ -48,7 +50,7 @@ unsigned int vdso_total_pages __ro_after_init; * The VDSO data page. */ static union vdso_data_store vdso_data_store __page_aligned_data; -static struct vdso_data *vdso_data = &vdso_data_store.data; +struct vdso_data *vdso_data = vdso_data_store.data;
static struct page *vdso_data_page __ro_after_init; static const struct vm_special_mapping vdso_data_mapping = { @@ -88,7 +90,7 @@ struct elfinfo { /* Cached result of boot-time check for whether the arch timer exists, * and if so, whether the virtual counter is useable. */ -static bool cntvct_ok __ro_after_init; +bool cntvct_ok __ro_after_init;
static bool __init cntvct_functional(void) { @@ -274,84 +276,3 @@ void arm_install_vdso(struct mm_struct *mm, unsigned long addr) mm->context.vdso = addr; }
-static void vdso_write_begin(struct vdso_data *vdata) -{ - ++vdso_data->seq_count; - smp_wmb(); /* Pairs with smp_rmb in vdso_read_retry */ -} - -static void vdso_write_end(struct vdso_data *vdata) -{ - smp_wmb(); /* Pairs with smp_rmb in vdso_read_begin */ - ++vdso_data->seq_count; -} - -static bool tk_is_cntvct(const struct timekeeper *tk) -{ - if (!IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) - return false; - - if (!tk->tkr_mono.clock->archdata.vdso_direct) - return false; - - return true; -} - -/** - * update_vsyscall - update the vdso data page - * - * Increment the sequence counter, making it odd, indicating to - * userspace that an update is in progress. Update the fields used - * for coarse clocks and, if the architected system timer is in use, - * the fields used for high precision clocks. Increment the sequence - * counter again, making it even, indicating to userspace that the - * update is finished. - * - * Userspace is expected to sample seq_count before reading any other - * fields from the data page. If seq_count is odd, userspace is - * expected to wait until it becomes even. After copying data from - * the page, userspace must sample seq_count again; if it has changed - * from its previous value, userspace must retry the whole sequence. - * - * Calls to update_vsyscall are serialized by the timekeeping core. - */ -void update_vsyscall(struct timekeeper *tk) -{ - struct timespec64 *wtm = &tk->wall_to_monotonic; - - if (!cntvct_ok) { - /* The entry points have been zeroed, so there is no - * point in updating the data page. - */ - return; - } - - vdso_write_begin(vdso_data); - - vdso_data->tk_is_cntvct = tk_is_cntvct(tk); - vdso_data->xtime_coarse_sec = tk->xtime_sec; - vdso_data->xtime_coarse_nsec = (u32)(tk->tkr_mono.xtime_nsec >> - tk->tkr_mono.shift); - vdso_data->wtm_clock_sec = wtm->tv_sec; - vdso_data->wtm_clock_nsec = wtm->tv_nsec; - - if (vdso_data->tk_is_cntvct) { - vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data->xtime_clock_sec = tk->xtime_sec; - vdso_data->xtime_clock_snsec = tk->tkr_mono.xtime_nsec; - vdso_data->cs_mult = tk->tkr_mono.mult; - vdso_data->cs_shift = tk->tkr_mono.shift; - vdso_data->cs_mask = tk->tkr_mono.mask; - } - - vdso_write_end(vdso_data); - - flush_dcache_page(virt_to_page(vdso_data)); -} - -void update_vsyscall_tz(void) -{ - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data->tz_dsttime = sys_tz.tz_dsttime; - flush_dcache_page(virt_to_page(vdso_data)); -} diff --git a/arch/arm/vdso/Makefile b/arch/arm/vdso/Makefile index fadf554d9391..0c8a819ef4f1 100644 --- a/arch/arm/vdso/Makefile +++ b/arch/arm/vdso/Makefile @@ -1,7 +1,13 @@ # SPDX-License-Identifier: GPL-2.0 + +# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before +# the inclusion of generic Makefile. +ARCH_REL_TYPE_ABS := R_ARM_JUMP_SLOT|R_ARM_GLOB_DAT|R_ARM_ABS32 +include $(srctree)/lib/vdso/Makefile + hostprogs-y := vdsomunge
-obj-vdso := vgettimeofday.o datapage.o +obj-vdso := vgettimeofday.o datapage.o note.o
# Build rules targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.so.raw vdso.lds @@ -25,7 +31,11 @@ CFLAGS_REMOVE_vdso.o = -pg
# Force -O2 to avoid libgcc dependencies CFLAGS_REMOVE_vgettimeofday.o = -pg -Os +ifeq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o = -O2 +else +CFLAGS_vgettimeofday.o = -O2 -include $(c-gettimeofday-y) +endif
# Disable gcov profiling for VDSO code GCOV_PROFILE := n @@ -39,6 +49,7 @@ $(obj)/vdso.o : $(obj)/vdso.so # Link rule for the .so file $(obj)/vdso.so.raw: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,ld) + $(call if_changed,vdso_check)
$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/vdsomunge FORCE $(call if_changed,vdsomunge) diff --git a/arch/arm/vdso/note.c b/arch/arm/vdso/note.c new file mode 100644 index 000000000000..eff5bf9efb8b --- /dev/null +++ b/arch/arm/vdso/note.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2012-2018 ARM Limited + * + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. + * Here we can supply some information useful to userland. + */ + +#include <linux/uts.h> +#include <linux/version.h> +#include <linux/elfnote.h> +#include <linux/build-salt.h> + +ELFNOTE32("Linux", 0, LINUX_VERSION_CODE); +BUILD_SALT; diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index 7bdbf5d5c47d..fea6b3c89f43 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -1,5 +1,8 @@ /* + * ARM userspace implementations of gettimeofday() and similar. + * * Copyright 2015 Mentor Graphics Corporation. + * Copyright (C) 2018 ARM Limited * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -14,258 +17,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ - -#include <linux/compiler.h> -#include <linux/hrtimer.h> #include <linux/time.h> -#include <asm/barrier.h> -#include <asm/bug.h> -#include <asm/cp15.h> -#include <asm/page.h> -#include <asm/unistd.h> -#include <asm/vdso_datapage.h> - -#ifndef CONFIG_AEABI -#error This code depends on AEABI system call conventions -#endif - -extern struct vdso_data *__get_datapage(void); - -static notrace u32 __vdso_read_begin(const struct vdso_data *vdata) -{ - u32 seq; -repeat: - seq = READ_ONCE(vdata->seq_count); - if (seq & 1) { - cpu_relax(); - goto repeat; - } - return seq; -} - -static notrace u32 vdso_read_begin(const struct vdso_data *vdata) -{ - u32 seq; - - seq = __vdso_read_begin(vdata); - - smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */ - return seq; -} - -static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start) -{ - smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */ - return vdata->seq_count != start; -} - -static notrace long clock_gettime_fallback(clockid_t _clkid, - struct timespec *_ts) -{ - register struct timespec *ts asm("r1") = _ts; - register clockid_t clkid asm("r0") = _clkid; - register long ret asm ("r0"); - register long nr asm("r7") = __NR_clock_gettime; - - asm volatile( - " swi #0\n" - : "=r" (ret) - : "r" (clkid), "r" (ts), "r" (nr) - : "memory"); - - return ret; -} - -static notrace int do_realtime_coarse(struct timespec *ts, - struct vdso_data *vdata) -{ - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - ts->tv_sec = vdata->xtime_coarse_sec; - ts->tv_nsec = vdata->xtime_coarse_nsec; - - } while (vdso_read_retry(vdata, seq)); - - return 0; -} - -static notrace int do_monotonic_coarse(struct timespec *ts, - struct vdso_data *vdata) -{ - struct timespec tomono; - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - ts->tv_sec = vdata->xtime_coarse_sec; - ts->tv_nsec = vdata->xtime_coarse_nsec; - - tomono.tv_sec = vdata->wtm_clock_sec; - tomono.tv_nsec = vdata->wtm_clock_nsec; - - } while (vdso_read_retry(vdata, seq)); - - ts->tv_sec += tomono.tv_sec; - timespec_add_ns(ts, tomono.tv_nsec); - - return 0; -} - -#ifdef CONFIG_ARM_ARCH_TIMER - -static notrace u64 get_ns(struct vdso_data *vdata) -{ - u64 cycle_delta; - u64 cycle_now; - u64 nsec; - - isb(); - cycle_now = read_sysreg(CNTVCT); - - cycle_delta = (cycle_now - vdata->cs_cycle_last) & vdata->cs_mask; - - nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_snsec; - nsec >>= vdata->cs_shift; +#include <linux/types.h>
- return nsec; -} - -static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata) -{ - u64 nsecs; - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - if (!vdata->tk_is_cntvct) - return -1; - - ts->tv_sec = vdata->xtime_clock_sec; - nsecs = get_ns(vdata); - - } while (vdso_read_retry(vdata, seq)); - - ts->tv_nsec = 0; - timespec_add_ns(ts, nsecs); - - return 0; -} - -static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata) -{ - struct timespec tomono; - u64 nsecs; - u32 seq; - - do { - seq = vdso_read_begin(vdata); - - if (!vdata->tk_is_cntvct) - return -1; - - ts->tv_sec = vdata->xtime_clock_sec; - nsecs = get_ns(vdata); - - tomono.tv_sec = vdata->wtm_clock_sec; - tomono.tv_nsec = vdata->wtm_clock_nsec; - - } while (vdso_read_retry(vdata, seq)); - - ts->tv_sec += tomono.tv_sec; - ts->tv_nsec = 0; - timespec_add_ns(ts, nsecs + tomono.tv_nsec); - - return 0; -} - -#else /* CONFIG_ARM_ARCH_TIMER */ - -static notrace int do_realtime(struct timespec *ts, struct vdso_data *vdata) -{ - return -1; -} - -static notrace int do_monotonic(struct timespec *ts, struct vdso_data *vdata) +int __vdso_clock_gettime(clockid_t clock, + struct old_timespec32 *ts) { - return -1; + return __cvdso_clock_gettime32(clock, ts); }
-#endif /* CONFIG_ARM_ARCH_TIMER */ - -notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts) +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) { - struct vdso_data *vdata; - int ret = -1; - - vdata = __get_datapage(); - - switch (clkid) { - case CLOCK_REALTIME_COARSE: - ret = do_realtime_coarse(ts, vdata); - break; - case CLOCK_MONOTONIC_COARSE: - ret = do_monotonic_coarse(ts, vdata); - break; - case CLOCK_REALTIME: - ret = do_realtime(ts, vdata); - break; - case CLOCK_MONOTONIC: - ret = do_monotonic(ts, vdata); - break; - default: - break; - } - - if (ret) - ret = clock_gettime_fallback(clkid, ts); - - return ret; -} - -static notrace long gettimeofday_fallback(struct timeval *_tv, - struct timezone *_tz) -{ - register struct timezone *tz asm("r1") = _tz; - register struct timeval *tv asm("r0") = _tv; - register long ret asm ("r0"); - register long nr asm("r7") = __NR_gettimeofday; - - asm volatile( - " swi #0\n" - : "=r" (ret) - : "r" (tv), "r" (tz), "r" (nr) - : "memory"); - - return ret; -} - -notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) -{ - struct timespec ts; - struct vdso_data *vdata; - int ret; - - vdata = __get_datapage(); - - ret = do_realtime(&ts, vdata); - if (ret) - return gettimeofday_fallback(tv, tz); - - if (tv) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; - } - if (tz) { - tz->tz_minuteswest = vdata->tz_minuteswest; - tz->tz_dsttime = vdata->tz_dsttime; - } - - return ret; + return __cvdso_gettimeofday(tv, tz); }
/* Avoid unresolved references emitted by GCC */
On Fri, Jun 21, 2019 at 10:52:43AM +0100, Vincenzo Frascino wrote:
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes:
- Modification vdso.c to be compliant with the common vdso datapage
- Use of lib/vdso for gettimeofday
- Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This patch causes a crash with qemu's mcimx6ul-evk emulation while running imx_v6_v7_defconfig.
[ 19.976852] Run /sbin/init as init process [ 20.044931] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
There is nothing else useful in the log, unfortunately.
Reverting the following three patches fixes the problem.
74d06efb9c2f ARM: 8932/1: Add clock_gettime64 entry point 052e76a31b4a ARM: 8931/1: Add clock_getres entry point 20e2fc42312f ARM: 8930/1: Add support for generic vDSO
Guenter
Hi Guenter,
On 12/4/19 1:51 PM, Guenter Roeck wrote:
On Fri, Jun 21, 2019 at 10:52:43AM +0100, Vincenzo Frascino wrote:
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes:
- Modification vdso.c to be compliant with the common vdso datapage
- Use of lib/vdso for gettimeofday
- Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This patch causes a crash with qemu's mcimx6ul-evk emulation while running imx_v6_v7_defconfig.
Thank you for reporting this. Could you please provide some details on how I can reproduce the scenario you are describing?
[ 19.976852] Run /sbin/init as init process [ 20.044931] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
There is nothing else useful in the log, unfortunately.
Reverting the following three patches fixes the problem.
74d06efb9c2f ARM: 8932/1: Add clock_gettime64 entry point 052e76a31b4a ARM: 8931/1: Add clock_getres entry point 20e2fc42312f ARM: 8930/1: Add support for generic vDSO
Guenter
On Wed, Dec 04, 2019 at 01:58:25PM +0000, Vincenzo Frascino wrote:
Hi Guenter,
On 12/4/19 1:51 PM, Guenter Roeck wrote:
On Fri, Jun 21, 2019 at 10:52:43AM +0100, Vincenzo Frascino wrote:
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes:
- Modification vdso.c to be compliant with the common vdso datapage
- Use of lib/vdso for gettimeofday
- Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This patch causes a crash with qemu's mcimx6ul-evk emulation while running imx_v6_v7_defconfig.
Thank you for reporting this. Could you please provide some details on how I can reproduce the scenario you are describing?
- Build imx_v6_v7_defconfig - Get root file system or initrd, for example from https://github.com/groeck/linux-build-test/tree/master/rootfs/arm - Run image. Example, with initrd: qemu-system-arm -M mcimx6ul-evk -kernel arch/arm/boot/zImage \ -no-reboot -initrd rootfs-armv7a.cpio \ -m 256 -display none -serial null \ --append 'rdinit=/sbin/init earlycon=ec_imx6q,mmio,0x21e8000,115200n8 console=ttymxc1,115200' -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb \ -nographic -monitor null -serial stdio
qemu has to be v3.1 or later to support the machine.
Hope this helps, Guenter
Hi Guenter,
On 12/4/19 4:16 PM, Guenter Roeck wrote:
On Wed, Dec 04, 2019 at 01:58:25PM +0000, Vincenzo Frascino wrote:
Hi Guenter,
On 12/4/19 1:51 PM, Guenter Roeck wrote:
On Fri, Jun 21, 2019 at 10:52:43AM +0100, Vincenzo Frascino wrote:
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes:
- Modification vdso.c to be compliant with the common vdso datapage
- Use of lib/vdso for gettimeofday
- Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This patch causes a crash with qemu's mcimx6ul-evk emulation while running imx_v6_v7_defconfig.
Thank you for reporting this. Could you please provide some details on how I can reproduce the scenario you are describing?
- Build imx_v6_v7_defconfig
- Get root file system or initrd, for example from https://github.com/groeck/linux-build-test/tree/master/rootfs/arm
- Run image. Example, with initrd: qemu-system-arm -M mcimx6ul-evk -kernel arch/arm/boot/zImage \ -no-reboot -initrd rootfs-armv7a.cpio \ -m 256 -display none -serial null \ --append 'rdinit=/sbin/init earlycon=ec_imx6q,mmio,0x21e8000,115200n8 console=ttymxc1,115200' -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb \ -nographic -monitor null -serial stdio
qemu has to be v3.1 or later to support the machine.
Thanks for this. Could you please try the patch below the scissors? Seems fixing the issue for me.
Hope this helps, Guenter
On Wed, Dec 04, 2019 at 05:15:26PM +0000, Vincenzo Frascino wrote:
Hi Guenter,
On 12/4/19 4:16 PM, Guenter Roeck wrote:
On Wed, Dec 04, 2019 at 01:58:25PM +0000, Vincenzo Frascino wrote:
Hi Guenter,
On 12/4/19 1:51 PM, Guenter Roeck wrote:
On Fri, Jun 21, 2019 at 10:52:43AM +0100, Vincenzo Frascino wrote:
The arm vDSO library requires some adaptations to use to take advantage of the newly introduced generic vDSO library.
Introduce the following changes:
- Modification vdso.c to be compliant with the common vdso datapage
- Use of lib/vdso for gettimeofday
- Implementation of elf note
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
This patch causes a crash with qemu's mcimx6ul-evk emulation while running imx_v6_v7_defconfig.
Thank you for reporting this. Could you please provide some details on how I can reproduce the scenario you are describing?
- Build imx_v6_v7_defconfig
- Get root file system or initrd, for example from https://github.com/groeck/linux-build-test/tree/master/rootfs/arm
- Run image. Example, with initrd: qemu-system-arm -M mcimx6ul-evk -kernel arch/arm/boot/zImage \ -no-reboot -initrd rootfs-armv7a.cpio \ -m 256 -display none -serial null \ --append 'rdinit=/sbin/init earlycon=ec_imx6q,mmio,0x21e8000,115200n8 console=ttymxc1,115200' -dtb arch/arm/boot/dts/imx6ul-14x14-evk.dtb \ -nographic -monitor null -serial stdio
qemu has to be v3.1 or later to support the machine.
Thanks for this. Could you please try the patch below the scissors? Seems fixing the issue for me.
Hope this helps, Guenter
-- Regards, Vincenzo
--->8---
Author: Vincenzo Frascino vincenzo.frascino@arm.com Date: Wed Dec 4 16:58:55 2019 +0000
arm: Fix __arch_get_hw_counter() access to CNTVCT __arch_get_hw_counter() should check clock_mode to see if it can access CNTVCT. With the conversion to unified vDSO this check has been left out. This causes on imx v6 and v7 (imx_v6_v7_defconfig) and other platforms to hang at boot during the execution of the init process as per below: [ 19.976852] Run /sbin/init as init process [ 20.044931] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004 Fix the problem verifying that clock_mode is set coherently before accessing CNTVCT. Cc: Russell King <linux@armlinux.org.uk> Reported-by: Guenter Roeck <linux@roeck-us.net> Investigated-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
WFM.
Tested-by: Guenter Roeck linux@roeck-us.net
Guenter
diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 5b879ae7afc1..0ad2429c324f 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -75,6 +75,9 @@ static __always_inline u64 __arch_get_hw_counter(int clock_mode) #ifdef CONFIG_ARM_ARCH_TIMER u64 cycle_now;
if (!clock_mode)
return -EINVAL;
isb(); cycle_now = read_sysreg(CNTVCT);
On Wed, Dec 4, 2019 at 6:23 PM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
On 12/4/19 4:16 PM, Guenter Roeck wrote:
[...]
--->8---
Author: Vincenzo Frascino vincenzo.frascino@arm.com Date: Wed Dec 4 16:58:55 2019 +0000
arm: Fix __arch_get_hw_counter() access to CNTVCT __arch_get_hw_counter() should check clock_mode to see if it can access CNTVCT. With the conversion to unified vDSO this check has been left out. This causes on imx v6 and v7 (imx_v6_v7_defconfig) and other platforms to hang at boot during the execution of the init process as per below: [ 19.976852] Run /sbin/init as init process [ 20.044931] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004 Fix the problem verifying that clock_mode is set coherently before accessing CNTVCT. Cc: Russell King <linux@armlinux.org.uk> Reported-by: Guenter Roeck <linux@roeck-us.net> Investigated-by: Arnd Bergmann <arnd@arndb.de>
There are only 2 "Investigated-by" vs 7k+ "Suggested-by"... Is there a real difference?
Signed-off-by: Vincenzo Frascino <vincenzo.frascino@arm.com>
diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 5b879ae7afc1..0ad2429c324f 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -75,6 +75,9 @@ static __always_inline u64 __arch_get_hw_counter(int clock_mode) #ifdef CONFIG_ARM_ARCH_TIMER u64 cycle_now;
if (!clock_mode)
return -EINVAL;
Reviewed-by: Philippe Mathieu-Daudé f4bug@amsat.org
isb(); cycle_now = read_sysreg(CNTVCT);
Hi Philippe,
On 05/12/2019 09:42, Philippe Mathieu-Daudé wrote:
There are only 2 "Investigated-by" vs 7k+ "Suggested-by"... Is there a real difference?
Not sure about that. My take is that Suggested-by is used when someone suggests you how to possibly implement a feature and you go and do that. Investigated-by is when there is a fix to make and someone comes to you with the exact solution like in this case Arnd did.
On Thu, Dec 5, 2019 at 11:00 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Hi Philippe,
On 05/12/2019 09:42, Philippe Mathieu-Daudé wrote:
There are only 2 "Investigated-by" vs 7k+ "Suggested-by"... Is there a real difference?
Not sure about that. My take is that Suggested-by is used when someone suggests you how to possibly implement a feature and you go and do that. Investigated-by is when there is a fix to make and someone comes to you with the exact solution like in this case Arnd did.
It's not a standard tag, but I suggested it because it does explain better what I did.
You could also just explain in clear text that I did the analysis and then add the more normal Suggested-by tag, I don't care either way.
Arnd
On Thu, Dec 5, 2019 at 12:02 PM Arnd Bergmann arnd@arndb.de wrote:
On Thu, Dec 5, 2019 at 11:00 AM Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Hi Philippe,
On 05/12/2019 09:42, Philippe Mathieu-Daudé wrote:
There are only 2 "Investigated-by" vs 7k+ "Suggested-by"... Is there a real difference?
Not sure about that. My take is that Suggested-by is used when someone suggests you how to possibly implement a feature and you go and do that. Investigated-by is when there is a fix to make and someone comes to you with the exact solution like in this case Arnd did.
It's not a standard tag, but I suggested it because it does explain better what I did.
You could also just explain in clear text that I did the analysis and then add the more normal Suggested-by tag, I don't care either way.
No problem, I was just wondering the subtle difference between both tags. I don't mind which one you use, as long as this issue get fixed :) Thanks for the patch BTW!
Regards,
Phil.
Arnd
The generic vDSO library provides an implementation of clock_getres() that can be leveraged by each architecture.
Add clock_getres() entry point on arm to be on pair with arm64.
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm/include/asm/vdso/gettimeofday.h | 20 ++++++++++++++++++++ arch/arm/vdso/vdso.lds.S | 1 + arch/arm/vdso/vgettimeofday.c | 6 ++++++ 3 files changed, 27 insertions(+)
diff --git a/arch/arm/include/asm/vdso/gettimeofday.h b/arch/arm/include/asm/vdso/gettimeofday.h index 30ce4e87dffc..5b879ae7afc1 100644 --- a/arch/arm/include/asm/vdso/gettimeofday.h +++ b/arch/arm/include/asm/vdso/gettimeofday.h @@ -12,6 +12,8 @@ #include <asm/unistd.h> #include <uapi/linux/time.h>
+#define VDSO_HAS_CLOCK_GETRES 1 + extern struct vdso_data *__get_datapage(void);
static __always_inline int gettimeofday_fallback( @@ -50,6 +52,24 @@ static __always_inline long clock_gettime_fallback( return ret; }
+static __always_inline int clock_getres_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + register struct __kernel_timespec *ts asm("r1") = _ts; + register clockid_t clkid asm("r0") = _clkid; + register long ret asm ("r0"); + register long nr asm("r7") = __NR_clock_getres_time64; + + asm volatile( + " swi #0\n" + : "=r" (ret) + : "r" (clkid), "r" (ts), "r" (nr) + : "memory"); + + return ret; +} + static __always_inline u64 __arch_get_hw_counter(int clock_mode) { #ifdef CONFIG_ARM_ARCH_TIMER diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S index 89ca89f12d23..1d81e8c3acf6 100644 --- a/arch/arm/vdso/vdso.lds.S +++ b/arch/arm/vdso/vdso.lds.S @@ -82,6 +82,7 @@ VERSION global: __vdso_clock_gettime; __vdso_gettimeofday; + __vdso_clock_getres; local: *; }; } diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index fea6b3c89f43..d3330c0c1147 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -32,6 +32,12 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, return __cvdso_gettimeofday(tv, tz); }
+int __vdso_clock_getres(clockid_t clock_id, + struct old_timespec32 *res) +{ + return __cvdso_clock_getres_time32(clock_id, res); +} + /* Avoid unresolved references emitted by GCC */
void __aeabi_unwind_cpp_pr0(void)
With the release of Linux 5.1 has been added a new syscall, clock_gettime64, that provided a 64 bit time value for a specified clock_ID to make the kernel Y2038 safe on 32 bit architectures.
Update the arm specific vDSO library accordingly with what it has been done for the kernel syscall exposing the clock_gettime64 entry point.
Cc: Russell King linux@armlinux.org.uk Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/arm/vdso/vdso.lds.S | 1 + arch/arm/vdso/vgettimeofday.c | 6 ++++++ 2 files changed, 7 insertions(+)
diff --git a/arch/arm/vdso/vdso.lds.S b/arch/arm/vdso/vdso.lds.S index 1d81e8c3acf6..05581140fd12 100644 --- a/arch/arm/vdso/vdso.lds.S +++ b/arch/arm/vdso/vdso.lds.S @@ -83,6 +83,7 @@ VERSION __vdso_clock_gettime; __vdso_gettimeofday; __vdso_clock_getres; + __vdso_clock_gettime64; local: *; }; } diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index d3330c0c1147..0742a0bb4763 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -26,6 +26,12 @@ int __vdso_clock_gettime(clockid_t clock, return __cvdso_clock_gettime32(clock, ts); }
+int __vdso_clock_gettime64(clockid_t clock, + struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} + int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) {
The mips 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: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/mips/Kconfig | 2 + arch/mips/include/asm/vdso.h | 78 +---------- arch/mips/include/asm/vdso/gettimeofday.h | 151 ++++++++++++++++++++++ arch/mips/{ => include/asm}/vdso/vdso.h | 6 +- arch/mips/include/asm/vdso/vsyscall.h | 43 ++++++ arch/mips/kernel/vdso.c | 37 +----- arch/mips/vdso/Makefile | 27 +++- arch/mips/vdso/elf.S | 2 +- arch/mips/vdso/sigreturn.S | 2 +- arch/mips/vdso/vgettimeofday.c | 40 ++++++ 10 files changed, 273 insertions(+), 115 deletions(-) create mode 100644 arch/mips/include/asm/vdso/gettimeofday.h rename arch/mips/{ => include/asm}/vdso/vdso.h (89%) create mode 100644 arch/mips/include/asm/vdso/vsyscall.h create mode 100644 arch/mips/vdso/vgettimeofday.c
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 70d3200476bf..390c052cac9a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -34,6 +34,7 @@ config MIPS select GENERIC_SCHED_CLOCK if !CAVIUM_OCTEON_SOC select GENERIC_SMP_IDLE_THREAD select GENERIC_TIME_VSYSCALL + select GENERIC_GETTIMEOFDAY select HANDLE_DOMAIN_IRQ select HAVE_ARCH_COMPILER_H select HAVE_ARCH_JUMP_LABEL @@ -72,6 +73,7 @@ config MIPS select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select HAVE_VIRT_CPU_ACCOUNTING_GEN if 64BIT || !SMP + select HAVE_GENERIC_VDSO select IRQ_FORCED_THREADING select ISA if EISA select MODULES_USE_ELF_RELA if MODULES && 64BIT diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h index a013fa4a3682..cc7b516129a8 100644 --- a/arch/mips/include/asm/vdso.h +++ b/arch/mips/include/asm/vdso.h @@ -8,6 +8,7 @@ #define __ASM_VDSO_H
#include <linux/mm_types.h> +#include <vdso/datapage.h>
#include <asm/barrier.h>
@@ -49,84 +50,9 @@ extern struct mips_vdso_image vdso_image_o32; extern struct mips_vdso_image vdso_image_n32; #endif
-/** - * union mips_vdso_data - Data provided by the kernel for the VDSO. - * @xtime_sec: Current real time (seconds part). - * @xtime_nsec: Current real time (nanoseconds part, shifted). - * @wall_to_mono_sec: Wall-to-monotonic offset (seconds part). - * @wall_to_mono_nsec: Wall-to-monotonic offset (nanoseconds part). - * @seq_count: Counter to synchronise updates (odd = updating). - * @cs_shift: Clocksource shift value. - * @clock_mode: Clocksource to use for time functions. - * @cs_mult: Clocksource multiplier value. - * @cs_cycle_last: Clock cycle value at last update. - * @cs_mask: Clocksource mask value. - * @tz_minuteswest: Minutes west of Greenwich (from timezone). - * @tz_dsttime: Type of DST correction (from timezone). - * - * This structure contains data needed by functions within the VDSO. It is - * populated by the kernel and mapped read-only into user memory. The time - * fields are mirrors of internal data from the timekeeping infrastructure. - * - * Note: Care should be taken when modifying as the layout must remain the same - * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel). - */ union mips_vdso_data { - struct { - u64 xtime_sec; - u64 xtime_nsec; - u64 wall_to_mono_sec; - u64 wall_to_mono_nsec; - u32 seq_count; - u32 cs_shift; - u8 clock_mode; - u32 cs_mult; - u64 cs_cycle_last; - u64 cs_mask; - s32 tz_minuteswest; - s32 tz_dsttime; - }; - + struct vdso_data data[CS_BASES]; u8 page[PAGE_SIZE]; };
-static inline u32 vdso_data_read_begin(const union mips_vdso_data *data) -{ - u32 seq; - - while (true) { - seq = READ_ONCE(data->seq_count); - if (likely(!(seq & 1))) { - /* Paired with smp_wmb() in vdso_data_write_*(). */ - smp_rmb(); - return seq; - } - - cpu_relax(); - } -} - -static inline bool vdso_data_read_retry(const union mips_vdso_data *data, - u32 start_seq) -{ - /* Paired with smp_wmb() in vdso_data_write_*(). */ - smp_rmb(); - return unlikely(data->seq_count != start_seq); -} - -static inline void vdso_data_write_begin(union mips_vdso_data *data) -{ - ++data->seq_count; - - /* Ensure sequence update is written before other data page values. */ - smp_wmb(); -} - -static inline void vdso_data_write_end(union mips_vdso_data *data) -{ - /* Ensure data values are written before updating sequence again. */ - smp_wmb(); - ++data->seq_count; -} - #endif /* __ASM_VDSO_H */ diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h new file mode 100644 index 000000000000..aa20865b288b --- /dev/null +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2018 ARM Limited + * Copyright (C) 2015 Imagination Technologies + * Author: Alex Smith alex.smith@imgtec.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __ASM_VDSO_GETTIMEOFDAY_H +#define __ASM_VDSO_GETTIMEOFDAY_H + +#ifndef __ASSEMBLY__ + +#include <linux/compiler.h> +#include <linux/time.h> + +#include <asm/vdso/vdso.h> +#include <asm/clocksource.h> +#include <asm/io.h> +#include <asm/unistd.h> +#include <asm/vdso.h> + +#ifdef CONFIG_MIPS_CLOCK_VSYSCALL + +static __always_inline long gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + register struct timezone *tz asm("a1") = _tz; + register struct __kernel_old_timeval *tv asm("a0") = _tv; + register long ret asm("v0"); + register long nr asm("v0") = __NR_gettimeofday; + register long error asm("a3"); + + asm volatile( + " syscall\n" + : "=r" (ret), "=r" (error) + : "r" (tv), "r" (tz), "r" (nr) + : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", + "$14", "$15", "$24", "$25", "hi", "lo", "memory"); + + return error ? -ret : ret; +} + +#else + +static __always_inline long gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + return -1; +} + +#endif + +static __always_inline long clock_gettime_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + register struct __kernel_timespec *ts asm("a1") = _ts; + register clockid_t clkid asm("a0") = _clkid; + register long ret asm("v0"); +#if _MIPS_SIM == _MIPS_SIM_ABI64 + register long nr asm("v0") = __NR_clock_gettime; +#else + register long nr asm("v0") = __NR_clock_gettime64; +#endif + register long error asm("a3"); + + asm volatile( + " syscall\n" + : "=r" (ret), "=r" (error) + : "r" (clkid), "r" (ts), "r" (nr) + : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", + "$14", "$15", "$24", "$25", "hi", "lo", "memory"); + + return error ? -ret : ret; +} + +#ifdef CONFIG_CSRC_R4K + +static __always_inline u64 read_r4k_count(void) +{ + unsigned int count; + + __asm__ __volatile__( + " .set push\n" + " .set mips32r2\n" + " rdhwr %0, $2\n" + " .set pop\n" + : "=r" (count)); + + return count; +} + +#endif + +#ifdef CONFIG_CLKSRC_MIPS_GIC + +static __always_inline u64 read_gic_count(const struct vdso_data *data) +{ + void __iomem *gic = get_gic(data); + u32 hi, hi2, lo; + + do { + hi = __raw_readl(gic + sizeof(lo)); + lo = __raw_readl(gic); + hi2 = __raw_readl(gic + sizeof(lo)); + } while (hi2 != hi); + + return (((u64)hi) << 32) + lo; +} + +#endif + +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode) +{ +#ifdef CONFIG_CLKSRC_MIPS_GIC + const struct vdso_data *data = get_vdso_data(); +#endif + u64 cycle_now; + + switch (clock_mode) { +#ifdef CONFIG_CSRC_R4K + case VDSO_CLOCK_R4K: + cycle_now = read_r4k_count(); + break; +#endif +#ifdef CONFIG_CLKSRC_MIPS_GIC + case VDSO_CLOCK_GIC: + cycle_now = read_gic_count(data); + break; +#endif + default: + cycle_now = 0; + break; + } + + return cycle_now; +} + +static __always_inline const struct vdso_data *__arch_get_vdso_data(void) +{ + return get_vdso_data(); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/mips/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h similarity index 89% rename from arch/mips/vdso/vdso.h rename to arch/mips/include/asm/vdso/vdso.h index 14b1931be69c..526695bc65ee 100644 --- a/arch/mips/vdso/vdso.h +++ b/arch/mips/include/asm/vdso/vdso.h @@ -68,14 +68,14 @@ static inline unsigned long get_vdso_base(void) return addr; }
-static inline const union mips_vdso_data *get_vdso_data(void) +static inline const struct vdso_data *get_vdso_data(void) { - return (const union mips_vdso_data *)(get_vdso_base() - PAGE_SIZE); + return (const struct vdso_data *)(get_vdso_base() - PAGE_SIZE); }
#ifdef CONFIG_CLKSRC_MIPS_GIC
-static inline void __iomem *get_gic(const union mips_vdso_data *data) +static inline void __iomem *get_gic(const struct vdso_data *data) { return (void __iomem *)data - PAGE_SIZE; } diff --git a/arch/mips/include/asm/vdso/vsyscall.h b/arch/mips/include/asm/vdso/vsyscall.h new file mode 100644 index 000000000000..195314732233 --- /dev/null +++ b/arch/mips/include/asm/vdso/vsyscall.h @@ -0,0 +1,43 @@ +/* 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> + +extern struct vdso_data *vdso_data; + +/* + * Update the vDSO data page to keep in sync with kernel timekeeping. + */ +static __always_inline +struct vdso_data *__mips_get_k_vdso_data(void) +{ + return vdso_data; +} +#define __arch_get_k_vdso_data __mips_get_k_vdso_data + +static __always_inline +int __mips_get_clock_mode(struct timekeeper *tk) +{ + u32 clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode; + + return clock_mode; +} +#define __arch_get_clock_mode __mips_get_clock_mode + +static __always_inline +int __mips_use_vsyscall(struct vdso_data *vdata) +{ + return (vdata[CS_HRES_COARSE].clock_mode != VDSO_CLOCK_NONE); +} +#define __arch_use_vsyscall __mips_use_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/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c index 3a372686ffca..bc35f8499111 100644 --- a/arch/mips/kernel/vdso.c +++ b/arch/mips/kernel/vdso.c @@ -20,9 +20,12 @@ #include <asm/mips-cps.h> #include <asm/page.h> #include <asm/vdso.h> +#include <vdso/helpers.h> +#include <vdso/vsyscall.h>
/* Kernel-provided data used by the VDSO. */ -static union mips_vdso_data vdso_data __page_aligned_data; +static union mips_vdso_data mips_vdso_data __page_aligned_data; +struct vdso_data *vdso_data = mips_vdso_data.data;
/* * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as @@ -66,34 +69,6 @@ static int __init init_vdso(void) } subsys_initcall(init_vdso);
-void update_vsyscall(struct timekeeper *tk) -{ - vdso_data_write_begin(&vdso_data); - - vdso_data.xtime_sec = tk->xtime_sec; - vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec; - vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec; - vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec; - vdso_data.cs_shift = tk->tkr_mono.shift; - - vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode; - if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { - vdso_data.cs_mult = tk->tkr_mono.mult; - vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data.cs_mask = tk->tkr_mono.mask; - } - - vdso_data_write_end(&vdso_data); -} - -void update_vsyscall_tz(void) -{ - if (vdso_data.clock_mode != VDSO_CLOCK_NONE) { - vdso_data.tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data.tz_dsttime = sys_tz.tz_dsttime; - } -} - static unsigned long vdso_base(void) { unsigned long base; @@ -163,7 +138,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) */ if (cpu_has_dc_aliases) { base = __ALIGN_MASK(base, shm_align_mask); - base += ((unsigned long)&vdso_data - gic_size) & shm_align_mask; + base += ((unsigned long)vdso_data - gic_size) & shm_align_mask; }
data_addr = base + gic_size; @@ -189,7 +164,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
/* Map data page. */ ret = remap_pfn_range(vma, data_addr, - virt_to_phys(&vdso_data) >> PAGE_SHIFT, + virt_to_phys(vdso_data) >> PAGE_SHIFT, PAGE_SIZE, PAGE_READONLY); if (ret) goto out; diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index 7221df24cb23..95df49402a53 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -1,6 +1,12 @@ # SPDX-License-Identifier: GPL-2.0 # Objects to go into the VDSO. -obj-vdso-y := elf.o gettimeofday.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_MIPS_JUMP_SLOT|R_MIPS_GLOB_DAT +include $(srctree)/lib/vdso/Makefile + +obj-vdso-y := elf.o vgettimeofday.o sigreturn.o
# Common compiler flags between ABIs. ccflags-vdso := \ @@ -15,15 +21,25 @@ ifdef CONFIG_CC_IS_CLANG ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS)) endif
+# +# The -fno-jump-tables flag only prevents the compiler from generating +# jump tables but does not prevent the compiler from emitting absolute +# offsets. cflags-vdso := $(ccflags-vdso) \ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \ - -O2 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ - -DDISABLE_BRANCH_PROFILING \ + -O3 -g -fPIC -fno-strict-aliasing -fno-common -fno-builtin -G 0 \ + -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \ $(call cc-option, -fno-asynchronous-unwind-tables) \ $(call cc-option, -fno-stack-protector) aflags-vdso := $(ccflags-vdso) \ -D__ASSEMBLY__ -Wa,-gdwarf-2
+ifneq ($(c-gettimeofday-y),) +CFLAGS_vgettimeofday.o = -include $(c-gettimeofday-y) +endif + +CFLAGS_REMOVE_vgettimeofday.o = -pg + # # For the pre-R6 code in arch/mips/vdso/vdso.h for locating # the base address of VDSO, the linker will emit a R_MIPS_PC32 @@ -48,6 +64,8 @@ VDSO_LDFLAGS := \ $(addprefix -Wl$(comma),$(filter -E%,$(KBUILD_CFLAGS))) \ -nostdlib -shared -Wl,--hash-style=sysv -Wl,--build-id
+CFLAGS_REMOVE_vdso.o = -pg + GCOV_PROFILE := n UBSAN_SANITIZE := n
@@ -96,6 +114,7 @@ $(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE $(call if_changed,vdsold) + $(call if_changed,vdso_check)
$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \ $(obj)/genvdso FORCE @@ -134,6 +153,7 @@ $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE $(call if_changed,vdsold) + $(call if_changed,vdso_check)
$(obj)/vdso-o32-image.c: VDSO_NAME := o32 $(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \ @@ -174,6 +194,7 @@ $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE $(call if_changed,vdsold) + $(call if_changed,vdso_check)
$(obj)/vdso-n32-image.c: VDSO_NAME := n32 $(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \ diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S index e7543e8f426c..a25cb147f1ca 100644 --- a/arch/mips/vdso/elf.S +++ b/arch/mips/vdso/elf.S @@ -4,7 +4,7 @@ * Author: Alex Smith alex.smith@imgtec.com */
-#include "vdso.h" +#include <asm/vdso/vdso.h>
#include <asm/isa-rev.h>
diff --git a/arch/mips/vdso/sigreturn.S b/arch/mips/vdso/sigreturn.S index c3597632874b..e5c0ab98ab46 100644 --- a/arch/mips/vdso/sigreturn.S +++ b/arch/mips/vdso/sigreturn.S @@ -4,7 +4,7 @@ * Author: Alex Smith alex.smith@imgtec.com */
-#include "vdso.h" +#include <asm/vdso/vdso.h>
#include <uapi/asm/unistd.h>
diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c new file mode 100644 index 000000000000..1c46dace041e --- /dev/null +++ b/arch/mips/vdso/vgettimeofday.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MIPS64 and compat userspace implementations of gettimeofday() + * and similar. + * + * Copyright (C) 2015 Imagination Technologies + * Copyright (C) 2018 ARM Limited + * + */ +#include <linux/time.h> +#include <linux/types.h> + +#if _MIPS_SIM != _MIPS_SIM_ABI64 +int __vdso_clock_gettime(clockid_t clock, + struct old_timespec32 *ts) +{ + return __cvdso_clock_gettime32(clock, ts); +} + +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) +{ + return __cvdso_gettimeofday(tv, tz); +} + +#else + +int __vdso_clock_gettime(clockid_t clock, + struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} + +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) +{ + return __cvdso_gettimeofday(tv, tz); +} + +#endif
Hello,
Vincenzo Frascino wrote:
The mips 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: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
Applied to mips-next.
Thanks, Paul
[ This message was auto-generated; if you believe anything is incorrect then please email paul.burton@mips.com to report it. ]
Consequently to the unified vDSO transition of the MIPS architecture few compilation issues appeared due to: - A wrong source path for the configuration environment settings for the O32 and N32 vDSO library generation. - A flip/flop vDSO building bug that would cause to rebuild the vDSO library every second time.
This patch series addresses both the issues providing the respective fixes.
This patchset is rebased on top of mips-next.
Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
Vincenzo Frascino (2): mips: vdso: Fix source path mips: vdso: Fix flip/flop vdso building bug
arch/mips/vdso/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
The vdso library for o32 and n32 does not compile compile correctly due to a wrong inclusion path for config-n32-o32-env.c resulting in the error below:
cc1: fatal error: arch/mips/vdso/config-n32-o32-env.c: No such file or dnirectory compilation terminated. arch/mips/vdso/Makefile:153: recipe for target 'arch/mips/vdso/vgettimeofday-o32.o' failed make[3]: *** [arch/mips/vdso/vgettimeofday-o32.o] Error 1 scripts/Makefile.build:490: recipe for target 'arch/mips/vdso' failed
Fix the config-n32-o32-env.c inclusion path prepending the $(srctree) variable.
Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/mips/vdso/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index de853c6aab28..6b482ac52e61 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -40,8 +40,8 @@ CFLAGS_vgettimeofday.o = -include $(c-gettimeofday-y) # config-n32-o32-env.c prepares the environment to build a 32bit vDSO # library on a 64bit kernel. # Note: Needs to be included before than the generic library. -CFLAGS_vgettimeofday-o32.o = -include $(src)/config-n32-o32-env.c -include $(c-gettimeofday-y) -CFLAGS_vgettimeofday-n32.o = -include $(src)/config-n32-o32-env.c -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-o32.o = -include $(srctree)/$(src)/config-n32-o32-env.c -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-n32.o = -include $(srctree)/$(src)/config-n32-o32-env.c -include $(c-gettimeofday-y) endif
CFLAGS_REMOVE_vgettimeofday.o = -pg
Running "make" on an already compiled kernel tree will rebuild the vdso library even if this has not been modified.
$ make GEN Makefile Using linux as source for kernel CALL linux/scripts/atomic/check-atomics.sh CALL linux/scripts/checksyscalls.sh <stdin>:1511:2: warning: #warning syscall clone3 not implemented [-Wcpp] CHK include/generated/compile.h VDSO arch/mips/vdso/vdso.so.dbg.raw OBJCOPY arch/mips/vdso/vdso.so.raw GENVDSO arch/mips/vdso/vdso-image.c CC arch/mips/vdso/vdso-image.o AR arch/mips/vdso/built-in.a AR arch/mips/built-in.a CHK include/generated/autoksyms.h GEN .version CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o AR init/built-in.a LD vmlinux.o MODPOST vmlinux.o MODINFO modules.builtin.modinfo KSYM .tmp_kallsyms1.o KSYM .tmp_kallsyms2.o LD vmlinux SORTEX vmlinux SYSMAP System.map Building modules, stage 2. ITS arch/mips/boot/vmlinux.gz.its OBJCOPY arch/mips/boot/vmlinux.bin MODPOST 7 modules GZIP arch/mips/boot/vmlinux.bin.gz ITB arch/mips/boot/vmlinux.gz.itb
The issue is generated by the fact that "if_changed" is called twice in a single target.
Fix the build bug merging the two commands into a single function.
Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/mips/vdso/Makefile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index 6b482ac52e61..69cfa0a5339e 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -79,11 +79,14 @@ UBSAN_SANITIZE := n # Shared build commands. #
+quiet_cmd_vdsold_and_vdso_check = LD $@ + cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check) + quiet_cmd_vdsold = VDSO $@ cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \ -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
-quiet_cmd_vdsoas_o_S = AS $@ +quiet_cmd_vdsoas_o_S = AS $@ cmd_vdsoas_o_S = $(CC) $(a_flags) -c -o $@ $<
# Strip rule for the raw .so files @@ -119,8 +122,7 @@ $(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi) $(obj)/vdso.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) $(native-abi)
$(obj)/vdso.so.dbg.raw: $(obj)/vdso.lds $(obj-vdso) FORCE - $(call if_changed,vdsold) - $(call if_changed,vdso_check) + $(call if_changed,vdsold_and_vdso_check)
$(obj)/vdso-image.c: $(obj)/vdso.so.dbg.raw $(obj)/vdso.so.raw \ $(obj)/genvdso FORCE @@ -158,8 +160,7 @@ $(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S)
$(obj)/vdso-o32.so.dbg.raw: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE - $(call if_changed,vdsold) - $(call if_changed,vdso_check) + $(call if_changed,vdsold_and_vdso_check)
$(obj)/vdso-o32-image.c: VDSO_NAME := o32 $(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg.raw $(obj)/vdso-o32.so.raw \ @@ -199,8 +200,7 @@ $(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE $(call if_changed_dep,cpp_lds_S)
$(obj)/vdso-n32.so.dbg.raw: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE - $(call if_changed,vdsold) - $(call if_changed,vdso_check) + $(call if_changed,vdsold_and_vdso_check)
$(obj)/vdso-n32-image.c: VDSO_NAME := n32 $(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg.raw $(obj)/vdso-n32.so.raw \
Hello,
Vincenzo Frascino wrote:
Consequently to the unified vDSO transition of the MIPS architecture few compilation issues appeared due to:
- A wrong source path for the configuration environment settings for
the O32 and N32 vDSO library generation.
- A flip/flop vDSO building bug that would cause to rebuild the vDSO
library every second time.
This patch series addresses both the issues providing the respective fixes.
This patchset is rebased on top of mips-next.
Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
Vincenzo Frascino (2): mips: vdso: Fix source path mips: vdso: Fix flip/flop vdso building bug
arch/mips/vdso/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
Series applied to mips-next.
Thanks, Paul
[ This message was auto-generated; if you believe anything is incorrect then please email paul.burton@mips.com to report it. ]
The generic vDSO library provides an implementation of clock_getres() that can be leveraged by each architecture.
Add clock_getres() entry point on mips.
Cc: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/mips/include/asm/vdso/gettimeofday.h | 26 +++++++++++++++++++++++ arch/mips/vdso/vdso.lds.S | 1 + arch/mips/vdso/vgettimeofday.c | 12 +++++++++++ 3 files changed, 39 insertions(+)
diff --git a/arch/mips/include/asm/vdso/gettimeofday.h b/arch/mips/include/asm/vdso/gettimeofday.h index aa20865b288b..c59fe08b0347 100644 --- a/arch/mips/include/asm/vdso/gettimeofday.h +++ b/arch/mips/include/asm/vdso/gettimeofday.h @@ -22,6 +22,8 @@ #include <asm/unistd.h> #include <asm/vdso.h>
+#define VDSO_HAS_CLOCK_GETRES 1 + #ifdef CONFIG_MIPS_CLOCK_VSYSCALL
static __always_inline long gettimeofday_fallback( @@ -79,6 +81,30 @@ static __always_inline long clock_gettime_fallback( return error ? -ret : ret; }
+static __always_inline int clock_getres_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + register struct __kernel_timespec *ts asm("a1") = _ts; + register clockid_t clkid asm("a0") = _clkid; + register long ret asm("v0"); +#if _MIPS_SIM == _MIPS_SIM_ABI64 + register long nr asm("v0") = __NR_clock_getres; +#else + register long nr asm("v0") = __NR_clock_getres_time64; +#endif + register long error asm("a3"); + + asm volatile( + " syscall\n" + : "=r" (ret), "=r" (error) + : "r" (clkid), "r" (ts), "r" (nr) + : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", + "$14", "$15", "$24", "$25", "hi", "lo", "memory"); + + return error ? -ret : ret; +} + #ifdef CONFIG_CSRC_R4K
static __always_inline u64 read_r4k_count(void) diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S index 94d90c440590..ad9f2f2c0c97 100644 --- a/arch/mips/vdso/vdso.lds.S +++ b/arch/mips/vdso/vdso.lds.S @@ -95,6 +95,7 @@ VERSION global: __vdso_clock_gettime; __vdso_gettimeofday; + __vdso_clock_getres; #endif local: *; }; diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c index 1c46dace041e..48e1ab32204b 100644 --- a/arch/mips/vdso/vgettimeofday.c +++ b/arch/mips/vdso/vgettimeofday.c @@ -23,6 +23,12 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, return __cvdso_gettimeofday(tv, tz); }
+int __vdso_clock_getres(clockid_t clock_id, + struct old_timespec32 *res) +{ + return __cvdso_clock_getres_time32(clock_id, res); +} + #else
int __vdso_clock_gettime(clockid_t clock, @@ -37,4 +43,10 @@ int __vdso_gettimeofday(struct __kernel_old_timeval *tv, return __cvdso_gettimeofday(tv, tz); }
+int __vdso_clock_getres(clockid_t clock_id, + struct __kernel_timespec *res) +{ + return __cvdso_clock_getres(clock_id, res); +} + #endif
Hello,
Vincenzo Frascino wrote:
The generic vDSO library provides an implementation of clock_getres() that can be leveraged by each architecture.
Add clock_getres() entry point on mips.
Cc: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
Applied to mips-next.
Thanks, Paul
[ This message was auto-generated; if you believe anything is incorrect then please email paul.burton@mips.com to report it. ]
With the release of Linux 5.1 has been added a new syscall, clock_gettime64, that provided a 64 bit time value for a specified clock_ID to make the kernel Y2038 safe on 32 bit architectures.
Update the mips32 specific vDSO library accordingly with what it has been done for the kernel syscall exposing the clock_gettime64 entry point.
Cc: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/mips/vdso/vdso.lds.S | 3 +++ arch/mips/vdso/vgettimeofday.c | 6 ++++++ 2 files changed, 9 insertions(+)
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S index ad9f2f2c0c97..da4627430aba 100644 --- a/arch/mips/vdso/vdso.lds.S +++ b/arch/mips/vdso/vdso.lds.S @@ -96,6 +96,9 @@ VERSION __vdso_clock_gettime; __vdso_gettimeofday; __vdso_clock_getres; +#if _MIPS_SIM != _MIPS_SIM_ABI64 + __vdso_clock_gettime64; +#endif #endif local: *; }; diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c index 48e1ab32204b..6ebdc37c89fc 100644 --- a/arch/mips/vdso/vgettimeofday.c +++ b/arch/mips/vdso/vgettimeofday.c @@ -29,6 +29,12 @@ int __vdso_clock_getres(clockid_t clock_id, return __cvdso_clock_getres_time32(clock_id, res); }
+int __vdso_clock_gettime64(clockid_t clock, + struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} + #else
int __vdso_clock_gettime(clockid_t clock,
Hello,
Vincenzo Frascino wrote:
With the release of Linux 5.1 has been added a new syscall, clock_gettime64, that provided a 64 bit time value for a specified clock_ID to make the kernel Y2038 safe on 32 bit architectures.
Update the mips32 specific vDSO library accordingly with what it has been done for the kernel syscall exposing the clock_gettime64 entry point.
Cc: Ralf Baechle ralf@linux-mips.org Cc: Paul Burton paul.burton@mips.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com
Applied to mips-next.
Thanks, Paul
[ This message was auto-generated; if you believe anything is incorrect then please email paul.burton@mips.com to report it. ]
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@linutronix.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/x86/Kconfig | 3 + arch/x86/entry/vdso/Makefile | 9 + arch/x86/entry/vdso/vclock_gettime.c | 241 +++-------------------- arch/x86/entry/vdso/vdsox32.lds.S | 1 + arch/x86/entry/vsyscall/Makefile | 2 - arch/x86/entry/vsyscall/vsyscall_gtod.c | 83 -------- arch/x86/include/asm/pvclock.h | 2 +- arch/x86/include/asm/vdso/gettimeofday.h | 175 ++++++++++++++++ arch/x86/include/asm/vdso/vsyscall.h | 44 +++++ arch/x86/include/asm/vgtod.h | 75 +------ arch/x86/include/asm/vvar.h | 7 +- arch/x86/kernel/pvclock.c | 1 + 12 files changed, 270 insertions(+), 373 deletions(-) delete mode 100644 arch/x86/entry/vsyscall/vsyscall_gtod.c create mode 100644 arch/x86/include/asm/vdso/gettimeofday.h create mode 100644 arch/x86/include/asm/vdso/vsyscall.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2bbbd4d1ba31..51a98d6eae8e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -17,6 +17,7 @@ config X86_32 select HAVE_DEBUG_STACKOVERFLOW select MODULES_USE_ELF_REL select OLD_SIGACTION + select GENERIC_VDSO_32
config X86_64 def_bool y @@ -121,6 +122,7 @@ config X86 select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL + select GENERIC_GETTIMEOFDAY select HARDLOCKUP_CHECK_TIMESTAMP if X86_64 select HAVE_ACPI_APEI if ACPI select HAVE_ACPI_APEI_NMI if ACPI @@ -202,6 +204,7 @@ config X86 select HAVE_SYSCALL_TRACEPOINTS select HAVE_UNSTABLE_SCHED_CLOCK select HAVE_USER_RETURN_NOTIFIER + select HAVE_GENERIC_VDSO select HOTPLUG_SMT if SMP select IRQ_FORCED_THREADING select NEED_SG_DMA_LENGTH diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index 42fe42e82baf..39106111be86 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -3,6 +3,12 @@ # Building vDSO images for x86. #
+# Absolute relocation type $(ARCH_REL_TYPE_ABS) needs to be defined before +# the inclusion of generic Makefile. +ARCH_REL_TYPE_ABS := R_X86_64_JUMP_SLOT|R_X86_64_GLOB_DAT|R_X86_64_RELATIVE| +ARCH_REL_TYPE_ABS += R_386_GLOB_DAT|R_386_JMP_SLOT|R_386_RELATIVE +include $(srctree)/lib/vdso/Makefile + KBUILD_CFLAGS += $(DISABLE_LTO) KASAN_SANITIZE := n UBSAN_SANITIZE := n @@ -51,6 +57,7 @@ VDSO_LDFLAGS_vdso.lds = -m elf_x86_64 -soname linux-vdso.so.1 --no-undefined \
$(obj)/vdso64.so.dbg: $(obj)/vdso.lds $(vobjs) FORCE $(call if_changed,vdso) + $(call if_changed,vdso_check)
HOST_EXTRACFLAGS += -I$(srctree)/tools/include -I$(srctree)/include/uapi -I$(srctree)/arch/$(SUBARCH)/include/uapi hostprogs-y += vdso2c @@ -121,6 +128,7 @@ $(obj)/%.so: $(obj)/%.so.dbg FORCE
$(obj)/vdsox32.so.dbg: $(obj)/vdsox32.lds $(vobjx32s) FORCE $(call if_changed,vdso) + $(call if_changed,vdso_check)
CPPFLAGS_vdso32.lds = $(CPPFLAGS_vdso.lds) VDSO_LDFLAGS_vdso32.lds = -m elf_i386 -soname linux-gate.so.1 @@ -160,6 +168,7 @@ $(obj)/vdso32.so.dbg: FORCE \ $(obj)/vdso32/system_call.o \ $(obj)/vdso32/sigreturn.o $(call if_changed,vdso) + $(call if_changed,vdso_check)
# # The DSO images are built using a special linker script. diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 310e7bf59ad2..4a7ef4ca4f52 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -1,241 +1,58 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright 2006 Andi Kleen, SUSE Labs. - * * Fast user context implementation of clock_gettime, gettimeofday, and time. * + * Copyright 2006 Andi Kleen, SUSE Labs. + * Copyright 2019 ARM Limited + * * 32 Bit compat layer by Stefani Seibold stefani@seibold.net * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany - * - * The code should have no internal unresolved relocations. - * Check with readelf after changing. */ - -#include <uapi/linux/time.h> -#include <asm/vgtod.h> -#include <asm/vvar.h> -#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> -#include <clocksource/hyperv_timer.h> +#include <linux/types.h>
-#define gtod (&VVAR(vsyscall_gtod_data)) +#include "../../../../lib/vdso/gettimeofday.c"
-extern int __vdso_clock_gettime(clockid_t clock, struct timespec *ts); -extern int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz); +extern int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); extern time_t __vdso_time(time_t *t);
-#ifdef CONFIG_PARAVIRT_CLOCK -extern u8 pvclock_page[PAGE_SIZE] - __attribute__((visibility("hidden"))); -#endif - -#ifdef CONFIG_HYPERV_TSCPAGE -extern u8 hvclock_page[PAGE_SIZE] - __attribute__((visibility("hidden"))); -#endif - -#ifndef BUILD_VDSO32 - -notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) -{ - long ret; - asm ("syscall" : "=a" (ret), "=m" (*ts) : - "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : - "rcx", "r11"); - return ret; -} - -#else - -notrace static long vdso_fallback_gettime(long clock, struct timespec *ts) +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, + struct timezone *tz) { - long ret; - - asm ( - "mov %%ebx, %%edx \n" - "mov %[clock], %%ebx \n" - "call __kernel_vsyscall \n" - "mov %%edx, %%ebx \n" - : "=a" (ret), "=m" (*ts) - : "0" (__NR_clock_gettime), [clock] "g" (clock), "c" (ts) - : "edx"); - return ret; + return __cvdso_gettimeofday(tv, tz); } +int gettimeofday(struct __kernel_old_timeval *, struct timezone *) + __attribute__((weak, alias("__vdso_gettimeofday")));
-#endif - -#ifdef CONFIG_PARAVIRT_CLOCK -static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void) +time_t __vdso_time(time_t *t) { - return (const struct pvclock_vsyscall_time_info *)&pvclock_page; + return __cvdso_time(t); } +time_t time(time_t *t) + __attribute__((weak, alias("__vdso_time")));
-static notrace u64 vread_pvclock(void) -{ - const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti; - u32 version; - u64 ret; - - /* - * Note: The kernel and hypervisor must guarantee that cpu ID - * number maps 1:1 to per-CPU pvclock time info. - * - * Because the hypervisor is entirely unaware of guest userspace - * preemption, it cannot guarantee that per-CPU pvclock time - * info is updated if the underlying CPU changes or that that - * version is increased whenever underlying CPU changes. - * - * On KVM, we are guaranteed that pvti updates for any vCPU are - * atomic as seen by *all* vCPUs. This is an even stronger - * guarantee than we get with a normal seqlock. - * - * On Xen, we don't appear to have that guarantee, but Xen still - * supplies a valid seqlock using the version field. - * - * We only do pvclock vdso timing at all if - * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to - * mean that all vCPUs have matching pvti and that the TSC is - * synced, so we can just look at vCPU 0's pvti. - */ - - do { - version = pvclock_read_begin(pvti); - - if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) - return U64_MAX;
- ret = __pvclock_read_cycles(pvti, rdtsc_ordered()); - } while (pvclock_read_retry(pvti, version)); +#if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64) +/* both 64-bit and x32 use these */ +extern int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts);
- return ret; -} -#endif -#ifdef CONFIG_HYPERV_TSCPAGE -static notrace u64 vread_hvclock(void) +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { - const struct ms_hyperv_tsc_page *tsc_pg = - (const struct ms_hyperv_tsc_page *)&hvclock_page; - - return hv_read_tsc_page(tsc_pg); + return __cvdso_clock_gettime(clock, ts); } -#endif - -notrace static inline u64 vgetcyc(int mode) -{ - if (mode == VCLOCK_TSC) - return (u64)rdtsc_ordered(); -#ifdef CONFIG_PARAVIRT_CLOCK - else if (mode == VCLOCK_PVCLOCK) - return vread_pvclock(); -#endif -#ifdef CONFIG_HYPERV_TSCPAGE - else if (mode == VCLOCK_HVCLOCK) - return vread_hvclock(); -#endif - return U64_MAX; -} - -notrace static int do_hres(clockid_t clk, struct timespec *ts) -{ - struct vgtod_ts *base = >od->basetime[clk]; - u64 cycles, last, sec, ns; - unsigned int seq; - - do { - seq = gtod_read_begin(gtod); - cycles = vgetcyc(gtod->vclock_mode); - ns = base->nsec; - last = gtod->cycle_last; - if (unlikely((s64)cycles < 0)) - return vdso_fallback_gettime(clk, ts); - if (cycles > last) - ns += (cycles - last) * gtod->mult; - ns >>= gtod->shift; - sec = base->sec; - } while (unlikely(gtod_read_retry(gtod, seq))); - - /* - * Do this outside the loop: a race inside the loop could result - * in __iter_div_u64_rem() being extremely slow. - */ - ts->tv_sec = sec + __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -notrace static void do_coarse(clockid_t clk, struct timespec *ts) -{ - struct vgtod_ts *base = >od->basetime[clk]; - unsigned int seq; +int clock_gettime(clockid_t, struct __kernel_timespec *) + __attribute__((weak, alias("__vdso_clock_gettime")));
- do { - seq = gtod_read_begin(gtod); - ts->tv_sec = base->sec; - ts->tv_nsec = base->nsec; - } while (unlikely(gtod_read_retry(gtod, seq))); -} +#else +/* i386 only */ +extern int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts);
-notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) +int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { - unsigned int msk; - - /* Sort out negative (CPU/FD) and invalid clocks */ - if (unlikely((unsigned int) clock >= MAX_CLOCKS)) - return vdso_fallback_gettime(clock, ts); - - /* - * Convert the clockid to a bitmask and use it to check which - * clocks are handled in the VDSO directly. - */ - msk = 1U << clock; - if (likely(msk & VGTOD_HRES)) { - return do_hres(clock, ts); - } else if (msk & VGTOD_COARSE) { - do_coarse(clock, ts); - return 0; - } - return vdso_fallback_gettime(clock, ts); + return __cvdso_clock_gettime32(clock, ts); } - -int clock_gettime(clockid_t, struct timespec *) +int clock_gettime(clockid_t, struct old_timespec32 *) __attribute__((weak, alias("__vdso_clock_gettime")));
-notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) -{ - if (likely(tv != NULL)) { - struct timespec *ts = (struct timespec *) tv; - - do_hres(CLOCK_REALTIME, ts); - tv->tv_usec /= 1000; - } - if (unlikely(tz != NULL)) { - tz->tz_minuteswest = gtod->tz_minuteswest; - tz->tz_dsttime = gtod->tz_dsttime; - } - - return 0; -} -int gettimeofday(struct timeval *, struct timezone *) - __attribute__((weak, alias("__vdso_gettimeofday"))); - -/* - * This will break when the xtime seconds get inaccurate, but that is - * unlikely - */ -notrace time_t __vdso_time(time_t *t) -{ - /* This is atomic on x86 so we don't need any locks. */ - time_t result = READ_ONCE(gtod->basetime[CLOCK_REALTIME].sec); - - if (t) - *t = result; - return result; -} -time_t time(time_t *t) - __attribute__((weak, alias("__vdso_time"))); +#endif diff --git a/arch/x86/entry/vdso/vdsox32.lds.S b/arch/x86/entry/vdso/vdsox32.lds.S index 05cd1c5c4a15..16a8050a4fb6 100644 --- a/arch/x86/entry/vdso/vdsox32.lds.S +++ b/arch/x86/entry/vdso/vdsox32.lds.S @@ -21,6 +21,7 @@ VERSION { __vdso_gettimeofday; __vdso_getcpu; __vdso_time; + __vdso_clock_getres; local: *; }; } diff --git a/arch/x86/entry/vsyscall/Makefile b/arch/x86/entry/vsyscall/Makefile index 1ac4dd116c26..93c1b3e949a7 100644 --- a/arch/x86/entry/vsyscall/Makefile +++ b/arch/x86/entry/vsyscall/Makefile @@ -2,7 +2,5 @@ # # Makefile for the x86 low level vsyscall code # -obj-y := vsyscall_gtod.o - obj-$(CONFIG_X86_VSYSCALL_EMULATION) += vsyscall_64.o vsyscall_emu_64.o
diff --git a/arch/x86/entry/vsyscall/vsyscall_gtod.c b/arch/x86/entry/vsyscall/vsyscall_gtod.c deleted file mode 100644 index cfcdba082feb..000000000000 --- a/arch/x86/entry/vsyscall/vsyscall_gtod.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2001 Andrea Arcangeli andrea@suse.de SuSE - * Copyright 2003 Andi Kleen, SuSE Labs. - * - * Modified for x86 32 bit architecture by - * Stefani Seibold stefani@seibold.net - * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany - * - * Thanks to hpa@transmeta.com for some useful hint. - * Special thanks to Ingo Molnar for his early experience with - * a different vsyscall implementation for Linux/IA32 and for the name. - * - */ - -#include <linux/timekeeper_internal.h> -#include <asm/vgtod.h> -#include <asm/vvar.h> - -int vclocks_used __read_mostly; - -DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data); - -void update_vsyscall_tz(void) -{ - vsyscall_gtod_data.tz_minuteswest = sys_tz.tz_minuteswest; - vsyscall_gtod_data.tz_dsttime = sys_tz.tz_dsttime; -} - -void update_vsyscall(struct timekeeper *tk) -{ - int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; - struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; - struct vgtod_ts *base; - u64 nsec; - - /* Mark the new vclock used. */ - BUILD_BUG_ON(VCLOCK_MAX >= 32); - WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode)); - - gtod_write_begin(vdata); - - /* copy vsyscall data */ - vdata->vclock_mode = vclock_mode; - vdata->cycle_last = tk->tkr_mono.cycle_last; - vdata->mask = tk->tkr_mono.mask; - vdata->mult = tk->tkr_mono.mult; - vdata->shift = tk->tkr_mono.shift; - - base = &vdata->basetime[CLOCK_REALTIME]; - base->sec = tk->xtime_sec; - base->nsec = tk->tkr_mono.xtime_nsec; - - base = &vdata->basetime[CLOCK_TAI]; - base->sec = tk->xtime_sec + (s64)tk->tai_offset; - base->nsec = tk->tkr_mono.xtime_nsec; - - base = &vdata->basetime[CLOCK_MONOTONIC]; - base->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; - nsec = tk->tkr_mono.xtime_nsec; - nsec += ((u64)tk->wall_to_monotonic.tv_nsec << tk->tkr_mono.shift); - while (nsec >= (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { - nsec -= ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; - base->sec++; - } - base->nsec = nsec; - - base = &vdata->basetime[CLOCK_REALTIME_COARSE]; - base->sec = tk->xtime_sec; - base->nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift; - - base = &vdata->basetime[CLOCK_MONOTONIC_COARSE]; - base->sec = tk->xtime_sec + tk->wall_to_monotonic.tv_sec; - nsec = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift; - nsec += tk->wall_to_monotonic.tv_nsec; - while (nsec >= NSEC_PER_SEC) { - nsec -= NSEC_PER_SEC; - base->sec++; - } - base->nsec = nsec; - - gtod_write_end(vdata); -} diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h index b6033680d458..19b695ff2c68 100644 --- a/arch/x86/include/asm/pvclock.h +++ b/arch/x86/include/asm/pvclock.h @@ -2,7 +2,7 @@ #ifndef _ASM_X86_PVCLOCK_H #define _ASM_X86_PVCLOCK_H
-#include <linux/clocksource.h> +#include <asm/clocksource.h> #include <asm/pvclock-abi.h>
/* some helper functions for xen and kvm pv clock sources */ diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h new file mode 100644 index 000000000000..a274d4fea7a5 --- /dev/null +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -0,0 +1,175 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Fast user context implementation of clock_gettime, gettimeofday, and time. + * + * Copyright (C) 2019 ARM Limited. + * Copyright 2006 Andi Kleen, SUSE Labs. + * 32 Bit compat layer by Stefani Seibold stefani@seibold.net + * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany + */ +#ifndef __ASM_VDSO_GETTIMEOFDAY_H +#define __ASM_VDSO_GETTIMEOFDAY_H + +#ifndef __ASSEMBLY__ + +#include <clocksource/hyperv_timer.h> +#include <uapi/linux/time.h> +#include <asm/vgtod.h> +#include <asm/vvar.h> +#include <asm/unistd.h> +#include <asm/msr.h> +#include <asm/pvclock.h> + +#define __vdso_data (VVAR(_vdso_data)) + +#define VDSO_HAS_TIME 1 + +#ifdef CONFIG_PARAVIRT_CLOCK +extern u8 pvclock_page[PAGE_SIZE] + __attribute__((visibility("hidden"))); +#endif + +#ifdef CONFIG_HYPERV_TSCPAGE +extern u8 hvclock_page[PAGE_SIZE] + __attribute__((visibility("hidden"))); +#endif + +#ifndef BUILD_VDSO32 + +static __always_inline long clock_gettime_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + long ret; + asm ("syscall" : "=a" (ret), "=m" (*_ts) : + "0" (__NR_clock_gettime), "D" (_clkid), "S" (_ts) : + "rcx", "r11"); + return ret; +} + +static __always_inline long gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + long ret; + asm("syscall" : "=a" (ret) : + "0" (__NR_gettimeofday), "D" (_tv), "S" (_tz) : "memory"); + return ret; +} + +#else + +static __always_inline long clock_gettime_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + long ret; + + asm ( + "mov %%ebx, %%edx \n" + "mov %[clock], %%ebx \n" + "call __kernel_vsyscall \n" + "mov %%edx, %%ebx \n" + : "=a" (ret), "=m" (*_ts) + : "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts) + : "edx"); + return ret; +} + +static __always_inline long gettimeofday_fallback( + struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + long ret; + asm( + "mov %%ebx, %%edx \n" + "mov %2, %%ebx \n" + "call __kernel_vsyscall \n" + "mov %%edx, %%ebx \n" + : "=a" (ret) + : "0" (__NR_gettimeofday), "g" (_tv), "c" (_tz) + : "memory", "edx"); + return ret; +} + +#endif + +#ifdef CONFIG_PARAVIRT_CLOCK +static const struct pvclock_vsyscall_time_info *get_pvti0(void) +{ + return (const struct pvclock_vsyscall_time_info *)&pvclock_page; +} + +static u64 vread_pvclock(void) +{ + const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti; + u32 version; + u64 ret; + + /* + * Note: The kernel and hypervisor must guarantee that cpu ID + * number maps 1:1 to per-CPU pvclock time info. + * + * Because the hypervisor is entirely unaware of guest userspace + * preemption, it cannot guarantee that per-CPU pvclock time + * info is updated if the underlying CPU changes or that that + * version is increased whenever underlying CPU changes. + * + * On KVM, we are guaranteed that pvti updates for any vCPU are + * atomic as seen by *all* vCPUs. This is an even stronger + * guarantee than we get with a normal seqlock. + * + * On Xen, we don't appear to have that guarantee, but Xen still + * supplies a valid seqlock using the version field. + * + * We only do pvclock vdso timing at all if + * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to + * mean that all vCPUs have matching pvti and that the TSC is + * synced, so we can just look at vCPU 0's pvti. + */ + + do { + version = pvclock_read_begin(pvti); + + if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) + return U64_MAX; + + ret = __pvclock_read_cycles(pvti, rdtsc_ordered()); + } while (pvclock_read_retry(pvti, version)); + + return ret; +} +#endif +#ifdef CONFIG_HYPERV_TSCPAGE +static u64 vread_hvclock(void) +{ + const struct ms_hyperv_tsc_page *tsc_pg = + (const struct ms_hyperv_tsc_page *)&hvclock_page; + + return hv_read_tsc_page(tsc_pg); +} +#endif + +static inline u64 __arch_get_hw_counter(s32 clock_mode) +{ + if (clock_mode == VCLOCK_TSC) + return (u64)rdtsc_ordered(); +#ifdef CONFIG_PARAVIRT_CLOCK + else if (clock_mode == VCLOCK_PVCLOCK) + return vread_pvclock(); +#endif +#ifdef CONFIG_HYPERV_TSCPAGE + else if (clock_mode == VCLOCK_HVCLOCK) + return vread_hvclock(); +#endif + return U64_MAX; +} + +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/x86/include/asm/vdso/vsyscall.h b/arch/x86/include/asm/vdso/vsyscall.h new file mode 100644 index 000000000000..0026ab2123ce --- /dev/null +++ b/arch/x86/include/asm/vdso/vsyscall.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_VSYSCALL_H +#define __ASM_VDSO_VSYSCALL_H + +#ifndef __ASSEMBLY__ + +#include <linux/hrtimer.h> +#include <linux/timekeeper_internal.h> +#include <vdso/datapage.h> +#include <asm/vgtod.h> +#include <asm/vvar.h> + +int vclocks_used __read_mostly; + +DEFINE_VVAR(struct vdso_data, _vdso_data); +/* + * Update the vDSO data page to keep in sync with kernel timekeeping. + */ +static __always_inline +struct vdso_data *__x86_get_k_vdso_data(void) +{ + return _vdso_data; +} +#define __arch_get_k_vdso_data __x86_get_k_vdso_data + +static __always_inline +int __x86_get_clock_mode(struct timekeeper *tk) +{ + int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; + + /* Mark the new vclock used. */ + BUILD_BUG_ON(VCLOCK_MAX >= 32); + WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode)); + + return vclock_mode; +} +#define __arch_get_clock_mode __x86_get_clock_mode + +/* 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/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index 913a133f8e6f..a2638c6124ed 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -3,7 +3,9 @@ #define _ASM_X86_VGTOD_H
#include <linux/compiler.h> -#include <linux/clocksource.h> +#include <asm/clocksource.h> +#include <vdso/datapage.h> +#include <vdso/helpers.h>
#include <uapi/linux/time.h>
@@ -13,81 +15,10 @@ typedef u64 gtod_long_t; typedef unsigned long gtod_long_t; #endif
-/* - * There is one of these objects in the vvar page for each - * vDSO-accelerated clockid. For high-resolution clocks, this encodes - * the time corresponding to vsyscall_gtod_data.cycle_last. For coarse - * clocks, this encodes the actual time. - * - * To confuse the reader, for high-resolution clocks, nsec is left-shifted - * by vsyscall_gtod_data.shift. - */ -struct vgtod_ts { - u64 sec; - u64 nsec; -}; - -#define VGTOD_BASES (CLOCK_TAI + 1) -#define VGTOD_HRES (BIT(CLOCK_REALTIME) | BIT(CLOCK_MONOTONIC) | BIT(CLOCK_TAI)) -#define VGTOD_COARSE (BIT(CLOCK_REALTIME_COARSE) | BIT(CLOCK_MONOTONIC_COARSE)) - -/* - * vsyscall_gtod_data will be accessed by 32 and 64 bit code at the same time - * so be carefull by modifying this structure. - */ -struct vsyscall_gtod_data { - unsigned int seq; - - int vclock_mode; - u64 cycle_last; - u64 mask; - u32 mult; - u32 shift; - - struct vgtod_ts basetime[VGTOD_BASES]; - - int tz_minuteswest; - int tz_dsttime; -}; -extern struct vsyscall_gtod_data vsyscall_gtod_data; - extern int vclocks_used; static inline bool vclock_was_used(int vclock) { return READ_ONCE(vclocks_used) & (1 << vclock); }
-static inline unsigned int gtod_read_begin(const struct vsyscall_gtod_data *s) -{ - unsigned int ret; - -repeat: - ret = READ_ONCE(s->seq); - if (unlikely(ret & 1)) { - cpu_relax(); - goto repeat; - } - smp_rmb(); - return ret; -} - -static inline int gtod_read_retry(const struct vsyscall_gtod_data *s, - unsigned int start) -{ - smp_rmb(); - return unlikely(s->seq != start); -} - -static inline void gtod_write_begin(struct vsyscall_gtod_data *s) -{ - ++s->seq; - smp_wmb(); -} - -static inline void gtod_write_end(struct vsyscall_gtod_data *s) -{ - smp_wmb(); - ++s->seq; -} - #endif /* _ASM_X86_VGTOD_H */ diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h index e474f5c6e387..32f5d9a0b90e 100644 --- a/arch/x86/include/asm/vvar.h +++ b/arch/x86/include/asm/vvar.h @@ -32,19 +32,20 @@ extern char __vvar_page;
#define DECLARE_VVAR(offset, type, name) \ - extern type vvar_ ## name __attribute__((visibility("hidden"))); + extern type vvar_ ## name[CS_BASES] \ + __attribute__((visibility("hidden")));
#define VVAR(name) (vvar_ ## name)
#define DEFINE_VVAR(type, name) \ - type name \ + type name[CS_BASES] \ __attribute__((section(".vvar_" #name), aligned(16))) __visible
#endif
/* DECLARE_VVAR(offset, type, name) */
-DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data) +DECLARE_VVAR(128, struct vdso_data, _vdso_data)
#undef DECLARE_VVAR
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c index 0ff3e294d0e5..10125358b9c4 100644 --- a/arch/x86/kernel/pvclock.c +++ b/arch/x86/kernel/pvclock.c @@ -3,6 +3,7 @@
*/
+#include <linux/clocksource.h> #include <linux/kernel.h> #include <linux/percpu.h> #include <linux/notifier.h>
The generic vDSO library provides an implementation of clock_getres() that can be leveraged by each architecture.
Add clock_getres() entry point on x86.
Cc: Thomas Gleixner tglx@linutronix.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/x86/entry/vdso/vclock_gettime.c | 17 ++++++++++++++ arch/x86/entry/vdso/vdso.lds.S | 2 ++ arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 + arch/x86/include/asm/vdso/gettimeofday.h | 30 ++++++++++++++++++++++++ 4 files changed, 50 insertions(+)
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 4a7ef4ca4f52..de9212a4833e 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -36,6 +36,7 @@ time_t time(time_t *t) #if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64) /* both 64-bit and x32 use these */ extern int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); +extern int __vdso_clock_getres(clockid_t clock, struct __kernel_timespec *res);
int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { @@ -44,9 +45,18 @@ int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) int clock_gettime(clockid_t, struct __kernel_timespec *) __attribute__((weak, alias("__vdso_clock_gettime")));
+int __vdso_clock_getres(clockid_t clock, + struct __kernel_timespec *res) +{ + return __cvdso_clock_getres(clock, res); +} +int clock_getres(clockid_t, struct __kernel_timespec *) + __attribute__((weak, alias("__vdso_clock_getres"))); + #else /* i386 only */ extern int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); +extern int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res);
int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { @@ -55,4 +65,11 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) int clock_gettime(clockid_t, struct old_timespec32 *) __attribute__((weak, alias("__vdso_clock_gettime")));
+int __vdso_clock_getres(clockid_t clock, + struct old_timespec32 *res) +{ + return __cvdso_clock_getres_time32(clock, res); +} +int clock_getres(clockid_t, struct old_timespec32 *) + __attribute__((weak, alias("__vdso_clock_getres"))); #endif diff --git a/arch/x86/entry/vdso/vdso.lds.S b/arch/x86/entry/vdso/vdso.lds.S index d3a2dce4cfa9..36b644e16272 100644 --- a/arch/x86/entry/vdso/vdso.lds.S +++ b/arch/x86/entry/vdso/vdso.lds.S @@ -25,6 +25,8 @@ VERSION { __vdso_getcpu; time; __vdso_time; + clock_getres; + __vdso_clock_getres; local: *; }; } diff --git a/arch/x86/entry/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S index 422764a81d32..991b26cc855b 100644 --- a/arch/x86/entry/vdso/vdso32/vdso32.lds.S +++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S @@ -26,6 +26,7 @@ VERSION __vdso_clock_gettime; __vdso_gettimeofday; __vdso_time; + __vdso_clock_getres; };
LINUX_2.5 { diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index a274d4fea7a5..df8c8dfadfa7 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -24,6 +24,8 @@
#define VDSO_HAS_TIME 1
+#define VDSO_HAS_CLOCK_GETRES 1 + #ifdef CONFIG_PARAVIRT_CLOCK extern u8 pvclock_page[PAGE_SIZE] __attribute__((visibility("hidden"))); @@ -57,6 +59,17 @@ static __always_inline long gettimeofday_fallback( return ret; }
+static __always_inline long clock_getres_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + long ret; + asm ("syscall" : "=a" (ret), "=m" (*_ts) : + "0" (__NR_clock_getres), "D" (_clkid), "S" (_ts) : + "rcx", "r11"); + return ret; +} + #else
static __always_inline long clock_gettime_fallback( @@ -92,6 +105,23 @@ static __always_inline long gettimeofday_fallback( return ret; }
+static __always_inline long clock_getres_fallback( + clockid_t _clkid, + struct __kernel_timespec *_ts) +{ + long ret; + + asm ( + "mov %%ebx, %%edx \n" + "mov %[clock], %%ebx \n" + "call __kernel_vsyscall \n" + "mov %%edx, %%ebx \n" + : "=a" (ret), "=m" (*_ts) + : "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts) + : "edx"); + return ret; +} + #endif
#ifdef CONFIG_PARAVIRT_CLOCK
With the release of Linux 5.1 has been added a new syscall, clock_gettime64, that provided a 64 bit time value for a specified clock_ID to make the kernel Y2038 safe on 32 bit architectures.
Update the x86 specific vDSO library accordingly with what it has been done for the kernel syscall exposing the clock_gettime64 entry point.
Cc: Thomas Gleixner tglx@linutronix.de Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- arch/x86/entry/vdso/vclock_gettime.c | 7 +++++++ arch/x86/entry/vdso/vdso32/vdso32.lds.S | 1 + 2 files changed, 8 insertions(+)
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index de9212a4833e..d6d03e933191 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -65,6 +65,13 @@ int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) int clock_gettime(clockid_t, struct old_timespec32 *) __attribute__((weak, alias("__vdso_clock_gettime")));
+int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts) +{ + return __cvdso_clock_gettime(clock, ts); +} +int clock_gettime64(clockid_t, struct __kernel_timespec *) + __attribute__((weak, alias("__vdso_clock_gettime64"))); + int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res) { diff --git a/arch/x86/entry/vdso/vdso32/vdso32.lds.S b/arch/x86/entry/vdso/vdso32/vdso32.lds.S index 991b26cc855b..c7720995ab1a 100644 --- a/arch/x86/entry/vdso/vdso32/vdso32.lds.S +++ b/arch/x86/entry/vdso/vdso32/vdso32.lds.S @@ -27,6 +27,7 @@ VERSION __vdso_gettimeofday; __vdso_time; __vdso_clock_getres; + __vdso_clock_gettime64; };
LINUX_2.5 {
The current version of the multiarch vDSO selftest verifies only gettimeofday.
Extend the vDSO selftest to the other library functions: - time - clock_getres - clock_gettime
The extension has been used to verify the unified vdso library on the supported architectures.
Cc: Shuah Khan shuah@kernel.org Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com --- tools/testing/selftests/vDSO/Makefile | 2 + tools/testing/selftests/vDSO/vdso_config.h | 90 +++++++ tools/testing/selftests/vDSO/vdso_full_test.c | 244 ++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 tools/testing/selftests/vDSO/vdso_config.h create mode 100644 tools/testing/selftests/vDSO/vdso_full_test.c
diff --git a/tools/testing/selftests/vDSO/Makefile b/tools/testing/selftests/vDSO/Makefile index 9e03d61f52fd..68e9b4a1cdcf 100644 --- a/tools/testing/selftests/vDSO/Makefile +++ b/tools/testing/selftests/vDSO/Makefile @@ -5,6 +5,7 @@ uname_M := $(shell uname -m 2>/dev/null || echo not) ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
TEST_GEN_PROGS := $(OUTPUT)/vdso_test +TEST_GEN_PROGS += $(OUTPUT)/vdso_full_test ifeq ($(ARCH),x86) TEST_GEN_PROGS += $(OUTPUT)/vdso_standalone_test_x86 endif @@ -18,6 +19,7 @@ endif
all: $(TEST_GEN_PROGS) $(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c +$(OUTPUT)/vdso_full_test: parse_vdso.c vdso_full_test.c $(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \ vdso_standalone_test_x86.c parse_vdso.c \ diff --git a/tools/testing/selftests/vDSO/vdso_config.h b/tools/testing/selftests/vDSO/vdso_config.h new file mode 100644 index 000000000000..eeb725df6045 --- /dev/null +++ b/tools/testing/selftests/vDSO/vdso_config.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * vdso_config.h: Configuration options for vDSO tests. + * Copyright (c) 2019 Arm Ltd. + */ +#ifndef __VDSO_CONFIG_H__ +#define __VDSO_CONFIG_H__ + +/* + * Each architecture exports its vDSO implementation with different names + * and a different version from the others, so we need to handle it as a + * special case. + */ +#if defined(__arm__) +#define VDSO_VERSION 0 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#elif defined(__aarch64__) +#define VDSO_VERSION 3 +#define VDSO_NAMES 0 +#elif defined(__powerpc__) +#define VDSO_VERSION 1 +#define VDSO_NAMES 0 +#define VDSO_32BIT 1 +#elif defined(__powerpc64__) +#define VDSO_VERSION 1 +#define VDSO_NAMES 0 +#elif defined (__s390__) +#define VDSO_VERSION 2 +#define VDSO_NAMES 0 +#define VDSO_32BIT 1 +#elif defined (__s390X__) +#define VDSO_VERSION 2 +#define VDSO_NAMES 0 +#elif defined(__mips__) +#define VDSO_VERSION 0 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#elif defined(__sparc__) +#define VDSO_VERSION 0 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#elif defined(__i386__) +#define VDSO_VERSION 0 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#elif defined(__x86_64__) +#define VDSO_VERSION 0 +#define VDSO_NAMES 1 +#elif defined(__riscv__) +#define VDSO_VERSION 5 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#else /* nds32 */ +#define VDSO_VERSION 4 +#define VDSO_NAMES 1 +#define VDSO_32BIT 1 +#endif + +static const char *versions[6] = { + "LINUX_2.6", + "LINUX_2.6.15", + "LINUX_2.6.29", + "LINUX_2.6.39", + "LINUX_4", + "LINUX_4.15", +}; + +static const char *names[2][5] = { + { + "__kernel_gettimeofday", + "__kernel_clock_gettime", + "__kernel_time", + "__kernel_clock_getres", +#if defined(VDSO_32BIT) + "__kernel_clock_gettime64", +#endif + }, + { + "__vdso_gettimeofday", + "__vdso_clock_gettime", + "__vdso_time", + "__vdso_clock_getres", +#if defined(VDSO_32BIT) + "__vdso_clock_gettime64", +#endif + }, +}; + +#endif /* __VDSO_CONFIG_H__ */ diff --git a/tools/testing/selftests/vDSO/vdso_full_test.c b/tools/testing/selftests/vDSO/vdso_full_test.c new file mode 100644 index 000000000000..3d603f1394af --- /dev/null +++ b/tools/testing/selftests/vDSO/vdso_full_test.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * vdso_full_test.c: Sample code to test all the timers. + * Copyright (c) 2019 Arm Ltd. + * + * Compile with: + * gcc -std=gnu99 vdso_full_test.c parse_vdso.c + * + */ + +#include <stdint.h> +#include <elf.h> +#include <stdio.h> +#include <time.h> +#include <sys/auxv.h> +#include <sys/time.h> +#define _GNU_SOURCE +#include <unistd.h> +#include <sys/syscall.h> + +#include "../kselftest.h" +#include "vdso_config.h" + +extern void *vdso_sym(const char *version, const char *name); +extern void vdso_init_from_sysinfo_ehdr(uintptr_t base); +extern void vdso_init_from_auxv(void *auxv); + +static const char *version; +static const char **name; + +typedef long (*vdso_gettimeofday_t)(struct timeval *tv, struct timezone *tz); +typedef long (*vdso_clock_gettime_t)(clockid_t clk_id, struct timespec *ts); +typedef long (*vdso_clock_getres_t)(clockid_t clk_id, struct timespec *ts); +typedef time_t (*vdso_time_t)(time_t *t); + +static int vdso_test_gettimeofday(void) +{ + /* Find gettimeofday. */ + vdso_gettimeofday_t vdso_gettimeofday = + (vdso_gettimeofday_t)vdso_sym(version, name[0]); + + if (!vdso_gettimeofday) { + printf("Could not find %s\n", name[0]); + return KSFT_SKIP; + } + + struct timeval tv; + long ret = vdso_gettimeofday(&tv, 0); + + if (ret == 0) { + printf("The time is %lld.%06lld\n", + (long long)tv.tv_sec, (long long)tv.tv_usec); + } else { + printf("%s failed\n", name[0]); + return KSFT_FAIL; + } + + return KSFT_PASS; +} + +static int vdso_test_clock_gettime(clockid_t clk_id) +{ + /* Find clock_gettime. */ + vdso_clock_gettime_t vdso_clock_gettime = + (vdso_clock_gettime_t)vdso_sym(version, name[1]); + + if (!vdso_clock_gettime) { + printf("Could not find %s\n", name[1]); + return KSFT_SKIP; + } + + struct timespec ts; + long ret = vdso_clock_gettime(clk_id, &ts); + + if (ret == 0) { + printf("The time is %lld.%06lld\n", + (long long)ts.tv_sec, (long long)ts.tv_nsec); + } else { + printf("%s failed\n", name[1]); + return KSFT_FAIL; + } + + return KSFT_PASS; +} + +static int vdso_test_time(void) +{ + /* Find time. */ + vdso_time_t vdso_time = + (vdso_time_t)vdso_sym(version, name[2]); + + if (!vdso_time) { + printf("Could not find %s\n", name[2]); + return KSFT_SKIP; + } + + long ret = vdso_time(NULL); + + if (ret > 0) { + printf("The time in hours since January 1, 1970 is %lld\n", + (long long)(ret / 3600)); + } else { + printf("%s failed\n", name[2]); + return KSFT_FAIL; + } + + return KSFT_PASS; +} + +static int vdso_test_clock_getres(clockid_t clk_id) +{ + /* Find clock_getres. */ + vdso_clock_getres_t vdso_clock_getres = + (vdso_clock_getres_t)vdso_sym(version, name[3]); + + if (!vdso_clock_getres) { + printf("Could not find %s\n", name[3]); + return KSFT_SKIP; + } + + struct timespec ts, sys_ts; + long ret = vdso_clock_getres(clk_id, &ts); + + if (ret == 0) { + printf("The resolution is %lld %lld\n", + (long long)ts.tv_sec, (long long)ts.tv_nsec); + } else { + printf("%s failed\n", name[3]); + return KSFT_FAIL; + } + + ret = syscall(SYS_clock_getres, clk_id, &sys_ts); + + if ((sys_ts.tv_sec != ts.tv_sec) || (sys_ts.tv_nsec != ts.tv_nsec)) { + printf("%s failed\n", name[3]); + return KSFT_FAIL; + } + + return KSFT_PASS; +} + +const char *vdso_clock_name[12] = { + "CLOCK_REALTIME", + "CLOCK_MONOTONIC", + "CLOCK_PROCESS_CPUTIME_ID", + "CLOCK_THREAD_CPUTIME_ID", + "CLOCK_MONOTONIC_RAW", + "CLOCK_REALTIME_COARSE", + "CLOCK_MONOTONIC_COARSE", + "CLOCK_BOOTTIME", + "CLOCK_REALTIME_ALARM", + "CLOCK_BOOTTIME_ALARM", + "CLOCK_SGI_CYCLE", + "CLOCK_TAI", +}; + +/* + * This function calls vdso_test_clock_gettime and vdso_test_clock_getres + * with different values for clock_id. + */ +static inline int vdso_test_clock(clockid_t clock_id) +{ + int ret0, ret1; + + ret0 = vdso_test_clock_gettime(clock_id); + /* A skipped test is considered passed */ + if (ret0 == KSFT_SKIP) + ret0 = KSFT_PASS; + + ret1 = vdso_test_clock_getres(clock_id); + /* A skipped test is considered passed */ + if (ret1 == KSFT_SKIP) + ret1 = KSFT_PASS; + + ret0 += ret1; + + printf("clock_id: %s", vdso_clock_name[clock_id]); + + if (ret0 > 0) + printf(" [FAIL]\n"); + else + printf(" [PASS]\n"); + + return ret0; +} + +int main(int argc, char **argv) +{ + unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); + int ret; + + if (!sysinfo_ehdr) { + printf("AT_SYSINFO_EHDR is not present!\n"); + return KSFT_SKIP; + } + + version = versions[VDSO_VERSION]; + name = (const char **)&names[VDSO_NAMES]; + + printf("[vDSO kselftest] VDSO_VERSION: %s\n", version); + + vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); + + ret = vdso_test_gettimeofday(); + +#if _POSIX_TIMERS > 0 + +#ifdef CLOCK_REALTIME + ret += vdso_test_clock(CLOCK_REALTIME); +#endif + +#ifdef CLOCK_BOOTTIME + ret += vdso_test_clock(CLOCK_BOOTTIME); +#endif + +#ifdef CLOCK_TAI + ret += vdso_test_clock(CLOCK_TAI); +#endif + +#ifdef CLOCK_REALTIME_COARSE + ret += vdso_test_clock(CLOCK_REALTIME_COARSE); +#endif + +#ifdef CLOCK_MONOTONIC + ret += vdso_test_clock(CLOCK_MONOTONIC); +#endif + +#ifdef CLOCK_MONOTONIC_RAW + ret += vdso_test_clock(CLOCK_MONOTONIC_RAW); +#endif + +#ifdef CLOCK_MONOTONIC_COARSE + ret += vdso_test_clock(CLOCK_MONOTONIC_COARSE); +#endif + +#endif + + ret += vdso_test_time(); + + if (ret > 0) + return KSFT_FAIL; + + return KSFT_PASS; +}
Vincenzo,
On Fri, 21 Jun 2019, Vincenzo Frascino wrote:
vDSO (virtual dynamic shared object) is a mechanism that the Linux kernel provides as an alternative to system calls to reduce where possible the costs in terms of cycles. This is possible because certain syscalls like gettimeofday() do not write any data and return one or more values that are stored in the kernel, which makes relatively safe calling them directly as a library function.
Even if the mechanism is pretty much standard, every architecture in the last few years ended up implementing their own vDSO library in the architectural code.
....
This implementation contains the portings to the common library for: arm64, compat mode for arm64, arm, mips, x86_64, x32, compat mode for x86_64 and i386.
I picked up the core implementation and the ARM64 and x86 conversion. I did some refinements in several places, coding style, naming conventions, comments and changelogs including subject prefixes. Please double check!
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
As you can see from the commit dates, this has soaked for some time in a WIP branch and I did extensive regression testing. So far so good.
Thanks a lot for going through several iterations. It's a very much appreciated effort!
Especially with the upcoming time namespaces this will avoid a lot of duplicated and pointlessly different horrors all over the architecture space. Any architecture which wants to gain that support needs to convert to the generic VDSO first.
As you have become the dude who knows almost everything about VDSO including all the nasty pitfalls, I propose the patch below.
Thanks,
tglx
8<------------ Subject: MAINTAINERS: Add entry for the generic VDSO library From: Thomas Gleixner tglx@linutronix.de Date: Mon, 24 Jun 2019 02:03:50 +0200
Asign the following folks in alphabetic order:
- Andy for being the VDSO wizard of x86 and in general. He's also the performance monitor of choice and the code in the generic library is heavily influenced by his previous x86 VDSO work.
- Thomas for being the dude who has to deal with any form of time(r) nonsense anyway
- Vincenzo for being the poor sod who went through all the different architecture implementations in order to unify them. A lot of knowledge gained from VDSO implementation details to the intricacies of taming the build system.
Signed-off-by: Thomas Gleixner tglx@linutronix.de --- MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+)
--- a/MAINTAINERS +++ b/MAINTAINERS @@ -6665,6 +6665,18 @@ L: kvm@vger.kernel.org S: Supported F: drivers/uio/uio_pci_generic.c
+GENERIC VDSO LIBRARY: +M: Andy Lutomirksy luto@kernel.org +M: Thomas Gleixner tglx@linutronix.de +M: Vincenzo Frascino vincenzo.frascino@arm.com +L: linux-kernel@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso +S: Maintained +F: lib/vdso +F: kernel/time/vsyscall.c +F: include/vdso +F: include/asm-generic/vdso/vsyscall.h + GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp haver@linux.ibm.com S: Supported
On Sun, Jun 23, 2019 at 5:34 PM Thomas Gleixner tglx@linutronix.de wrote:
+GENERIC VDSO LIBRARY: +M: Andy Lutomirksy luto@kernel.org
Lutomirski, perhaps? Although I do appreciate the opportunity to say "not me!" :)
On Sun, 23 Jun 2019, Andy Lutomirski wrote:
On Sun, Jun 23, 2019 at 5:34 PM Thomas Gleixner tglx@linutronix.de wrote:
+GENERIC VDSO LIBRARY: +M: Andy Lutomirksy luto@kernel.org
Lutomirski, perhaps?
Ooops. Where did I copy that from?
Although I do appreciate the opportunity to say "not me!" :)
You just gave me the perfect exit plan. I'll change my surname to Gleyxner and head off to the goat farm :)
Thanks,
tglx
Hi Thomas,
On 24/06/2019 01:34, Thomas Gleixner wrote:
Vincenzo,
On Fri, 21 Jun 2019, Vincenzo Frascino wrote:
vDSO (virtual dynamic shared object) is a mechanism that the Linux kernel provides as an alternative to system calls to reduce where possible the costs in terms of cycles. This is possible because certain syscalls like gettimeofday() do not write any data and return one or more values that are stored in the kernel, which makes relatively safe calling them directly as a library function.
Even if the mechanism is pretty much standard, every architecture in the last few years ended up implementing their own vDSO library in the architectural code.
....
This implementation contains the portings to the common library for: arm64, compat mode for arm64, arm, mips, x86_64, x32, compat mode for x86_64 and i386.
I picked up the core implementation and the ARM64 and x86 conversion. I did some refinements in several places, coding style, naming conventions, comments and changelogs including subject prefixes. Please double check!
I tested your changes and they seem OK (git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso).
...
As you can see from the commit dates, this has soaked for some time in a WIP branch and I did extensive regression testing. So far so good.
Thanks a lot for going through several iterations. It's a very much appreciated effort!
It has been a lot of fun and I learned many many things about the vDSOs and the kernel that I did not know before. Thanks to you for your patience and guidance.
Especially with the upcoming time namespaces this will avoid a lot of duplicated and pointlessly different horrors all over the architecture space. Any architecture which wants to gain that support needs to convert to the generic VDSO first.
As you have become the dude who knows almost everything about VDSO including all the nasty pitfalls, I propose the patch below.
Thanks for this, it means a lot to me.
Thanks,
tglx
8<------------ Subject: MAINTAINERS: Add entry for the generic VDSO library From: Thomas Gleixner tglx@linutronix.de Date: Mon, 24 Jun 2019 02:03:50 +0200
Asign the following folks in alphabetic order:
Andy for being the VDSO wizard of x86 and in general. He's also the performance monitor of choice and the code in the generic library is heavily influenced by his previous x86 VDSO work.
Thomas for being the dude who has to deal with any form of time(r) nonsense anyway
Vincenzo for being the poor sod who went through all the different architecture implementations in order to unify them. A lot of knowledge gained from VDSO implementation details to the intricacies of taming the build system.
Signed-off-by: Thomas Gleixner tglx@linutronix.de
MAINTAINERS | 12 ++++++++++++ 1 file changed, 12 insertions(+)
--- a/MAINTAINERS +++ b/MAINTAINERS @@ -6665,6 +6665,18 @@ L: kvm@vger.kernel.org S: Supported F: drivers/uio/uio_pci_generic.c +GENERIC VDSO LIBRARY: +M: Andy Lutomirksy luto@kernel.org +M: Thomas Gleixner tglx@linutronix.de +M: Vincenzo Frascino vincenzo.frascino@arm.com +L: linux-kernel@vger.kernel.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/vdso +S: Maintained +F: lib/vdso +F: kernel/time/vsyscall.c +F: include/vdso +F: include/asm-generic/vdso/vsyscall.h
GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp haver@linux.ibm.com S: Supported
Vincenzo,
On Mon, 24 Jun 2019, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
I talked to Russell King and he suggested to file the ARM parts into his patch system and he'll pick them up after 5.3-rc1.
https://www.arm.linux.org.uk/developer/patches/
I paged out how to deal with it, but you'll surely manage :)
Thanks,
tglx
On Mon, Jun 24, 2019 at 04:18:28PM +0200, Thomas Gleixner wrote:
Vincenzo,
On Mon, 24 Jun 2019, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
I talked to Russell King and he suggested to file the ARM parts into his patch system and he'll pick them up after 5.3-rc1.
https://www.arm.linux.org.uk/developer/patches/
I paged out how to deal with it, but you'll surely manage :)
Easy way: ask git to add the "KernelVersion" tag as a header to the email using --add-header to e.g. git format-patch, and just mail them to patches@armlinux.org.uk
On Mon, Jun 24, 2019 at 03:23:46PM +0100, Russell King wrote:
On Mon, Jun 24, 2019 at 04:18:28PM +0200, Thomas Gleixner wrote:
Vincenzo,
On Mon, 24 Jun 2019, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
I talked to Russell King and he suggested to file the ARM parts into his patch system and he'll pick them up after 5.3-rc1.
https://www.arm.linux.org.uk/developer/patches/
I paged out how to deal with it, but you'll surely manage :)
Easy way: ask git to add the "KernelVersion" tag as a header to the email using --add-header to e.g. git format-patch, and just mail them to patches@armlinux.org.uk
Although I haven't send patches to Russell in a while, I still have a git alias in my .gitconfig (only works with one patch at a time IIRC, sending multiple patches may arrive in a different order):
[alias] send-rmk-email = !git send-email --add-header="KernelVersion: $(git describe --abbrev=0)" --no-thread --suppress-cc=all --to="patches@arm.linux.org.uk"
On 24/06/2019 15:49, Catalin Marinas wrote:
On Mon, Jun 24, 2019 at 03:23:46PM +0100, Russell King wrote:
On Mon, Jun 24, 2019 at 04:18:28PM +0200, Thomas Gleixner wrote:
Vincenzo,
On Mon, 24 Jun 2019, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
I talked to Russell King and he suggested to file the ARM parts into his patch system and he'll pick them up after 5.3-rc1.
https://www.arm.linux.org.uk/developer/patches/
I paged out how to deal with it, but you'll surely manage :)
Easy way: ask git to add the "KernelVersion" tag as a header to the email using --add-header to e.g. git format-patch, and just mail them to patches@armlinux.org.uk
Although I haven't send patches to Russell in a while, I still have a git alias in my .gitconfig (only works with one patch at a time IIRC, sending multiple patches may arrive in a different order):
[alias] send-rmk-email = !git send-email --add-header="KernelVersion: $(git describe --abbrev=0)" --no-thread --suppress-cc=all --to="patches@arm.linux.org.uk"
Thanks to all for the hints and the support. I will send the patches to Russel as agreed.
Hi Catalin,
On Mon, Jun 24, 2019 at 4:51 PM Catalin Marinas catalin.marinas@arm.com wrote:
On Mon, Jun 24, 2019 at 03:23:46PM +0100, Russell King wrote:
On Mon, Jun 24, 2019 at 04:18:28PM +0200, Thomas Gleixner wrote:
I talked to Russell King and he suggested to file the ARM parts into his patch system and he'll pick them up after 5.3-rc1.
https://www.arm.linux.org.uk/developer/patches/
I paged out how to deal with it, but you'll surely manage :)
Easy way: ask git to add the "KernelVersion" tag as a header to the email using --add-header to e.g. git format-patch, and just mail them to patches@armlinux.org.uk
Although I haven't send patches to Russell in a while, I still have a git alias in my .gitconfig (only works with one patch at a time IIRC, sending multiple patches may arrive in a different order):
[alias] send-rmk-email = !git send-email --add-header="KernelVersion: $(git describe --abbrev=0)" --no-thread --suppress-cc=all --to="patches@arm.linux.org.uk"
Doesn't seem to work: no header was added, and my patch was rejected. There does seem to be a "--add-header" option for git-format-patch, but it adds the header at the top, just below the "Subject:"-header, instead of below the "---", so that needs manual editing, too.
Gr{oetje,eeting}s,
Geert
Hello,
On Mon, Jun 24, 2019 at 02:34:24AM +0200, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
Apologies for not being more proactive on the MIPS front here; life & work are extra busy at the moment... But thanks Vincenzo for including MIPS in the work here.
Unfortunately after applying the 3 MIPS patches (19-21) atop the current tip.git timers/vdso branch at ecf9db3d1f1a ("x86/vdso: Give the [ph]vclock_page declarations real types") I see build failures for the o32 compat VDSO, shown below. This is using the gcc 8.1.0 mips-linux toolchain from here:
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.1.0/x...
Configuration is 64r6el_defconfig. The following helps remove the implicit declaration warnings (and eww to including C files via CFLAGS), but it still doesn't build:
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index 95df49402a53..aa38049bdb24 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -36,6 +36,8 @@ aflags-vdso := $(ccflags-vdso) \
ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o = -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-o32.o = -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-n32.o = -include $(c-gettimeofday-y) endif
CFLAGS_REMOVE_vgettimeofday.o = -pg
So the MIPS bits here need more work.
Thanks, Paul
CC arch/mips/vdso/vgettimeofday-o32.o In file included from ./include/linux/bitops.h:19, from ./include/linux/kernel.h:12, from ./include/linux/list.h:9, from ./include/linux/preempt.h:11, from ./include/linux/spinlock.h:51, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/bitops.h: In function '__fls': ./arch/mips/include/asm/bitops.h:518:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << 32))) { ^~ ./arch/mips/include/asm/bitops.h:520:8: warning: left shift count >= width of type [-Wshift-count-overflow] word <<= 32; ^~~ ./arch/mips/include/asm/bitops.h:523:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-16)))) { ^~ ./arch/mips/include/asm/bitops.h:527:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-8)))) { ^~ ./arch/mips/include/asm/bitops.h:531:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-4)))) { ^~ ./arch/mips/include/asm/bitops.h:535:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-2)))) { ^~ ./arch/mips/include/asm/bitops.h:539:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-1)))) ^~ In file included from ./arch/mips/include/asm/mmiowb.h:5, from ./include/linux/spinlock.h:60, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/io.h: In function 'phys_to_virt': ./arch/mips/include/asm/io.h:136:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] return (void *)(address + PAGE_OFFSET - PHYS_OFFSET); ^ In file included from ./include/linux/bitops.h:5, from ./include/linux/kernel.h:12, from ./include/linux/list.h:9, from ./include/linux/preempt.h:11, from ./include/linux/spinlock.h:51, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/mips-cm.h: In function 'mips_cm_max_vp_width': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:161:23: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3 CM_ENCODE_REV(8, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:367:28: note: in expansion of macro 'CM_REV_CM3' if (mips_cm_revision() >= CM_REV_CM3) ^~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:161:23: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3 CM_ENCODE_REV(8, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:367:28: note: in expansion of macro 'CM_REV_CM3' if (mips_cm_revision() >= CM_REV_CM3) ^~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:239:36: note: in expansion of macro 'GENMASK' #define CM_GCR_SYS_CONFIG2_MAXVPW GENMASK(3, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:368:35: note: in expansion of macro 'CM_GCR_SYS_CONFIG2_MAXVPW' return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW; ^~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:376:32: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' cfg = read_gcr_cl_config() & CM_GCR_Cx_CONFIG_PVPE; ^~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:377:24: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' return (cfg >> __ffs(CM_GCR_Cx_CONFIG_PVPE)) + 1; ^~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numclusters': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:117:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:117:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:133:37: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUM_CLUSTERS GENMASK(29, 23) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:120:37: note: in expansion of macro 'CM_GCR_CONFIG_NUM_CLUSTERS' num_clusters = read_gcr_config() & CM_GCR_CONFIG_NUM_CLUSTERS; ^~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:133:37: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUM_CLUSTERS GENMASK(29, 23) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:121:25: note: in expansion of macro 'CM_GCR_CONFIG_NUM_CLUSTERS' num_clusters >>= __ffs(CM_GCR_CONFIG_NUM_CLUSTERS); ^~~~~~~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_cluster_config': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:137:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:137:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numcores': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:135:32: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_PCORES GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:172:50: note: in expansion of macro 'CM_GCR_CONFIG_PCORES' return (mips_cps_cluster_config(cluster) + 1) & CM_GCR_CONFIG_PCORES; ^~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numiocu': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:134:33: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUMIOCU GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:189:48: note: in expansion of macro 'CM_GCR_CONFIG_NUMIOCU' num_iocu = mips_cps_cluster_config(cluster) & CM_GCR_CONFIG_NUMIOCU; ^~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:134:33: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUMIOCU GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:190:21: note: in expansion of macro 'CM_GCR_CONFIG_NUMIOCU' num_iocu >>= __ffs(CM_GCR_CONFIG_NUMIOCU); ^~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numvps': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:216:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:216:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:233:21: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' return (cfg + 1) & CM_GCR_Cx_CONFIG_PVPE; ^~~~~~~~~~~~~~~~~~~~~ arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_gettime': arch/mips/vdso/vgettimeofday.c:17:9: error: implicit declaration of function '__cvdso_clock_gettime32'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_gettime32(clock, ts); ^~~~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime arch/mips/vdso/vgettimeofday.c: In function '__vdso_gettimeofday': arch/mips/vdso/vgettimeofday.c:23:9: error: implicit declaration of function '__cvdso_gettimeofday'; did you mean '__vdso_gettimeofday'? [-Werror=implicit-function-declaration] return __cvdso_gettimeofday(tv, tz); ^~~~~~~~~~~~~~~~~~~~ __vdso_gettimeofday arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_getres': arch/mips/vdso/vgettimeofday.c:29:9: error: implicit declaration of function '__cvdso_clock_getres_time32'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_getres_time32(clock_id, res); ^~~~~~~~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_gettime64': arch/mips/vdso/vgettimeofday.c:35:9: error: implicit declaration of function '__cvdso_clock_gettime'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_gettime(clock, ts); ^~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime cc1: some warnings being treated as errors make[1]: *** [arch/mips/vdso/Makefile:148: arch/mips/vdso/vgettimeofday-o32.o] Error 1 make: *** [Makefile:1746: arch/mips/vdso/vgettimeofday-o32.o] Error 2
Hi Paul,
thank you for your review.
On 6/24/19 7:41 PM, Paul Burton wrote:
Hello,
On Mon, Jun 24, 2019 at 02:34:24AM +0200, Thomas Gleixner wrote:
I did not merge the ARM and MIPS parts as they lack any form of acknowlegment from their maintainers. Please talk to those folks. If they ack/review the changes then I can pick them up and they go into 5.3 or they have to go in a later cycle. Nevertheless it was well worth the trouble to have those conversions done to confirm that the new common library fits a bunch of different architectures.
Apologies for not being more proactive on the MIPS front here; life & work are extra busy at the moment... But thanks Vincenzo for including MIPS in the work here.
No problem.
Unfortunately after applying the 3 MIPS patches (19-21) atop the current tip.git timers/vdso branch at ecf9db3d1f1a ("x86/vdso: Give the [ph]vclock_page declarations real types") I see build failures for the o32 compat VDSO, shown below. This is using the gcc 8.1.0 mips-linux toolchain from here:
https://mirrors.edge.kernel.org/pub/tools/crosstool/files/bin/x86_64/8.1.0/x...
Configuration is 64r6el_defconfig. The following helps remove the implicit declaration warnings (and eww to including C files via CFLAGS), but it still doesn't build:
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile index 95df49402a53..aa38049bdb24 100644 --- a/arch/mips/vdso/Makefile +++ b/arch/mips/vdso/Makefile @@ -36,6 +36,8 @@ aflags-vdso := $(ccflags-vdso) \ ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o = -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-o32.o = -include $(c-gettimeofday-y) +CFLAGS_vgettimeofday-n32.o = -include $(c-gettimeofday-y) endif
CFLAGS_REMOVE_vgettimeofday.o = -pg
So the MIPS bits here need more work.
I admit, the one proposed was a nice challenge and it took me a while to understand the differences in between the O32, N32 and N64 binaries and what was causing the reported issue.
In the end I concluded that all the errors seen here depend on the fact that I tested my vdso implementation on MIPS32el only (as stated in the cover letter) and that when I tried to compile a 32BIT binary on a 64BIT configuration I did it wrongly for two reasons, for N32 and O32 binaries: - we need to undefine CONFIG_64BIT and define CONFIG_32BIT - we need to define CONFIG_GENERIC_ATOMIC64
I have a fix for this (patch in attachment), but I do not have the hardware to test it. If you could provide some feedback would be appreciated (really want to see MIPS merged with the other archs in 5.3 :) ).
Thanks, Paul
CC arch/mips/vdso/vgettimeofday-o32.o In file included from ./include/linux/bitops.h:19, from ./include/linux/kernel.h:12, from ./include/linux/list.h:9, from ./include/linux/preempt.h:11, from ./include/linux/spinlock.h:51, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/bitops.h: In function '__fls': ./arch/mips/include/asm/bitops.h:518:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << 32))) { ^~ ./arch/mips/include/asm/bitops.h:520:8: warning: left shift count >= width of type [-Wshift-count-overflow] word <<= 32; ^~~ ./arch/mips/include/asm/bitops.h:523:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-16)))) { ^~ ./arch/mips/include/asm/bitops.h:527:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-8)))) { ^~ ./arch/mips/include/asm/bitops.h:531:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-4)))) { ^~ ./arch/mips/include/asm/bitops.h:535:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-2)))) { ^~ ./arch/mips/include/asm/bitops.h:539:21: warning: left shift count >= width of type [-Wshift-count-overflow] if (!(word & (~0ul << (BITS_PER_LONG-1)))) ^~ In file included from ./arch/mips/include/asm/mmiowb.h:5, from ./include/linux/spinlock.h:60, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/io.h: In function 'phys_to_virt': ./arch/mips/include/asm/io.h:136:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] return (void *)(address + PAGE_OFFSET - PHYS_OFFSET); ^ In file included from ./include/linux/bitops.h:5, from ./include/linux/kernel.h:12, from ./include/linux/list.h:9, from ./include/linux/preempt.h:11, from ./include/linux/spinlock.h:51, from ./include/linux/seqlock.h:36, from ./include/linux/time.h:6, from arch/mips/vdso/vgettimeofday.c:10: ./arch/mips/include/asm/mips-cm.h: In function 'mips_cm_max_vp_width': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:161:23: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3 CM_ENCODE_REV(8, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:367:28: note: in expansion of macro 'CM_REV_CM3' if (mips_cm_revision() >= CM_REV_CM3) ^~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:161:23: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3 CM_ENCODE_REV(8, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:367:28: note: in expansion of macro 'CM_REV_CM3' if (mips_cm_revision() >= CM_REV_CM3) ^~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:239:36: note: in expansion of macro 'GENMASK' #define CM_GCR_SYS_CONFIG2_MAXVPW GENMASK(3, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:368:35: note: in expansion of macro 'CM_GCR_SYS_CONFIG2_MAXVPW' return read_gcr_sys_config2() & CM_GCR_SYS_CONFIG2_MAXVPW; ^~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:376:32: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' cfg = read_gcr_cl_config() & CM_GCR_Cx_CONFIG_PVPE; ^~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:377:24: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' return (cfg >> __ffs(CM_GCR_Cx_CONFIG_PVPE)) + 1; ^~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numclusters': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:117:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:117:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:133:37: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUM_CLUSTERS GENMASK(29, 23) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:120:37: note: in expansion of macro 'CM_GCR_CONFIG_NUM_CLUSTERS' num_clusters = read_gcr_config() & CM_GCR_CONFIG_NUM_CLUSTERS; ^~~~~~~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:133:37: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUM_CLUSTERS GENMASK(29, 23) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:121:25: note: in expansion of macro 'CM_GCR_CONFIG_NUM_CLUSTERS' num_clusters >>= __ffs(CM_GCR_CONFIG_NUM_CLUSTERS); ^~~~~~~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_cluster_config': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:137:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:137:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numcores': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:135:32: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_PCORES GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:172:50: note: in expansion of macro 'CM_GCR_CONFIG_PCORES' return (mips_cps_cluster_config(cluster) + 1) & CM_GCR_CONFIG_PCORES; ^~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numiocu': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:134:33: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUMIOCU GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:189:48: note: in expansion of macro 'CM_GCR_CONFIG_NUMIOCU' num_iocu = mips_cps_cluster_config(cluster) & CM_GCR_CONFIG_NUMIOCU; ^~~~~~~~~~~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:134:33: note: in expansion of macro 'GENMASK' #define CM_GCR_CONFIG_NUMIOCU GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:190:21: note: in expansion of macro 'CM_GCR_CONFIG_NUMIOCU' num_iocu >>= __ffs(CM_GCR_CONFIG_NUMIOCU); ^~~~~~~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h: In function 'mips_cps_numvps': ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:152:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MAJOR GENMASK(15, 8) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:156:22: note: in expansion of macro 'CM_GCR_REV_MAJOR' (((major) << __ffs(CM_GCR_REV_MAJOR)) | \ ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:216:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:153:28: note: in expansion of macro 'GENMASK' #define CM_GCR_REV_MINOR GENMASK(7, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cm.h:157:22: note: in expansion of macro 'CM_GCR_REV_MINOR' ((minor) << __ffs(CM_GCR_REV_MINOR))) ^~~~~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cm.h:162:25: note: in expansion of macro 'CM_ENCODE_REV' #define CM_REV_CM3_5 CM_ENCODE_REV(9, 0) ^~~~~~~~~~~~~ ./arch/mips/include/asm/mips-cps.h:216:27: note: in expansion of macro 'CM_REV_CM3_5' if (mips_cm_revision() < CM_REV_CM3_5) { ^~~~~~~~~~~~ ./include/linux/bits.h:20:39: warning: right shift count >= width of type [-Wshift-count-overflow] (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) ^~ ./arch/mips/include/asm/mips-cm.h:293:33: note: in expansion of macro 'GENMASK' #define CM_GCR_Cx_CONFIG_PVPE GENMASK(9, 0) ^~~~~~~ ./arch/mips/include/asm/mips-cps.h:233:21: note: in expansion of macro 'CM_GCR_Cx_CONFIG_PVPE' return (cfg + 1) & CM_GCR_Cx_CONFIG_PVPE; ^~~~~~~~~~~~~~~~~~~~~ arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_gettime': arch/mips/vdso/vgettimeofday.c:17:9: error: implicit declaration of function '__cvdso_clock_gettime32'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_gettime32(clock, ts); ^~~~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime arch/mips/vdso/vgettimeofday.c: In function '__vdso_gettimeofday': arch/mips/vdso/vgettimeofday.c:23:9: error: implicit declaration of function '__cvdso_gettimeofday'; did you mean '__vdso_gettimeofday'? [-Werror=implicit-function-declaration] return __cvdso_gettimeofday(tv, tz); ^~~~~~~~~~~~~~~~~~~~ __vdso_gettimeofday arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_getres': arch/mips/vdso/vgettimeofday.c:29:9: error: implicit declaration of function '__cvdso_clock_getres_time32'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_getres_time32(clock_id, res); ^~~~~~~~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime arch/mips/vdso/vgettimeofday.c: In function '__vdso_clock_gettime64': arch/mips/vdso/vgettimeofday.c:35:9: error: implicit declaration of function '__cvdso_clock_gettime'; did you mean '__vdso_clock_gettime'? [-Werror=implicit-function-declaration] return __cvdso_clock_gettime(clock, ts); ^~~~~~~~~~~~~~~~~~~~~ __vdso_clock_gettime cc1: some warnings being treated as errors make[1]: *** [arch/mips/vdso/Makefile:148: arch/mips/vdso/vgettimeofday-o32.o] Error 1 make: *** [Makefile:1746: arch/mips/vdso/vgettimeofday-o32.o] Error 2
Hi Vincenzo,
On Tue, Jun 25, 2019 at 12:16:55AM +0100, Vincenzo Frascino wrote:
In the end I concluded that all the errors seen here depend on the fact that I tested my vdso implementation on MIPS32el only (as stated in the cover letter) and that when I tried to compile a 32BIT binary on a 64BIT configuration I did it wrongly for two reasons, for N32 and O32 binaries:
- we need to undefine CONFIG_64BIT and define CONFIG_32BIT
- we need to define CONFIG_GENERIC_ATOMIC64
I have a fix for this (patch in attachment), but I do not have the hardware to test it. If you could provide some feedback would be appreciated (really want to see MIPS merged with the other archs in 5.3 :) ).
Thanks for the quick turnaround on your patch!
I'm certainly willing to test it, but in a few hours I'll be spending the bulk of a day on airplanes[1] so it might take a few days until I get to it.
Thanks, Paul
[1] ...and travel isn't the hackathon it used to be with my 9 month old son around :)
Hi Paul,
On 25/06/2019 18:11, Paul Burton wrote:
Hi Vincenzo,
On Tue, Jun 25, 2019 at 12:16:55AM +0100, Vincenzo Frascino wrote:
In the end I concluded that all the errors seen here depend on the fact that I tested my vdso implementation on MIPS32el only (as stated in the cover letter) and that when I tried to compile a 32BIT binary on a 64BIT configuration I did it wrongly for two reasons, for N32 and O32 binaries:
- we need to undefine CONFIG_64BIT and define CONFIG_32BIT
- we need to define CONFIG_GENERIC_ATOMIC64
I have a fix for this (patch in attachment), but I do not have the hardware to test it. If you could provide some feedback would be appreciated (really want to see MIPS merged with the other archs in 5.3 :) ).
Thanks for the quick turnaround on your patch!
I'm certainly willing to test it, but in a few hours I'll be spending the bulk of a day on airplanes[1] so it might take a few days until I get to it.
Sounds like a plan. Let us know when you have an update.
Thanks, Paul
[1] ...and travel isn't the hackathon it used to be with my 9 month old son around :)
On Fri, 21 Jun 2019 10:52:27 +0100 Vincenzo Frascino vincenzo.frascino@arm.com wrote:
Hi,
vDSO (virtual dynamic shared object) is a mechanism that the Linux kernel provides as an alternative to system calls to reduce where possible the costs in terms of cycles.
[ ... ]
Some numbers for the ARM(32) part:
I booted my trusted old Calxeda Midway server (Cortex A-15 cores) and ran the vdsotest benchmark on it. The results are: (vdso: times, in nsec/call; n/t: "not tested" (=not implemented)) call 5.2-rc3 5.2-rc3-vdso clock-gettime-monotonic: 147 142 clock-getres-monotonic: n/t 34 clock-gettime-monotonic-coarse: 90 96 clock-getres-monotonic-coarse: n/t 36 clock-gettime-monotonic-raw: 431 142 clock-getres-monotonic-raw: n/t 35 clock-gettime-tai: 598 150 clock-getres-tai: n/t 34 clock-gettime-boottime: 592 142 clock-getres-boottime: n/t 34 clock-gettime-realtime: 149 142 clock-getres-realtime: n/t 34 clock-gettime-realtime-coarse: 86 96 clock-getres-realtime-coarse: n/t 36 getcpu: n/t n/t gettimeofday: 133 110
So there are some minor improvements, two minor regressions, some significant improvements (factor 3-4), and some dramatic improvements (where we actually gained VDSO support). Overall a pretty impressive outcome for an "Odd fixes" architecture, especially as it should reduce the future maintenance burden.
Cheers, Andre.
linux-kselftest-mirror@lists.linaro.org