From patchwork Wed Nov 17 06:43:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12692829 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1AC39C433EF for ; Wed, 17 Nov 2021 06:51:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D397F61BF5 for ; Wed, 17 Nov 2021 06:51:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org D397F61BF5 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=eCT2VWwKH/3GxAU6AUEiEOq+F5Z7OWhSbjm6iDprZmk=; b=rN2ZBsOqPeNBKwuMloX6k+Aqkd Tqu5mCj/l2MuXTSzg/P6JAsDxm428mDIEftERsroHXJ5WLqp0qmKSlGk3Acz3z3BhBxuxNZ63Rcwq 0zCzPOupizRQ+NFRkNM3CTE4h4JHi5gtB9ZwgktAqzskfI6aD4tDp+zg/ibWVdSMFw4tnqnqgvDD1 //OSUfT1iOsSp5M0PAWRP9Vjnk2BHqb7V7nM4HZMTS6ApBZzyEfAO5e2aQRa3N/SeuKlYE0dMJlCU N/aJevnkUUtleqLphX31nKi3MWYaKNyhAuGCEAhXQgtGQi4pR30kE8GzfCMH+S4+VCRXF2D25ITZv czO692Vg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mnElg-003YDl-Cf; Wed, 17 Nov 2021 06:50:04 +0000 Received: from mail-pg1-x549.google.com ([2607:f8b0:4864:20::549]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mnElY-003YB7-FX for linux-arm-kernel@lists.infradead.org; Wed, 17 Nov 2021 06:50:01 +0000 Received: by mail-pg1-x549.google.com with SMTP id n22-20020a6563d6000000b0029261ffde9bso692980pgv.22 for ; Tue, 16 Nov 2021 22:49:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=pnVV0dDUXWANaZ8aWNvfjhrF5PhVCI804E2zH0wOM3E=; b=ceapl6AvPZI3/vC2mwRnLl7KjxDguO+n/2FhAKPMEsWeJcr6nh2z5ML5Zyspn+X+oi eOG5b9oMdf4M0ijZrTl3BB+twEpz7SLT3PQGPwwee7YEWvqiKhz4kpHkQkPFScEOubhh PHmDRXKLhg8b0bK463OW3zcR6hYneuOfXGsKWWo0vpCxB5Qab3vX428m4V6U9V6ADRMU LHifHn8XYOmf6vtXXDBZNhcbWng3mx7aesw+zV7tK1qcFe0GJ3Eed3XMfN+CafmGWV7W 3nbmgaPA40qIFpGunX/KR6GztN7/vjVwbUY5DsFDQ2Av8jeR4NKCYgtkakr8LNjARLVp VoQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=pnVV0dDUXWANaZ8aWNvfjhrF5PhVCI804E2zH0wOM3E=; b=ZYD2d3A/xflpn+EKn4NXdXOwW5UCUsPC96iz+zUrTQ1y0y7UM6EX+JkW8jmoR5Fr8n yLoizi+zvqYzSxW3gm2iSgYiVOxKixCzZktja+Tq6mdueVF4trMH4/O5PaEnQaSt5sXn x12zfIDmfsirYjYoslDsB+7oq1isDs2PyT8mOPb/Ey3rWjgpQS6VzDOvefFw2T/9JHES m+HnEeXXo3/zXa+io+1SWPbELflMV8zOsaAdzmsjYg4cW51UX5byLN/Y/kfhXPK6Si63 UaxyIHMHAO6L0gPq7IXbZc+pjR3fw5SG3tbtUp1uZVenfKGSKM4Gx9T3InmswyLcsat7 TzRw== X-Gm-Message-State: AOAM532a371SufXipRoNu8KM1/PKsrmmqS8t+IlUGeKORqamHwKdSJFu GU9u0kXr1vPIcmV6F0xstVBFyiAbRvY= X-Google-Smtp-Source: ABdhPJyGFmsrlVNrwecF2T+roRV3vrXO6UsZB0R8DGqP/IeotHb/4HF1tiOSvziAZ09+qdqIbL0UHS+Zs7Q= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:903:408c:b0:142:45a9:672c with SMTP id z12-20020a170903408c00b0014245a9672cmr51484560plc.7.1637131794924; Tue, 16 Nov 2021 22:49:54 -0800 (PST) Date: Tue, 16 Nov 2021 22:43:34 -0800 In-Reply-To: <20211117064359.2362060-1-reijiw@google.com> Message-Id: <20211117064359.2362060-5-reijiw@google.com> Mime-Version: 1.0 References: <20211117064359.2362060-1-reijiw@google.com> X-Mailer: git-send-email 2.34.0.rc1.387.gb447b232ab-goog Subject: [RFC PATCH v3 04/29] KVM: arm64: Make ID_AA64PFR0_EL1 writable From: Reiji Watanabe To: Marc Zyngier , kvmarm@lists.cs.columbia.edu Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org, James Morse , Alexandru Elisei , Suzuki K Poulose , Paolo Bonzini , Will Deacon , Andrew Jones , Peng Liang , Peter Shier , Ricardo Koller , Oliver Upton , Jing Zhang , Raghavendra Rao Anata , Reiji Watanabe X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211116_224956_580737_9B143FA3 X-CRM114-Status: GOOD ( 24.04 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This patch adds id_reg_info for ID_AA64PFR0_EL1 to make it writable by userspace. The CSV2/CSV3 fields of the register were already writable and values that were written for them affected all vCPUs before. Now they only affect the vCPU. Return an error if userspace tries to set SVE/GIC field of the register to a value that conflicts with SVE/GIC configuration for the guest. SIMD/FP/SVE fields of the requested value are validated according to Arm ARM. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 159 ++++++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 56 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 1552cd5581b7..35400869067a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -401,6 +401,92 @@ static void id_reg_info_init(struct id_reg_info *id_reg) id_reg->init(id_reg); } +#define kvm_has_gic3(kvm) \ + (irqchip_in_kernel(kvm) && \ + (kvm)->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) + +static int validate_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_info *id_reg, u64 val) +{ + int fp, simd; + bool vcpu_has_sve = vcpu_has_sve(vcpu); + bool pfr0_has_sve = id_aa64pfr0_sve(val); + int gic; + + simd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); + if (simd != fp) + return -EINVAL; + + /* fp must be supported when sve is supported */ + if (pfr0_has_sve && (fp < 0)) + return -EINVAL; + + /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT */ + if (vcpu_has_sve ^ pfr0_has_sve) + return -EPERM; + + gic = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_GIC_SHIFT); + if ((gic > 0) ^ kvm_has_gic3(vcpu->kvm)) + return -EPERM; + + return 0; +} + +static void init_id_aa64pfr0_el1_info(struct id_reg_info *id_reg) +{ + u64 limit = id_reg->vcpu_limit_val; + unsigned int gic; + + limit &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_AMU); + if (!system_supports_sve()) + limit &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); + + /* + * The default is to expose CSV2 == 1 and CSV3 == 1 if the HW + * isn't affected. Userspace can override this as long as it + * doesn't promise the impossible. + */ + limit &= ~(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2) | + ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3)); + + if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED) + limit |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2), 1); + if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED) + limit |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3), 1); + + gic = cpuid_feature_extract_unsigned_field(limit, ID_AA64PFR0_GIC_SHIFT); + if (gic > 1) { + /* Limit to GICv3.0/4.0 */ + limit &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_GIC); + limit |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_GIC), 1); + } + id_reg->vcpu_limit_val = limit; +} + +static u64 get_reset_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_info *idr) +{ + u64 val = idr->vcpu_limit_val; + + if (!vcpu_has_sve(vcpu)) + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); + + if (!kvm_has_gic3(vcpu->kvm)) + val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_GIC); + + return val; +} + +static struct id_reg_info id_aa64pfr0_el1_info = { + .sys_reg = SYS_ID_AA64PFR0_EL1, + .ftr_check_types = S_FCT(ID_AA64PFR0_ASIMD_SHIFT, FCT_LOWER_SAFE) | + S_FCT(ID_AA64PFR0_FP_SHIFT, FCT_LOWER_SAFE), + .init = init_id_aa64pfr0_el1_info, + .validate = validate_id_aa64pfr0_el1, + .get_reset_val = get_reset_id_aa64pfr0_el1, +}; + /* * An ID register that needs special handling to control the value for the * guest must have its own id_reg_info in id_reg_info_table. @@ -409,7 +495,9 @@ static void id_reg_info_init(struct id_reg_info *id_reg) * validation, etc.) */ #define GET_ID_REG_INFO(id) (id_reg_info_table[IDREG_IDX(id)]) -static struct id_reg_info *id_reg_info_table[KVM_ARM_ID_REG_MAX_NUM] = {}; +static struct id_reg_info *id_reg_info_table[KVM_ARM_ID_REG_MAX_NUM] = { + [IDREG_IDX(SYS_ID_AA64PFR0_EL1)] = &id_aa64pfr0_el1_info, +}; static int validate_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 val) @@ -1239,20 +1327,22 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, static u64 __read_id_reg(const struct kvm_vcpu *vcpu, u32 id) { u64 val = __vcpu_sys_reg(vcpu, IDREG_SYS_IDX(id)); + u64 lim, gic, gic_lim; + const struct id_reg_info *id_reg; switch (id) { case SYS_ID_AA64PFR0_EL1: - if (!vcpu_has_sve(vcpu)) - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_AMU); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2), (u64)vcpu->kvm->arch.pfr0_csv2); - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3), (u64)vcpu->kvm->arch.pfr0_csv3); - if (irqchip_in_kernel(vcpu->kvm) && - vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) { - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_GIC); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_GIC), 1); + gic = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_GIC_SHIFT); + if (kvm_has_gic3(vcpu->kvm) && (gic == 0)) { + /* + * This is a case where userspace configured gic3 after + * the vcpu was created, and then it didn't set + * ID_AA64PFR0_EL1. + */ + id_reg = GET_ID_REG_INFO(id); + lim = id_reg->vcpu_limit_val; + gic_lim = cpuid_feature_extract_unsigned_field(lim, ID_AA64PFR0_GIC_SHIFT); + val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_GIC), gic_lim); } break; case SYS_ID_AA64PFR1_EL1: @@ -1373,48 +1463,6 @@ static void reset_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd) __vcpu_sys_reg(vcpu, IDREG_SYS_IDX(id)) = val; } -static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, - const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) -{ - const u64 id = sys_reg_to_index(rd); - u8 csv2, csv3; - int err; - u64 val; - - err = reg_from_user(&val, uaddr, id); - if (err) - return err; - - /* - * Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as - * it doesn't promise more than what is actually provided (the - * guest could otherwise be covered in ectoplasmic residue). - */ - csv2 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_CSV2_SHIFT); - if (csv2 > 1 || - (csv2 && arm64_get_spectre_v2_state() != SPECTRE_UNAFFECTED)) - return -EINVAL; - - /* Same thing for CSV3 */ - csv3 = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR0_CSV3_SHIFT); - if (csv3 > 1 || - (csv3 && arm64_get_meltdown_state() != SPECTRE_UNAFFECTED)) - return -EINVAL; - - /* We can only differ with CSV[23], and anything else is an error */ - val ^= read_id_reg(vcpu, rd, false); - val &= ~((0xFUL << ID_AA64PFR0_CSV2_SHIFT) | - (0xFUL << ID_AA64PFR0_CSV3_SHIFT)); - if (val) - return -EINVAL; - - vcpu->kvm->arch.pfr0_csv2 = csv2; - vcpu->kvm->arch.pfr0_csv3 = csv3 ; - - return 0; -} - /* cpufeature ID register user accessors */ static int __get_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, @@ -1705,8 +1753,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* AArch64 ID registers */ /* CRm=4 */ - { SYS_DESC(SYS_ID_AA64PFR0_EL1), .access = access_id_reg, - .get_user = get_id_reg, .set_user = set_id_aa64pfr0_el1, }, + ID_SANITISED(ID_AA64PFR0_EL1), ID_SANITISED(ID_AA64PFR1_EL1), ID_UNALLOCATED(4,2), ID_UNALLOCATED(4,3),