162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Derived from arch/arm/kvm/guest.c: 762306a36Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 862306a36Sopenharmony_ci * Author: Christoffer Dall <c.dall@virtualopensystems.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/bits.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/nospec.h> 1562306a36Sopenharmony_ci#include <linux/kvm_host.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/stddef.h> 1862306a36Sopenharmony_ci#include <linux/string.h> 1962306a36Sopenharmony_ci#include <linux/vmalloc.h> 2062306a36Sopenharmony_ci#include <linux/fs.h> 2162306a36Sopenharmony_ci#include <kvm/arm_hypercalls.h> 2262306a36Sopenharmony_ci#include <asm/cputype.h> 2362306a36Sopenharmony_ci#include <linux/uaccess.h> 2462306a36Sopenharmony_ci#include <asm/fpsimd.h> 2562306a36Sopenharmony_ci#include <asm/kvm.h> 2662306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 2762306a36Sopenharmony_ci#include <asm/kvm_nested.h> 2862306a36Sopenharmony_ci#include <asm/sigcontext.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "trace.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciconst struct _kvm_stats_desc kvm_vm_stats_desc[] = { 3362306a36Sopenharmony_ci KVM_GENERIC_VM_STATS() 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciconst struct kvm_stats_header kvm_vm_stats_header = { 3762306a36Sopenharmony_ci .name_size = KVM_STATS_NAME_SIZE, 3862306a36Sopenharmony_ci .num_desc = ARRAY_SIZE(kvm_vm_stats_desc), 3962306a36Sopenharmony_ci .id_offset = sizeof(struct kvm_stats_header), 4062306a36Sopenharmony_ci .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, 4162306a36Sopenharmony_ci .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 4262306a36Sopenharmony_ci sizeof(kvm_vm_stats_desc), 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciconst struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { 4662306a36Sopenharmony_ci KVM_GENERIC_VCPU_STATS(), 4762306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, hvc_exit_stat), 4862306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, wfe_exit_stat), 4962306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, wfi_exit_stat), 5062306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, mmio_exit_user), 5162306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), 5262306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, signal_exits), 5362306a36Sopenharmony_ci STATS_DESC_COUNTER(VCPU, exits) 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciconst struct kvm_stats_header kvm_vcpu_stats_header = { 5762306a36Sopenharmony_ci .name_size = KVM_STATS_NAME_SIZE, 5862306a36Sopenharmony_ci .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc), 5962306a36Sopenharmony_ci .id_offset = sizeof(struct kvm_stats_header), 6062306a36Sopenharmony_ci .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, 6162306a36Sopenharmony_ci .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 6262306a36Sopenharmony_ci sizeof(kvm_vcpu_stats_desc), 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic bool core_reg_offset_is_vreg(u64 off) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return off >= KVM_REG_ARM_CORE_REG(fp_regs.vregs) && 6862306a36Sopenharmony_ci off < KVM_REG_ARM_CORE_REG(fp_regs.fpsr); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic u64 core_reg_offset_from_id(u64 id) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci int size; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci switch (off) { 8162306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... 8262306a36Sopenharmony_ci KVM_REG_ARM_CORE_REG(regs.regs[30]): 8362306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.sp): 8462306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pc): 8562306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pstate): 8662306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(sp_el1): 8762306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(elr_el1): 8862306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[0]) ... 8962306a36Sopenharmony_ci KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]): 9062306a36Sopenharmony_ci size = sizeof(__u64); 9162306a36Sopenharmony_ci break; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... 9462306a36Sopenharmony_ci KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): 9562306a36Sopenharmony_ci size = sizeof(__uint128_t); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): 9962306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): 10062306a36Sopenharmony_ci size = sizeof(__u32); 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (!IS_ALIGNED(off, size / sizeof(__u32))) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * The KVM_REG_ARM64_SVE regs must be used instead of 11262306a36Sopenharmony_ci * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on 11362306a36Sopenharmony_ci * SVE-enabled vcpus: 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off)) 11662306a36Sopenharmony_ci return -EINVAL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return size; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic void *core_reg_addr(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci u64 off = core_reg_offset_from_id(reg->id); 12462306a36Sopenharmony_ci int size = core_reg_size_from_offset(vcpu, off); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (size < 0) 12762306a36Sopenharmony_ci return NULL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (KVM_REG_SIZE(reg->id) != size) 13062306a36Sopenharmony_ci return NULL; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci switch (off) { 13362306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.regs[0]) ... 13462306a36Sopenharmony_ci KVM_REG_ARM_CORE_REG(regs.regs[30]): 13562306a36Sopenharmony_ci off -= KVM_REG_ARM_CORE_REG(regs.regs[0]); 13662306a36Sopenharmony_ci off /= 2; 13762306a36Sopenharmony_ci return &vcpu->arch.ctxt.regs.regs[off]; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.sp): 14062306a36Sopenharmony_ci return &vcpu->arch.ctxt.regs.sp; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pc): 14362306a36Sopenharmony_ci return &vcpu->arch.ctxt.regs.pc; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(regs.pstate): 14662306a36Sopenharmony_ci return &vcpu->arch.ctxt.regs.pstate; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(sp_el1): 14962306a36Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, SP_EL1); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(elr_el1): 15262306a36Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, ELR_EL1); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_EL1]): 15562306a36Sopenharmony_ci return __ctxt_sys_reg(&vcpu->arch.ctxt, SPSR_EL1); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_ABT]): 15862306a36Sopenharmony_ci return &vcpu->arch.ctxt.spsr_abt; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_UND]): 16162306a36Sopenharmony_ci return &vcpu->arch.ctxt.spsr_und; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_IRQ]): 16462306a36Sopenharmony_ci return &vcpu->arch.ctxt.spsr_irq; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(spsr[KVM_SPSR_FIQ]): 16762306a36Sopenharmony_ci return &vcpu->arch.ctxt.spsr_fiq; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ... 17062306a36Sopenharmony_ci KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]): 17162306a36Sopenharmony_ci off -= KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]); 17262306a36Sopenharmony_ci off /= 4; 17362306a36Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.vregs[off]; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpsr): 17662306a36Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.fpsr; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci case KVM_REG_ARM_CORE_REG(fp_regs.fpcr): 17962306a36Sopenharmony_ci return &vcpu->arch.ctxt.fp_regs.fpcr; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci default: 18262306a36Sopenharmony_ci return NULL; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci /* 18962306a36Sopenharmony_ci * Because the kvm_regs structure is a mix of 32, 64 and 19062306a36Sopenharmony_ci * 128bit fields, we index it as if it was a 32bit 19162306a36Sopenharmony_ci * array. Hence below, nr_regs is the number of entries, and 19262306a36Sopenharmony_ci * off the index in the "array". 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr; 19562306a36Sopenharmony_ci int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32); 19662306a36Sopenharmony_ci void *addr; 19762306a36Sopenharmony_ci u32 off; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Our ID is an index into the kvm_regs struct. */ 20062306a36Sopenharmony_ci off = core_reg_offset_from_id(reg->id); 20162306a36Sopenharmony_ci if (off >= nr_regs || 20262306a36Sopenharmony_ci (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) 20362306a36Sopenharmony_ci return -ENOENT; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci addr = core_reg_addr(vcpu, reg); 20662306a36Sopenharmony_ci if (!addr) 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (copy_to_user(uaddr, addr, KVM_REG_SIZE(reg->id))) 21062306a36Sopenharmony_ci return -EFAULT; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return 0; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr; 21862306a36Sopenharmony_ci int nr_regs = sizeof(struct kvm_regs) / sizeof(__u32); 21962306a36Sopenharmony_ci __uint128_t tmp; 22062306a36Sopenharmony_ci void *valp = &tmp, *addr; 22162306a36Sopenharmony_ci u64 off; 22262306a36Sopenharmony_ci int err = 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Our ID is an index into the kvm_regs struct. */ 22562306a36Sopenharmony_ci off = core_reg_offset_from_id(reg->id); 22662306a36Sopenharmony_ci if (off >= nr_regs || 22762306a36Sopenharmony_ci (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs) 22862306a36Sopenharmony_ci return -ENOENT; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci addr = core_reg_addr(vcpu, reg); 23162306a36Sopenharmony_ci if (!addr) 23262306a36Sopenharmony_ci return -EINVAL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (KVM_REG_SIZE(reg->id) > sizeof(tmp)) 23562306a36Sopenharmony_ci return -EINVAL; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (copy_from_user(valp, uaddr, KVM_REG_SIZE(reg->id))) { 23862306a36Sopenharmony_ci err = -EFAULT; 23962306a36Sopenharmony_ci goto out; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) { 24362306a36Sopenharmony_ci u64 mode = (*(u64 *)valp) & PSR_AA32_MODE_MASK; 24462306a36Sopenharmony_ci switch (mode) { 24562306a36Sopenharmony_ci case PSR_AA32_MODE_USR: 24662306a36Sopenharmony_ci if (!kvm_supports_32bit_el0()) 24762306a36Sopenharmony_ci return -EINVAL; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case PSR_AA32_MODE_FIQ: 25062306a36Sopenharmony_ci case PSR_AA32_MODE_IRQ: 25162306a36Sopenharmony_ci case PSR_AA32_MODE_SVC: 25262306a36Sopenharmony_ci case PSR_AA32_MODE_ABT: 25362306a36Sopenharmony_ci case PSR_AA32_MODE_UND: 25462306a36Sopenharmony_ci if (!vcpu_el1_is_32bit(vcpu)) 25562306a36Sopenharmony_ci return -EINVAL; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case PSR_MODE_EL2h: 25862306a36Sopenharmony_ci case PSR_MODE_EL2t: 25962306a36Sopenharmony_ci if (!vcpu_has_nv(vcpu)) 26062306a36Sopenharmony_ci return -EINVAL; 26162306a36Sopenharmony_ci fallthrough; 26262306a36Sopenharmony_ci case PSR_MODE_EL0t: 26362306a36Sopenharmony_ci case PSR_MODE_EL1t: 26462306a36Sopenharmony_ci case PSR_MODE_EL1h: 26562306a36Sopenharmony_ci if (vcpu_el1_is_32bit(vcpu)) 26662306a36Sopenharmony_ci return -EINVAL; 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci default: 26962306a36Sopenharmony_ci err = -EINVAL; 27062306a36Sopenharmony_ci goto out; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci memcpy(addr, valp, KVM_REG_SIZE(reg->id)); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (*vcpu_cpsr(vcpu) & PSR_MODE32_BIT) { 27762306a36Sopenharmony_ci int i, nr_reg; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci switch (*vcpu_cpsr(vcpu)) { 28062306a36Sopenharmony_ci /* 28162306a36Sopenharmony_ci * Either we are dealing with user mode, and only the 28262306a36Sopenharmony_ci * first 15 registers (+ PC) must be narrowed to 32bit. 28362306a36Sopenharmony_ci * AArch32 r0-r14 conveniently map to AArch64 x0-x14. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci case PSR_AA32_MODE_USR: 28662306a36Sopenharmony_ci case PSR_AA32_MODE_SYS: 28762306a36Sopenharmony_ci nr_reg = 15; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Otherwise, this is a privileged mode, and *all* the 29262306a36Sopenharmony_ci * registers must be narrowed to 32bit. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci default: 29562306a36Sopenharmony_ci nr_reg = 31; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci for (i = 0; i < nr_reg; i++) 30062306a36Sopenharmony_ci vcpu_set_reg(vcpu, i, (u32)vcpu_get_reg(vcpu, i)); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci *vcpu_pc(vcpu) = (u32)*vcpu_pc(vcpu); 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ciout: 30562306a36Sopenharmony_ci return err; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci#define vq_word(vq) (((vq) - SVE_VQ_MIN) / 64) 30962306a36Sopenharmony_ci#define vq_mask(vq) ((u64)1 << ((vq) - SVE_VQ_MIN) % 64) 31062306a36Sopenharmony_ci#define vq_present(vqs, vq) (!!((vqs)[vq_word(vq)] & vq_mask(vq))) 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int get_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci unsigned int max_vq, vq; 31562306a36Sopenharmony_ci u64 vqs[KVM_ARM64_SVE_VLS_WORDS]; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 31862306a36Sopenharmony_ci return -ENOENT; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (WARN_ON(!sve_vl_valid(vcpu->arch.sve_max_vl))) 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci memset(vqs, 0, sizeof(vqs)); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci max_vq = vcpu_sve_max_vq(vcpu); 32662306a36Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq) 32762306a36Sopenharmony_ci if (sve_vq_available(vq)) 32862306a36Sopenharmony_ci vqs[vq_word(vq)] |= vq_mask(vq); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (copy_to_user((void __user *)reg->addr, vqs, sizeof(vqs))) 33162306a36Sopenharmony_ci return -EFAULT; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int set_sve_vls(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci unsigned int max_vq, vq; 33962306a36Sopenharmony_ci u64 vqs[KVM_ARM64_SVE_VLS_WORDS]; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 34262306a36Sopenharmony_ci return -ENOENT; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (kvm_arm_vcpu_sve_finalized(vcpu)) 34562306a36Sopenharmony_ci return -EPERM; /* too late! */ 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (WARN_ON(vcpu->arch.sve_state)) 34862306a36Sopenharmony_ci return -EINVAL; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (copy_from_user(vqs, (const void __user *)reg->addr, sizeof(vqs))) 35162306a36Sopenharmony_ci return -EFAULT; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci max_vq = 0; 35462306a36Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; ++vq) 35562306a36Sopenharmony_ci if (vq_present(vqs, vq)) 35662306a36Sopenharmony_ci max_vq = vq; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (max_vq > sve_vq_from_vl(kvm_sve_max_vl)) 35962306a36Sopenharmony_ci return -EINVAL; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * Vector lengths supported by the host can't currently be 36362306a36Sopenharmony_ci * hidden from the guest individually: instead we can only set a 36462306a36Sopenharmony_ci * maximum via ZCR_EL2.LEN. So, make sure the available vector 36562306a36Sopenharmony_ci * lengths match the set requested exactly up to the requested 36662306a36Sopenharmony_ci * maximum: 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci for (vq = SVE_VQ_MIN; vq <= max_vq; ++vq) 36962306a36Sopenharmony_ci if (vq_present(vqs, vq) != sve_vq_available(vq)) 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Can't run with no vector lengths at all: */ 37362306a36Sopenharmony_ci if (max_vq < SVE_VQ_MIN) 37462306a36Sopenharmony_ci return -EINVAL; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* vcpu->arch.sve_state will be alloc'd by kvm_vcpu_finalize_sve() */ 37762306a36Sopenharmony_ci vcpu->arch.sve_max_vl = sve_vl_from_vq(max_vq); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci return 0; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci#define SVE_REG_SLICE_SHIFT 0 38362306a36Sopenharmony_ci#define SVE_REG_SLICE_BITS 5 38462306a36Sopenharmony_ci#define SVE_REG_ID_SHIFT (SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS) 38562306a36Sopenharmony_ci#define SVE_REG_ID_BITS 5 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci#define SVE_REG_SLICE_MASK \ 38862306a36Sopenharmony_ci GENMASK(SVE_REG_SLICE_SHIFT + SVE_REG_SLICE_BITS - 1, \ 38962306a36Sopenharmony_ci SVE_REG_SLICE_SHIFT) 39062306a36Sopenharmony_ci#define SVE_REG_ID_MASK \ 39162306a36Sopenharmony_ci GENMASK(SVE_REG_ID_SHIFT + SVE_REG_ID_BITS - 1, SVE_REG_ID_SHIFT) 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci#define SVE_NUM_SLICES (1 << SVE_REG_SLICE_BITS) 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci#define KVM_SVE_ZREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_ZREG(0, 0)) 39662306a36Sopenharmony_ci#define KVM_SVE_PREG_SIZE KVM_REG_SIZE(KVM_REG_ARM64_SVE_PREG(0, 0)) 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci/* 39962306a36Sopenharmony_ci * Number of register slices required to cover each whole SVE register. 40062306a36Sopenharmony_ci * NOTE: Only the first slice every exists, for now. 40162306a36Sopenharmony_ci * If you are tempted to modify this, you must also rework sve_reg_to_region() 40262306a36Sopenharmony_ci * to match: 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci#define vcpu_sve_slices(vcpu) 1 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci/* Bounds of a single SVE register slice within vcpu->arch.sve_state */ 40762306a36Sopenharmony_cistruct sve_state_reg_region { 40862306a36Sopenharmony_ci unsigned int koffset; /* offset into sve_state in kernel memory */ 40962306a36Sopenharmony_ci unsigned int klen; /* length in kernel memory */ 41062306a36Sopenharmony_ci unsigned int upad; /* extra trailing padding in user memory */ 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci/* 41462306a36Sopenharmony_ci * Validate SVE register ID and get sanitised bounds for user/kernel SVE 41562306a36Sopenharmony_ci * register copy 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_cistatic int sve_reg_to_region(struct sve_state_reg_region *region, 41862306a36Sopenharmony_ci struct kvm_vcpu *vcpu, 41962306a36Sopenharmony_ci const struct kvm_one_reg *reg) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci /* reg ID ranges for Z- registers */ 42262306a36Sopenharmony_ci const u64 zreg_id_min = KVM_REG_ARM64_SVE_ZREG(0, 0); 42362306a36Sopenharmony_ci const u64 zreg_id_max = KVM_REG_ARM64_SVE_ZREG(SVE_NUM_ZREGS - 1, 42462306a36Sopenharmony_ci SVE_NUM_SLICES - 1); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* reg ID ranges for P- registers and FFR (which are contiguous) */ 42762306a36Sopenharmony_ci const u64 preg_id_min = KVM_REG_ARM64_SVE_PREG(0, 0); 42862306a36Sopenharmony_ci const u64 preg_id_max = KVM_REG_ARM64_SVE_FFR(SVE_NUM_SLICES - 1); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci unsigned int vq; 43162306a36Sopenharmony_ci unsigned int reg_num; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci unsigned int reqoffset, reqlen; /* User-requested offset and length */ 43462306a36Sopenharmony_ci unsigned int maxlen; /* Maximum permitted length */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci size_t sve_state_size; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci const u64 last_preg_id = KVM_REG_ARM64_SVE_PREG(SVE_NUM_PREGS - 1, 43962306a36Sopenharmony_ci SVE_NUM_SLICES - 1); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* Verify that the P-regs and FFR really do have contiguous IDs: */ 44262306a36Sopenharmony_ci BUILD_BUG_ON(KVM_REG_ARM64_SVE_FFR(0) != last_preg_id + 1); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Verify that we match the UAPI header: */ 44562306a36Sopenharmony_ci BUILD_BUG_ON(SVE_NUM_SLICES != KVM_ARM64_SVE_MAX_SLICES); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci reg_num = (reg->id & SVE_REG_ID_MASK) >> SVE_REG_ID_SHIFT; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (reg->id >= zreg_id_min && reg->id <= zreg_id_max) { 45062306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0) 45162306a36Sopenharmony_ci return -ENOENT; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci vq = vcpu_sve_max_vq(vcpu); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) - 45662306a36Sopenharmony_ci SVE_SIG_REGS_OFFSET; 45762306a36Sopenharmony_ci reqlen = KVM_SVE_ZREG_SIZE; 45862306a36Sopenharmony_ci maxlen = SVE_SIG_ZREG_SIZE(vq); 45962306a36Sopenharmony_ci } else if (reg->id >= preg_id_min && reg->id <= preg_id_max) { 46062306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0) 46162306a36Sopenharmony_ci return -ENOENT; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci vq = vcpu_sve_max_vq(vcpu); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) - 46662306a36Sopenharmony_ci SVE_SIG_REGS_OFFSET; 46762306a36Sopenharmony_ci reqlen = KVM_SVE_PREG_SIZE; 46862306a36Sopenharmony_ci maxlen = SVE_SIG_PREG_SIZE(vq); 46962306a36Sopenharmony_ci } else { 47062306a36Sopenharmony_ci return -EINVAL; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci sve_state_size = vcpu_sve_state_size(vcpu); 47462306a36Sopenharmony_ci if (WARN_ON(!sve_state_size)) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci region->koffset = array_index_nospec(reqoffset, sve_state_size); 47862306a36Sopenharmony_ci region->klen = min(maxlen, reqlen); 47962306a36Sopenharmony_ci region->upad = reqlen - region->klen; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return 0; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int get_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci int ret; 48762306a36Sopenharmony_ci struct sve_state_reg_region region; 48862306a36Sopenharmony_ci char __user *uptr = (char __user *)reg->addr; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */ 49162306a36Sopenharmony_ci if (reg->id == KVM_REG_ARM64_SVE_VLS) 49262306a36Sopenharmony_ci return get_sve_vls(vcpu, reg); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* Try to interpret reg ID as an architectural SVE register... */ 49562306a36Sopenharmony_ci ret = sve_reg_to_region(®ion, vcpu, reg); 49662306a36Sopenharmony_ci if (ret) 49762306a36Sopenharmony_ci return ret; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (!kvm_arm_vcpu_sve_finalized(vcpu)) 50062306a36Sopenharmony_ci return -EPERM; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset, 50362306a36Sopenharmony_ci region.klen) || 50462306a36Sopenharmony_ci clear_user(uptr + region.klen, region.upad)) 50562306a36Sopenharmony_ci return -EFAULT; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return 0; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int set_sve_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci int ret; 51362306a36Sopenharmony_ci struct sve_state_reg_region region; 51462306a36Sopenharmony_ci const char __user *uptr = (const char __user *)reg->addr; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Handle the KVM_REG_ARM64_SVE_VLS pseudo-reg as a special case: */ 51762306a36Sopenharmony_ci if (reg->id == KVM_REG_ARM64_SVE_VLS) 51862306a36Sopenharmony_ci return set_sve_vls(vcpu, reg); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Try to interpret reg ID as an architectural SVE register... */ 52162306a36Sopenharmony_ci ret = sve_reg_to_region(®ion, vcpu, reg); 52262306a36Sopenharmony_ci if (ret) 52362306a36Sopenharmony_ci return ret; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (!kvm_arm_vcpu_sve_finalized(vcpu)) 52662306a36Sopenharmony_ci return -EPERM; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr, 52962306a36Sopenharmony_ci region.klen)) 53062306a36Sopenharmony_ci return -EFAULT; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return -EINVAL; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int copy_core_reg_indices(const struct kvm_vcpu *vcpu, 54662306a36Sopenharmony_ci u64 __user *uindices) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci unsigned int i; 54962306a36Sopenharmony_ci int n = 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) { 55262306a36Sopenharmony_ci u64 reg = KVM_REG_ARM64 | KVM_REG_ARM_CORE | i; 55362306a36Sopenharmony_ci int size = core_reg_size_from_offset(vcpu, i); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (size < 0) 55662306a36Sopenharmony_ci continue; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci switch (size) { 55962306a36Sopenharmony_ci case sizeof(__u32): 56062306a36Sopenharmony_ci reg |= KVM_REG_SIZE_U32; 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci case sizeof(__u64): 56462306a36Sopenharmony_ci reg |= KVM_REG_SIZE_U64; 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci case sizeof(__uint128_t): 56862306a36Sopenharmony_ci reg |= KVM_REG_SIZE_U128; 56962306a36Sopenharmony_ci break; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci default: 57262306a36Sopenharmony_ci WARN_ON(1); 57362306a36Sopenharmony_ci continue; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (uindices) { 57762306a36Sopenharmony_ci if (put_user(reg, uindices)) 57862306a36Sopenharmony_ci return -EFAULT; 57962306a36Sopenharmony_ci uindices++; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci n++; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return n; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic unsigned long num_core_regs(const struct kvm_vcpu *vcpu) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci return copy_core_reg_indices(vcpu, NULL); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic const u64 timer_reg_list[] = { 59462306a36Sopenharmony_ci KVM_REG_ARM_TIMER_CTL, 59562306a36Sopenharmony_ci KVM_REG_ARM_TIMER_CNT, 59662306a36Sopenharmony_ci KVM_REG_ARM_TIMER_CVAL, 59762306a36Sopenharmony_ci KVM_REG_ARM_PTIMER_CTL, 59862306a36Sopenharmony_ci KVM_REG_ARM_PTIMER_CNT, 59962306a36Sopenharmony_ci KVM_REG_ARM_PTIMER_CVAL, 60062306a36Sopenharmony_ci}; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci#define NUM_TIMER_REGS ARRAY_SIZE(timer_reg_list) 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic bool is_timer_reg(u64 index) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci switch (index) { 60762306a36Sopenharmony_ci case KVM_REG_ARM_TIMER_CTL: 60862306a36Sopenharmony_ci case KVM_REG_ARM_TIMER_CNT: 60962306a36Sopenharmony_ci case KVM_REG_ARM_TIMER_CVAL: 61062306a36Sopenharmony_ci case KVM_REG_ARM_PTIMER_CTL: 61162306a36Sopenharmony_ci case KVM_REG_ARM_PTIMER_CNT: 61262306a36Sopenharmony_ci case KVM_REG_ARM_PTIMER_CVAL: 61362306a36Sopenharmony_ci return true; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci return false; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci for (int i = 0; i < NUM_TIMER_REGS; i++) { 62162306a36Sopenharmony_ci if (put_user(timer_reg_list[i], uindices)) 62262306a36Sopenharmony_ci return -EFAULT; 62362306a36Sopenharmony_ci uindices++; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 63262306a36Sopenharmony_ci u64 val; 63362306a36Sopenharmony_ci int ret; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ret = copy_from_user(&val, uaddr, KVM_REG_SIZE(reg->id)); 63662306a36Sopenharmony_ci if (ret != 0) 63762306a36Sopenharmony_ci return -EFAULT; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return kvm_arm_timer_set_reg(vcpu, reg->id, val); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int get_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci void __user *uaddr = (void __user *)(long)reg->addr; 64562306a36Sopenharmony_ci u64 val; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci val = kvm_arm_timer_get_reg(vcpu, reg->id); 64862306a36Sopenharmony_ci return copy_to_user(uaddr, &val, KVM_REG_SIZE(reg->id)) ? -EFAULT : 0; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic unsigned long num_sve_regs(const struct kvm_vcpu *vcpu) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci const unsigned int slices = vcpu_sve_slices(vcpu); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Policed by KVM_GET_REG_LIST: */ 65962306a36Sopenharmony_ci WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci return slices * (SVE_NUM_PREGS + SVE_NUM_ZREGS + 1 /* FFR */) 66262306a36Sopenharmony_ci + 1; /* KVM_REG_ARM64_SVE_VLS */ 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int copy_sve_reg_indices(const struct kvm_vcpu *vcpu, 66662306a36Sopenharmony_ci u64 __user *uindices) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci const unsigned int slices = vcpu_sve_slices(vcpu); 66962306a36Sopenharmony_ci u64 reg; 67062306a36Sopenharmony_ci unsigned int i, n; 67162306a36Sopenharmony_ci int num_regs = 0; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* Policed by KVM_GET_REG_LIST: */ 67762306a36Sopenharmony_ci WARN_ON(!kvm_arm_vcpu_sve_finalized(vcpu)); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Enumerate this first, so that userspace can save/restore in 68162306a36Sopenharmony_ci * the order reported by KVM_GET_REG_LIST: 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_ci reg = KVM_REG_ARM64_SVE_VLS; 68462306a36Sopenharmony_ci if (put_user(reg, uindices++)) 68562306a36Sopenharmony_ci return -EFAULT; 68662306a36Sopenharmony_ci ++num_regs; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci for (i = 0; i < slices; i++) { 68962306a36Sopenharmony_ci for (n = 0; n < SVE_NUM_ZREGS; n++) { 69062306a36Sopenharmony_ci reg = KVM_REG_ARM64_SVE_ZREG(n, i); 69162306a36Sopenharmony_ci if (put_user(reg, uindices++)) 69262306a36Sopenharmony_ci return -EFAULT; 69362306a36Sopenharmony_ci num_regs++; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci for (n = 0; n < SVE_NUM_PREGS; n++) { 69762306a36Sopenharmony_ci reg = KVM_REG_ARM64_SVE_PREG(n, i); 69862306a36Sopenharmony_ci if (put_user(reg, uindices++)) 69962306a36Sopenharmony_ci return -EFAULT; 70062306a36Sopenharmony_ci num_regs++; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci reg = KVM_REG_ARM64_SVE_FFR(i); 70462306a36Sopenharmony_ci if (put_user(reg, uindices++)) 70562306a36Sopenharmony_ci return -EFAULT; 70662306a36Sopenharmony_ci num_regs++; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci return num_regs; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/** 71362306a36Sopenharmony_ci * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * This is for all registers. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_ciunsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci unsigned long res = 0; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci res += num_core_regs(vcpu); 72262306a36Sopenharmony_ci res += num_sve_regs(vcpu); 72362306a36Sopenharmony_ci res += kvm_arm_num_sys_reg_descs(vcpu); 72462306a36Sopenharmony_ci res += kvm_arm_get_fw_num_regs(vcpu); 72562306a36Sopenharmony_ci res += NUM_TIMER_REGS; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return res; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci/** 73162306a36Sopenharmony_ci * kvm_arm_copy_reg_indices - get indices of all registers. 73262306a36Sopenharmony_ci * 73362306a36Sopenharmony_ci * We do core registers right here, then we append system regs. 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ciint kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci int ret; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci ret = copy_core_reg_indices(vcpu, uindices); 74062306a36Sopenharmony_ci if (ret < 0) 74162306a36Sopenharmony_ci return ret; 74262306a36Sopenharmony_ci uindices += ret; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci ret = copy_sve_reg_indices(vcpu, uindices); 74562306a36Sopenharmony_ci if (ret < 0) 74662306a36Sopenharmony_ci return ret; 74762306a36Sopenharmony_ci uindices += ret; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci ret = kvm_arm_copy_fw_reg_indices(vcpu, uindices); 75062306a36Sopenharmony_ci if (ret < 0) 75162306a36Sopenharmony_ci return ret; 75262306a36Sopenharmony_ci uindices += kvm_arm_get_fw_num_regs(vcpu); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = copy_timer_indices(vcpu, uindices); 75562306a36Sopenharmony_ci if (ret < 0) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci uindices += NUM_TIMER_REGS; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci return kvm_arm_copy_sys_reg_indices(vcpu, uindices); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ciint kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci /* We currently use nothing arch-specific in upper 32 bits */ 76562306a36Sopenharmony_ci if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32) 76662306a36Sopenharmony_ci return -EINVAL; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 76962306a36Sopenharmony_ci case KVM_REG_ARM_CORE: return get_core_reg(vcpu, reg); 77062306a36Sopenharmony_ci case KVM_REG_ARM_FW: 77162306a36Sopenharmony_ci case KVM_REG_ARM_FW_FEAT_BMAP: 77262306a36Sopenharmony_ci return kvm_arm_get_fw_reg(vcpu, reg); 77362306a36Sopenharmony_ci case KVM_REG_ARM64_SVE: return get_sve_reg(vcpu, reg); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (is_timer_reg(reg->id)) 77762306a36Sopenharmony_ci return get_timer_reg(vcpu, reg); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return kvm_arm_sys_reg_get_reg(vcpu, reg); 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ciint kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci /* We currently use nothing arch-specific in upper 32 bits */ 78562306a36Sopenharmony_ci if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32) 78662306a36Sopenharmony_ci return -EINVAL; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci switch (reg->id & KVM_REG_ARM_COPROC_MASK) { 78962306a36Sopenharmony_ci case KVM_REG_ARM_CORE: return set_core_reg(vcpu, reg); 79062306a36Sopenharmony_ci case KVM_REG_ARM_FW: 79162306a36Sopenharmony_ci case KVM_REG_ARM_FW_FEAT_BMAP: 79262306a36Sopenharmony_ci return kvm_arm_set_fw_reg(vcpu, reg); 79362306a36Sopenharmony_ci case KVM_REG_ARM64_SVE: return set_sve_reg(vcpu, reg); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (is_timer_reg(reg->id)) 79762306a36Sopenharmony_ci return set_timer_reg(vcpu, reg); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return kvm_arm_sys_reg_set_reg(vcpu, reg); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, 80362306a36Sopenharmony_ci struct kvm_sregs *sregs) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci return -EINVAL; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, 80962306a36Sopenharmony_ci struct kvm_sregs *sregs) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci return -EINVAL; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ciint __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu, 81562306a36Sopenharmony_ci struct kvm_vcpu_events *events) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE); 81862306a36Sopenharmony_ci events->exception.serror_has_esr = cpus_have_const_cap(ARM64_HAS_RAS_EXTN); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (events->exception.serror_pending && events->exception.serror_has_esr) 82162306a36Sopenharmony_ci events->exception.serror_esr = vcpu_get_vsesr(vcpu); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* 82462306a36Sopenharmony_ci * We never return a pending ext_dabt here because we deliver it to 82562306a36Sopenharmony_ci * the virtual CPU directly when setting the event and it's no longer 82662306a36Sopenharmony_ci * 'pending' at this point. 82762306a36Sopenharmony_ci */ 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci return 0; 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ciint __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, 83362306a36Sopenharmony_ci struct kvm_vcpu_events *events) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci bool serror_pending = events->exception.serror_pending; 83662306a36Sopenharmony_ci bool has_esr = events->exception.serror_has_esr; 83762306a36Sopenharmony_ci bool ext_dabt_pending = events->exception.ext_dabt_pending; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (serror_pending && has_esr) { 84062306a36Sopenharmony_ci if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) 84162306a36Sopenharmony_ci return -EINVAL; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (!((events->exception.serror_esr) & ~ESR_ELx_ISS_MASK)) 84462306a36Sopenharmony_ci kvm_set_sei_esr(vcpu, events->exception.serror_esr); 84562306a36Sopenharmony_ci else 84662306a36Sopenharmony_ci return -EINVAL; 84762306a36Sopenharmony_ci } else if (serror_pending) { 84862306a36Sopenharmony_ci kvm_inject_vabt(vcpu); 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci if (ext_dabt_pending) 85262306a36Sopenharmony_ci kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu)); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return 0; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ciu32 __attribute_const__ kvm_target_cpu(void) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci unsigned long implementor = read_cpuid_implementor(); 86062306a36Sopenharmony_ci unsigned long part_number = read_cpuid_part_number(); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci switch (implementor) { 86362306a36Sopenharmony_ci case ARM_CPU_IMP_ARM: 86462306a36Sopenharmony_ci switch (part_number) { 86562306a36Sopenharmony_ci case ARM_CPU_PART_AEM_V8: 86662306a36Sopenharmony_ci return KVM_ARM_TARGET_AEM_V8; 86762306a36Sopenharmony_ci case ARM_CPU_PART_FOUNDATION: 86862306a36Sopenharmony_ci return KVM_ARM_TARGET_FOUNDATION_V8; 86962306a36Sopenharmony_ci case ARM_CPU_PART_CORTEX_A53: 87062306a36Sopenharmony_ci return KVM_ARM_TARGET_CORTEX_A53; 87162306a36Sopenharmony_ci case ARM_CPU_PART_CORTEX_A57: 87262306a36Sopenharmony_ci return KVM_ARM_TARGET_CORTEX_A57; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci break; 87562306a36Sopenharmony_ci case ARM_CPU_IMP_APM: 87662306a36Sopenharmony_ci switch (part_number) { 87762306a36Sopenharmony_ci case APM_CPU_PART_XGENE: 87862306a36Sopenharmony_ci return KVM_ARM_TARGET_XGENE_POTENZA; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* Return a default generic target */ 88462306a36Sopenharmony_ci return KVM_ARM_TARGET_GENERIC_V8; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci return -EINVAL; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, 89862306a36Sopenharmony_ci struct kvm_translation *tr) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci return -EINVAL; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci/** 90462306a36Sopenharmony_ci * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging 90562306a36Sopenharmony_ci * @kvm: pointer to the KVM struct 90662306a36Sopenharmony_ci * @kvm_guest_debug: the ioctl data buffer 90762306a36Sopenharmony_ci * 90862306a36Sopenharmony_ci * This sets up and enables the VM for guest debugging. Userspace 90962306a36Sopenharmony_ci * passes in a control flag to enable different debug types and 91062306a36Sopenharmony_ci * potentially other architecture specific information in the rest of 91162306a36Sopenharmony_ci * the structure. 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, 91462306a36Sopenharmony_ci struct kvm_guest_debug *dbg) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci int ret = 0; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci trace_kvm_set_guest_debug(vcpu, dbg->control); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) { 92162306a36Sopenharmony_ci ret = -EINVAL; 92262306a36Sopenharmony_ci goto out; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (dbg->control & KVM_GUESTDBG_ENABLE) { 92662306a36Sopenharmony_ci vcpu->guest_debug = dbg->control; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* Hardware assisted Break and Watch points */ 92962306a36Sopenharmony_ci if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { 93062306a36Sopenharmony_ci vcpu->arch.external_debug_state = dbg->arch; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci } else { 93462306a36Sopenharmony_ci /* If not enabled clear all flags */ 93562306a36Sopenharmony_ci vcpu->guest_debug = 0; 93662306a36Sopenharmony_ci vcpu_clear_flag(vcpu, DBG_SS_ACTIVE_PENDING); 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ciout: 94062306a36Sopenharmony_ci return ret; 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ciint kvm_arm_vcpu_arch_set_attr(struct kvm_vcpu *vcpu, 94462306a36Sopenharmony_ci struct kvm_device_attr *attr) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci int ret; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci switch (attr->group) { 94962306a36Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 95062306a36Sopenharmony_ci mutex_lock(&vcpu->kvm->arch.config_lock); 95162306a36Sopenharmony_ci ret = kvm_arm_pmu_v3_set_attr(vcpu, attr); 95262306a36Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.config_lock); 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 95562306a36Sopenharmony_ci ret = kvm_arm_timer_set_attr(vcpu, attr); 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 95862306a36Sopenharmony_ci ret = kvm_arm_pvtime_set_attr(vcpu, attr); 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci default: 96162306a36Sopenharmony_ci ret = -ENXIO; 96262306a36Sopenharmony_ci break; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return ret; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ciint kvm_arm_vcpu_arch_get_attr(struct kvm_vcpu *vcpu, 96962306a36Sopenharmony_ci struct kvm_device_attr *attr) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci int ret; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci switch (attr->group) { 97462306a36Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 97562306a36Sopenharmony_ci ret = kvm_arm_pmu_v3_get_attr(vcpu, attr); 97662306a36Sopenharmony_ci break; 97762306a36Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 97862306a36Sopenharmony_ci ret = kvm_arm_timer_get_attr(vcpu, attr); 97962306a36Sopenharmony_ci break; 98062306a36Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 98162306a36Sopenharmony_ci ret = kvm_arm_pvtime_get_attr(vcpu, attr); 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci default: 98462306a36Sopenharmony_ci ret = -ENXIO; 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci return ret; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ciint kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, 99262306a36Sopenharmony_ci struct kvm_device_attr *attr) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci int ret; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci switch (attr->group) { 99762306a36Sopenharmony_ci case KVM_ARM_VCPU_PMU_V3_CTRL: 99862306a36Sopenharmony_ci ret = kvm_arm_pmu_v3_has_attr(vcpu, attr); 99962306a36Sopenharmony_ci break; 100062306a36Sopenharmony_ci case KVM_ARM_VCPU_TIMER_CTRL: 100162306a36Sopenharmony_ci ret = kvm_arm_timer_has_attr(vcpu, attr); 100262306a36Sopenharmony_ci break; 100362306a36Sopenharmony_ci case KVM_ARM_VCPU_PVTIME_CTRL: 100462306a36Sopenharmony_ci ret = kvm_arm_pvtime_has_attr(vcpu, attr); 100562306a36Sopenharmony_ci break; 100662306a36Sopenharmony_ci default: 100762306a36Sopenharmony_ci ret = -ENXIO; 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci return ret; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ciint kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, 101562306a36Sopenharmony_ci struct kvm_arm_copy_mte_tags *copy_tags) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci gpa_t guest_ipa = copy_tags->guest_ipa; 101862306a36Sopenharmony_ci size_t length = copy_tags->length; 101962306a36Sopenharmony_ci void __user *tags = copy_tags->addr; 102062306a36Sopenharmony_ci gpa_t gfn; 102162306a36Sopenharmony_ci bool write = !(copy_tags->flags & KVM_ARM_TAGS_FROM_GUEST); 102262306a36Sopenharmony_ci int ret = 0; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (!kvm_has_mte(kvm)) 102562306a36Sopenharmony_ci return -EINVAL; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (copy_tags->reserved[0] || copy_tags->reserved[1]) 102862306a36Sopenharmony_ci return -EINVAL; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (copy_tags->flags & ~KVM_ARM_TAGS_FROM_GUEST) 103162306a36Sopenharmony_ci return -EINVAL; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (length & ~PAGE_MASK || guest_ipa & ~PAGE_MASK) 103462306a36Sopenharmony_ci return -EINVAL; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* Lengths above INT_MAX cannot be represented in the return value */ 103762306a36Sopenharmony_ci if (length > INT_MAX) 103862306a36Sopenharmony_ci return -EINVAL; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci gfn = gpa_to_gfn(guest_ipa); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci mutex_lock(&kvm->slots_lock); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci while (length > 0) { 104562306a36Sopenharmony_ci kvm_pfn_t pfn = gfn_to_pfn_prot(kvm, gfn, write, NULL); 104662306a36Sopenharmony_ci void *maddr; 104762306a36Sopenharmony_ci unsigned long num_tags; 104862306a36Sopenharmony_ci struct page *page; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (is_error_noslot_pfn(pfn)) { 105162306a36Sopenharmony_ci ret = -EFAULT; 105262306a36Sopenharmony_ci goto out; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci page = pfn_to_online_page(pfn); 105662306a36Sopenharmony_ci if (!page) { 105762306a36Sopenharmony_ci /* Reject ZONE_DEVICE memory */ 105862306a36Sopenharmony_ci ret = -EFAULT; 105962306a36Sopenharmony_ci goto out; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci maddr = page_address(page); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (!write) { 106462306a36Sopenharmony_ci if (page_mte_tagged(page)) 106562306a36Sopenharmony_ci num_tags = mte_copy_tags_to_user(tags, maddr, 106662306a36Sopenharmony_ci MTE_GRANULES_PER_PAGE); 106762306a36Sopenharmony_ci else 106862306a36Sopenharmony_ci /* No tags in memory, so write zeros */ 106962306a36Sopenharmony_ci num_tags = MTE_GRANULES_PER_PAGE - 107062306a36Sopenharmony_ci clear_user(tags, MTE_GRANULES_PER_PAGE); 107162306a36Sopenharmony_ci kvm_release_pfn_clean(pfn); 107262306a36Sopenharmony_ci } else { 107362306a36Sopenharmony_ci /* 107462306a36Sopenharmony_ci * Only locking to serialise with a concurrent 107562306a36Sopenharmony_ci * set_pte_at() in the VMM but still overriding the 107662306a36Sopenharmony_ci * tags, hence ignoring the return value. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_ci try_page_mte_tagging(page); 107962306a36Sopenharmony_ci num_tags = mte_copy_tags_from_user(maddr, tags, 108062306a36Sopenharmony_ci MTE_GRANULES_PER_PAGE); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* uaccess failed, don't leave stale tags */ 108362306a36Sopenharmony_ci if (num_tags != MTE_GRANULES_PER_PAGE) 108462306a36Sopenharmony_ci mte_clear_page_tags(maddr); 108562306a36Sopenharmony_ci set_page_mte_tagged(page); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci kvm_release_pfn_dirty(pfn); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (num_tags != MTE_GRANULES_PER_PAGE) { 109162306a36Sopenharmony_ci ret = -EFAULT; 109262306a36Sopenharmony_ci goto out; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci gfn++; 109662306a36Sopenharmony_ci tags += num_tags; 109762306a36Sopenharmony_ci length -= PAGE_SIZE; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciout: 110162306a36Sopenharmony_ci mutex_unlock(&kvm->slots_lock); 110262306a36Sopenharmony_ci /* If some data has been copied report the number of bytes copied */ 110362306a36Sopenharmony_ci if (length != copy_tags->length) 110462306a36Sopenharmony_ci return copy_tags->length - length; 110562306a36Sopenharmony_ci return ret; 110662306a36Sopenharmony_ci} 1107