| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* KVM paravirtual clock driver. A clocksource implementation |
|---|
| 2 | 3 | Copyright (C) 2008 Glauber de Oliveira Costa, Red Hat Inc. |
|---|
| 3 | | - |
|---|
| 4 | | - This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - it under the terms of the GNU General Public License as published by |
|---|
| 6 | | - the Free Software Foundation; either version 2 of the License, or |
|---|
| 7 | | - (at your option) any later version. |
|---|
| 8 | | - |
|---|
| 9 | | - This program is distributed in the hope that it will be useful, |
|---|
| 10 | | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | | - GNU General Public License for more details. |
|---|
| 13 | | - |
|---|
| 14 | | - You should have received a copy of the GNU General Public License |
|---|
| 15 | | - along with this program; if not, write to the Free Software |
|---|
| 16 | | - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 17 | 4 | */ |
|---|
| 18 | 5 | |
|---|
| 19 | 6 | #include <linux/clocksource.h> |
|---|
| .. | .. |
|---|
| 33 | 20 | #include <asm/hypervisor.h> |
|---|
| 34 | 21 | #include <asm/mem_encrypt.h> |
|---|
| 35 | 22 | #include <asm/x86_init.h> |
|---|
| 36 | | -#include <asm/reboot.h> |
|---|
| 37 | 23 | #include <asm/kvmclock.h> |
|---|
| 38 | 24 | |
|---|
| 39 | 25 | static int kvmclock __initdata = 1; |
|---|
| .. | .. |
|---|
| 111 | 97 | if (!stable) |
|---|
| 112 | 98 | clear_sched_clock_stable(); |
|---|
| 113 | 99 | kvm_sched_clock_offset = kvm_clock_read(); |
|---|
| 114 | | - pv_time_ops.sched_clock = kvm_sched_clock_read; |
|---|
| 100 | + pv_ops.time.sched_clock = kvm_sched_clock_read; |
|---|
| 115 | 101 | |
|---|
| 116 | 102 | pr_info("kvm-clock: using sched offset of %llu cycles", |
|---|
| 117 | 103 | kvm_sched_clock_offset); |
|---|
| .. | .. |
|---|
| 163 | 149 | return ret; |
|---|
| 164 | 150 | } |
|---|
| 165 | 151 | |
|---|
| 152 | +static int kvm_cs_enable(struct clocksource *cs) |
|---|
| 153 | +{ |
|---|
| 154 | + vclocks_set_used(VDSO_CLOCKMODE_PVCLOCK); |
|---|
| 155 | + return 0; |
|---|
| 156 | +} |
|---|
| 157 | + |
|---|
| 166 | 158 | struct clocksource kvm_clock = { |
|---|
| 167 | 159 | .name = "kvm-clock", |
|---|
| 168 | 160 | .read = kvm_clock_get_cycles, |
|---|
| 169 | 161 | .rating = 400, |
|---|
| 170 | 162 | .mask = CLOCKSOURCE_MASK(64), |
|---|
| 171 | 163 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
|---|
| 164 | + .enable = kvm_cs_enable, |
|---|
| 172 | 165 | }; |
|---|
| 173 | 166 | EXPORT_SYMBOL_GPL(kvm_clock); |
|---|
| 174 | 167 | |
|---|
| .. | .. |
|---|
| 201 | 194 | } |
|---|
| 202 | 195 | #endif |
|---|
| 203 | 196 | |
|---|
| 204 | | -/* |
|---|
| 205 | | - * After the clock is registered, the host will keep writing to the |
|---|
| 206 | | - * registered memory location. If the guest happens to shutdown, this memory |
|---|
| 207 | | - * won't be valid. In cases like kexec, in which you install a new kernel, this |
|---|
| 208 | | - * means a random memory location will be kept being written. So before any |
|---|
| 209 | | - * kind of shutdown from our side, we unregister the clock by writing anything |
|---|
| 210 | | - * that does not have the 'enable' bit set in the msr |
|---|
| 211 | | - */ |
|---|
| 212 | | -#ifdef CONFIG_KEXEC_CORE |
|---|
| 213 | | -static void kvm_crash_shutdown(struct pt_regs *regs) |
|---|
| 197 | +void kvmclock_disable(void) |
|---|
| 214 | 198 | { |
|---|
| 215 | 199 | native_write_msr(msr_kvm_system_time, 0, 0); |
|---|
| 216 | | - kvm_disable_steal_time(); |
|---|
| 217 | | - native_machine_crash_shutdown(regs); |
|---|
| 218 | | -} |
|---|
| 219 | | -#endif |
|---|
| 220 | | - |
|---|
| 221 | | -static void kvm_shutdown(void) |
|---|
| 222 | | -{ |
|---|
| 223 | | - native_write_msr(msr_kvm_system_time, 0, 0); |
|---|
| 224 | | - kvm_disable_steal_time(); |
|---|
| 225 | | - native_machine_shutdown(); |
|---|
| 226 | 200 | } |
|---|
| 227 | 201 | |
|---|
| 228 | 202 | static void __init kvmclock_init_mem(void) |
|---|
| .. | .. |
|---|
| 266 | 240 | |
|---|
| 267 | 241 | static int __init kvm_setup_vsyscall_timeinfo(void) |
|---|
| 268 | 242 | { |
|---|
| 269 | | -#ifdef CONFIG_X86_64 |
|---|
| 270 | | - u8 flags; |
|---|
| 271 | | - |
|---|
| 272 | | - if (!per_cpu(hv_clock_per_cpu, 0) || !kvmclock_vsyscall) |
|---|
| 273 | | - return 0; |
|---|
| 274 | | - |
|---|
| 275 | | - flags = pvclock_read_flags(&hv_clock_boot[0].pvti); |
|---|
| 276 | | - if (!(flags & PVCLOCK_TSC_STABLE_BIT)) |
|---|
| 277 | | - return 0; |
|---|
| 278 | | - |
|---|
| 279 | | - kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK; |
|---|
| 280 | | -#endif |
|---|
| 281 | | - |
|---|
| 282 | 243 | kvmclock_init_mem(); |
|---|
| 244 | + |
|---|
| 245 | +#ifdef CONFIG_X86_64 |
|---|
| 246 | + if (per_cpu(hv_clock_per_cpu, 0) && kvmclock_vsyscall) { |
|---|
| 247 | + u8 flags; |
|---|
| 248 | + |
|---|
| 249 | + flags = pvclock_read_flags(&hv_clock_boot[0].pvti); |
|---|
| 250 | + if (!(flags & PVCLOCK_TSC_STABLE_BIT)) |
|---|
| 251 | + return 0; |
|---|
| 252 | + |
|---|
| 253 | + kvm_clock.vdso_clock_mode = VDSO_CLOCKMODE_PVCLOCK; |
|---|
| 254 | + } |
|---|
| 255 | +#endif |
|---|
| 283 | 256 | |
|---|
| 284 | 257 | return 0; |
|---|
| 285 | 258 | } |
|---|
| .. | .. |
|---|
| 350 | 323 | #endif |
|---|
| 351 | 324 | x86_platform.save_sched_clock_state = kvm_save_sched_clock_state; |
|---|
| 352 | 325 | x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state; |
|---|
| 353 | | - machine_ops.shutdown = kvm_shutdown; |
|---|
| 354 | | -#ifdef CONFIG_KEXEC_CORE |
|---|
| 355 | | - machine_ops.crash_shutdown = kvm_crash_shutdown; |
|---|
| 356 | | -#endif |
|---|
| 357 | 326 | kvm_get_preset_lpj(); |
|---|
| 327 | + |
|---|
| 328 | + /* |
|---|
| 329 | + * X86_FEATURE_NONSTOP_TSC is TSC runs at constant rate |
|---|
| 330 | + * with P/T states and does not stop in deep C-states. |
|---|
| 331 | + * |
|---|
| 332 | + * Invariant TSC exposed by host means kvmclock is not necessary: |
|---|
| 333 | + * can use TSC as clocksource. |
|---|
| 334 | + * |
|---|
| 335 | + */ |
|---|
| 336 | + if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && |
|---|
| 337 | + boot_cpu_has(X86_FEATURE_NONSTOP_TSC) && |
|---|
| 338 | + !check_tsc_unstable()) |
|---|
| 339 | + kvm_clock.rating = 299; |
|---|
| 340 | + |
|---|
| 358 | 341 | clocksource_register_hz(&kvm_clock, NSEC_PER_SEC); |
|---|
| 359 | 342 | pv_info.name = "KVM"; |
|---|
| 360 | 343 | } |
|---|