···67376737The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related67386738features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are67396739supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls.67406740+67416741+8.31 KVM_CAP_PTP_KVM67426742+--------------------67436743+67446744+:Architectures: arm6467456745+67466746+This capability indicates that the KVM virtual PTP service is67476747+supported in the host. A VMM can check whether the service is67486748+available to the guest on migration.67496749+
···11+.. SPDX-License-Identifier: GPL-2.022+33+PTP_KVM support for arm/arm6444+=============================55+66+PTP_KVM is used for high precision time sync between host and guests.77+It relies on transferring the wall clock and counter value from the88+host to the guest using a KVM-specific hypercall.99+1010+* ARM_SMCCC_HYP_KVM_PTP_FUNC_ID: 0x860000011111+1212+This hypercall uses the SMC32/HVC32 calling convention:1313+1414+ARM_SMCCC_HYP_KVM_PTP_FUNC_ID1515+ ============== ======== =====================================1616+ Function ID: (uint32) 0x860000011717+ Arguments: (uint32) KVM_PTP_VIRT_COUNTER(0)1818+ KVM_PTP_PHYS_COUNTER(1)1919+ Return Values: (int32) NOT_SUPPORTED(-1) on error, or2020+ (uint32) Upper 32 bits of wall clock time (r0)2121+ (uint32) Lower 32 bits of wall clock time (r1)2222+ (uint32) Upper 32 bits of counter (r2)2323+ (uint32) Lower 32 bits of counter (r3)2424+ Endianness: No Restrictions.2525+ ============== ======== =====================================
···206206 case KVM_CAP_ARM_INJECT_EXT_DABT:207207 case KVM_CAP_SET_GUEST_DEBUG:208208 case KVM_CAP_VCPU_ATTRIBUTES:209209+ case KVM_CAP_PTP_KVM:209210 r = 1;210211 break;211212 case KVM_CAP_ARM_SET_DEVICE_ADDR:
+71-9
arch/arm64/kvm/hypercalls.c
···99#include <kvm/arm_hypercalls.h>1010#include <kvm/arm_psci.h>11111212+static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)1313+{1414+ struct system_time_snapshot systime_snapshot;1515+ u64 cycles = ~0UL;1616+ u32 feature;1717+1818+ /*1919+ * system time and counter value must captured at the same2020+ * time to keep consistency and precision.2121+ */2222+ ktime_get_snapshot(&systime_snapshot);2323+2424+ /*2525+ * This is only valid if the current clocksource is the2626+ * architected counter, as this is the only one the guest2727+ * can see.2828+ */2929+ if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)3030+ return;3131+3232+ /*3333+ * The guest selects one of the two reference counters3434+ * (virtual or physical) with the first argument of the SMCCC3535+ * call. In case the identifier is not supported, error out.3636+ */3737+ feature = smccc_get_arg1(vcpu);3838+ switch (feature) {3939+ case KVM_PTP_VIRT_COUNTER:4040+ cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2);4141+ break;4242+ case KVM_PTP_PHYS_COUNTER:4343+ cycles = systime_snapshot.cycles;4444+ break;4545+ default:4646+ return;4747+ }4848+4949+ /*5050+ * This relies on the top bit of val[0] never being set for5151+ * valid values of system time, because that is *really* far5252+ * in the future (about 292 years from 1970, and at that stage5353+ * nobody will give a damn about it).5454+ */5555+ val[0] = upper_32_bits(systime_snapshot.real);5656+ val[1] = lower_32_bits(systime_snapshot.real);5757+ val[2] = upper_32_bits(cycles);5858+ val[3] = lower_32_bits(cycles);5959+}6060+1261int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)1362{1463 u32 func_id = smccc_get_function(vcpu);1515- long val = SMCCC_RET_NOT_SUPPORTED;6464+ u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};1665 u32 feature;1766 gpa_t gpa;18671968 switch (func_id) {2069 case ARM_SMCCC_VERSION_FUNC_ID:2121- val = ARM_SMCCC_VERSION_1_1;7070+ val[0] = ARM_SMCCC_VERSION_1_1;2271 break;2372 case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:2473 feature = smccc_get_arg1(vcpu);···7728 case SPECTRE_VULNERABLE:7829 break;7930 case SPECTRE_MITIGATED:8080- val = SMCCC_RET_SUCCESS;3131+ val[0] = SMCCC_RET_SUCCESS;8132 break;8233 case SPECTRE_UNAFFECTED:8383- val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;3434+ val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;8435 break;8536 }8637 break;···10354 break;10455 fallthrough;10556 case SPECTRE_UNAFFECTED:106106- val = SMCCC_RET_NOT_REQUIRED;5757+ val[0] = SMCCC_RET_NOT_REQUIRED;10758 break;10859 }10960 break;11061 case ARM_SMCCC_HV_PV_TIME_FEATURES:111111- val = SMCCC_RET_SUCCESS;6262+ val[0] = SMCCC_RET_SUCCESS;11263 break;11364 }11465 break;11566 case ARM_SMCCC_HV_PV_TIME_FEATURES:116116- val = kvm_hypercall_pv_features(vcpu);6767+ val[0] = kvm_hypercall_pv_features(vcpu);11768 break;11869 case ARM_SMCCC_HV_PV_TIME_ST:11970 gpa = kvm_init_stolen_time(vcpu);12071 if (gpa != GPA_INVALID)121121- val = gpa;7272+ val[0] = gpa;7373+ break;7474+ case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:7575+ val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;7676+ val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;7777+ val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;7878+ val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;7979+ break;8080+ case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:8181+ val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);8282+ val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);8383+ break;8484+ case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:8585+ kvm_ptp_get_time(vcpu, val);12286 break;12387 case ARM_SMCCC_TRNG_VERSION:12488 case ARM_SMCCC_TRNG_FEATURES:···14381 return kvm_psci_call(vcpu);14482 }14583146146- smccc_set_retval(vcpu, val, 0, 0, 0);8484+ smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);14785 return 1;14886}
···108108config PTP_1588_CLOCK_KVM109109 tristate "KVM virtual PTP clock"110110 depends on PTP_1588_CLOCK111111- depends on KVM_GUEST && X86111111+ depends on (KVM_GUEST && X86) || (HAVE_ARM_SMCCC_DISCOVERY && ARM_ARCH_TIMER)112112 default y113113 help114114 This driver adds support for using kvm infrastructure as a PTP
···88#include <linux/err.h>99#include <linux/init.h>1010#include <linux/kernel.h>1111+#include <linux/slab.h>1112#include <linux/module.h>1313+#include <linux/ptp_kvm.h>1214#include <uapi/linux/kvm_para.h>1315#include <asm/kvm_para.h>1414-#include <asm/pvclock.h>1515-#include <asm/kvmclock.h>1616#include <uapi/asm/kvm_para.h>17171818#include <linux/ptp_clock_kernel.h>···24242525static DEFINE_SPINLOCK(kvm_ptp_lock);26262727-static struct pvclock_vsyscall_time_info *hv_clock;2828-2929-static struct kvm_clock_pairing clock_pair;3030-static phys_addr_t clock_pair_gpa;3131-3227static int ptp_kvm_get_time_fn(ktime_t *device_time,3328 struct system_counterval_t *system_counter,3429 void *ctx)3530{3636- unsigned long ret;3131+ long ret;3232+ u64 cycle;3733 struct timespec64 tspec;3838- unsigned version;3939- int cpu;4040- struct pvclock_vcpu_time_info *src;3434+ struct clocksource *cs;41354236 spin_lock(&kvm_ptp_lock);43374438 preempt_disable_notrace();4545- cpu = smp_processor_id();4646- src = &hv_clock[cpu].pvti;4747-4848- do {4949- /*5050- * We are using a TSC value read in the hosts5151- * kvm_hc_clock_pairing handling.5252- * So any changes to tsc_to_system_mul5353- * and tsc_shift or any other pvclock5454- * data invalidate that measurement.5555- */5656- version = pvclock_read_begin(src);5757-5858- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,5959- clock_pair_gpa,6060- KVM_CLOCK_PAIRING_WALLCLOCK);6161- if (ret != 0) {6262- pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);6363- spin_unlock(&kvm_ptp_lock);6464- preempt_enable_notrace();6565- return -EOPNOTSUPP;6666- }6767-6868- tspec.tv_sec = clock_pair.sec;6969- tspec.tv_nsec = clock_pair.nsec;7070- ret = __pvclock_read_cycles(src, clock_pair.tsc);7171- } while (pvclock_read_retry(src, version));3939+ ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs);4040+ if (ret) {4141+ spin_unlock(&kvm_ptp_lock);4242+ preempt_enable_notrace();4343+ return ret;4444+ }72457346 preempt_enable_notrace();74477575- system_counter->cycles = ret;7676- system_counter->cs = &kvm_clock;4848+ system_counter->cycles = cycle;4949+ system_counter->cs = cs;77507851 *device_time = timespec64_to_ktime(tspec);7952···8411185112static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)86113{8787- unsigned long ret;114114+ long ret;88115 struct timespec64 tspec;8911690117 spin_lock(&kvm_ptp_lock);911189292- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,9393- clock_pair_gpa,9494- KVM_CLOCK_PAIRING_WALLCLOCK);9595- if (ret != 0) {9696- pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);119119+ ret = kvm_arch_ptp_get_clock(&tspec);120120+ if (ret) {97121 spin_unlock(&kvm_ptp_lock);9898- return -EOPNOTSUPP;122122+ return ret;99123 }100124101101- tspec.tv_sec = clock_pair.sec;102102- tspec.tv_nsec = clock_pair.nsec;103125 spin_unlock(&kvm_ptp_lock);104126105127 memcpy(ts, &tspec, sizeof(struct timespec64));···136168{137169 long ret;138170139139- if (!kvm_para_available())140140- return -ENODEV;141141-142142- clock_pair_gpa = slow_virt_to_phys(&clock_pair);143143- hv_clock = pvclock_get_pvti_cpu0_va();144144-145145- if (!hv_clock)146146- return -ENODEV;147147-148148- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,149149- KVM_CLOCK_PAIRING_WALLCLOCK);150150- if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)151151- return -ENODEV;171171+ ret = kvm_arch_ptp_init();172172+ if (ret) {173173+ pr_err("fail to initialize ptp_kvm");174174+ return ret;175175+ }152176153177 kvm_ptp_clock.caps = ptp_kvm_caps;154178
+28
drivers/ptp/ptp_kvm_arm.c
···11+// SPDX-License-Identifier: GPL-2.0-only22+/*33+ * Virtual PTP 1588 clock for use with KVM guests44+ * Copyright (C) 2019 ARM Ltd.55+ * All Rights Reserved66+ */77+88+#include <linux/arm-smccc.h>99+#include <linux/ptp_kvm.h>1010+1111+#include <asm/arch_timer.h>1212+#include <asm/hypervisor.h>1313+1414+int kvm_arch_ptp_init(void)1515+{1616+ int ret;1717+1818+ ret = kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_PTP);1919+ if (ret <= 0)2020+ return -EOPNOTSUPP;2121+2222+ return 0;2323+}2424+2525+int kvm_arch_ptp_get_clock(struct timespec64 *ts)2626+{2727+ return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL);2828+}
+97
drivers/ptp/ptp_kvm_x86.c
···11+// SPDX-License-Identifier: GPL-2.0-or-later22+/*33+ * Virtual PTP 1588 clock for use with KVM guests44+ *55+ * Copyright (C) 2017 Red Hat Inc.66+ */77+88+#include <linux/device.h>99+#include <linux/kernel.h>1010+#include <asm/pvclock.h>1111+#include <asm/kvmclock.h>1212+#include <linux/module.h>1313+#include <uapi/asm/kvm_para.h>1414+#include <uapi/linux/kvm_para.h>1515+#include <linux/ptp_clock_kernel.h>1616+#include <linux/ptp_kvm.h>1717+1818+struct pvclock_vsyscall_time_info *hv_clock;1919+2020+static phys_addr_t clock_pair_gpa;2121+static struct kvm_clock_pairing clock_pair;2222+2323+int kvm_arch_ptp_init(void)2424+{2525+ long ret;2626+2727+ if (!kvm_para_available())2828+ return -ENODEV;2929+3030+ clock_pair_gpa = slow_virt_to_phys(&clock_pair);3131+ hv_clock = pvclock_get_pvti_cpu0_va();3232+ if (!hv_clock)3333+ return -ENODEV;3434+3535+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,3636+ KVM_CLOCK_PAIRING_WALLCLOCK);3737+ if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)3838+ return -ENODEV;3939+4040+ return 0;4141+}4242+4343+int kvm_arch_ptp_get_clock(struct timespec64 *ts)4444+{4545+ long ret;4646+4747+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,4848+ clock_pair_gpa,4949+ KVM_CLOCK_PAIRING_WALLCLOCK);5050+ if (ret != 0) {5151+ pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);5252+ return -EOPNOTSUPP;5353+ }5454+5555+ ts->tv_sec = clock_pair.sec;5656+ ts->tv_nsec = clock_pair.nsec;5757+5858+ return 0;5959+}6060+6161+int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,6262+ struct clocksource **cs)6363+{6464+ struct pvclock_vcpu_time_info *src;6565+ unsigned int version;6666+ long ret;6767+ int cpu;6868+6969+ cpu = smp_processor_id();7070+ src = &hv_clock[cpu].pvti;7171+7272+ do {7373+ /*7474+ * We are using a TSC value read in the hosts7575+ * kvm_hc_clock_pairing handling.7676+ * So any changes to tsc_to_system_mul7777+ * and tsc_shift or any other pvclock7878+ * data invalidate that measurement.7979+ */8080+ version = pvclock_read_begin(src);8181+8282+ ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,8383+ clock_pair_gpa,8484+ KVM_CLOCK_PAIRING_WALLCLOCK);8585+ if (ret != 0) {8686+ pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);8787+ return -EOPNOTSUPP;8888+ }8989+ tspec->tv_sec = clock_pair.sec;9090+ tspec->tv_nsec = clock_pair.nsec;9191+ *cycle = __pvclock_read_cycles(src, clock_pair.tsc);9292+ } while (pvclock_read_retry(src, version));9393+9494+ *cs = &kvm_clock;9595+9696+ return 0;9797+}
+41
include/linux/arm-smccc.h
···5555#define ARM_SMCCC_OWNER_TRUSTED_OS 505656#define ARM_SMCCC_OWNER_TRUSTED_OS_END 6357575858+#define ARM_SMCCC_FUNC_QUERY_CALL_UID 0xff015959+5860#define ARM_SMCCC_QUIRK_NONE 05961#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */6062···8987 ARM_SMCCC_SMC_32, \9088 0, 0x7fff)91899090+#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \9191+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \9292+ ARM_SMCCC_SMC_32, \9393+ ARM_SMCCC_OWNER_VENDOR_HYP, \9494+ ARM_SMCCC_FUNC_QUERY_CALL_UID)9595+9696+/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */9797+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 0xb66fb428U9898+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 0xe911c52eU9999+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 0x564bcaa9U100100+#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 0x743a004dU101101+102102+/* KVM "vendor specific" services */103103+#define ARM_SMCCC_KVM_FUNC_FEATURES 0104104+#define ARM_SMCCC_KVM_FUNC_PTP 1105105+#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127106106+#define ARM_SMCCC_KVM_NUM_FUNCS 128107107+108108+#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID \109109+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \110110+ ARM_SMCCC_SMC_32, \111111+ ARM_SMCCC_OWNER_VENDOR_HYP, \112112+ ARM_SMCCC_KVM_FUNC_FEATURES)113113+92114#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1115115+116116+/*117117+ * ptp_kvm is a feature used for time sync between vm and host.118118+ * ptp_kvm module in guest kernel will get service from host using119119+ * this hypercall ID.120120+ */121121+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \122122+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \123123+ ARM_SMCCC_SMC_32, \124124+ ARM_SMCCC_OWNER_VENDOR_HYP, \125125+ ARM_SMCCC_KVM_FUNC_PTP)126126+127127+/* ptp_kvm counter type ID */128128+#define KVM_PTP_VIRT_COUNTER 0129129+#define KVM_PTP_PHYS_COUNTER 19313094131/* Paravirtualised time calls (defined by ARM DEN0057A) */95132#define ARM_SMCCC_HV_PV_TIME_FEATURES \
+6
include/linux/clocksource.h
···1717#include <linux/timer.h>1818#include <linux/init.h>1919#include <linux/of.h>2020+#include <linux/clocksource_ids.h>2021#include <asm/div64.h>2122#include <asm/io.h>2223···6362 * 400-499: Perfect6463 * The ideal clocksource. A must-use where6564 * available.6565+ * @id: Defaults to CSID_GENERIC. The id value is captured6666+ * in certain snapshot functions to allow callers to6767+ * validate the clocksource from which the snapshot was6868+ * taken.6669 * @flags: Flags describing special properties6770 * @enable: Optional function to enable the clocksource6871 * @disable: Optional function to disable the clocksource···105100 const char *name;106101 struct list_head list;107102 int rating;103103+ enum clocksource_ids id;108104 enum vdso_clock_mode vdso_clock_mode;109105 unsigned long flags;110106
+12
include/linux/clocksource_ids.h
···11+/* SPDX-License-Identifier: GPL-2.0 */22+#ifndef _LINUX_CLOCKSOURCE_IDS_H33+#define _LINUX_CLOCKSOURCE_IDS_H44+55+/* Enum to give clocksources a unique identifier */66+enum clocksource_ids {77+ CSID_GENERIC = 0,88+ CSID_ARM_ARCH_COUNTER,99+ CSID_MAX,1010+};1111+1212+#endif
+19
include/linux/ptp_kvm.h
···11+/* SPDX-License-Identifier: GPL-2.0-or-later */22+/*33+ * Virtual PTP 1588 clock for use with KVM guests44+ *55+ * Copyright (C) 2017 Red Hat Inc.66+ */77+88+#ifndef _PTP_KVM_H_99+#define _PTP_KVM_H_1010+1111+struct timespec64;1212+struct clocksource;1313+1414+int kvm_arch_ptp_init(void);1515+int kvm_arch_ptp_get_clock(struct timespec64 *ts);1616+int kvm_arch_ptp_get_crosststamp(u64 *cycle,1717+ struct timespec64 *tspec, struct clocksource **cs);1818+1919+#endif /* _PTP_KVM_H_ */
+7-5
include/linux/timekeeping.h
···33#define _LINUX_TIMEKEEPING_H4455#include <linux/errno.h>66+#include <linux/clocksource_ids.h>6778/* Included from linux/ktime.h */89···244243 * @cs_was_changed_seq: The sequence number of clocksource change events245244 */246245struct system_time_snapshot {247247- u64 cycles;248248- ktime_t real;249249- ktime_t raw;250250- unsigned int clock_was_set_seq;251251- u8 cs_was_changed_seq;246246+ u64 cycles;247247+ ktime_t real;248248+ ktime_t raw;249249+ enum clocksource_ids cs_id;250250+ unsigned int clock_was_set_seq;251251+ u8 cs_was_changed_seq;252252};253253254254/**