Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch Rewrite Xen timecounter and hardclock timer.



details:   https://anonhg.NetBSD.org/src/rev/0b031a3a12c8
branches:  trunk
changeset: 323758:0b031a3a12c8
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Fri Jun 29 21:53:12 2018 +0000

description:
Rewrite Xen timecounter and hardclock timer.

With this change, the Xen timecounter should now be globally
monotonic, as every timecounter is supposed to be.  Should also fix a
litany of races in the timecounter logic.

Proposed last year; see mailing list for further details:
https://mail-index.netbsd.org/port-xen/2017/10/31/msg009112.html

ok cherry

diffstat:

 sys/arch/x86/include/cpu.h |    28 +-
 sys/arch/xen/xen/clock.c   |  1279 +++++++++++++++++++++++++++++--------------
 2 files changed, 884 insertions(+), 423 deletions(-)

diffs (truncated from 1493 to 300 lines):

diff -r c0d2f05b7e03 -r 0b031a3a12c8 sys/arch/x86/include/cpu.h
--- a/sys/arch/x86/include/cpu.h        Fri Jun 29 20:18:36 2018 +0000
+++ b/sys/arch/x86/include/cpu.h        Fri Jun 29 21:53:12 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpu.h,v 1.92 2018/06/14 14:36:46 maxv Exp $    */
+/*     $NetBSD: cpu.h,v 1.93 2018/06/29 21:53:12 riastradh Exp $       */
 
 /*
  * Copyright (c) 1990 The Regents of the University of California.
@@ -236,6 +236,32 @@
        struct cpu_tss  *ci_tss;        /* Per-cpu TSSes; shared among LWPs */
        int ci_tss_sel;                 /* TSS selector of this cpu */
 
+#ifdef XEN
+       /* Xen raw system time at which we last ran hardclock.  */
+       uint64_t        ci_xen_hardclock_systime_ns;
+
+       /*
+        * Last TSC-adjusted local Xen system time we observed.  Used
+        * to detect whether the Xen clock has gone backwards.
+        */
+       uint64_t        ci_xen_last_systime_ns;
+
+       /*
+        * Distance in nanoseconds from the local view of system time
+        * to the global view of system time, if the local time is
+        * behind the global time.
+        */
+       uint64_t        ci_xen_systime_ns_skew;
+
+       /* Event counters for various pathologies that might happen.  */
+       struct evcnt    ci_xen_cpu_tsc_backwards_evcnt;
+       struct evcnt    ci_xen_tsc_delta_negative_evcnt;
+       struct evcnt    ci_xen_raw_systime_wraparound_evcnt;
+       struct evcnt    ci_xen_raw_systime_backwards_evcnt;
+       struct evcnt    ci_xen_systime_backwards_hardclock_evcnt;
+       struct evcnt    ci_xen_missed_hardclock_evcnt;
+#endif
+
        /*
         * The following two are actually region_descriptors,
         * but that would pollute the namespace.
diff -r c0d2f05b7e03 -r 0b031a3a12c8 sys/arch/xen/xen/clock.c
--- a/sys/arch/xen/xen/clock.c  Fri Jun 29 20:18:36 2018 +0000
+++ b/sys/arch/xen/xen/clock.c  Fri Jun 29 21:53:12 2018 +0000
@@ -1,9 +1,11 @@
-/*     $NetBSD: clock.c,v 1.67 2018/06/24 13:35:33 jdolecek Exp $      */
+/*     $NetBSD: clock.c,v 1.68 2018/06/29 21:53:12 riastradh Exp $     */
 
-/*
+/*-
+ * Copyright (c) 2017, 2018 The NetBSD Foundation, Inc.
+ * All rights reserved.
  *
- * Copyright (c) 2004 Christian Limpach.
- * All rights reserved.
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Taylor R. Campbell.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -14,580 +16,1013 @@
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "opt_xen.h"
 
+#ifndef XEN_CLOCK_DEBUG
+#define        XEN_CLOCK_DEBUG 0
+#endif
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.67 2018/06/24 13:35:33 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.68 2018/06/29 21:53:12 riastradh Exp $");
 
 #include <sys/param.h>
+#include <sys/types.h>
+#include <sys/atomic.h>
+#include <sys/callout.h>
+#include <sys/cpu.h>
+#include <sys/device.h>
+#include <sys/evcnt.h>
+#include <sys/intr.h>
+#include <sys/kernel.h>
+#include <sys/lwp.h>
+#include <sys/percpu.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/timetc.h>
-#include <sys/timevar.h>
-#include <sys/kernel.h>
-#include <sys/device.h>
-#include <sys/sysctl.h>
-
-#include <xen/xen.h>
-#include <xen/hypervisor.h>
-#include <xen/evtchn.h>
-#include <xen/xen-public/vcpu.h>
-#include <machine/cpu_counter.h>
 
 #include <dev/clock_subr.h>
+
+#include <machine/cpu.h>
+#include <machine/cpu_counter.h>
+#include <machine/lock.h>
+
+#include <xen/evtchn.h>
+#include <xen/hypervisor.h>
+#include <xen/xen-public/vcpu.h>
+#include <xen/xen.h>
+
 #include <x86/rtc.h>
 
-static int xen_timer_handler(void *, struct intrframe *);
-static int (*xen_timer_handler_stub)(void *) = (void *) xen_timer_handler;
-static struct intrhand *ih;
+#define NS_PER_TICK ((uint64_t)1000000000ULL/hz)
 
-/* A timecounter: Xen system_time extrapolated with a TSC. */
-u_int xen_get_timecount(struct timecounter*);
+static uint64_t        xen_vcputime_systime_ns(void);
+static uint64_t        xen_vcputime_raw_systime_ns(void);
+static void    xen_wallclock_time(struct timespec *);
+static uint64_t        xen_global_systime_ns(void);
+static unsigned        xen_get_timecount(struct timecounter *);
+static int     xen_rtc_get(struct todr_chip_handle *, struct timeval *);
+static int     xen_rtc_set(struct todr_chip_handle *, struct timeval *);
+static int     xen_timer_handler(void *, struct clockframe *);
+
+/*
+ * xen timecounter:
+ *
+ *     Xen vCPU system time, plus an adjustment with rdtsc.
+ */
 static struct timecounter xen_timecounter = {
        .tc_get_timecount = xen_get_timecount,
        .tc_poll_pps = NULL,
        .tc_counter_mask = ~0U,
-       .tc_frequency = 1000000000ULL,
+       .tc_frequency = 1000000000ULL,  /* 1 GHz, i.e. units of nanoseconds */
        .tc_name = "xen_system_time",
-       .tc_quality = 10000 /*
-                            * This needs to take precedence over any hardware
-                            * timecounters (e.g., ACPI in Xen3 dom0), because
-                            * they can't correct for Xen scheduling latency.
-                            */
+       .tc_quality = 10000,
 };
 
-/* These are periodically updated in shared_info, and then copied here. */
-struct shadow {
-       uint64_t tsc_stamp;
-       uint64_t system_time;
-       unsigned long time_version; /* XXXSMP */
-       uint32_t freq_mul;
-       int8_t freq_shift;
-       struct timespec ts;
+/*
+ * xen_global_systime_ns_stamp
+ *
+ *     The latest Xen vCPU system time that has been observed on any
+ *     CPU, for a global monotonic view of the Xen system time clock.
+ */
+static volatile uint64_t xen_global_systime_ns_stamp __cacheline_aligned;
+
+/*
+ * xen time of day register:
+ *
+ *     Xen wall clock time, plus a Xen vCPU system time adjustment.
+ */
+static struct todr_chip_handle xen_todr_chip = {
+       .todr_gettime = xen_rtc_get,
+       .todr_settime = xen_rtc_set,
 };
 
-/* Protects volatile variables ci_shadow & xen_clock_bias */
-static kmutex_t tmutex;
-
-/* Per CPU shadow time values */
-static volatile struct shadow ci_shadow[MAXCPUS];
-
-/* The time when the last hardclock(9) call should have taken place,
- * per cpu.
+/*
+ * xen timer interrupt handles -- per-CPU struct intrhand *
  */
-static volatile uint64_t vcpu_system_time[MAXCPUS];
-
-/*
- * The clock (as returned by xen_get_timecount) may need to be held
- * back to maintain the illusion that hardclock(9) was called when it
- * was supposed to be, not when Xen got around to scheduling us.
- */
-static volatile uint64_t xen_clock_bias[MAXCPUS];
+static struct percpu *xen_timer_ih_percpu __read_mostly;
 
 #ifdef DOM0OPS
-/* If we're dom0, send our time to Xen every minute or so. */
-int xen_timepush_ticks = 0;
-static callout_t xen_timepush_co;
+/*
+ * xen timepush state:
+ *
+ *     Callout to periodically, after a sysctl-configurable number of
+ *     NetBSD ticks, set the Xen hypervisor's wall clock time.
+ */
+static struct {
+       struct callout  ch;
+       int             ticks;
+} xen_timepush;
+
+static void    xen_timepush_init(void);
+static void    xen_timepush_intr(void *);
+static int     sysctl_xen_timepush(SYSCTLFN_ARGS);
 #endif
 
-#define NS_PER_TICK (1000000000ULL/hz)
+/*
+ * startrtclock()
+ *
+ *     Initialize the real-time clock from x86 machdep autoconf.
+ */
+void
+startrtclock(void)
+{
+
+       todr_attach(&xen_todr_chip);
+}
 
 /*
- * Reads a consistent set of time-base values from Xen, into a shadow data
- * area.  Must be called at splhigh (per timecounter requirements).
+ * setstatclockrate(rate)
+ *
+ *     Set the statclock to run at rate, in units of ticks per second.
+ *
+ *     Currently Xen does not have a separate statclock, so this is a
+ *     noop; instad the statclock runs in hardclock.
  */
-static void
-get_time_values_from_xen(struct cpu_info *ci)
+void
+setstatclockrate(int rate)
+{
+}
+
+/*
+ * idle_block()
+ *
+ *     Called from the idle loop when we have nothing to do but wait
+ *     for an interrupt.
+ */
+void
+idle_block(void)
 {
 
-       volatile struct shadow *shadow = &ci_shadow[ci->ci_cpuid];
+       KASSERT(curcpu()->ci_ipending == 0);
+       HYPERVISOR_block();
+}
+
+/*
+ * xen_rdtsc()
+ *
+ *     Read the local pCPU's tsc.
+ */
+static inline uint64_t
+xen_rdtsc(void)
+{
+       uint32_t lo, hi;
+
+       asm volatile("rdtsc" : "=a"(lo), "=d"(hi));
+
+       return ((uint64_t)hi << 32) | lo;
+}



Home | Main Index | Thread Index | Old Index