Commit f8cb5f82 authored by Jianyong Wu's avatar Jianyong Wu Committed by Dongxu Sun
Browse files

KVM: arm64: Add support for the KVM PTP service

mainline inclusion
from mainline-v5.13-rc1
commit 3bf72569
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8DWT1
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3bf725699bf62494b3e179f1795f08c7d749f061



--------------------------------

Implement the hypervisor side of the KVM PTP interface.

The service offers wall time and cycle count from host to guest.
The caller must specify whether they want the host's view of
either the virtual or physical counter.

Signed-off-by: default avatarJianyong Wu <jianyong.wu@arm.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201209060932.212364-7-jianyong.wu@arm.com


Signed-off-by: default avatarKunkun Jiang <jiangkunkun@huawei.com>
Signed-off-by: default avatarDongxu Sun <sundongxu3@huawei.com>
parent 6a78ee88
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -6763,6 +6763,15 @@ guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf
(0x40000001). Otherwise, a guest may use the paravirtual features
regardless of what has actually been exposed through the CPUID leaf.

8.31 KVM_CAP_PTP_KVM
--------------------

:Architectures: arm64

This capability indicates that the KVM virtual PTP service is
supported in the host. A VMM can check whether the service is
available to the guest on migration.

9. Known KVM API problems
=========================

+1 −0
Original line number Diff line number Diff line
@@ -10,3 +10,4 @@ ARM
   hyp-abi
   psci
   pvtime
   ptp_kvm
+25 −0
Original line number Diff line number Diff line
.. SPDX-License-Identifier: GPL-2.0

PTP_KVM support for arm/arm64
=============================

PTP_KVM is used for high precision time sync between host and guests.
It relies on transferring the wall clock and counter value from the
host to the guest using a KVM-specific hypercall.

* ARM_SMCCC_HYP_KVM_PTP_FUNC_ID: 0x86000001

This hypercall uses the SMC32/HVC32 calling convention:

ARM_SMCCC_HYP_KVM_PTP_FUNC_ID
    =============    ==========    ==========
    Function ID:     (uint32)      0x86000001
    Arguments:       (uint32)      KVM_PTP_VIRT_COUNTER(0)
                                   KVM_PTP_PHYS_COUNTER(1)
    Return Values:   (int32)       NOT_SUPPORTED(-1) on error, or
                     (uint32)      Upper 32 bits of wall clock time (r0)
                     (uint32)      Lower 32 bits of wall clock time (r1)
                     (uint32)      Upper 32 bits of counter (r2)
                     (uint32)      Lower 32 bits of counter (r3)
    Endianness:                    No Restrictions.
    =============    ==========    ==========
+1 −0
Original line number Diff line number Diff line
@@ -228,6 +228,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
	case KVM_CAP_ARM_NISV_TO_USER:
	case KVM_CAP_ARM_INJECT_EXT_DABT:
	case KVM_CAP_ARM_CPU_FEATURE:
	case KVM_CAP_PTP_KVM:
		r = 1;
		break;
	case KVM_CAP_ARM_SET_DEVICE_ADDR:
+53 −0
Original line number Diff line number Diff line
@@ -9,6 +9,55 @@
#include <kvm/arm_hypercalls.h>
#include <kvm/arm_psci.h>

static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
{
	struct system_time_snapshot systime_snapshot;
	u64 cycles = ~0UL;
	u32 feature;

	/*
	 * system time and counter value must captured at the same
	 * time to keep consistency and precision.
	 */
	ktime_get_snapshot(&systime_snapshot);

	/*
	 * This is only valid if the current clocksource is the
	 * architected counter, as this is the only one the guest
	 * can see.
	 */
	if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)
		return;

	/*
	 * The guest selects one of the two reference counters
	 * (virtual or physical) with the first argument of the SMCCC
	 * call. In case the identifier is not supported, error out.
	 */
	feature = smccc_get_arg1(vcpu);
	switch (feature) {
	case KVM_PTP_VIRT_COUNTER:
		cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2);
		break;
	case KVM_PTP_PHYS_COUNTER:
		cycles = systime_snapshot.cycles;
		break;
	default:
		return;
	}

	/*
	 * This relies on the top bit of val[0] never being set for
	 * valid values of system time, because that is *really* far
	 * in the future (about 292 years from 1970, and at that stage
	 * nobody will give a damn about it).
	 */
	val[0] = upper_32_bits(systime_snapshot.real);
	val[1] = lower_32_bits(systime_snapshot.real);
	val[2] = upper_32_bits(cycles);
	val[3] = lower_32_bits(cycles);
}

int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
{
	u32 func_id = smccc_get_function(vcpu);
@@ -94,6 +143,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
		break;
	case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
		val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
		val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
		break;
	case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
		kvm_ptp_get_time(vcpu, val);
		break;
	case ARM_SMCCC_HV_PV_SCHED_FEATURES:
		val[0] = kvm_hypercall_pvsched_features(vcpu);
Loading