提交 e27c4929 编写于 作者: A Arnd Bergmann 提交者: Thomas Gleixner

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: NArnd Bergmann <arnd@arndb.de>
Signed-off-by: NThomas Gleixner <tglx@linutronix.de>
Reviewed-by: NBoris Ostrovsky <boris.ostrovsky@oracle.com>
Acked-by: NRadim Krčmář <rkrcmar@redhat.com>
Acked-by: NJan 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
上级 06aa3769
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
extern unsigned char vrtc_cmos_read(unsigned char reg); extern unsigned char vrtc_cmos_read(unsigned char reg);
extern void vrtc_cmos_write(unsigned char val, unsigned char reg); extern void vrtc_cmos_write(unsigned char val, unsigned char reg);
extern void vrtc_get_time(struct timespec *now); extern void vrtc_get_time(struct timespec64 *now);
extern int vrtc_set_mmss(const struct timespec *now); extern int vrtc_set_mmss(const struct timespec64 *now);
#endif #endif
...@@ -95,8 +95,8 @@ static inline unsigned char current_lock_cmos_reg(void) ...@@ -95,8 +95,8 @@ static inline unsigned char current_lock_cmos_reg(void)
unsigned char rtc_cmos_read(unsigned char addr); unsigned char rtc_cmos_read(unsigned char addr);
void rtc_cmos_write(unsigned char val, unsigned char addr); void rtc_cmos_write(unsigned char val, unsigned char addr);
extern int mach_set_rtc_mmss(const struct timespec *now); extern int mach_set_rtc_mmss(const struct timespec64 *now);
extern void mach_get_cmos_time(struct timespec *now); extern void mach_get_cmos_time(struct timespec64 *now);
#define RTC_IRQ 8 #define RTC_IRQ 8
......
...@@ -12,7 +12,7 @@ void pvclock_set_flags(u8 flags); ...@@ -12,7 +12,7 @@ void pvclock_set_flags(u8 flags);
unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src);
void pvclock_read_wallclock(struct pvclock_wall_clock *wall, void pvclock_read_wallclock(struct pvclock_wall_clock *wall,
struct pvclock_vcpu_time_info *vcpu, struct pvclock_vcpu_time_info *vcpu,
struct timespec *ts); struct timespec64 *ts);
void pvclock_resume(void); void pvclock_resume(void);
void pvclock_touch_watchdogs(void); void pvclock_touch_watchdogs(void);
......
...@@ -170,7 +170,7 @@ struct x86_cpuinit_ops { ...@@ -170,7 +170,7 @@ struct x86_cpuinit_ops {
void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node); void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node);
}; };
struct timespec; struct timespec64;
/** /**
* struct x86_legacy_devices - legacy x86 devices * struct x86_legacy_devices - legacy x86 devices
...@@ -264,8 +264,8 @@ struct x86_hyper_runtime { ...@@ -264,8 +264,8 @@ struct x86_hyper_runtime {
struct x86_platform_ops { struct x86_platform_ops {
unsigned long (*calibrate_cpu)(void); unsigned long (*calibrate_cpu)(void);
unsigned long (*calibrate_tsc)(void); unsigned long (*calibrate_tsc)(void);
void (*get_wallclock)(struct timespec *ts); void (*get_wallclock)(struct timespec64 *ts);
int (*set_wallclock)(const struct timespec *ts); int (*set_wallclock)(const struct timespec64 *ts);
void (*iommu_shutdown)(void); void (*iommu_shutdown)(void);
bool (*is_untracked_pat_range)(u64 start, u64 end); bool (*is_untracked_pat_range)(u64 start, u64 end);
void (*nmi_init)(void); void (*nmi_init)(void);
......
...@@ -37,7 +37,7 @@ static uint32_t __init jailhouse_detect(void) ...@@ -37,7 +37,7 @@ static uint32_t __init jailhouse_detect(void)
return jailhouse_cpuid_base(); return jailhouse_cpuid_base();
} }
static void jailhouse_get_wallclock(struct timespec *now) static void jailhouse_get_wallclock(struct timespec64 *now)
{ {
memset(now, 0, sizeof(*now)); memset(now, 0, sizeof(*now));
} }
......
...@@ -53,7 +53,7 @@ static struct pvclock_wall_clock *wall_clock; ...@@ -53,7 +53,7 @@ static struct pvclock_wall_clock *wall_clock;
* have elapsed since the hypervisor wrote the data. So we try to account for * have elapsed since the hypervisor wrote the data. So we try to account for
* that with system time * that with system time
*/ */
static void kvm_get_wallclock(struct timespec *now) static void kvm_get_wallclock(struct timespec64 *now)
{ {
struct pvclock_vcpu_time_info *vcpu_time; struct pvclock_vcpu_time_info *vcpu_time;
int low, high; int low, high;
...@@ -72,7 +72,7 @@ static void kvm_get_wallclock(struct timespec *now) ...@@ -72,7 +72,7 @@ static void kvm_get_wallclock(struct timespec *now)
put_cpu(); put_cpu();
} }
static int kvm_set_wallclock(const struct timespec *now) static int kvm_set_wallclock(const struct timespec64 *now)
{ {
return -ENODEV; return -ENODEV;
} }
......
...@@ -123,28 +123,35 @@ u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src) ...@@ -123,28 +123,35 @@ u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src)
void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock, void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
struct pvclock_vcpu_time_info *vcpu_time, struct pvclock_vcpu_time_info *vcpu_time,
struct timespec *ts) struct timespec64 *ts)
{ {
u32 version; u32 version;
u64 delta; u64 delta;
struct timespec now; struct timespec64 now;
/* get wallclock at system boot */ /* get wallclock at system boot */
do { do {
version = wall_clock->version; version = wall_clock->version;
rmb(); /* fetch version before time */ rmb(); /* fetch version before time */
/*
* Note: wall_clock->sec is a u32 value, so it can
* only store dates between 1970 and 2106. To allow
* times beyond that, we need to create a new hypercall
* interface with an extended pvclock_wall_clock structure
* like ARM has.
*/
now.tv_sec = wall_clock->sec; now.tv_sec = wall_clock->sec;
now.tv_nsec = wall_clock->nsec; now.tv_nsec = wall_clock->nsec;
rmb(); /* fetch time before checking version */ rmb(); /* fetch time before checking version */
} while ((wall_clock->version & 1) || (version != wall_clock->version)); } while ((wall_clock->version & 1) || (version != wall_clock->version));
delta = pvclock_clocksource_read(vcpu_time); /* time since system boot */ delta = pvclock_clocksource_read(vcpu_time); /* time since system boot */
delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec; delta += now.tv_sec * NSEC_PER_SEC + now.tv_nsec;
now.tv_nsec = do_div(delta, NSEC_PER_SEC); now.tv_nsec = do_div(delta, NSEC_PER_SEC);
now.tv_sec = delta; now.tv_sec = delta;
set_normalized_timespec(ts, now.tv_sec, now.tv_nsec); set_normalized_timespec64(ts, now.tv_sec, now.tv_nsec);
} }
void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti) void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti)
......
...@@ -39,7 +39,7 @@ EXPORT_SYMBOL(rtc_lock); ...@@ -39,7 +39,7 @@ EXPORT_SYMBOL(rtc_lock);
* jump to the next second precisely 500 ms later. Check the Motorola * jump to the next second precisely 500 ms later. Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details. * MC146818A or Dallas DS12887 data sheet for details.
*/ */
int mach_set_rtc_mmss(const struct timespec *now) int mach_set_rtc_mmss(const struct timespec64 *now)
{ {
unsigned long long nowtime = now->tv_sec; unsigned long long nowtime = now->tv_sec;
struct rtc_time tm; struct rtc_time tm;
...@@ -60,7 +60,7 @@ int mach_set_rtc_mmss(const struct timespec *now) ...@@ -60,7 +60,7 @@ int mach_set_rtc_mmss(const struct timespec *now)
return retval; return retval;
} }
void mach_get_cmos_time(struct timespec *now) void mach_get_cmos_time(struct timespec64 *now)
{ {
unsigned int status, year, mon, day, hour, min, sec, century = 0; unsigned int status, year, mon, day, hour, min, sec, century = 0;
unsigned long flags; unsigned long flags;
...@@ -118,7 +118,7 @@ void mach_get_cmos_time(struct timespec *now) ...@@ -118,7 +118,7 @@ void mach_get_cmos_time(struct timespec *now)
} else } else
year += CMOS_YEARS_OFFS; year += CMOS_YEARS_OFFS;
now->tv_sec = mktime(year, mon, day, hour, min, sec); now->tv_sec = mktime64(year, mon, day, hour, min, sec);
now->tv_nsec = 0; now->tv_nsec = 0;
} }
...@@ -145,13 +145,13 @@ void rtc_cmos_write(unsigned char val, unsigned char addr) ...@@ -145,13 +145,13 @@ void rtc_cmos_write(unsigned char val, unsigned char addr)
} }
EXPORT_SYMBOL(rtc_cmos_write); EXPORT_SYMBOL(rtc_cmos_write);
int update_persistent_clock(struct timespec now) int update_persistent_clock64(struct timespec64 now)
{ {
return x86_platform.set_wallclock(&now); return x86_platform.set_wallclock(&now);
} }
/* not static: needed by APM */ /* not static: needed by APM */
void read_persistent_clock(struct timespec *ts) void read_persistent_clock64(struct timespec64 *ts)
{ {
x86_platform.get_wallclock(ts); x86_platform.get_wallclock(ts);
} }
......
...@@ -57,7 +57,7 @@ void vrtc_cmos_write(unsigned char val, unsigned char reg) ...@@ -57,7 +57,7 @@ void vrtc_cmos_write(unsigned char val, unsigned char reg)
} }
EXPORT_SYMBOL_GPL(vrtc_cmos_write); EXPORT_SYMBOL_GPL(vrtc_cmos_write);
void vrtc_get_time(struct timespec *now) void vrtc_get_time(struct timespec64 *now)
{ {
u8 sec, min, hour, mday, mon; u8 sec, min, hour, mday, mon;
unsigned long flags; unsigned long flags;
...@@ -83,18 +83,18 @@ void vrtc_get_time(struct timespec *now) ...@@ -83,18 +83,18 @@ void vrtc_get_time(struct timespec *now)
pr_info("vRTC: sec: %d min: %d hour: %d day: %d " pr_info("vRTC: sec: %d min: %d hour: %d day: %d "
"mon: %d year: %d\n", sec, min, hour, mday, mon, year); "mon: %d year: %d\n", sec, min, hour, mday, mon, year);
now->tv_sec = mktime(year, mon, mday, hour, min, sec); now->tv_sec = mktime64(year, mon, mday, hour, min, sec);
now->tv_nsec = 0; now->tv_nsec = 0;
} }
int vrtc_set_mmss(const struct timespec *now) int vrtc_set_mmss(const struct timespec64 *now)
{ {
unsigned long flags; unsigned long flags;
struct rtc_time tm; struct rtc_time tm;
int year; int year;
int retval = 0; int retval = 0;
rtc_time_to_tm(now->tv_sec, &tm); rtc_time64_to_tm(now->tv_sec, &tm);
if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) { if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) {
/* /*
* tm.year is the number of years since 1900, and the * tm.year is the number of years since 1900, and the
...@@ -110,8 +110,8 @@ int vrtc_set_mmss(const struct timespec *now) ...@@ -110,8 +110,8 @@ int vrtc_set_mmss(const struct timespec *now)
vrtc_cmos_write(tm.tm_sec, RTC_SECONDS); vrtc_cmos_write(tm.tm_sec, RTC_SECONDS);
spin_unlock_irqrestore(&rtc_lock, flags); spin_unlock_irqrestore(&rtc_lock, flags);
} else { } else {
pr_err("%s: Invalid vRTC value: write of %lx to vRTC failed\n", pr_err("%s: Invalid vRTC value: write of %llx to vRTC failed\n",
__func__, now->tv_sec); __func__, (s64)now->tv_sec);
retval = -EINVAL; retval = -EINVAL;
} }
return retval; return retval;
......
...@@ -57,7 +57,7 @@ static u64 xen_clocksource_get_cycles(struct clocksource *cs) ...@@ -57,7 +57,7 @@ static u64 xen_clocksource_get_cycles(struct clocksource *cs)
return xen_clocksource_read(); return xen_clocksource_read();
} }
static void xen_read_wallclock(struct timespec *ts) static void xen_read_wallclock(struct timespec64 *ts)
{ {
struct shared_info *s = HYPERVISOR_shared_info; struct shared_info *s = HYPERVISOR_shared_info;
struct pvclock_wall_clock *wall_clock = &(s->wc); struct pvclock_wall_clock *wall_clock = &(s->wc);
...@@ -68,12 +68,12 @@ static void xen_read_wallclock(struct timespec *ts) ...@@ -68,12 +68,12 @@ static void xen_read_wallclock(struct timespec *ts)
put_cpu_var(xen_vcpu); put_cpu_var(xen_vcpu);
} }
static void xen_get_wallclock(struct timespec *now) static void xen_get_wallclock(struct timespec64 *now)
{ {
xen_read_wallclock(now); xen_read_wallclock(now);
} }
static int xen_set_wallclock(const struct timespec *now) static int xen_set_wallclock(const struct timespec64 *now)
{ {
return -ENODEV; return -ENODEV;
} }
...@@ -461,7 +461,7 @@ static void __init xen_time_init(void) ...@@ -461,7 +461,7 @@ static void __init xen_time_init(void)
{ {
struct pvclock_vcpu_time_info *pvti; struct pvclock_vcpu_time_info *pvti;
int cpu = smp_processor_id(); int cpu = smp_processor_id();
struct timespec tp; struct timespec64 tp;
/* As Dom0 is never moved, no penalty on using TSC there */ /* As Dom0 is never moved, no penalty on using TSC there */
if (xen_initial_domain()) if (xen_initial_domain())
...@@ -479,7 +479,7 @@ static void __init xen_time_init(void) ...@@ -479,7 +479,7 @@ static void __init xen_time_init(void)
/* Set initial system time with full resolution */ /* Set initial system time with full resolution */
xen_read_wallclock(&tp); xen_read_wallclock(&tp);
do_settimeofday(&tp); do_settimeofday64(&tp);
setup_force_cpu_cap(X86_FEATURE_TSC); setup_force_cpu_cap(X86_FEATURE_TSC);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册