18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/arm-smccc.h> 88c2ecf20Sopenharmony_ci#include <linux/preempt.h> 98c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 108c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 118c2ecf20Sopenharmony_ci#include <linux/wait.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/cputype.h> 148c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <kvm/arm_psci.h> 178c2ecf20Sopenharmony_ci#include <kvm/arm_hypercalls.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * This is an implementation of the Power State Coordination Interface 218c2ecf20Sopenharmony_ci * as described in ARM document number ARM DEN 0022A. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic unsigned long psci_affinity_mask(unsigned long affinity_level) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci if (affinity_level <= 3) 298c2ecf20Sopenharmony_ci return MPIDR_HWID_BITMASK & AFFINITY_MASK(affinity_level); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci return 0; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci /* 378c2ecf20Sopenharmony_ci * NOTE: For simplicity, we make VCPU suspend emulation to be 388c2ecf20Sopenharmony_ci * same-as WFI (Wait-for-interrupt) emulation. 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * This means for KVM the wakeup events are interrupts and 418c2ecf20Sopenharmony_ci * this is consistent with intended use of StateID as described 428c2ecf20Sopenharmony_ci * in section 5.4.1 of PSCI v0.2 specification (ARM DEN 0022A). 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Further, we also treat power-down request to be same as 458c2ecf20Sopenharmony_ci * stand-by request as-per section 5.4.2 clause 3 of PSCI v0.2 468c2ecf20Sopenharmony_ci * specification (ARM DEN 0022A). This means all suspend states 478c2ecf20Sopenharmony_ci * for KVM will preserve the register state. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci kvm_vcpu_block(vcpu); 508c2ecf20Sopenharmony_ci kvm_clear_request(KVM_REQ_UNHALT, vcpu); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return PSCI_RET_SUCCESS; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci vcpu->arch.power_off = true; 588c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_SLEEP, vcpu); 598c2ecf20Sopenharmony_ci kvm_vcpu_kick(vcpu); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct vcpu_reset_state *reset_state; 658c2ecf20Sopenharmony_ci struct kvm *kvm = source_vcpu->kvm; 668c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = NULL; 678c2ecf20Sopenharmony_ci unsigned long cpu_id; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK; 708c2ecf20Sopenharmony_ci if (vcpu_mode_is_32bit(source_vcpu)) 718c2ecf20Sopenharmony_ci cpu_id &= ~((u32) 0); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * Make sure the caller requested a valid CPU and that the CPU is 778c2ecf20Sopenharmony_ci * turned off. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci if (!vcpu) 808c2ecf20Sopenharmony_ci return PSCI_RET_INVALID_PARAMS; 818c2ecf20Sopenharmony_ci if (!vcpu->arch.power_off) { 828c2ecf20Sopenharmony_ci if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1) 838c2ecf20Sopenharmony_ci return PSCI_RET_ALREADY_ON; 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci return PSCI_RET_INVALID_PARAMS; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci reset_state = &vcpu->arch.reset_state; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci reset_state->pc = smccc_get_arg2(source_vcpu); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Propagate caller endianness */ 938c2ecf20Sopenharmony_ci reset_state->be = kvm_vcpu_is_be(source_vcpu); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * NOTE: We always update r0 (or x0) because for PSCI v0.1 978c2ecf20Sopenharmony_ci * the general purpose registers are undefined upon CPU_ON. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci reset_state->r0 = smccc_get_arg3(source_vcpu); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci WRITE_ONCE(reset_state->reset, true); 1028c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_VCPU_RESET, vcpu); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * Make sure the reset request is observed if the change to 1068c2ecf20Sopenharmony_ci * power_state is observed. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci smp_wmb(); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci vcpu->arch.power_off = false; 1118c2ecf20Sopenharmony_ci kvm_vcpu_wake_up(vcpu); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return PSCI_RET_SUCCESS; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int i, matching_cpus = 0; 1198c2ecf20Sopenharmony_ci unsigned long mpidr; 1208c2ecf20Sopenharmony_ci unsigned long target_affinity; 1218c2ecf20Sopenharmony_ci unsigned long target_affinity_mask; 1228c2ecf20Sopenharmony_ci unsigned long lowest_affinity_level; 1238c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 1248c2ecf20Sopenharmony_ci struct kvm_vcpu *tmp; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci target_affinity = smccc_get_arg1(vcpu); 1278c2ecf20Sopenharmony_ci lowest_affinity_level = smccc_get_arg2(vcpu); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Determine target affinity mask */ 1308c2ecf20Sopenharmony_ci target_affinity_mask = psci_affinity_mask(lowest_affinity_level); 1318c2ecf20Sopenharmony_ci if (!target_affinity_mask) 1328c2ecf20Sopenharmony_ci return PSCI_RET_INVALID_PARAMS; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Ignore other bits of target affinity */ 1358c2ecf20Sopenharmony_ci target_affinity &= target_affinity_mask; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * If one or more VCPU matching target affinity are running 1398c2ecf20Sopenharmony_ci * then ON else OFF 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, tmp, kvm) { 1428c2ecf20Sopenharmony_ci mpidr = kvm_vcpu_get_mpidr_aff(tmp); 1438c2ecf20Sopenharmony_ci if ((mpidr & target_affinity_mask) == target_affinity) { 1448c2ecf20Sopenharmony_ci matching_cpus++; 1458c2ecf20Sopenharmony_ci if (!tmp->arch.power_off) 1468c2ecf20Sopenharmony_ci return PSCI_0_2_AFFINITY_LEVEL_ON; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!matching_cpus) 1518c2ecf20Sopenharmony_ci return PSCI_RET_INVALID_PARAMS; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return PSCI_0_2_AFFINITY_LEVEL_OFF; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void kvm_prepare_system_event(struct kvm_vcpu *vcpu, u32 type) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int i; 1598c2ecf20Sopenharmony_ci struct kvm_vcpu *tmp; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * The KVM ABI specifies that a system event exit may call KVM_RUN 1638c2ecf20Sopenharmony_ci * again and may perform shutdown/reboot at a later time that when the 1648c2ecf20Sopenharmony_ci * actual request is made. Since we are implementing PSCI and a 1658c2ecf20Sopenharmony_ci * caller of PSCI reboot and shutdown expects that the system shuts 1668c2ecf20Sopenharmony_ci * down or reboots immediately, let's make sure that VCPUs are not run 1678c2ecf20Sopenharmony_ci * after this call is handled and before the VCPUs have been 1688c2ecf20Sopenharmony_ci * re-initialized. 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, tmp, vcpu->kvm) 1718c2ecf20Sopenharmony_ci tmp->arch.power_off = true; 1728c2ecf20Sopenharmony_ci kvm_make_all_cpus_request(vcpu->kvm, KVM_REQ_SLEEP); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci memset(&vcpu->run->system_event, 0, sizeof(vcpu->run->system_event)); 1758c2ecf20Sopenharmony_ci vcpu->run->system_event.type = type; 1768c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic void kvm_psci_system_off(struct kvm_vcpu *vcpu) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_SHUTDOWN); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void kvm_psci_system_reset(struct kvm_vcpu *vcpu) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void kvm_psci_narrow_to_32bit(struct kvm_vcpu *vcpu) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci int i; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Zero the input registers' upper 32 bits. They will be fully 1958c2ecf20Sopenharmony_ci * zeroed on exit, so we're fine changing them in place. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci for (i = 1; i < 4; i++) 1988c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, i, lower_32_bits(vcpu_get_reg(vcpu, i))); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic unsigned long kvm_psci_check_allowed_function(struct kvm_vcpu *vcpu, u32 fn) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci switch(fn) { 2048c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_SUSPEND: 2058c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_ON: 2068c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_AFFINITY_INFO: 2078c2ecf20Sopenharmony_ci /* Disallow these functions for 32bit guests */ 2088c2ecf20Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) 2098c2ecf20Sopenharmony_ci return PSCI_RET_NOT_SUPPORTED; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 2198c2ecf20Sopenharmony_ci u32 psci_fn = smccc_get_function(vcpu); 2208c2ecf20Sopenharmony_ci unsigned long val; 2218c2ecf20Sopenharmony_ci int ret = 1; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci val = kvm_psci_check_allowed_function(vcpu, psci_fn); 2248c2ecf20Sopenharmony_ci if (val) 2258c2ecf20Sopenharmony_ci goto out; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci switch (psci_fn) { 2288c2ecf20Sopenharmony_ci case PSCI_0_2_FN_PSCI_VERSION: 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Bits[31:16] = Major Version = 0 2318c2ecf20Sopenharmony_ci * Bits[15:0] = Minor Version = 2 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci val = KVM_ARM_PSCI_0_2; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_SUSPEND: 2368c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_SUSPEND: 2378c2ecf20Sopenharmony_ci val = kvm_psci_vcpu_suspend(vcpu); 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_OFF: 2408c2ecf20Sopenharmony_ci kvm_psci_vcpu_off(vcpu); 2418c2ecf20Sopenharmony_ci val = PSCI_RET_SUCCESS; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_ON: 2448c2ecf20Sopenharmony_ci kvm_psci_narrow_to_32bit(vcpu); 2458c2ecf20Sopenharmony_ci fallthrough; 2468c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_ON: 2478c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 2488c2ecf20Sopenharmony_ci val = kvm_psci_vcpu_on(vcpu); 2498c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci case PSCI_0_2_FN_AFFINITY_INFO: 2528c2ecf20Sopenharmony_ci kvm_psci_narrow_to_32bit(vcpu); 2538c2ecf20Sopenharmony_ci fallthrough; 2548c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_AFFINITY_INFO: 2558c2ecf20Sopenharmony_ci val = kvm_psci_vcpu_affinity_info(vcpu); 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci case PSCI_0_2_FN_MIGRATE_INFO_TYPE: 2588c2ecf20Sopenharmony_ci /* 2598c2ecf20Sopenharmony_ci * Trusted OS is MP hence does not require migration 2608c2ecf20Sopenharmony_ci * or 2618c2ecf20Sopenharmony_ci * Trusted OS is not present 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci val = PSCI_0_2_TOS_MP; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case PSCI_0_2_FN_SYSTEM_OFF: 2668c2ecf20Sopenharmony_ci kvm_psci_system_off(vcpu); 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * We shouldn't be going back to guest VCPU after 2698c2ecf20Sopenharmony_ci * receiving SYSTEM_OFF request. 2708c2ecf20Sopenharmony_ci * 2718c2ecf20Sopenharmony_ci * If user space accidentally/deliberately resumes 2728c2ecf20Sopenharmony_ci * guest VCPU after SYSTEM_OFF request then guest 2738c2ecf20Sopenharmony_ci * VCPU should see internal failure from PSCI return 2748c2ecf20Sopenharmony_ci * value. To achieve this, we preload r0 (or x0) with 2758c2ecf20Sopenharmony_ci * PSCI return value INTERNAL_FAILURE. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci val = PSCI_RET_INTERNAL_FAILURE; 2788c2ecf20Sopenharmony_ci ret = 0; 2798c2ecf20Sopenharmony_ci break; 2808c2ecf20Sopenharmony_ci case PSCI_0_2_FN_SYSTEM_RESET: 2818c2ecf20Sopenharmony_ci kvm_psci_system_reset(vcpu); 2828c2ecf20Sopenharmony_ci /* 2838c2ecf20Sopenharmony_ci * Same reason as SYSTEM_OFF for preloading r0 (or x0) 2848c2ecf20Sopenharmony_ci * with PSCI return value INTERNAL_FAILURE. 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_ci val = PSCI_RET_INTERNAL_FAILURE; 2878c2ecf20Sopenharmony_ci ret = 0; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci default: 2908c2ecf20Sopenharmony_ci val = PSCI_RET_NOT_SUPPORTED; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciout: 2958c2ecf20Sopenharmony_ci smccc_set_retval(vcpu, val, 0, 0, 0); 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int kvm_psci_1_0_call(struct kvm_vcpu *vcpu) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci u32 psci_fn = smccc_get_function(vcpu); 3028c2ecf20Sopenharmony_ci u32 feature; 3038c2ecf20Sopenharmony_ci unsigned long val; 3048c2ecf20Sopenharmony_ci int ret = 1; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci switch(psci_fn) { 3078c2ecf20Sopenharmony_ci case PSCI_0_2_FN_PSCI_VERSION: 3088c2ecf20Sopenharmony_ci val = KVM_ARM_PSCI_1_0; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case PSCI_1_0_FN_PSCI_FEATURES: 3118c2ecf20Sopenharmony_ci feature = smccc_get_arg1(vcpu); 3128c2ecf20Sopenharmony_ci val = kvm_psci_check_allowed_function(vcpu, feature); 3138c2ecf20Sopenharmony_ci if (val) 3148c2ecf20Sopenharmony_ci break; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci switch(feature) { 3178c2ecf20Sopenharmony_ci case PSCI_0_2_FN_PSCI_VERSION: 3188c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_SUSPEND: 3198c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_SUSPEND: 3208c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_OFF: 3218c2ecf20Sopenharmony_ci case PSCI_0_2_FN_CPU_ON: 3228c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_CPU_ON: 3238c2ecf20Sopenharmony_ci case PSCI_0_2_FN_AFFINITY_INFO: 3248c2ecf20Sopenharmony_ci case PSCI_0_2_FN64_AFFINITY_INFO: 3258c2ecf20Sopenharmony_ci case PSCI_0_2_FN_MIGRATE_INFO_TYPE: 3268c2ecf20Sopenharmony_ci case PSCI_0_2_FN_SYSTEM_OFF: 3278c2ecf20Sopenharmony_ci case PSCI_0_2_FN_SYSTEM_RESET: 3288c2ecf20Sopenharmony_ci case PSCI_1_0_FN_PSCI_FEATURES: 3298c2ecf20Sopenharmony_ci case ARM_SMCCC_VERSION_FUNC_ID: 3308c2ecf20Sopenharmony_ci val = 0; 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci default: 3338c2ecf20Sopenharmony_ci val = PSCI_RET_NOT_SUPPORTED; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci default: 3388c2ecf20Sopenharmony_ci return kvm_psci_0_2_call(vcpu); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci smccc_set_retval(vcpu, val, 0, 0, 0); 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 3488c2ecf20Sopenharmony_ci u32 psci_fn = smccc_get_function(vcpu); 3498c2ecf20Sopenharmony_ci unsigned long val; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci switch (psci_fn) { 3528c2ecf20Sopenharmony_ci case KVM_PSCI_FN_CPU_OFF: 3538c2ecf20Sopenharmony_ci kvm_psci_vcpu_off(vcpu); 3548c2ecf20Sopenharmony_ci val = PSCI_RET_SUCCESS; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci case KVM_PSCI_FN_CPU_ON: 3578c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 3588c2ecf20Sopenharmony_ci val = kvm_psci_vcpu_on(vcpu); 3598c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci default: 3628c2ecf20Sopenharmony_ci val = PSCI_RET_NOT_SUPPORTED; 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci smccc_set_retval(vcpu, val, 0, 0, 0); 3678c2ecf20Sopenharmony_ci return 1; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/** 3718c2ecf20Sopenharmony_ci * kvm_psci_call - handle PSCI call if r0 value is in range 3728c2ecf20Sopenharmony_ci * @vcpu: Pointer to the VCPU struct 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * Handle PSCI calls from guests through traps from HVC instructions. 3758c2ecf20Sopenharmony_ci * The calling convention is similar to SMC calls to the secure world 3768c2ecf20Sopenharmony_ci * where the function number is placed in r0. 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * This function returns: > 0 (success), 0 (success but exit to user 3798c2ecf20Sopenharmony_ci * space), and < 0 (errors) 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * Errors: 3828c2ecf20Sopenharmony_ci * -EINVAL: Unrecognized PSCI function 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ciint kvm_psci_call(struct kvm_vcpu *vcpu) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci switch (kvm_psci_version(vcpu, vcpu->kvm)) { 3878c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_1_0: 3888c2ecf20Sopenharmony_ci return kvm_psci_1_0_call(vcpu); 3898c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_0_2: 3908c2ecf20Sopenharmony_ci return kvm_psci_0_2_call(vcpu); 3918c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_0_1: 3928c2ecf20Sopenharmony_ci return kvm_psci_0_1_call(vcpu); 3938c2ecf20Sopenharmony_ci default: 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci }; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciint kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci return 4; /* PSCI version and three workaround registers */ 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciint kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_PSCI_VERSION, uindices++)) 4068c2ecf20Sopenharmony_ci return -EFAULT; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1, uindices++)) 4098c2ecf20Sopenharmony_ci return -EFAULT; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++)) 4128c2ecf20Sopenharmony_ci return -EFAULT; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++)) 4158c2ecf20Sopenharmony_ci return -EFAULT; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci#define KVM_REG_FEATURE_LEVEL_WIDTH 4 4218c2ecf20Sopenharmony_ci#define KVM_REG_FEATURE_LEVEL_MASK (BIT(KVM_REG_FEATURE_LEVEL_WIDTH) - 1) 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci * Convert the workaround level into an easy-to-compare number, where higher 4258c2ecf20Sopenharmony_ci * values mean better protection. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_cistatic int get_kernel_wa_level(u64 regid) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci switch (regid) { 4308c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 4318c2ecf20Sopenharmony_ci switch (arm64_get_spectre_v2_state()) { 4328c2ecf20Sopenharmony_ci case SPECTRE_VULNERABLE: 4338c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 4348c2ecf20Sopenharmony_ci case SPECTRE_MITIGATED: 4358c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_AVAIL; 4368c2ecf20Sopenharmony_ci case SPECTRE_UNAFFECTED: 4378c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_REQUIRED; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1_NOT_AVAIL; 4408c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 4418c2ecf20Sopenharmony_ci switch (arm64_get_spectre_v4_state()) { 4428c2ecf20Sopenharmony_ci case SPECTRE_MITIGATED: 4438c2ecf20Sopenharmony_ci /* 4448c2ecf20Sopenharmony_ci * As for the hypercall discovery, we pretend we 4458c2ecf20Sopenharmony_ci * don't have any FW mitigation if SSBS is there at 4468c2ecf20Sopenharmony_ci * all times. 4478c2ecf20Sopenharmony_ci */ 4488c2ecf20Sopenharmony_ci if (cpus_have_final_cap(ARM64_SSBS)) 4498c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 4508c2ecf20Sopenharmony_ci fallthrough; 4518c2ecf20Sopenharmony_ci case SPECTRE_UNAFFECTED: 4528c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 4538c2ecf20Sopenharmony_ci case SPECTRE_VULNERABLE: 4548c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 4588c2ecf20Sopenharmony_ci switch (arm64_get_spectre_bhb_state()) { 4598c2ecf20Sopenharmony_ci case SPECTRE_VULNERABLE: 4608c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 4618c2ecf20Sopenharmony_ci case SPECTRE_MITIGATED: 4628c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL; 4638c2ecf20Sopenharmony_ci case SPECTRE_UNAFFECTED: 4648c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return -EINVAL; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ciint kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 4758c2ecf20Sopenharmony_ci u64 val; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci switch (reg->id) { 4788c2ecf20Sopenharmony_ci case KVM_REG_ARM_PSCI_VERSION: 4798c2ecf20Sopenharmony_ci val = kvm_psci_version(vcpu, vcpu->kvm); 4808c2ecf20Sopenharmony_ci break; 4818c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 4828c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 4838c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 4848c2ecf20Sopenharmony_ci val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK; 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci default: 4878c2ecf20Sopenharmony_ci return -ENOENT; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id))) 4918c2ecf20Sopenharmony_ci return -EFAULT; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciint kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 4998c2ecf20Sopenharmony_ci u64 val; 5008c2ecf20Sopenharmony_ci int wa_level; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != sizeof(val)) 5038c2ecf20Sopenharmony_ci return -ENOENT; 5048c2ecf20Sopenharmony_ci if (copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id))) 5058c2ecf20Sopenharmony_ci return -EFAULT; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci switch (reg->id) { 5088c2ecf20Sopenharmony_ci case KVM_REG_ARM_PSCI_VERSION: 5098c2ecf20Sopenharmony_ci { 5108c2ecf20Sopenharmony_ci bool wants_02; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci wants_02 = test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci switch (val) { 5158c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_0_1: 5168c2ecf20Sopenharmony_ci if (wants_02) 5178c2ecf20Sopenharmony_ci return -EINVAL; 5188c2ecf20Sopenharmony_ci vcpu->kvm->arch.psci_version = val; 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_0_2: 5218c2ecf20Sopenharmony_ci case KVM_ARM_PSCI_1_0: 5228c2ecf20Sopenharmony_ci if (!wants_02) 5238c2ecf20Sopenharmony_ci return -EINVAL; 5248c2ecf20Sopenharmony_ci vcpu->kvm->arch.psci_version = val; 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1: 5318c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3: 5328c2ecf20Sopenharmony_ci if (val & ~KVM_REG_FEATURE_LEVEL_MASK) 5338c2ecf20Sopenharmony_ci return -EINVAL; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (get_kernel_wa_level(reg->id) < val) 5368c2ecf20Sopenharmony_ci return -EINVAL; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci return 0; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2: 5418c2ecf20Sopenharmony_ci if (val & ~(KVM_REG_FEATURE_LEVEL_MASK | 5428c2ecf20Sopenharmony_ci KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED)) 5438c2ecf20Sopenharmony_ci return -EINVAL; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* The enabled bit must not be set unless the level is AVAIL. */ 5468c2ecf20Sopenharmony_ci if ((val & KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED) && 5478c2ecf20Sopenharmony_ci (val & KVM_REG_FEATURE_LEVEL_MASK) != KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL) 5488c2ecf20Sopenharmony_ci return -EINVAL; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* 5518c2ecf20Sopenharmony_ci * Map all the possible incoming states to the only two we 5528c2ecf20Sopenharmony_ci * really want to deal with. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci switch (val & KVM_REG_FEATURE_LEVEL_MASK) { 5558c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL: 5568c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_UNKNOWN: 5578c2ecf20Sopenharmony_ci wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_AVAIL: 5608c2ecf20Sopenharmony_ci case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED: 5618c2ecf20Sopenharmony_ci wa_level = KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED; 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci default: 5648c2ecf20Sopenharmony_ci return -EINVAL; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * We can deal with NOT_AVAIL on NOT_REQUIRED, but not the 5698c2ecf20Sopenharmony_ci * other way around. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci if (get_kernel_wa_level(reg->id) < wa_level) 5728c2ecf20Sopenharmony_ci return -EINVAL; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci default: 5768c2ecf20Sopenharmony_ci return -ENOENT; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci} 581