2019-10-21 16:28:15 +01:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2019 Arm Ltd.
# include <linux/arm-smccc.h>
# include <linux/kvm_host.h>
# include <asm/kvm_emulate.h>
# include <kvm/arm_hypercalls.h>
# include <kvm/arm_psci.h>
2020-12-09 14:09:29 +08:00
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 ) ;
}
2019-10-21 16:28:15 +01:00
int kvm_hvc_call_handler ( struct kvm_vcpu * vcpu )
{
u32 func_id = smccc_get_function ( vcpu ) ;
2020-12-09 14:09:25 +08:00
u64 val [ 4 ] = { SMCCC_RET_NOT_SUPPORTED } ;
2019-10-21 16:28:15 +01:00
u32 feature ;
2019-10-21 16:28:18 +01:00
gpa_t gpa ;
2019-10-21 16:28:15 +01:00
switch ( func_id ) {
case ARM_SMCCC_VERSION_FUNC_ID :
2020-12-09 14:09:25 +08:00
val [ 0 ] = ARM_SMCCC_VERSION_1_1 ;
2019-10-21 16:28:15 +01:00
break ;
case ARM_SMCCC_ARCH_FEATURES_FUNC_ID :
feature = smccc_get_arg1 ( vcpu ) ;
switch ( feature ) {
case ARM_SMCCC_ARCH_WORKAROUND_1 :
2020-09-15 23:30:17 +01:00
switch ( arm64_get_spectre_v2_state ( ) ) {
case SPECTRE_VULNERABLE :
2019-10-21 16:28:15 +01:00
break ;
2020-09-15 23:30:17 +01:00
case SPECTRE_MITIGATED :
2020-12-09 14:09:25 +08:00
val [ 0 ] = SMCCC_RET_SUCCESS ;
2019-10-21 16:28:15 +01:00
break ;
2020-09-15 23:30:17 +01:00
case SPECTRE_UNAFFECTED :
2020-12-09 14:09:25 +08:00
val [ 0 ] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED ;
2019-10-21 16:28:15 +01:00
break ;
}
break ;
case ARM_SMCCC_ARCH_WORKAROUND_2 :
2020-09-18 14:08:54 +01:00
switch ( arm64_get_spectre_v4_state ( ) ) {
case SPECTRE_VULNERABLE :
2019-10-21 16:28:15 +01:00
break ;
2020-09-18 14:08:54 +01:00
case SPECTRE_MITIGATED :
/*
* SSBS everywhere : Indicate no firmware
* support , as the SSBS support will be
* indicated to the guest and the default is
* safe .
*
* Otherwise , expose a permanent mitigation
* to the guest , and hide SSBS so that the
* guest stays protected .
*/
if ( cpus_have_final_cap ( ARM64_SSBS ) )
break ;
fallthrough ;
case SPECTRE_UNAFFECTED :
2020-12-09 14:09:25 +08:00
val [ 0 ] = SMCCC_RET_NOT_REQUIRED ;
2019-10-21 16:28:15 +01:00
break ;
}
break ;
2019-10-21 16:28:16 +01:00
case ARM_SMCCC_HV_PV_TIME_FEATURES :
2020-12-09 14:09:25 +08:00
val [ 0 ] = SMCCC_RET_SUCCESS ;
2019-10-21 16:28:16 +01:00
break ;
2019-10-21 16:28:15 +01:00
}
break ;
2019-10-21 16:28:16 +01:00
case ARM_SMCCC_HV_PV_TIME_FEATURES :
2020-12-09 14:09:25 +08:00
val [ 0 ] = kvm_hypercall_pv_features ( vcpu ) ;
2019-10-21 16:28:16 +01:00
break ;
2019-10-21 16:28:18 +01:00
case ARM_SMCCC_HV_PV_TIME_ST :
gpa = kvm_init_stolen_time ( vcpu ) ;
if ( gpa ! = GPA_INVALID )
2020-12-09 14:09:25 +08:00
val [ 0 ] = gpa ;
break ;
case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID :
val [ 0 ] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 ;
val [ 1 ] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 ;
val [ 2 ] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 ;
val [ 3 ] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 ;
break ;
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID :
val [ 0 ] = BIT ( ARM_SMCCC_KVM_FUNC_FEATURES ) ;
2020-12-09 14:09:29 +08:00
val [ 0 ] | = BIT ( ARM_SMCCC_KVM_FUNC_PTP ) ;
break ;
case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID :
kvm_ptp_get_time ( vcpu , val ) ;
2019-10-21 16:28:18 +01:00
break ;
2021-01-06 10:34:53 +00:00
case ARM_SMCCC_TRNG_VERSION :
case ARM_SMCCC_TRNG_FEATURES :
case ARM_SMCCC_TRNG_GET_UUID :
case ARM_SMCCC_TRNG_RND32 :
case ARM_SMCCC_TRNG_RND64 :
return kvm_trng_call ( vcpu ) ;
2019-10-21 16:28:15 +01:00
default :
return kvm_psci_call ( vcpu ) ;
}
2020-12-09 14:09:25 +08:00
smccc_set_retval ( vcpu , val [ 0 ] , val [ 1 ] , val [ 2 ] , val [ 3 ] ) ;
2019-10-21 16:28:15 +01:00
return 1 ;
}