| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: xen_clock.c,v 1.1.2.1 2020/04/16 19:23:50 bouyer Exp $ */ | | 1 | /* $NetBSD: xen_clock.c,v 1.1.2.2 2020/04/16 20:21:44 bouyer Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2017, 2018 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2017, 2018 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. | | 8 | * by Taylor R. Campbell. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -26,27 +26,27 @@ | | | @@ -26,27 +26,27 @@ |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include "opt_xen.h" | | 32 | #include "opt_xen.h" |
33 | | | 33 | |
34 | #ifndef XEN_CLOCK_DEBUG | | 34 | #ifndef XEN_CLOCK_DEBUG |
35 | #define XEN_CLOCK_DEBUG 0 | | 35 | #define XEN_CLOCK_DEBUG 0 |
36 | #endif | | 36 | #endif |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: xen_clock.c,v 1.1.2.1 2020/04/16 19:23:50 bouyer Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: xen_clock.c,v 1.1.2.2 2020/04/16 20:21:44 bouyer Exp $"); |
40 | | | 40 | |
41 | #include <sys/param.h> | | 41 | #include <sys/param.h> |
42 | #include <sys/types.h> | | 42 | #include <sys/types.h> |
43 | #include <sys/atomic.h> | | 43 | #include <sys/atomic.h> |
44 | #include <sys/callout.h> | | 44 | #include <sys/callout.h> |
45 | #include <sys/cpu.h> | | 45 | #include <sys/cpu.h> |
46 | #include <sys/device.h> | | 46 | #include <sys/device.h> |
47 | #include <sys/evcnt.h> | | 47 | #include <sys/evcnt.h> |
48 | #include <sys/intr.h> | | 48 | #include <sys/intr.h> |
49 | #include <sys/kernel.h> | | 49 | #include <sys/kernel.h> |
50 | #include <sys/lwp.h> | | 50 | #include <sys/lwp.h> |
51 | #include <sys/proc.h> | | 51 | #include <sys/proc.h> |
52 | #include <sys/sysctl.h> | | 52 | #include <sys/sysctl.h> |
| @@ -104,148 +104,26 @@ static volatile uint64_t xen_global_syst | | | @@ -104,148 +104,26 @@ static volatile uint64_t xen_global_syst |
104 | * Callout to periodically, after a sysctl-configurable number of | | 104 | * Callout to periodically, after a sysctl-configurable number of |
105 | * NetBSD ticks, set the Xen hypervisor's wall clock time. | | 105 | * NetBSD ticks, set the Xen hypervisor's wall clock time. |
106 | */ | | 106 | */ |
107 | static struct { | | 107 | static struct { |
108 | struct callout ch; | | 108 | struct callout ch; |
109 | int ticks; | | 109 | int ticks; |
110 | } xen_timepush; | | 110 | } xen_timepush; |
111 | | | 111 | |
112 | static void xen_timepush_init(void); | | 112 | static void xen_timepush_init(void); |
113 | static void xen_timepush_intr(void *); | | 113 | static void xen_timepush_intr(void *); |
114 | static int sysctl_xen_timepush(SYSCTLFN_ARGS); | | 114 | static int sysctl_xen_timepush(SYSCTLFN_ARGS); |
115 | #endif | | 115 | #endif |
116 | | | 116 | |
117 | #ifdef XENPV | | | |
118 | static int xen_rtc_get(struct todr_chip_handle *, struct timeval *); | | | |
119 | static int xen_rtc_set(struct todr_chip_handle *, struct timeval *); | | | |
120 | static void xen_wallclock_time(struct timespec *); | | | |
121 | /* | | | |
122 | * xen time of day register: | | | |
123 | * | | | |
124 | * Xen wall clock time, plus a Xen vCPU system time adjustment. | | | |
125 | */ | | | |
126 | static struct todr_chip_handle xen_todr_chip = { | | | |
127 | .todr_gettime = xen_rtc_get, | | | |
128 | .todr_settime = xen_rtc_set, | | | |
129 | }; | | | |
130 | | | | |
131 | /* | | | |
132 | * startrtclock() | | | |
133 | * | | | |
134 | * Initialize the real-time clock from x86 machdep autoconf. | | | |
135 | */ | | | |
136 | void | | | |
137 | startrtclock(void) | | | |
138 | { | | | |
139 | | | | |
140 | todr_attach(&xen_todr_chip); | | | |
141 | } | | | |
142 | | | | |
143 | /* | | | |
144 | * setstatclockrate(rate) | | | |
145 | * | | | |
146 | * Set the statclock to run at rate, in units of ticks per second. | | | |
147 | * | | | |
148 | * Currently Xen does not have a separate statclock, so this is a | | | |
149 | * noop; instad the statclock runs in hardclock. | | | |
150 | */ | | | |
151 | void | | | |
152 | setstatclockrate(int rate) | | | |
153 | { | | | |
154 | } | | | |
155 | | | | |
156 | /* | | | |
157 | * xen_rtc_get(todr, tv) | | | |
158 | * | | | |
159 | * Get the current real-time clock from the Xen wall clock time | | | |
160 | * and vCPU system time adjustment. | | | |
161 | */ | | | |
162 | static int | | | |
163 | xen_rtc_get(struct todr_chip_handle *todr, struct timeval *tvp) | | | |
164 | { | | | |
165 | struct timespec ts; | | | |
166 | | | | |
167 | xen_wallclock_time(&ts); | | | |
168 | TIMESPEC_TO_TIMEVAL(tvp, &ts); | | | |
169 | | | | |
170 | return 0; | | | |
171 | } | | | |
172 | | | | |
173 | /* | | | |
174 | * xen_rtc_set(todr, tv) | | | |
175 | * | | | |
176 | * Set the Xen wall clock time, if we can. | | | |
177 | */ | | | |
178 | static int | | | |
179 | xen_rtc_set(struct todr_chip_handle *todr, struct timeval *tvp) | | | |
180 | { | | | |
181 | #ifdef DOM0OPS | | | |
182 | struct clock_ymdhms dt; | | | |
183 | xen_platform_op_t op; | | | |
184 | uint64_t systime_ns; | | | |
185 | | | | |
186 | if (xendomain_is_privileged()) { | | | |
187 | /* Convert to ymdhms and set the x86 ISA RTC. */ | | | |
188 | clock_secs_to_ymdhms(tvp->tv_sec, &dt); | | | |
189 | rtc_set_ymdhms(NULL, &dt); | | | |
190 | | | | |
191 | /* Get the global system time so we can preserve it. */ | | | |
192 | systime_ns = xen_global_systime_ns(); | | | |
193 | | | | |
194 | /* Set the hypervisor wall clock time. */ | | | |
195 | op.cmd = XENPF_settime; | | | |
196 | op.u.settime.secs = tvp->tv_sec; | | | |
197 | op.u.settime.nsecs = tvp->tv_usec * 1000; | | | |
198 | op.u.settime.system_time = systime_ns; | | | |
199 | return HYPERVISOR_platform_op(&op); | | | |
200 | } | | | |
201 | #endif | | | |
202 | | | | |
203 | /* XXX Should this fail if not on privileged dom0? */ | | | |
204 | return 0; | | | |
205 | } | | | |
206 | | | | |
207 | /* | | | |
208 | * xen_wallclock_time(tsp) | | | |
209 | * | | | |
210 | * Return a snapshot of the current low-resolution wall clock | | | |
211 | * time, as reported by the hypervisor, in tsp. | | | |
212 | */ | | | |
213 | static void | | | |
214 | xen_wallclock_time(struct timespec *tsp) | | | |
215 | { | | | |
216 | struct xen_wallclock_ticket ticket; | | | |
217 | uint64_t systime_ns; | | | |
218 | | | | |
219 | int s = splsched(); /* make sure we won't be interrupted */ | | | |
220 | /* Read the last wall clock sample from the hypervisor. */ | | | |
221 | do { | | | |
222 | xen_wallclock_enter(&ticket); | | | |
223 | tsp->tv_sec = HYPERVISOR_shared_info->wc_sec; | | | |
224 | tsp->tv_nsec = HYPERVISOR_shared_info->wc_nsec; | | | |
225 | } while (!xen_wallclock_exit(&ticket)); | | | |
226 | | | | |
227 | /* Get the global system time. */ | | | |
228 | systime_ns = xen_global_systime_ns(); | | | |
229 | splx(s); | | | |
230 | | | | |
231 | /* Add the system time to the wall clock time. */ | | | |
232 | systime_ns += tsp->tv_nsec; | | | |
233 | tsp->tv_sec += systime_ns / 1000000000ull; | | | |
234 | tsp->tv_nsec = systime_ns % 1000000000ull; | | | |
235 | } | | | |
236 | | | | |
237 | #endif /* XENPV */ | | | |
238 | | | | |
239 | /* | | 117 | /* |
240 | * idle_block() | | 118 | * idle_block() |
241 | * | | 119 | * |
242 | * Called from the idle loop when we have nothing to do but wait | | 120 | * Called from the idle loop when we have nothing to do but wait |
243 | * for an interrupt. | | 121 | * for an interrupt. |
244 | */ | | 122 | */ |
245 | void | | 123 | void |
246 | idle_block(void) | | 124 | idle_block(void) |
247 | { | | 125 | { |
248 | KASSERT(curcpu()->ci_ipending == 0); | | 126 | KASSERT(curcpu()->ci_ipending == 0); |
249 | HYPERVISOR_block(); | | 127 | HYPERVISOR_block(); |
250 | KASSERT(curcpu()->ci_ipending == 0); | | 128 | KASSERT(curcpu()->ci_ipending == 0); |
251 | } | | 129 | } |
| @@ -1001,13 +879,135 @@ sysctl_xen_timepush(SYSCTLFN_ARGS) | | | @@ -1001,13 +879,135 @@ sysctl_xen_timepush(SYSCTLFN_ARGS) |
1001 | if (ticks != xen_timepush.ticks) { | | 879 | if (ticks != xen_timepush.ticks) { |
1002 | xen_timepush.ticks = ticks; | | 880 | xen_timepush.ticks = ticks; |
1003 | | | 881 | |
1004 | if (ticks == 0) | | 882 | if (ticks == 0) |
1005 | callout_stop(&xen_timepush.ch); | | 883 | callout_stop(&xen_timepush.ch); |
1006 | else | | 884 | else |
1007 | callout_schedule(&xen_timepush.ch, ticks); | | 885 | callout_schedule(&xen_timepush.ch, ticks); |
1008 | } | | 886 | } |
1009 | | | 887 | |
1010 | return 0; | | 888 | return 0; |
1011 | } | | 889 | } |
1012 | | | 890 | |
1013 | #endif /* DOM0OPS */ | | 891 | #endif /* DOM0OPS */ |
| | | 892 | |
| | | 893 | #ifdef XENPV |
| | | 894 | static int xen_rtc_get(struct todr_chip_handle *, struct timeval *); |
| | | 895 | static int xen_rtc_set(struct todr_chip_handle *, struct timeval *); |
| | | 896 | static void xen_wallclock_time(struct timespec *); |
| | | 897 | /* |
| | | 898 | * xen time of day register: |
| | | 899 | * |
| | | 900 | * Xen wall clock time, plus a Xen vCPU system time adjustment. |
| | | 901 | */ |
| | | 902 | static struct todr_chip_handle xen_todr_chip = { |
| | | 903 | .todr_gettime = xen_rtc_get, |
| | | 904 | .todr_settime = xen_rtc_set, |
| | | 905 | }; |
| | | 906 | |
| | | 907 | /* |
| | | 908 | * startrtclock() |
| | | 909 | * |
| | | 910 | * Initialize the real-time clock from x86 machdep autoconf. |
| | | 911 | */ |
| | | 912 | void |
| | | 913 | startrtclock(void) |
| | | 914 | { |
| | | 915 | |
| | | 916 | todr_attach(&xen_todr_chip); |
| | | 917 | } |
| | | 918 | |
| | | 919 | /* |
| | | 920 | * setstatclockrate(rate) |
| | | 921 | * |
| | | 922 | * Set the statclock to run at rate, in units of ticks per second. |
| | | 923 | * |
| | | 924 | * Currently Xen does not have a separate statclock, so this is a |
| | | 925 | * noop; instad the statclock runs in hardclock. |
| | | 926 | */ |
| | | 927 | void |
| | | 928 | setstatclockrate(int rate) |
| | | 929 | { |
| | | 930 | } |
| | | 931 | |
| | | 932 | /* |
| | | 933 | * xen_rtc_get(todr, tv) |
| | | 934 | * |
| | | 935 | * Get the current real-time clock from the Xen wall clock time |
| | | 936 | * and vCPU system time adjustment. |
| | | 937 | */ |
| | | 938 | static int |
| | | 939 | xen_rtc_get(struct todr_chip_handle *todr, struct timeval *tvp) |
| | | 940 | { |
| | | 941 | struct timespec ts; |
| | | 942 | |
| | | 943 | xen_wallclock_time(&ts); |
| | | 944 | TIMESPEC_TO_TIMEVAL(tvp, &ts); |
| | | 945 | |
| | | 946 | return 0; |
| | | 947 | } |
| | | 948 | |
| | | 949 | /* |
| | | 950 | * xen_rtc_set(todr, tv) |
| | | 951 | * |
| | | 952 | * Set the Xen wall clock time, if we can. |
| | | 953 | */ |
| | | 954 | static int |
| | | 955 | xen_rtc_set(struct todr_chip_handle *todr, struct timeval *tvp) |
| | | 956 | { |
| | | 957 | #ifdef DOM0OPS |
| | | 958 | struct clock_ymdhms dt; |
| | | 959 | xen_platform_op_t op; |
| | | 960 | uint64_t systime_ns; |
| | | 961 | |
| | | 962 | if (xendomain_is_privileged()) { |
| | | 963 | /* Convert to ymdhms and set the x86 ISA RTC. */ |
| | | 964 | clock_secs_to_ymdhms(tvp->tv_sec, &dt); |
| | | 965 | rtc_set_ymdhms(NULL, &dt); |
| | | 966 | |
| | | 967 | /* Get the global system time so we can preserve it. */ |
| | | 968 | systime_ns = xen_global_systime_ns(); |
| | | 969 | |
| | | 970 | /* Set the hypervisor wall clock time. */ |
| | | 971 | op.cmd = XENPF_settime; |
| | | 972 | op.u.settime.secs = tvp->tv_sec; |
| | | 973 | op.u.settime.nsecs = tvp->tv_usec * 1000; |
| | | 974 | op.u.settime.system_time = systime_ns; |
| | | 975 | return HYPERVISOR_platform_op(&op); |
| | | 976 | } |
| | | 977 | #endif |
| | | 978 | |
| | | 979 | /* XXX Should this fail if not on privileged dom0? */ |
| | | 980 | return 0; |
| | | 981 | } |
| | | 982 | |
| | | 983 | /* |
| | | 984 | * xen_wallclock_time(tsp) |
| | | 985 | * |
| | | 986 | * Return a snapshot of the current low-resolution wall clock |
| | | 987 | * time, as reported by the hypervisor, in tsp. |
| | | 988 | */ |
| | | 989 | static void |
| | | 990 | xen_wallclock_time(struct timespec *tsp) |
| | | 991 | { |
| | | 992 | struct xen_wallclock_ticket ticket; |
| | | 993 | uint64_t systime_ns; |
| | | 994 | |
| | | 995 | int s = splsched(); /* make sure we won't be interrupted */ |
| | | 996 | /* Read the last wall clock sample from the hypervisor. */ |
| | | 997 | do { |
| | | 998 | xen_wallclock_enter(&ticket); |
| | | 999 | tsp->tv_sec = HYPERVISOR_shared_info->wc_sec; |
| | | 1000 | tsp->tv_nsec = HYPERVISOR_shared_info->wc_nsec; |
| | | 1001 | } while (!xen_wallclock_exit(&ticket)); |
| | | 1002 | |
| | | 1003 | /* Get the global system time. */ |
| | | 1004 | systime_ns = xen_global_systime_ns(); |
| | | 1005 | splx(s); |
| | | 1006 | |
| | | 1007 | /* Add the system time to the wall clock time. */ |
| | | 1008 | systime_ns += tsp->tv_nsec; |
| | | 1009 | tsp->tv_sec += systime_ns / 1000000000ull; |
| | | 1010 | tsp->tv_nsec = systime_ns % 1000000000ull; |
| | | 1011 | } |
| | | 1012 | |
| | | 1013 | #endif /* XENPV */ |