mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-16 01:04:08 +08:00
KVM: arm64: Add support for the KVM PTP service
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: Jianyong Wu <jianyong.wu@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20201209060932.212364-7-jianyong.wu@arm.com
This commit is contained in:
parent
100148d0fc
commit
3bf725699b
@ -6724,3 +6724,13 @@ vcpu_info is set.
|
|||||||
The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related
|
The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related
|
||||||
features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are
|
features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are
|
||||||
supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls.
|
supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
@ -10,3 +10,4 @@ ARM
|
|||||||
hyp-abi
|
hyp-abi
|
||||||
psci
|
psci
|
||||||
pvtime
|
pvtime
|
||||||
|
ptp_kvm
|
||||||
|
25
Documentation/virt/kvm/arm/ptp_kvm.rst
Normal file
25
Documentation/virt/kvm/arm/ptp_kvm.rst
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.. 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.
|
||||||
|
============= ========== ==========
|
@ -206,6 +206,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
|||||||
case KVM_CAP_ARM_INJECT_EXT_DABT:
|
case KVM_CAP_ARM_INJECT_EXT_DABT:
|
||||||
case KVM_CAP_SET_GUEST_DEBUG:
|
case KVM_CAP_SET_GUEST_DEBUG:
|
||||||
case KVM_CAP_VCPU_ATTRIBUTES:
|
case KVM_CAP_VCPU_ATTRIBUTES:
|
||||||
|
case KVM_CAP_PTP_KVM:
|
||||||
r = 1;
|
r = 1;
|
||||||
break;
|
break;
|
||||||
case KVM_CAP_ARM_SET_DEVICE_ADDR:
|
case KVM_CAP_ARM_SET_DEVICE_ADDR:
|
||||||
|
@ -9,6 +9,55 @@
|
|||||||
#include <kvm/arm_hypercalls.h>
|
#include <kvm/arm_hypercalls.h>
|
||||||
#include <kvm/arm_psci.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)
|
int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
u32 func_id = smccc_get_function(vcpu);
|
u32 func_id = smccc_get_function(vcpu);
|
||||||
@ -79,6 +128,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
|
|||||||
break;
|
break;
|
||||||
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
|
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
|
||||||
val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
|
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;
|
break;
|
||||||
case ARM_SMCCC_TRNG_VERSION:
|
case ARM_SMCCC_TRNG_VERSION:
|
||||||
case ARM_SMCCC_TRNG_FEATURES:
|
case ARM_SMCCC_TRNG_FEATURES:
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
|
|
||||||
/* KVM "vendor specific" services */
|
/* KVM "vendor specific" services */
|
||||||
#define ARM_SMCCC_KVM_FUNC_FEATURES 0
|
#define ARM_SMCCC_KVM_FUNC_FEATURES 0
|
||||||
|
#define ARM_SMCCC_KVM_FUNC_PTP 1
|
||||||
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
|
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
|
||||||
#define ARM_SMCCC_KVM_NUM_FUNCS 128
|
#define ARM_SMCCC_KVM_NUM_FUNCS 128
|
||||||
|
|
||||||
@ -114,6 +115,21 @@
|
|||||||
|
|
||||||
#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1
|
#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ptp_kvm is a feature used for time sync between vm and host.
|
||||||
|
* ptp_kvm module in guest kernel will get service from host using
|
||||||
|
* this hypercall ID.
|
||||||
|
*/
|
||||||
|
#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \
|
||||||
|
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||||
|
ARM_SMCCC_SMC_32, \
|
||||||
|
ARM_SMCCC_OWNER_VENDOR_HYP, \
|
||||||
|
ARM_SMCCC_KVM_FUNC_PTP)
|
||||||
|
|
||||||
|
/* ptp_kvm counter type ID */
|
||||||
|
#define KVM_PTP_VIRT_COUNTER 0
|
||||||
|
#define KVM_PTP_PHYS_COUNTER 1
|
||||||
|
|
||||||
/* Paravirtualised time calls (defined by ARM DEN0057A) */
|
/* Paravirtualised time calls (defined by ARM DEN0057A) */
|
||||||
#define ARM_SMCCC_HV_PV_TIME_FEATURES \
|
#define ARM_SMCCC_HV_PV_TIME_FEATURES \
|
||||||
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||||
|
@ -1078,6 +1078,7 @@ struct kvm_ppc_resize_hpt {
|
|||||||
#define KVM_CAP_DIRTY_LOG_RING 192
|
#define KVM_CAP_DIRTY_LOG_RING 192
|
||||||
#define KVM_CAP_X86_BUS_LOCK_EXIT 193
|
#define KVM_CAP_X86_BUS_LOCK_EXIT 193
|
||||||
#define KVM_CAP_PPC_DAWR1 194
|
#define KVM_CAP_PPC_DAWR1 194
|
||||||
|
#define KVM_CAP_PTP_KVM 195
|
||||||
|
|
||||||
#ifdef KVM_CAP_IRQ_ROUTING
|
#ifdef KVM_CAP_IRQ_ROUTING
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user