18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Derived from arch/arm/kvm/guest.c: 78c2ecf20Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 88c2ecf20Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bits.h> 128c2ecf20Sopenharmony_ci#include <linux/errno.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/nospec.h> 158c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/stddef.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 208c2ecf20Sopenharmony_ci#include <linux/fs.h> 218c2ecf20Sopenharmony_ci#include <kvm/arm_psci.h> 228c2ecf20Sopenharmony_ci#include <asm/cputype.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <asm/fpsimd.h> 258c2ecf20Sopenharmony_ci#include <asm/kvm.h> 268c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 278c2ecf20Sopenharmony_ci#include <asm/kvm_coproc.h> 288c2ecf20Sopenharmony_ci#include <asm/sigcontext.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "trace.h" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct kvm_stats_debugfs_item debugfs_entries[] = { 338c2ecf20Sopenharmony_ci VCPU_STAT("halt_successful_poll", halt_successful_poll), 348c2ecf20Sopenharmony_ci VCPU_STAT("halt_attempted_poll", halt_attempted_poll), 358c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_invalid", halt_poll_invalid), 368c2ecf20Sopenharmony_ci VCPU_STAT("halt_wakeup", halt_wakeup), 378c2ecf20Sopenharmony_ci VCPU_STAT("hvc_exit_stat", hvc_exit_stat), 388c2ecf20Sopenharmony_ci VCPU_STAT("wfe_exit_stat", wfe_exit_stat), 398c2ecf20Sopenharmony_ci VCPU_STAT("wfi_exit_stat", wfi_exit_stat), 408c2ecf20Sopenharmony_ci VCPU_STAT("mmio_exit_user", mmio_exit_user), 418c2ecf20Sopenharmony_ci VCPU_STAT("mmio_exit_kernel", mmio_exit_kernel), 428c2ecf20Sopenharmony_ci VCPU_STAT("exits", exits), 438c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_success_ns", halt_poll_success_ns), 448c2ecf20Sopenharmony_ci VCPU_STAT("halt_poll_fail_ns", halt_poll_fail_ns), 458c2ecf20Sopenharmony_ci { NULL } 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic bool core_reg_offset_is_vreg(u64 off) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) && 518c2ecf20Sopenharmony_ci off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic u64 core_reg_offset_from_id(u64 id) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci int size; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci switch (off) { 648c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... 658c2ecf20Sopenharmony_ci KVM_REG_ARM_CORE_REG(regs.regs[30]): 668c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.sp): 678c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pc): 688c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pstate): 698c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(sp_el1): 708c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(elr_el1): 718c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[0]) ... 728c2ecf20Sopenharmony_ci KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): 738c2ecf20Sopenharmony_ci size = sizeof(__u64); 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... 778c2ecf20Sopenharmony_ci KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): 788c2ecf20Sopenharmony_ci size = sizeof(__uint128_t); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): 828c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): 838c2ecf20Sopenharmony_ci size = sizeof(__u32); 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci default: 878c2ecf20Sopenharmony_ci return -EINVAL; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!IS_ALIGNED(off, size / sizeof(__u32))) 918c2ecf20Sopenharmony_ci return -EINVAL; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * The KVM_REG_ARM64_SVE regs must be used instead of 958c2ecf20Sopenharmony_ci * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on 968c2ecf20Sopenharmony_ci * SVE-enabled vcpus: 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off)) 998c2ecf20Sopenharmony_ci return -EINVAL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return size; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci u64 off = core_reg_offset_from_id(reg->id); 1078c2ecf20Sopenharmony_ci int size = core_reg_size_from_offset(vcpu, off); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (size < 0) 1108c2ecf20Sopenharmony_ci return NULL; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != size) 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci switch (off) { 1168c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... 1178c2ecf20Sopenharmony_ci KVM_REG_ARM_CORE_REG(regs.regs[30]): 1188c2ecf20Sopenharmony_ci off -= KVM_REG_ARM_CORE_REG(regs.regs[0]); 1198c2ecf20Sopenharmony_ci off /= 2; 1208c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.regs.regs[off]; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.sp): 1238c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.regs.sp; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pc): 1268c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.regs.pc; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pstate): 1298c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.regs.pstate; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(sp_el1): 1328c2ecf20Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(elr_el1): 1358c2ecf20Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, ELR_EL1); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]): 1388c2ecf20Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, SPSR_EL1); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_ABT]): 1418c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.spsr_abt; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_UND]): 1448c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.spsr_und; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_IRQ]): 1478c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.spsr_irq; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_FIQ]): 1508c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.spsr_fiq; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... 1538c2ecf20Sopenharmony_ci KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): 1548c2ecf20Sopenharmony_ci off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]); 1558c2ecf20Sopenharmony_ci off /= 4; 1568c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.vregs[off]; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): 1598c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.fpsr; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): 1628c2ecf20Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.fpcr; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci default: 1658c2ecf20Sopenharmony_ci return NULL; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * Because the kvm_regs structure is a mix of 32, 64 and 1738c2ecf20Sopenharmony_ci * 128bit fields, we index it as if it was a 32bit 1748c2ecf20Sopenharmony_ci * array. Hence below, nr_regs is the number of entries, and 1758c2ecf20Sopenharmony_ci * off the index in the "array". 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr; 1788c2ecf20Sopenharmony_ci int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32); 1798c2ecf20Sopenharmony_ci void *addr; 1808c2ecf20Sopenharmony_ci u32 off; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* Our ID is an index into the kvm_regs struct. */ 1838c2ecf20Sopenharmony_ci off = core_reg_offset_from_id(reg->id); 1848c2ecf20Sopenharmony_ci if (off >= nr_regs || 1858c2ecf20Sopenharmony_ci (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) 1868c2ecf20Sopenharmony_ci return -ENOENT; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci addr = core_reg_addr(vcpu, reg); 1898c2ecf20Sopenharmony_ci if (!addr) 1908c2ecf20Sopenharmony_ci return -EINVAL; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (copy_to_user(uaddr, addr, KVM_REG_SIZE(reg->id))) 1938c2ecf20Sopenharmony_ci return -EFAULT; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return 0; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr; 2018c2ecf20Sopenharmony_ci int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32); 2028c2ecf20Sopenharmony_ci __uint128_t tmp; 2038c2ecf20Sopenharmony_ci void *valp = &tmp, *addr; 2048c2ecf20Sopenharmony_ci u64 off; 2058c2ecf20Sopenharmony_ci int err = 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* Our ID is an index into the kvm_regs struct. */ 2088c2ecf20Sopenharmony_ci off = core_reg_offset_from_id(reg->id); 2098c2ecf20Sopenharmony_ci if (off >= nr_regs || 2108c2ecf20Sopenharmony_ci (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) 2118c2ecf20Sopenharmony_ci return -ENOENT; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci addr = core_reg_addr(vcpu, reg); 2148c2ecf20Sopenharmony_ci if (!addr) 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (copy_from_user(valp, uaddr, KVM_REG_SIZE(reg->id))) { 2218c2ecf20Sopenharmony_ci err = -EFAULT; 2228c2ecf20Sopenharmony_ci goto out; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) { 2268c2ecf20Sopenharmony_ci u64 mode = (*(u64 *)valp) & PSR_AA32_MODE_MASK; 2278c2ecf20Sopenharmony_ci switch (mode) { 2288c2ecf20Sopenharmony_ci case PSR_AA32_MODE_USR: 2298c2ecf20Sopenharmony_ci if (!system_supports_32bit_el0()) 2308c2ecf20Sopenharmony_ci return -EINVAL; 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci case PSR_AA32_MODE_FIQ: 2338c2ecf20Sopenharmony_ci case PSR_AA32_MODE_IRQ: 2348c2ecf20Sopenharmony_ci case PSR_AA32_MODE_SVC: 2358c2ecf20Sopenharmony_ci case PSR_AA32_MODE_ABT: 2368c2ecf20Sopenharmony_ci case PSR_AA32_MODE_UND: 2378c2ecf20Sopenharmony_ci if (!vcpu_el1_is_32bit(vcpu)) 2388c2ecf20Sopenharmony_ci return -EINVAL; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case PSR_MODE_EL0t: 2418c2ecf20Sopenharmony_ci case PSR_MODE_EL1t: 2428c2ecf20Sopenharmony_ci case PSR_MODE_EL1h: 2438c2ecf20Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci default: 2478c2ecf20Sopenharmony_ci err = -EINVAL; 2488c2ecf20Sopenharmony_ci goto out; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci memcpy(addr, valp, KVM_REG_SIZE(reg->id)); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) { 2558c2ecf20Sopenharmony_ci int i; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 2588c2ecf20Sopenharmony_ci *vcpu_reg32(vcpu, i) = (u32)*vcpu_reg32(vcpu, i); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ciout: 2618c2ecf20Sopenharmony_ci return err; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64) 2658c2ecf20Sopenharmony_ci#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64) 2668c2ecf20Sopenharmony_ci#define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] & vq_mask(vq))) 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci unsigned int max_vq, vq; 2718c2ecf20Sopenharmony_ci u64 vqs[KVM_ARM64_SVE_VLS_WORDS]; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 2748c2ecf20Sopenharmony_ci return -ENOENT; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl))) 2778c2ecf20Sopenharmony_ci return -EINVAL; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci memset(vqs, 0, sizeof(vqs)); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci max_vq = sve_vq_from_vl(vcpu->arch.sve_max_vl); 2828c2ecf20Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq) 2838c2ecf20Sopenharmony_ci if (sve_vq_available(vq)) 2848c2ecf20Sopenharmony_ci vqs[vq_word(vq)] |= vq_mask(vq); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs))) 2878c2ecf20Sopenharmony_ci return -EFAULT; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned int max_vq, vq; 2958c2ecf20Sopenharmony_ci u64 vqs[KVM_ARM64_SVE_VLS_WORDS]; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 2988c2ecf20Sopenharmony_ci return -ENOENT; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci if (kvm_arm_vcpu_sve_finalized(vcpu)) 3018c2ecf20Sopenharmony_ci return -EPERM; /* too late! */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (WARN_ON(vcpu->arch.sve_state)) 3048c2ecf20Sopenharmony_ci return -EINVAL; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs))) 3078c2ecf20Sopenharmony_ci return -EFAULT; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci max_vq = 0; 3108c2ecf20Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq) 3118c2ecf20Sopenharmony_ci if (vq_present(vqs, vq)) 3128c2ecf20Sopenharmony_ci max_vq = vq; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (max_vq > sve_vq_from_vl(kvm_sve_max_vl)) 3158c2ecf20Sopenharmony_ci return -EINVAL; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* 3188c2ecf20Sopenharmony_ci * Vector lengths supported by the host can't currently be 3198c2ecf20Sopenharmony_ci * hidden from the guest individually: instead we can only set a 3208c2ecf20Sopenharmony_ci * maximum via ZCR_EL2.LEN. So, make sure the available vector 3218c2ecf20Sopenharmony_ci * lengths match the set requested exactly up to the requested 3228c2ecf20Sopenharmony_ci * maximum: 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq) 3258c2ecf20Sopenharmony_ci if (vq_present(vqs, vq) != sve_vq_available(vq)) 3268c2ecf20Sopenharmony_ci return -EINVAL; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Can't run with no vector lengths at all: */ 3298c2ecf20Sopenharmony_ci if (max_vq < SVE_VQ_MIN) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */ 3338c2ecf20Sopenharmony_ci vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci#define SVE_REG_SLICE_SHIFT 0 3398c2ecf20Sopenharmony_ci#define SVE_REG_SLICE_BITS 5 3408c2ecf20Sopenharmony_ci#define SVE_REG_ID_SHIFT (SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS) 3418c2ecf20Sopenharmony_ci#define SVE_REG_ID_BITS 5 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci#define SVE_REG_SLICE_MASK \ 3448c2ecf20Sopenharmony_ci GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1, \ 3458c2ecf20Sopenharmony_ci SVE_REG_SLICE_SHIFT) 3468c2ecf20Sopenharmony_ci#define SVE_REG_ID_MASK \ 3478c2ecf20Sopenharmony_ci GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT) 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS) 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0)) 3528c2ecf20Sopenharmony_ci#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0)) 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * Number of register slices required to cover each whole SVE register. 3568c2ecf20Sopenharmony_ci * NOTE: Only the first slice every exists, for now. 3578c2ecf20Sopenharmony_ci * If you are tempted to modify this, you must also rework sve_reg_to_region() 3588c2ecf20Sopenharmony_ci * to match: 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci#define vcpu_sve_slices(vcpu) 1 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* Bounds of a single SVE register slice within vcpu->arch.sve_state */ 3638c2ecf20Sopenharmony_cistruct sve_state_reg_region { 3648c2ecf20Sopenharmony_ci unsigned int koffset; /* offset into sve_state in kernel memory */ 3658c2ecf20Sopenharmony_ci unsigned int klen; /* length in kernel memory */ 3668c2ecf20Sopenharmony_ci unsigned int upad; /* extra trailing padding in user memory */ 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/* 3708c2ecf20Sopenharmony_ci * Validate SVE register ID and get sanitised bounds for user/kernel SVE 3718c2ecf20Sopenharmony_ci * register copy 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_cistatic int sve_reg_to_region(struct sve_state_reg_region *region, 3748c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu, 3758c2ecf20Sopenharmony_ci const struct kvm_one_reg *reg) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci /* reg ID ranges for Z- registers */ 3788c2ecf20Sopenharmony_ci const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0); 3798c2ecf20Sopenharmony_ci const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1, 3808c2ecf20Sopenharmony_ci SVE_NUM_SLICES - 1); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* reg ID ranges for P- registers and FFR (which are contiguous) */ 3838c2ecf20Sopenharmony_ci const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0); 3848c2ecf20Sopenharmony_ci const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci unsigned int vq; 3878c2ecf20Sopenharmony_ci unsigned int reg_num; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci unsigned int reqoffset, reqlen; /* User-requested offset and length */ 3908c2ecf20Sopenharmony_ci unsigned int maxlen; /* Maximum permitted length */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci size_t sve_state_size; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci const u64 last_preg_id = KVM_REG_ARM64_SVE_PREG(SVE_NUM_PREGS - 1, 3958c2ecf20Sopenharmony_ci SVE_NUM_SLICES - 1); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Verify that the P-regs and FFR really do have contiguous IDs: */ 3988c2ecf20Sopenharmony_ci BUILD_BUG_ON(KVM_REG_ARM64_SVE_FFR(0) != last_preg_id + 1); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci /* Verify that we match the UAPI header: */ 4018c2ecf20Sopenharmony_ci BUILD_BUG_ON(SVE_NUM_SLICES != KVM_ARM64_SVE_MAX_SLICES); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) { 4068c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0) 4078c2ecf20Sopenharmony_ci return -ENOENT; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci vq = sve_vq_from_vl(vcpu->arch.sve_max_vl); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) - 4128c2ecf20Sopenharmony_ci SVE_SIG_REGS_OFFSET; 4138c2ecf20Sopenharmony_ci reqlen = KVM_SVE_ZREG_SIZE; 4148c2ecf20Sopenharmony_ci maxlen = SVE_SIG_ZREG_SIZE(vq); 4158c2ecf20Sopenharmony_ci } else if (reg->id >= preg_id_min && reg->id <= preg_id_max) { 4168c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0) 4178c2ecf20Sopenharmony_ci return -ENOENT; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci vq = sve_vq_from_vl(vcpu->arch.sve_max_vl); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) - 4228c2ecf20Sopenharmony_ci SVE_SIG_REGS_OFFSET; 4238c2ecf20Sopenharmony_ci reqlen = KVM_SVE_PREG_SIZE; 4248c2ecf20Sopenharmony_ci maxlen = SVE_SIG_PREG_SIZE(vq); 4258c2ecf20Sopenharmony_ci } else { 4268c2ecf20Sopenharmony_ci return -EINVAL; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci sve_state_size = vcpu_sve_state_size(vcpu); 4308c2ecf20Sopenharmony_ci if (WARN_ON(!sve_state_size)) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci region->koffset = array_index_nospec(reqoffset, sve_state_size); 4348c2ecf20Sopenharmony_ci region->klen = min(maxlen, reqlen); 4358c2ecf20Sopenharmony_ci region->upad = reqlen - region->klen; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci int ret; 4438c2ecf20Sopenharmony_ci struct sve_state_reg_region region; 4448c2ecf20Sopenharmony_ci char __user *uptr = (char __user *)reg->addr; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */ 4478c2ecf20Sopenharmony_ci if (reg->id == KVM_REG_ARM64_SVE_VLS) 4488c2ecf20Sopenharmony_ci return get_sve_vls(vcpu, reg); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci /* Try to interpret reg ID as an architectural SVE register... */ 4518c2ecf20Sopenharmony_ci ret = sve_reg_to_region(®ion, vcpu, reg); 4528c2ecf20Sopenharmony_ci if (ret) 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!kvm_arm_vcpu_sve_finalized(vcpu)) 4568c2ecf20Sopenharmony_ci return -EPERM; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset, 4598c2ecf20Sopenharmony_ci region.klen) || 4608c2ecf20Sopenharmony_ci clear_user(uptr + region.klen, region.upad)) 4618c2ecf20Sopenharmony_ci return -EFAULT; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int ret; 4698c2ecf20Sopenharmony_ci struct sve_state_reg_region region; 4708c2ecf20Sopenharmony_ci const char __user *uptr = (const char __user *)reg->addr; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */ 4738c2ecf20Sopenharmony_ci if (reg->id == KVM_REG_ARM64_SVE_VLS) 4748c2ecf20Sopenharmony_ci return set_sve_vls(vcpu, reg); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* Try to interpret reg ID as an architectural SVE register... */ 4778c2ecf20Sopenharmony_ci ret = sve_reg_to_region(®ion, vcpu, reg); 4788c2ecf20Sopenharmony_ci if (ret) 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (!kvm_arm_vcpu_sve_finalized(vcpu)) 4828c2ecf20Sopenharmony_ci return -EPERM; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr, 4858c2ecf20Sopenharmony_ci region.klen)) 4868c2ecf20Sopenharmony_ci return -EFAULT; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci return -EINVAL; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci return -EINVAL; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int copy_core_reg_indices(const struct kvm_vcpu *vcpu, 5028c2ecf20Sopenharmony_ci u64 __user *uindices) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci unsigned int i; 5058c2ecf20Sopenharmony_ci int n = 0; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) { 5088c2ecf20Sopenharmony_ci u64 reg = KVM_REG_ARM64 | KVM_REG_ARM_CORE | i; 5098c2ecf20Sopenharmony_ci int size = core_reg_size_from_offset(vcpu, i); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (size < 0) 5128c2ecf20Sopenharmony_ci continue; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci switch (size) { 5158c2ecf20Sopenharmony_ci case sizeof(__u32): 5168c2ecf20Sopenharmony_ci reg |= KVM_REG_SIZE_U32; 5178c2ecf20Sopenharmony_ci break; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci case sizeof(__u64): 5208c2ecf20Sopenharmony_ci reg |= KVM_REG_SIZE_U64; 5218c2ecf20Sopenharmony_ci break; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci case sizeof(__uint128_t): 5248c2ecf20Sopenharmony_ci reg |= KVM_REG_SIZE_U128; 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci default: 5288c2ecf20Sopenharmony_ci WARN_ON(1); 5298c2ecf20Sopenharmony_ci continue; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (uindices) { 5338c2ecf20Sopenharmony_ci if (put_user(reg, uindices)) 5348c2ecf20Sopenharmony_ci return -EFAULT; 5358c2ecf20Sopenharmony_ci uindices++; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci n++; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return n; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic unsigned long num_core_regs(const struct kvm_vcpu *vcpu) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci return copy_core_reg_indices(vcpu, NULL); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci/** 5508c2ecf20Sopenharmony_ci * ARM64 versions of the TIMER registers, always available on arm64 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci#define NUM_TIMER_REGS 3 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic bool is_timer_reg(u64 index) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci switch (index) { 5588c2ecf20Sopenharmony_ci case KVM_REG_ARM_TIMER_CTL: 5598c2ecf20Sopenharmony_ci case KVM_REG_ARM_TIMER_CNT: 5608c2ecf20Sopenharmony_ci case KVM_REG_ARM_TIMER_CVAL: 5618c2ecf20Sopenharmony_ci return true; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci return false; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) 5698c2ecf20Sopenharmony_ci return -EFAULT; 5708c2ecf20Sopenharmony_ci uindices++; 5718c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) 5728c2ecf20Sopenharmony_ci return -EFAULT; 5738c2ecf20Sopenharmony_ci uindices++; 5748c2ecf20Sopenharmony_ci if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) 5758c2ecf20Sopenharmony_ci return -EFAULT; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 5838c2ecf20Sopenharmony_ci u64 val; 5848c2ecf20Sopenharmony_ci int ret; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)); 5878c2ecf20Sopenharmony_ci if (ret != 0) 5888c2ecf20Sopenharmony_ci return -EFAULT; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return kvm_arm_timer_set_reg(vcpu, reg->id, val); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 5968c2ecf20Sopenharmony_ci u64 val; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci val = kvm_arm_timer_get_reg(vcpu, reg->id); 5998c2ecf20Sopenharmony_ci return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic unsigned long num_sve_regs(const struct kvm_vcpu *vcpu) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci const unsigned int slices = vcpu_sve_slices(vcpu); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Policed by KVM_GET_REG_LIST: */ 6108c2ecf20Sopenharmony_ci WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */) 6138c2ecf20Sopenharmony_ci + 1; /* KVM_REG_ARM64_SVE_VLS */ 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic int copy_sve_reg_indices(const struct kvm_vcpu *vcpu, 6178c2ecf20Sopenharmony_ci u64 __user *uindices) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci const unsigned int slices = vcpu_sve_slices(vcpu); 6208c2ecf20Sopenharmony_ci u64 reg; 6218c2ecf20Sopenharmony_ci unsigned int i, n; 6228c2ecf20Sopenharmony_ci int num_regs = 0; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 6258c2ecf20Sopenharmony_ci return 0; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Policed by KVM_GET_REG_LIST: */ 6288c2ecf20Sopenharmony_ci WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * Enumerate this first, so that userspace can save/restore in 6328c2ecf20Sopenharmony_ci * the order reported by KVM_GET_REG_LIST: 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci reg = KVM_REG_ARM64_SVE_VLS; 6358c2ecf20Sopenharmony_ci if (put_user(reg, uindices++)) 6368c2ecf20Sopenharmony_ci return -EFAULT; 6378c2ecf20Sopenharmony_ci ++num_regs; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (i = 0; i < slices; i++) { 6408c2ecf20Sopenharmony_ci for (n = 0; n < SVE_NUM_ZREGS; n++) { 6418c2ecf20Sopenharmony_ci reg = KVM_REG_ARM64_SVE_ZREG(n, i); 6428c2ecf20Sopenharmony_ci if (put_user(reg, uindices++)) 6438c2ecf20Sopenharmony_ci return -EFAULT; 6448c2ecf20Sopenharmony_ci num_regs++; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci for (n = 0; n < SVE_NUM_PREGS; n++) { 6488c2ecf20Sopenharmony_ci reg = KVM_REG_ARM64_SVE_PREG(n, i); 6498c2ecf20Sopenharmony_ci if (put_user(reg, uindices++)) 6508c2ecf20Sopenharmony_ci return -EFAULT; 6518c2ecf20Sopenharmony_ci num_regs++; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci reg = KVM_REG_ARM64_SVE_FFR(i); 6558c2ecf20Sopenharmony_ci if (put_user(reg, uindices++)) 6568c2ecf20Sopenharmony_ci return -EFAULT; 6578c2ecf20Sopenharmony_ci num_regs++; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return num_regs; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/** 6648c2ecf20Sopenharmony_ci * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG 6658c2ecf20Sopenharmony_ci * 6668c2ecf20Sopenharmony_ci * This is for all registers. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ciunsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci unsigned long res = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci res += num_core_regs(vcpu); 6738c2ecf20Sopenharmony_ci res += num_sve_regs(vcpu); 6748c2ecf20Sopenharmony_ci res += kvm_arm_num_sys_reg_descs(vcpu); 6758c2ecf20Sopenharmony_ci res += kvm_arm_get_fw_num_regs(vcpu); 6768c2ecf20Sopenharmony_ci res += NUM_TIMER_REGS; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return res; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/** 6828c2ecf20Sopenharmony_ci * kvm_arm_copy_reg_indices - get indices of all registers. 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * We do core registers right here, then we append system regs. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ciint kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci int ret; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ret = copy_core_reg_indices(vcpu, uindices); 6918c2ecf20Sopenharmony_ci if (ret < 0) 6928c2ecf20Sopenharmony_ci return ret; 6938c2ecf20Sopenharmony_ci uindices += ret; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci ret = copy_sve_reg_indices(vcpu, uindices); 6968c2ecf20Sopenharmony_ci if (ret < 0) 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci uindices += ret; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); 7018c2ecf20Sopenharmony_ci if (ret < 0) 7028c2ecf20Sopenharmony_ci return ret; 7038c2ecf20Sopenharmony_ci uindices += kvm_arm_get_fw_num_regs(vcpu); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ret = copy_timer_indices(vcpu, uindices); 7068c2ecf20Sopenharmony_ci if (ret < 0) 7078c2ecf20Sopenharmony_ci return ret; 7088c2ecf20Sopenharmony_ci uindices += NUM_TIMER_REGS; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return kvm_arm_copy_sys_reg_indices(vcpu, uindices); 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ciint kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci /* We currently use nothing arch-specific in upper 32 bits */ 7168c2ecf20Sopenharmony_ci if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 7208c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg); 7218c2ecf20Sopenharmony_ci case KVM_REG_ARM_FW: return kvm_arm_get_fw_reg(vcpu, reg); 7228c2ecf20Sopenharmony_ci case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (is_timer_reg(reg->id)) 7268c2ecf20Sopenharmony_ci return get_timer_reg(vcpu, reg); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci return kvm_arm_sys_reg_get_reg(vcpu, reg); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciint kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci /* We currently use nothing arch-specific in upper 32 bits */ 7348c2ecf20Sopenharmony_ci if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32) 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 7388c2ecf20Sopenharmony_ci case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); 7398c2ecf20Sopenharmony_ci case KVM_REG_ARM_FW: return kvm_arm_set_fw_reg(vcpu, reg); 7408c2ecf20Sopenharmony_ci case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (is_timer_reg(reg->id)) 7448c2ecf20Sopenharmony_ci return set_timer_reg(vcpu, reg); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return kvm_arm_sys_reg_set_reg(vcpu, reg); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, 7508c2ecf20Sopenharmony_ci struct kvm_sregs *sregs) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci return -EINVAL; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, 7568c2ecf20Sopenharmony_ci struct kvm_sregs *sregs) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci return -EINVAL; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciint __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu, 7628c2ecf20Sopenharmony_ci struct kvm_vcpu_events *events) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE); 7658c2ecf20Sopenharmony_ci events->exception.serror_has_esr = cpus_have_const_cap(ARM64_HAS_RAS_EXTN); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (events->exception.serror_pending && events->exception.serror_has_esr) 7688c2ecf20Sopenharmony_ci events->exception.serror_esr = vcpu_get_vsesr(vcpu); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* 7718c2ecf20Sopenharmony_ci * We never return a pending ext_dabt here because we deliver it to 7728c2ecf20Sopenharmony_ci * the virtual CPU directly when setting the event and it's no longer 7738c2ecf20Sopenharmony_ci * 'pending' at this point. 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return 0; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ciint __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, 7808c2ecf20Sopenharmony_ci struct kvm_vcpu_events *events) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci bool serror_pending = events->exception.serror_pending; 7838c2ecf20Sopenharmony_ci bool has_esr = events->exception.serror_has_esr; 7848c2ecf20Sopenharmony_ci bool ext_dabt_pending = events->exception.ext_dabt_pending; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (serror_pending && has_esr) { 7878c2ecf20Sopenharmony_ci if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) 7888c2ecf20Sopenharmony_ci return -EINVAL; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!((events->exception.serror_esr) & ~ESR_ELx_ISS_MASK)) 7918c2ecf20Sopenharmony_ci kvm_set_sei_esr(vcpu, events->exception.serror_esr); 7928c2ecf20Sopenharmony_ci else 7938c2ecf20Sopenharmony_ci return -EINVAL; 7948c2ecf20Sopenharmony_ci } else if (serror_pending) { 7958c2ecf20Sopenharmony_ci kvm_inject_vabt(vcpu); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (ext_dabt_pending) 7998c2ecf20Sopenharmony_ci kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return 0; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ciint __attribute_const__ kvm_target_cpu(void) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci unsigned long implementor = read_cpuid_implementor(); 8078c2ecf20Sopenharmony_ci unsigned long part_number = read_cpuid_part_number(); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci switch (implementor) { 8108c2ecf20Sopenharmony_ci case ARM_CPU_IMP_ARM: 8118c2ecf20Sopenharmony_ci switch (part_number) { 8128c2ecf20Sopenharmony_ci case ARM_CPU_PART_AEM_V8: 8138c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_AEM_V8; 8148c2ecf20Sopenharmony_ci case ARM_CPU_PART_FOUNDATION: 8158c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_FOUNDATION_V8; 8168c2ecf20Sopenharmony_ci case ARM_CPU_PART_CORTEX_A53: 8178c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_CORTEX_A53; 8188c2ecf20Sopenharmony_ci case ARM_CPU_PART_CORTEX_A57: 8198c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_CORTEX_A57; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci case ARM_CPU_IMP_APM: 8238c2ecf20Sopenharmony_ci switch (part_number) { 8248c2ecf20Sopenharmony_ci case APM_CPU_PART_POTENZA: 8258c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_XGENE_POTENZA; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* Return a default generic target */ 8318c2ecf20Sopenharmony_ci return KVM_ARM_TARGET_GENERIC_V8; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ciint kvm_vcpu_preferred_target(struct kvm_vcpu_init *init) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci int target = kvm_target_cpu(); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (target < 0) 8398c2ecf20Sopenharmony_ci return -ENODEV; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci memset(init, 0, sizeof(*init)); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * For now, we don't return any features. 8458c2ecf20Sopenharmony_ci * In future, we might use features to return target 8468c2ecf20Sopenharmony_ci * specific features available for the preferred 8478c2ecf20Sopenharmony_ci * target type. 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci init->target = (__u32)target; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci return 0; 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci return -EINVAL; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci return -EINVAL; 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, 8658c2ecf20Sopenharmony_ci struct kvm_translation *tr) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci return -EINVAL; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ 8718c2ecf20Sopenharmony_ci KVM_GUESTDBG_USE_SW_BP | \ 8728c2ecf20Sopenharmony_ci KVM_GUESTDBG_USE_HW | \ 8738c2ecf20Sopenharmony_ci KVM_GUESTDBG_SINGLESTEP) 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci/** 8768c2ecf20Sopenharmony_ci * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging 8778c2ecf20Sopenharmony_ci * @kvm: pointer to the KVM struct 8788c2ecf20Sopenharmony_ci * @kvm_guest_debug: the ioctl data buffer 8798c2ecf20Sopenharmony_ci * 8808c2ecf20Sopenharmony_ci * This sets up and enables the VM for guest debugging. Userspace 8818c2ecf20Sopenharmony_ci * passes in a control flag to enable different debug types and 8828c2ecf20Sopenharmony_ci * potentially other architecture specific information in the rest of 8838c2ecf20Sopenharmony_ci * the structure. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, 8868c2ecf20Sopenharmony_ci struct kvm_guest_debug *dbg) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci int ret = 0; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci trace_kvm_set_guest_debug(vcpu, dbg->control); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) { 8938c2ecf20Sopenharmony_ci ret = -EINVAL; 8948c2ecf20Sopenharmony_ci goto out; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (dbg->control & KVM_GUESTDBG_ENABLE) { 8988c2ecf20Sopenharmony_ci vcpu->guest_debug = dbg->control; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Hardware assisted Break and Watch points */ 9018c2ecf20Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { 9028c2ecf20Sopenharmony_ci vcpu->arch.external_debug_state = dbg->arch; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci } else { 9068c2ecf20Sopenharmony_ci /* If not enabled clear all flags */ 9078c2ecf20Sopenharmony_ci vcpu->guest_debug = 0; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciout: 9118c2ecf20Sopenharmony_ci return ret; 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ciint kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, 9158c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci int ret; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci switch (attr->group) { 9208c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 9218c2ecf20Sopenharmony_ci ret = kvm_arm_pmu_v3_set_attr(vcpu, attr); 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 9248c2ecf20Sopenharmony_ci ret = kvm_arm_timer_set_attr(vcpu, attr); 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 9278c2ecf20Sopenharmony_ci ret = kvm_arm_pvtime_set_attr(vcpu, attr); 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci default: 9308c2ecf20Sopenharmony_ci ret = -ENXIO; 9318c2ecf20Sopenharmony_ci break; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return ret; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ciint kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, 9388c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci int ret; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci switch (attr->group) { 9438c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 9448c2ecf20Sopenharmony_ci ret = kvm_arm_pmu_v3_get_attr(vcpu, attr); 9458c2ecf20Sopenharmony_ci break; 9468c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 9478c2ecf20Sopenharmony_ci ret = kvm_arm_timer_get_attr(vcpu, attr); 9488c2ecf20Sopenharmony_ci break; 9498c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 9508c2ecf20Sopenharmony_ci ret = kvm_arm_pvtime_get_attr(vcpu, attr); 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci default: 9538c2ecf20Sopenharmony_ci ret = -ENXIO; 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return ret; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ciint kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, 9618c2ecf20Sopenharmony_ci struct kvm_device_attr *attr) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci int ret; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci switch (attr->group) { 9668c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 9678c2ecf20Sopenharmony_ci ret = kvm_arm_pmu_v3_has_attr(vcpu, attr); 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 9708c2ecf20Sopenharmony_ci ret = kvm_arm_timer_has_attr(vcpu, attr); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 9738c2ecf20Sopenharmony_ci ret = kvm_arm_pvtime_has_attr(vcpu, attr); 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci default: 9768c2ecf20Sopenharmony_ci ret = -ENXIO; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return ret; 9818c2ecf20Sopenharmony_ci} 982