Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: Convert x86_platform_ops to timespec64

The x86 platform operations are fairly isolated, so it's easy to change
them from using timespec to timespec64. It has been checked that all the
users and callers are safe, and there is only one critical function that is
broken beyond 2106:

pvclock_read_wallclock() uses a 32-bit number of seconds since the epoch
to communicate the boot time between host and guest in a virtual
environment. This will work until 2106, but fixing this is outside the
scope of this change, Add a comment at least.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: Radim Krčmář <rkrcmar@redhat.com>
Acked-by: Jan Kiszka <jan.kiszka@siemens.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: jailhouse-dev@googlegroups.com
Cc: Borislav Petkov <bp@suse.de>
Cc: kvm@vger.kernel.org
Cc: y2038@lists.linaro.org
Cc: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Cc: xen-devel@lists.xenproject.org
Cc: John Stultz <john.stultz@linaro.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Joao Martins <joao.m.martins@oracle.com>
Link: https://lkml.kernel.org/r/20180427201435.3194219-1-arnd@arndb.de

authored by

Arnd Bergmann and committed by
Thomas Gleixner
e27c4929 06aa3769

+38 -31
+2 -2
arch/x86/include/asm/intel_mid_vrtc.h
··· 4 4 5 5 extern unsigned char vrtc_cmos_read(unsigned char reg); 6 6 extern void vrtc_cmos_write(unsigned char val, unsigned char reg); 7 - extern void vrtc_get_time(struct timespec *now); 8 - extern int vrtc_set_mmss(const struct timespec *now); 7 + extern void vrtc_get_time(struct timespec64 *now); 8 + extern int vrtc_set_mmss(const struct timespec64 *now); 9 9 10 10 #endif
+2 -2
arch/x86/include/asm/mc146818rtc.h
··· 95 95 unsigned char rtc_cmos_read(unsigned char addr); 96 96 void rtc_cmos_write(unsigned char val, unsigned char addr); 97 97 98 - extern int mach_set_rtc_mmss(const struct timespec *now); 99 - extern void mach_get_cmos_time(struct timespec *now); 98 + extern int mach_set_rtc_mmss(const struct timespec64 *now); 99 + extern void mach_get_cmos_time(struct timespec64 *now); 100 100 101 101 #define RTC_IRQ 8 102 102
+1 -1
arch/x86/include/asm/pvclock.h
··· 12 12 unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); 13 13 void pvclock_read_wallclock(struct pvclock_wall_clock *wall, 14 14 struct pvclock_vcpu_time_info *vcpu, 15 - struct timespec *ts); 15 + struct timespec64 *ts); 16 16 void pvclock_resume(void); 17 17 18 18 void pvclock_touch_watchdogs(void);
+3 -3
arch/x86/include/asm/x86_init.h
··· 170 170 void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node); 171 171 }; 172 172 173 - struct timespec; 173 + struct timespec64; 174 174 175 175 /** 176 176 * struct x86_legacy_devices - legacy x86 devices ··· 264 264 struct x86_platform_ops { 265 265 unsigned long (*calibrate_cpu)(void); 266 266 unsigned long (*calibrate_tsc)(void); 267 - void (*get_wallclock)(struct timespec *ts); 268 - int (*set_wallclock)(const struct timespec *ts); 267 + void (*get_wallclock)(struct timespec64 *ts); 268 + int (*set_wallclock)(const struct timespec64 *ts); 269 269 void (*iommu_shutdown)(void); 270 270 bool (*is_untracked_pat_range)(u64 start, u64 end); 271 271 void (*nmi_init)(void);
+1 -1
arch/x86/kernel/jailhouse.c
··· 37 37 return jailhouse_cpuid_base(); 38 38 } 39 39 40 - static void jailhouse_get_wallclock(struct timespec *now) 40 + static void jailhouse_get_wallclock(struct timespec64 *now) 41 41 { 42 42 memset(now, 0, sizeof(*now)); 43 43 }
+2 -2
arch/x86/kernel/kvmclock.c
··· 53 53 * have elapsed since the hypervisor wrote the data. So we try to account for 54 54 * that with system time 55 55 */ 56 - static void kvm_get_wallclock(struct timespec *now) 56 + static void kvm_get_wallclock(struct timespec64 *now) 57 57 { 58 58 struct pvclock_vcpu_time_info *vcpu_time; 59 59 int low, high; ··· 72 72 put_cpu(); 73 73 } 74 74 75 - static int kvm_set_wallclock(const struct timespec *now) 75 + static int kvm_set_wallclock(const struct timespec64 *now) 76 76 { 77 77 return -ENODEV; 78 78 }
+11 -4
arch/x86/kernel/pvclock.c
··· 123 123 124 124 void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock, 125 125 struct pvclock_vcpu_time_info *vcpu_time, 126 - struct timespec *ts) 126 + struct timespec64 *ts) 127 127 { 128 128 u32 version; 129 129 u64 delta; 130 - struct timespec now; 130 + struct timespec64 now; 131 131 132 132 /* get wallclock at system boot */ 133 133 do { 134 134 version = wall_clock->version; 135 135 rmb(); /* fetch version before time */ 136 + /* 137 + * Note: wall_clock->sec is a u32 value, so it can 138 + * only store dates between 1970 and 2106. To allow 139 + * times beyond that, we need to create a new hypercall 140 + * interface with an extended pvclock_wall_clock structure 141 + * like ARM has. 142 + */ 136 143 now.tv_sec = wall_clock->sec; 137 144 now.tv_nsec = wall_clock->nsec; 138 145 rmb(); /* fetch time before checking version */ 139 146 } while ((wall_clock->version & 1) || (version != wall_clock->version)); 140 147 141 148 delta = pvclock_clocksource_read(vcpu_time); /* time since system boot */ 142 - delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec; 149 + delta += now.tv_sec * NSEC_PER_SEC + now.tv_nsec; 143 150 144 151 now.tv_nsec = do_div(delta, NSEC_PER_SEC); 145 152 now.tv_sec = delta; 146 153 147 - set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); 154 + set_normalized_timespec64(ts, now.tv_sec, now.tv_nsec); 148 155 } 149 156 150 157 void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti)
+5 -5
arch/x86/kernel/rtc.c
··· 39 39 * jump to the next second precisely 500 ms later. Check the Motorola 40 40 * MC146818A or Dallas DS12887 data sheet for details. 41 41 */ 42 - int mach_set_rtc_mmss(const struct timespec *now) 42 + int mach_set_rtc_mmss(const struct timespec64 *now) 43 43 { 44 44 unsigned long long nowtime = now->tv_sec; 45 45 struct rtc_time tm; ··· 60 60 return retval; 61 61 } 62 62 63 - void mach_get_cmos_time(struct timespec *now) 63 + void mach_get_cmos_time(struct timespec64 *now) 64 64 { 65 65 unsigned int status, year, mon, day, hour, min, sec, century = 0; 66 66 unsigned long flags; ··· 118 118 } else 119 119 year += CMOS_YEARS_OFFS; 120 120 121 - now->tv_sec = mktime(year, mon, day, hour, min, sec); 121 + now->tv_sec = mktime64(year, mon, day, hour, min, sec); 122 122 now->tv_nsec = 0; 123 123 } 124 124 ··· 145 145 } 146 146 EXPORT_SYMBOL(rtc_cmos_write); 147 147 148 - int update_persistent_clock(struct timespec now) 148 + int update_persistent_clock64(struct timespec64 now) 149 149 { 150 150 return x86_platform.set_wallclock(&now); 151 151 } 152 152 153 153 /* not static: needed by APM */ 154 - void read_persistent_clock(struct timespec *ts) 154 + void read_persistent_clock64(struct timespec64 *ts) 155 155 { 156 156 x86_platform.get_wallclock(ts); 157 157 }
+6 -6
arch/x86/platform/intel-mid/intel_mid_vrtc.c
··· 57 57 } 58 58 EXPORT_SYMBOL_GPL(vrtc_cmos_write); 59 59 60 - void vrtc_get_time(struct timespec *now) 60 + void vrtc_get_time(struct timespec64 *now) 61 61 { 62 62 u8 sec, min, hour, mday, mon; 63 63 unsigned long flags; ··· 83 83 pr_info("vRTC: sec: %d min: %d hour: %d day: %d " 84 84 "mon: %d year: %d\n", sec, min, hour, mday, mon, year); 85 85 86 - now->tv_sec = mktime(year, mon, mday, hour, min, sec); 86 + now->tv_sec = mktime64(year, mon, mday, hour, min, sec); 87 87 now->tv_nsec = 0; 88 88 } 89 89 90 - int vrtc_set_mmss(const struct timespec *now) 90 + int vrtc_set_mmss(const struct timespec64 *now) 91 91 { 92 92 unsigned long flags; 93 93 struct rtc_time tm; 94 94 int year; 95 95 int retval = 0; 96 96 97 - rtc_time_to_tm(now->tv_sec, &tm); 97 + rtc_time64_to_tm(now->tv_sec, &tm); 98 98 if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { 99 99 /* 100 100 * tm.year is the number of years since 1900, and the ··· 110 110 vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); 111 111 spin_unlock_irqrestore(&rtc_lock, flags); 112 112 } else { 113 - pr_err("%s: Invalid vRTC value: write of %lx to vRTC failed\n", 114 - __func__, now->tv_sec); 113 + pr_err("%s: Invalid vRTC value: write of %llx to vRTC failed\n", 114 + __func__, (s64)now->tv_sec); 115 115 retval = -EINVAL; 116 116 } 117 117 return retval;
+5 -5
arch/x86/xen/time.c
··· 57 57 return xen_clocksource_read(); 58 58 } 59 59 60 - static void xen_read_wallclock(struct timespec *ts) 60 + static void xen_read_wallclock(struct timespec64 *ts) 61 61 { 62 62 struct shared_info *s = HYPERVISOR_shared_info; 63 63 struct pvclock_wall_clock *wall_clock = &(s->wc); ··· 68 68 put_cpu_var(xen_vcpu); 69 69 } 70 70 71 - static void xen_get_wallclock(struct timespec *now) 71 + static void xen_get_wallclock(struct timespec64 *now) 72 72 { 73 73 xen_read_wallclock(now); 74 74 } 75 75 76 - static int xen_set_wallclock(const struct timespec *now) 76 + static int xen_set_wallclock(const struct timespec64 *now) 77 77 { 78 78 return -ENODEV; 79 79 } ··· 461 461 { 462 462 struct pvclock_vcpu_time_info *pvti; 463 463 int cpu = smp_processor_id(); 464 - struct timespec tp; 464 + struct timespec64 tp; 465 465 466 466 /* As Dom0 is never moved, no penalty on using TSC there */ 467 467 if (xen_initial_domain()) ··· 479 479 480 480 /* Set initial system time with full resolution */ 481 481 xen_read_wallclock(&tp); 482 - do_settimeofday(&tp); 482 + do_settimeofday64(&tp); 483 483 484 484 setup_force_cpu_cap(X86_FEATURE_TSC); 485 485