1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE 4 * Copyright 2003 Andi Kleen, SuSE Labs. 5 * 6 * Modified for x86 32 bit architecture by 7 * Stefani Seibold <stefani@seibold.net> 8 * sponsored by Rohde & Schwarz GmbH & Co. KG Munich/Germany 9 * 10 * Thanks to hpa@transmeta.com for some useful hint. 11 * Special thanks to Ingo Molnar for his early experience with 12 * a different vsyscall implementation for Linux/IA32 and for the name. 13 * 14 */ 15 16#include <linux/timekeeper_internal.h> 17#include <asm/vgtod.h> 18#include <asm/vvar.h> 19 20int vclocks_used __read_mostly; 21 22DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data); 23 24void update_vsyscall_tz(void) 25{ 26 vsyscall_gtod_data.tz_minuteswest = sys_tz.tz_minuteswest; 27 vsyscall_gtod_data.tz_dsttime = sys_tz.tz_dsttime; 28} 29 30void update_vsyscall(struct timekeeper *tk) 31{ 32 int vclock_mode = tk->tkr_mono.clock->archdata.vclock_mode; 33 struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; 34 35 /* Mark the new vclock used. */ 36 BUILD_BUG_ON(VCLOCK_MAX >= 32); 37 WRITE_ONCE(vclocks_used, READ_ONCE(vclocks_used) | (1 << vclock_mode)); 38 39 gtod_write_begin(vdata); 40 41 /* copy vsyscall data */ 42 vdata->vclock_mode = vclock_mode; 43 vdata->cycle_last = tk->tkr_mono.cycle_last; 44 vdata->mask = tk->tkr_mono.mask; 45 vdata->mult = tk->tkr_mono.mult; 46 vdata->shift = tk->tkr_mono.shift; 47 48 vdata->wall_time_sec = tk->xtime_sec; 49 vdata->wall_time_snsec = tk->tkr_mono.xtime_nsec; 50 51 vdata->monotonic_time_sec = tk->xtime_sec 52 + tk->wall_to_monotonic.tv_sec; 53 vdata->monotonic_time_snsec = tk->tkr_mono.xtime_nsec 54 + ((u64)tk->wall_to_monotonic.tv_nsec 55 << tk->tkr_mono.shift); 56 while (vdata->monotonic_time_snsec >= 57 (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { 58 vdata->monotonic_time_snsec -= 59 ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; 60 vdata->monotonic_time_sec++; 61 } 62 63 vdata->wall_time_coarse_sec = tk->xtime_sec; 64 vdata->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >> 65 tk->tkr_mono.shift); 66 67 vdata->monotonic_time_coarse_sec = 68 vdata->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; 69 vdata->monotonic_time_coarse_nsec = 70 vdata->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; 71 72 while (vdata->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { 73 vdata->monotonic_time_coarse_nsec -= NSEC_PER_SEC; 74 vdata->monotonic_time_coarse_sec++; 75 } 76 77 gtod_write_end(vdata); 78} 79