From patchwork Fri Mar 11 04:47:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777398 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 3ECF9C433EF for ; Fri, 11 Mar 2022 04:51:33 +0000 (UTC) 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=g3KM6oWEiXbXFL5bYmgkd8eP8Zm4UyQtWtcP96Oo6No=; b=bVfytz6FMtrWGvHjjOecqTd6LU 31C6GkDiqng7EAAZLAnKjLdDGcp2q0nWvMpT6rcQWjXLUkdF+kdK7Wp3oFcn6+Ai9jAXQtaNG1UFm 7guek7IVS9bRnMFvkmJn4rdMIfoG8loWKmdZKGU1jYXoY+LARFIyWDqjWS529NMvKlvvDxWMjAWXX M8kqtZ0jPP5Ejhqhk+WDA+LYxzRKjcV2QAr+nE0YuR9UEycVieX8NVMNNOHPFjkScZmd2+B44fpNM Gz7Mx1FqgSq6qWhgUPxOvUOUQoT5GPBT9DX4H954aQLlC1LocFG3x1rXRMm4ltMQqbMnqXCIoVaDv WNENwg7g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDO-00Ezy7-Mj; Fri, 11 Mar 2022 04:49:23 +0000 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCg-00EzVf-PT for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:42 +0000 Received: by mail-pl1-x64a.google.com with SMTP id e7-20020a170902ef4700b00151de30039bso3916944plx.17 for ; Thu, 10 Mar 2022 20:48:34 -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=glthwEK6ZgvlT5BCv3FygX03+dB4t3Wompz6ZLZl/V4=; b=oviYyd1hL6FXW8xYwUit8H/JinCSV5FQkoO3lcvrchXcQFvfEiSq1X3c9NPTP7/j9d qTg5Fl6CX7dEBMl+88l0cCWi2zq0tyvG3mtfS4gFalQJ0YwYzamZ86x01f6n3pq0dXyp vN0gbdRRdKvSFLmojQIab9Ya9ZYaOVtOFX9HQGKJkllCYLQExOkmgw5HewYzzsahrafn Aj1lUK0Dn4B8o6PJ6V3opL61uVO2pHF8po63kJVpRRIW+y2oMBBP5J4hx7OgyirSpHT+ QIN7GB2gBKoDJFzJ9Z07xJKB24YK8XhJ7zVVeaQdV9vLEBdDkylJajXhrEPlQ/t5qrWr vUiw== 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=glthwEK6ZgvlT5BCv3FygX03+dB4t3Wompz6ZLZl/V4=; b=pR1iu92HYZd7Faqx2boSI670lOEoTucMawvHkGd7Mlkj0FZY/8DlezDx3RrcSIYQ3M ikvwS97tYlZnANT6WRa9v/sOtjDMOiJQWj5EiINRWuqZ8v89QQMZES0JkVnQXHmx5dyN TVPxjxI8SJldOkTH7g8lv9/HoQ4ICCd7cpkppmvfRajAEC/2aad+pQTCx315GzfN6NF+ V99MRuMh+qCZms8c4BLwJJWfeJ72Z/xqj+0zFum599BZ9ZW5PKtq9RkmyhMU7Sah77s7 yqUF9VJjCgMohD7Oclf+5VsVUp/AAuq4mnbe0pnCaUHijNi9Kb9dYHD0j9HvJVEyVqt4 bSSQ== X-Gm-Message-State: AOAM530OflKvO2F5rSwJ/mCNedoCnaHtBsmfTzNpustdOoewyJQbYnO/ auMeZoKnYseghELwjfU22PeVGtJDFN4= X-Google-Smtp-Source: ABdhPJyDl7llyO11kbEl8dR7kC5MFAqZY1r0+1cYoSOlTioTkSnQq8vl9f4N+JpB633eoMtJSJWLqXRsVXU= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:9043:b0:14f:aa08:8497 with SMTP id w3-20020a170902904300b0014faa088497mr8396367plz.109.1646974113545; Thu, 10 Mar 2022 20:48:33 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:47 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-2-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 01/25] KVM: arm64: Introduce a validation function for an ID register 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 , Fuad Tabba , 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-20220310_204838_888540_5E9FF9A1 X-CRM114-Status: GOOD ( 31.46 ) 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 Introduce arm64_check_features(), which does a basic validity checking of an ID register value against the register's limit value, which is generally the host's sanitized value. This function will be used by the following patches to check if an ID register value that userspace tries to set for a guest can be supported on the host. The validation is done using arm64_ftr_bits_kvm, which is created from arm64_ftr_regs, with some entries overwritten by entries from arm64_ftr_bits_kvm_override. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 229 ++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index ef6be92b1921..a9edf1ca7dcb 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -631,6 +631,7 @@ void check_local_cpu_capabilities(void); u64 read_sanitised_ftr_reg(u32 id); u64 __read_sysreg_by_encoding(u32 sys_id); +int arm64_check_features_kvm(u32 sys_reg, u64 val, u64 limit); static inline bool cpu_supports_mixed_endian_el0(void) { diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index e5f23dab1c8d..bc0ed09aa1b5 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -928,6 +928,10 @@ static void init_32bit_cpu_features(struct cpuinfo_32bit *info) init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2); } +#ifdef CONFIG_KVM +static void init_arm64_ftr_bits_kvm(void); +#endif + void __init init_cpu_features(struct cpuinfo_arm64 *info) { /* Before we start using the tables, make sure it is sorted */ @@ -970,6 +974,14 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) * after we have initialised the CPU feature infrastructure. */ setup_boot_cpu_capabilities(); + +#ifdef CONFIG_KVM + /* + * Initialize arm64_ftr_bits_kvm, which will be used to provide + * KVM with general feature checking for its guests. + */ + init_arm64_ftr_bits_kvm(); +#endif } static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new) @@ -3156,3 +3168,220 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, return sprintf(buf, "Vulnerable\n"); } } + +#ifdef CONFIG_KVM +/* + * arm64_ftr_bits_kvm[] is used for KVM to check if features that are + * indicated in an ID register value for the guest are available on the host. + * arm64_ftr_bits_kvm[] is created based on arm64_ftr_regs[]. But, for + * registers for which arm64_ftr_bits_kvm_override[] has a corresponding + * entry, replace arm64_ftr_bits entries in arm64_ftr_bits_kvm[] with the + * ones in arm64_ftr_bits_kvm_override[]. + * + * What to add to arm64_ftr_bits_kvm_override[] shouldn't be decided according + * to KVM's implementation, but according to schemes of ID register fields. + * (e.g. For ID_AA64DFR0_EL1.PMUVER, a higher value on the field indicates + * more features. So, the arm64_ftr_bits' type for the field can be + * FTR_LOWER_SAFE instead of FTR_EXACT unlike arm64_ftr_regs) + */ + +/* + * The number of __ftr_reg_bits_entry entries in arm64_ftr_bits_kvm must be + * the same as the number of __ftr_reg_entry entries in arm64_ftr_regs. + */ +static struct __ftr_reg_bits_entry { + u32 sys_id; + struct arm64_ftr_bits *ftr_bits; +} arm64_ftr_bits_kvm[ARRAY_SIZE(arm64_ftr_regs)]; + +/* + * Number of arm64_ftr_bits entries for each register. + * (Number of 4 bits fields in 64 bit register + 1 entry for ARM64_FTR_END) + */ +#define MAX_FTR_BITS_LEN 17 + +/* Use FTR_LOWER_SAFE for AA64DFR0_EL1.PMUVER and AA64DFR0_EL1.DEBUGVER. */ +static struct arm64_ftr_bits ftr_id_aa64dfr0_kvm[MAX_FTR_BITS_LEN] = { + S_ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64DFR0_PMUVER_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6), + ARM64_FTR_END, +}; + +#define ARM64_FTR_REG_BITS(id, table) { \ + .sys_id = id, \ + .ftr_bits = &((table)[0]), \ +} + +/* + * All entries in arm64_ftr_bits_kvm_override[] are used to override + * the corresponding entries in arm64_ftr_bits_kvm[]. + */ +static struct __ftr_reg_bits_entry arm64_ftr_bits_kvm_override[] = { + ARM64_FTR_REG_BITS(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0_kvm), +}; + +/* + * Override entries in @orig_ftrp with the ones in @new_ftrp when their shift + * fields match. The last entry of @orig_ftrp and @new_ftrp must be + * ARM64_FTR_END (.width == 0). + */ +static void arm64_ftr_reg_bits_override(struct arm64_ftr_bits *orig_ftrp, + const struct arm64_ftr_bits *new_ftrp) +{ + const struct arm64_ftr_bits *n_ftrp; + struct arm64_ftr_bits *o_ftrp; + + for (n_ftrp = new_ftrp; n_ftrp->width; n_ftrp++) { + for (o_ftrp = orig_ftrp; o_ftrp->width; o_ftrp++) { + if (o_ftrp->shift == n_ftrp->shift) { + *o_ftrp = *n_ftrp; + break; + } + } + } +} + +/* + * Copy arm64_ftr_bits entries from @src_ftrp to @dst_ftrp. The last entries + * of @dst_ftrp and @src_ftrp must be ARM64_FTR_END (.width == 0). + */ +static void copy_arm64_ftr_bits(struct arm64_ftr_bits *dst_ftrp, + const struct arm64_ftr_bits *src_ftrp) +{ + int i = 0; + + for (; src_ftrp[i].width; i++) { + if (WARN_ON_ONCE(i >= (MAX_FTR_BITS_LEN - 1))) + break; + + dst_ftrp[i] = src_ftrp[i]; + } + + dst_ftrp[i].width = 0; +} + +/* + * Initialize arm64_ftr_bits_kvm. Copy arm64_ftr_bits for each ID register + * from arm64_ftr_regs to arm64_ftr_bits_kvm, and then override entries in + * arm64_ftr_bits_kvm with ones in arm64_ftr_bits_kvm_override. + */ +static void init_arm64_ftr_bits_kvm(void) +{ + struct arm64_ftr_bits ftr_temp[MAX_FTR_BITS_LEN]; + static struct __ftr_reg_bits_entry *bits, *o_bits; + int i, j; + + /* Copy entries from arm64_ftr_regs to arm64_ftr_bits_kvm */ + for (i = 0; i < ARRAY_SIZE(arm64_ftr_bits_kvm); i++) { + bits = &arm64_ftr_bits_kvm[i]; + bits->sys_id = arm64_ftr_regs[i].sys_id; + bits->ftr_bits = (struct arm64_ftr_bits *)arm64_ftr_regs[i].reg->ftr_bits; + }; + + /* + * Override the entries in arm64_ftr_bits_kvm with the ones in + * arm64_ftr_bits_kvm_override. + */ + for (i = 0; i < ARRAY_SIZE(arm64_ftr_bits_kvm_override); i++) { + o_bits = &arm64_ftr_bits_kvm_override[i]; + for (j = 0; j < ARRAY_SIZE(arm64_ftr_bits_kvm); j++) { + bits = &arm64_ftr_bits_kvm[j]; + if (bits->sys_id != o_bits->sys_id) + continue; + + /* + * The code below tries to sustain the ordering of + * entries in bits even in o_bits, just in case + * arm64_ftr_bits entries in arm64_ftr_regs have + * any ordering requirements in the future (so that + * the ones in arm64_ftr_bits_kvm_override doesn't + * have to care). + * So, rather than directly copying them to empty + * slots in o_bits, the code simply copies entries + * from bits to o_bits first, then overrides them with + * original entries in o_bits. + */ + memset(ftr_temp, 0, sizeof(ftr_temp)); + + /* + * Temporary save all entries in o_bits->ftr_bits + * to ftr_temp. + */ + copy_arm64_ftr_bits(ftr_temp, o_bits->ftr_bits); + + /* + * Copy entries from bits->ftr_bits to o_bits->ftr_bits. + */ + copy_arm64_ftr_bits(o_bits->ftr_bits, bits->ftr_bits); + + /* + * Override entries in o_bits->ftr_bits with the + * saved ones, and update bits->ftr_bits with + * o_bits->ftr_bits. + */ + arm64_ftr_reg_bits_override(o_bits->ftr_bits, ftr_temp); + bits->ftr_bits = o_bits->ftr_bits; + break; + } + } +} + +static int search_cmp_ftr_reg_bits(const void *id, const void *regp) +{ + return ((int)(unsigned long)id - + (int)((const struct __ftr_reg_bits_entry *)regp)->sys_id); +} + +static const struct arm64_ftr_bits *get_arm64_ftr_bits_kvm(u32 sys_id) +{ + const struct __ftr_reg_bits_entry *ret; + + ret = bsearch((const void *)(unsigned long)sys_id, + arm64_ftr_bits_kvm, + ARRAY_SIZE(arm64_ftr_bits_kvm), + sizeof(arm64_ftr_bits_kvm[0]), + search_cmp_ftr_reg_bits); + if (ret) + return ret->ftr_bits; + + return NULL; +} + +/* + * Check if features (or levels of features) that are indicated in the ID + * register value @val are also indicated in @limit. + * This function is for KVM to check if features that are indicated in @val, + * which will be used as the ID register value for its guest, are supported + * on the host. + * For AA64MMFR0_EL1.TGranX_2 fields, which don't follow the standard ID + * scheme, the function checks if values of the fields in @val are the same + * as the ones in @limit. + */ +int arm64_check_features_kvm(u32 sys_reg, u64 val, u64 limit) +{ + const struct arm64_ftr_bits *ftrp = get_arm64_ftr_bits_kvm(sys_reg); + u64 exposed_mask = 0; + + if (!ftrp) + return -ENOENT; + + for (; ftrp->width; ftrp++) { + s64 ftr_val = arm64_ftr_value(ftrp, val); + s64 ftr_lim = arm64_ftr_value(ftrp, limit); + + exposed_mask |= arm64_ftr_mask(ftrp); + + if (ftr_val == ftr_lim) + continue; + + if (ftr_val != arm64_ftr_safe_value(ftrp, ftr_val, ftr_lim)) + return -E2BIG; + } + + /* Make sure that no unrecognized fields are set in @val. */ + if (val & ~exposed_mask) + return -E2BIG; + + return 0; +} +#endif /* CONFIG_KVM */ From patchwork Fri Mar 11 04:47:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777396 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 00E8EC433EF for ; Fri, 11 Mar 2022 04:50:50 +0000 (UTC) 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=P6lt3Ql1pEfz68+wQ95uwbIi7iskD02ZLP3jA9Ql96I=; b=w1UHP7vPDWwRfUy89omsj4qmYk az9YHYaiJisWDSu3KKTsRaHyj5nTwP6NWzDP1QhQQAtnnBJqBy4fOxzs1GDqv8K4Y8pBui14MMgPC Q7cNMU5Jpr07ZViegGPpa9IF/Qsx+H6Oj69FPxCe+3pHdMzDjaiGF1LgqDkDcEuga+C+ihJ+9wOIp qwQP79gw2VpWQMNnIGPDWX+LPOdihhdVrXmmdfu7Y2n9q2Uam/LAUJa7BN06BgpNzG3sAdx99IG+v G74so+UhX1o74gV3HuhUnIbYR9A/8HSU4UNgyYvPdl1TPx4tXttheY2jND3Xk/buiKCV9Zby1wgRm SRm9I/GQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCm-00EzbA-Tt; Fri, 11 Mar 2022 04:48:45 +0000 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCg-00EzW6-Li for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:40 +0000 Received: by mail-pj1-x104a.google.com with SMTP id w3-20020a17090ac98300b001b8b914e91aso4542352pjt.0 for ; Thu, 10 Mar 2022 20:48:35 -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=qTyrhuTFJ7wTiM9tvbSBgyvkTis1ZeMrxQeZx92tj2A=; b=kxXwwKf76XJVgOlrOSM6DlfVqX/r3m6LuNum/WvCEBqF/qgCmnns+PpZ8/o1y+g5G/ Kbg7RIzj8TfV2IM1veJH+op06M5dxHq0f+2obySLhGc7P1v4e3CM7YEyyaDkYRCNSaGi 3+3SoFIcPnUZEePvQcDX8xI6VQRkzZFCBP3HBnxusnXLd/G+F1Aw6hmn5kA2WJ4axU2j HcAulUblFsyadSuQYww+KZFE94Mr4Qs60zf37KZMZnXwYP53R4ZBJAUBMEBRSw6xjZgy GqbLJiTK/yAFQuzzk2KLg4iIn6jvN1ffGHq9Qs4rH284leJGJ1SfOb68WDW2kpB2PxTJ A5mg== 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=qTyrhuTFJ7wTiM9tvbSBgyvkTis1ZeMrxQeZx92tj2A=; b=iFIPEi9BMkc0ILuD0Nv1M4nCClWgMDa6oDpDwpRERqyl/AgxxUuZsGYEG1zwmB37xj 8gxijeK19vRbLJ5xBPYoH7GZb8hvGXP3TBU6G8x0+IHVRZbQTw7c4k0Pt0HBnJitpBWc pcB+nMVOE9Ies4YC6XBbJX4QRriqlGlSUSL53ohXwT2WBF5d33zVWcN+dPTDDxmMKBhP TLmmZnpF9EIV8jhr78R44J/4m4k+Il4a+9IFIr+MO2jNDDJD83eW7JAlZVHCTFTkfhhR iwzWEPYa3npmP7Od/HU7glmRm8L3TULscYD3Ju34nu5aUywho+hWVha+hPbZPjoEHL8v ERZg== X-Gm-Message-State: AOAM532uxbVj67mdcNkrix9fAEj2gReT+wMDlSz2takGxD6tEkC4NIYC gnS2Bpfgl5MiCAynMdDLbUqoTBvifFw= X-Google-Smtp-Source: ABdhPJxPyEOxxqDIYNwgjAeeZrHfimY7GNc7Ltn9lvGWCQ9Lw0fZekJQj1mHokO+KyKBt5e/7m5MR2Yd05I= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:cf12:b0:14f:e0c2:1515 with SMTP id i18-20020a170902cf1200b0014fe0c21515mr8814824plg.4.1646974115128; Thu, 10 Mar 2022 20:48:35 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:48 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-3-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 02/25] KVM: arm64: Save ID registers' sanitized value per guest 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 , Fuad Tabba , 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-20220310_204838_752415_5AC9B84F X-CRM114-Status: GOOD ( 21.88 ) 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 Introduce id_regs[] in kvm_arch as a storage of guest's ID registers, and save ID registers' sanitized value in the array at KVM_CREATE_VM. Use the saved ones when ID registers are read by the guest or userspace (via KVM_GET_ONE_REG). Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_host.h | 12 ++++++ arch/arm64/kvm/arm.c | 1 + arch/arm64/kvm/sys_regs.c | 65 ++++++++++++++++++++++++------- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 2869259e10c0..c041e5afe3d2 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -101,6 +101,13 @@ struct kvm_s2_mmu { struct kvm_arch_memory_slot { }; +/* + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), + * where 0<=crm<8, 0<=op2<8. + */ +#define KVM_ARM_ID_REG_MAX_NUM 64 +#define IDREG_IDX(id) ((sys_reg_CRm(id) << 3) | sys_reg_Op2(id)) + struct kvm_arch { struct kvm_s2_mmu mmu; @@ -137,6 +144,9 @@ struct kvm_arch { /* Memory Tagging Extension enabled for the guest */ bool mte_enabled; bool ran_once; + + /* ID registers for the guest. */ + u64 id_regs[KVM_ARM_ID_REG_MAX_NUM]; }; struct kvm_vcpu_fault_info { @@ -736,6 +746,8 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, struct kvm_arm_copy_mte_tags *copy_tags); +void set_default_id_regs(struct kvm *kvm); + /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 4783dbf66df2..91110d996ed6 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -156,6 +156,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm->arch.max_vcpus = kvm_arm_default_max_vcpus(); set_default_spectre(kvm); + set_default_id_regs(kvm); return ret; out_free_stage2_pgd: diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4dc2fba316ff..d2b3ad32ab5a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -33,6 +33,8 @@ #include "trace.h" +static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id); + /* * All of this file is extremely similar to the ARM coproc.c, but the * types are different. My gut feeling is that it should be pretty @@ -273,7 +275,7 @@ static bool trap_loregion(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1); + u64 val = read_id_reg_with_encoding(vcpu, SYS_ID_AA64MMFR1_EL1); u32 sr = reg_to_encoding(r); if (!(val & (0xfUL << ID_AA64MMFR1_LOR_SHIFT))) { @@ -1059,17 +1061,16 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, return true; } -/* Read a sanitised cpufeature ID register by sys_reg_desc */ -static u64 read_id_reg(const struct kvm_vcpu *vcpu, - struct sys_reg_desc const *r, bool raz) +static bool is_id_reg(u32 id) { - u32 id = reg_to_encoding(r); - u64 val; - - if (raz) - return 0; + return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 0 && + sys_reg_CRm(id) < 8); +} - val = read_sanitised_ftr_reg(id); +static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) +{ + u64 val = vcpu->kvm->arch.id_regs[IDREG_IDX(id)]; switch (id) { case SYS_ID_AA64PFR0_EL1: @@ -1119,6 +1120,14 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu, return val; } +static u64 read_id_reg(const struct kvm_vcpu *vcpu, + struct sys_reg_desc const *r, bool raz) +{ + u32 id = reg_to_encoding(r); + + return raz ? 0 : read_id_reg_with_encoding(vcpu, id); +} + static unsigned int id_visibility(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { @@ -1223,9 +1232,8 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, /* * cpufeature ID register user accessors * - * For now, these registers are immutable for userspace, so no values - * are stored, and for set_id_reg() we don't allow the effective value - * to be changed. + * For now, these registers are immutable for userspace, so for set_id_reg() + * we don't allow the effective value to be changed. */ static int __get_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, @@ -1837,8 +1845,8 @@ static bool trap_dbgdidr(struct kvm_vcpu *vcpu, if (p->is_write) { return ignore_write(vcpu, p); } else { - u64 dfr = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); - u64 pfr = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); + u64 dfr = read_id_reg_with_encoding(vcpu, SYS_ID_AA64DFR0_EL1); + u64 pfr = read_id_reg_with_encoding(vcpu, SYS_ID_AA64PFR0_EL1); u32 el3 = !!cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR0_EL3_SHIFT); p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) | @@ -2850,3 +2858,30 @@ void kvm_sys_reg_table_init(void) /* Clear all higher bits. */ cache_levels &= (1 << (i*3))-1; } + +/* + * Set the guest's ID registers that are defined in sys_reg_descs[] + * with ID_SANITISED() to the host's sanitized value. + */ +void set_default_id_regs(struct kvm *kvm) +{ + int i; + u32 id; + const struct sys_reg_desc *rd; + u64 val; + + for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) { + rd = &sys_reg_descs[i]; + if (rd->access != access_id_reg) + /* Not ID register, or hidden/reserved ID register */ + continue; + + id = reg_to_encoding(rd); + if (WARN_ON_ONCE(!is_id_reg(id))) + /* Shouldn't happen */ + continue; + + val = read_sanitised_ftr_reg(id); + kvm->arch.id_regs[IDREG_IDX(id)] = val; + } +} From patchwork Fri Mar 11 04:47:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777397 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 74D43C433F5 for ; Fri, 11 Mar 2022 04:51:20 +0000 (UTC) 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=jtuGNoBwg7COEGyTr1GyIqM24y2i0qqikvMDRIP5Cfw=; b=1R+cF2WbIMCHm7GRWr47S5gB9a ftwJWiSBbBHQrCSEaS+w4tR+AU+ycdUhcJocb9yFeLtUZZ4Y3ZsLHMPJojessuQWiFhu/OKUTuZFn tTXukCuvnmesYgm9EYM9REaFsScalri1pIlYVpzDWy9WiXWYjIviC3U1ZlLGjYhLCsLn1KANLHC2o B1ZhCi8XUPWcdRCc7njNYkZpNsBeKIv5TGJAC8+s0wHeMfCn5h11vbJiliyQdhtlENls2vYhS3FAB jsjRwfJ3Vh2z1BlRUs0F5IpqSWtvo8H44xhk71VQNH4hQskayQU74LkkeZj7oEGBWvoiwlRu3OZco NEphlwZA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXD4-00Ezmg-DJ; Fri, 11 Mar 2022 04:49:03 +0000 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCg-00EzWr-NY for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:41 +0000 Received: by mail-pj1-x104a.google.com with SMTP id m9-20020a17090ade0900b001bedf2d1d4cso7193238pjv.2 for ; Thu, 10 Mar 2022 20:48:36 -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=itjrKvkmji5CZ0o+KIYFWkvyLeg5IiPs5WJYbXvgK+8=; b=Li7qPfLioV93JpEKq19Ok+Dg8G87XLzPtDjLlWw2fL52gtSINIcADgsIePGvV3Kf/P phuTBCk+YD8jzO9FYKsLQmAInX8ee2tl1sAFFSi0/MC//+SZk7uEescnOlffFVXyXaIQ RSOVAXwwxPMICT2JYTNcZu3HpsJ/pwJsoZb2+Bil/iouucO9dgA8/BM0s0Qzk+nMLqQR 6j6KC/DX67F7MUsXhtaIkXOXjvpu190kRHXhnWrF2pe7G0wIkSt4mIsPtxy/H68apqdw AullT4eITUinB5sjqp7gSeaxmMZHDrVa8hvMbw0+8Ptisz5SxlrYoEaucPR6bGnpL0eE 6htQ== 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=itjrKvkmji5CZ0o+KIYFWkvyLeg5IiPs5WJYbXvgK+8=; b=pq3LWaa/UJ/N2GelLltUXwuV3EVkzu8d5tFS9QqhgpxOEFsMO1dJqecxsdkmwKmvrq 2+FHoaedAc+lliICooOJOZudSuuw+SQqZiCvQP2qJBEkAVz73jvgmSA8w9oo8/kjEUiX itg+A6m8+e5aPujscM1+px51HcNds4AinuQ3CtasHCgO2G+DxNAAjv/31pWB1dkDFAEo JwKzwXPjadqU5J5wvyJhQ9a5+695iMa51rG2q+Am39uFPxz+MZsBWha++cM8tAYiiPbA 9Ailqt/pZAnnOHorgWsd1BCiQA+Eiy9F7TJI15S0Cfxy6rJLqbwPABV6AFuEqtSmOZGn Nmgw== X-Gm-Message-State: AOAM530Xnbck641NP6bVdg+BB0eqU6nwqiQqiEQUj7atyhMk+DnOpaox LVT9NX6EUU77GDTLFs+ODX1us7wuoe4= X-Google-Smtp-Source: ABdhPJy4bEoUEXcEjnF/BS1tA3hdsHZKp1Fy0u3C/kgm8vH9RXp0SGfWtarHdf5U11EALkJNkiClW4pFsus= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90a:8911:b0:1bd:395e:40e5 with SMTP id u17-20020a17090a891100b001bd395e40e5mr19457723pjn.121.1646974116501; Thu, 10 Mar 2022 20:48:36 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:49 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-4-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 03/25] KVM: arm64: Introduce struct id_reg_desc 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 , Fuad Tabba , 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-20220310_204838_830713_95729F53 X-CRM114-Status: GOOD ( 39.76 ) 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 lays the groundwork to make ID registers writable. Introduce struct id_reg_desc for an ID register to manage the register specific control of its value for the guest, and provide set of functions commonly used for ID registers to make them writable. Use the id_reg_desc to do register specific initialization, validation of the ID register, etc. The id_reg_desc has reg_desc field (struct sys_reg_desc), which will be used instead of sys_reg_desc in sys_reg_descs[] for ID registers in the following patches (and then the entries in sys_reg_descs[] will be removed). At present, changing an ID register from userspace is allowed only if the ID register has the id_reg_desc, but that will be changed by the following patches. No ID register has the id_reg_desc yet, and the following patches will add them for all the ID registers currently in sys_reg_descs[]. kvm_set_id_reg_feature(), which is introduced in this patch, is going to be used by the following patch outside from sys_regs.c when an ID register field needs to be updated. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/sysreg.h | 3 +- arch/arm64/kvm/sys_regs.c | 299 ++++++++++++++++++++++++++++-- 3 files changed, 286 insertions(+), 17 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index c041e5afe3d2..9ffe6604a58a 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -747,6 +747,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, struct kvm_arm_copy_mte_tags *copy_tags); void set_default_id_regs(struct kvm *kvm); +int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval); /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 898bee0004ae..2c9d8c0a3b75 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -1214,9 +1214,10 @@ #define ICH_VTR_TDS_MASK (1 << ICH_VTR_TDS_SHIFT) #define ARM64_FEATURE_FIELD_BITS 4 +#define ARM64_FEATURE_FIELD_MASK GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0) /* Create a mask for the feature bits of the specified feature. */ -#define ARM64_FEATURE_MASK(x) (GENMASK_ULL(x##_SHIFT + ARM64_FEATURE_FIELD_BITS - 1, x##_SHIFT)) +#define ARM64_FEATURE_MASK(x) (ARM64_FEATURE_FIELD_MASK << x##_SHIFT) #ifdef __ASSEMBLY__ diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index d2b3ad32ab5a..6305c2622c32 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -34,6 +34,7 @@ #include "trace.h" static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id); +static inline struct id_reg_desc *get_id_reg_desc(u32 id); /* * All of this file is extremely similar to the ARM coproc.c, but the @@ -265,6 +266,99 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, return read_zero(vcpu, p); } +struct id_reg_desc { + const struct sys_reg_desc reg_desc; + + /* + * Limit value of the register for a vcpu. The value is the sanitized + * system value with bits set/cleared for unsupported features for the + * guest. + */ + u64 vcpu_limit_val; + + /* Fields that are not validated by arm64_check_features_kvm. */ + u64 ignore_mask; + + /* An optional initialization function of the id_reg_desc */ + void (*init)(struct id_reg_desc *id_reg); + + /* + * This is an optional ID register specific validation function. When + * userspace tries to set the ID register, arm64_check_features_kvm() + * will check if the requested value indicates any features that cannot + * be supported by KVM on the host. But, some ID register fields need + * a special checking, and this function can be used for such fields. + * e.g. When SVE is configured for a vCPU by KVM_ARM_VCPU_INIT, + * ID_AA64PFR0_EL1.SVE shouldn't be set to 0 for the vCPU. + * The validation function for ID_AA64PFR0_EL1 could be used to check + * the field is consistent with SVE configuration. + */ + int (*validate)(struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg, + u64 val); + + /* + * Return a bitmask of the vCPU's ID register fields that are not + * synced with saved (per VM) ID register value, which usually + * indicates opt-in CPU features that are not configured for the vCPU. + * ID registers are saved per VM, but some opt-in CPU features can + * be configured per vCPU. The saved (per VM) values for such + * features are for vCPUs with the features (and zero for + * vCPUs without the features). + * Return value of this function is used to handle such fields + * for per vCPU ID register read/write request with saved per VM + * ID register. See the __write_id_reg's comment for more detail. + */ + u64 (*vcpu_mask)(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg); +}; + +static void id_reg_desc_init(struct id_reg_desc *id_reg) +{ + u32 id = reg_to_encoding(&id_reg->reg_desc); + u64 val = read_sanitised_ftr_reg(id); + + id_reg->vcpu_limit_val = val; + if (id_reg->init) + id_reg->init(id_reg); + + /* + * id_reg->init() might update id_reg->vcpu_limit_val. + * Make sure that id_reg->vcpu_limit_val, which will be the default + * register value for guests, is a safe value to use for guests + * on the host. + */ + WARN_ON_ONCE(arm64_check_features_kvm(id, id_reg->vcpu_limit_val, val)); +} + +static int validate_id_reg(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + u64 limit, tmp_val; + u32 id = reg_to_encoding(&id_reg->reg_desc); + int err; + + limit = id_reg->vcpu_limit_val; + + /* + * Replace the fields that are indicated in ignore_mask with + * the value in the limit to not have arm64_check_features_kvm() + * check the field in @val. + */ + tmp_val = val & ~id_reg->ignore_mask; + tmp_val |= (limit & id_reg->ignore_mask); + + /* Check if the value indicates any feature that is not in the limit. */ + err = arm64_check_features_kvm(id, tmp_val, limit); + if (err) + return err; + + if (id_reg && id_reg->validate) + /* Run the ID register specific validity check. */ + err = id_reg->validate(vcpu, id_reg, val); + + return err; +} + /* * ARMv8.1 mandates at least a trivial LORegion implementation, where all the * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0 @@ -1068,10 +1162,106 @@ static bool is_id_reg(u32 id) sys_reg_CRm(id) < 8); } +static u64 read_kvm_id_reg(struct kvm *kvm, u32 id) +{ + return kvm->arch.id_regs[IDREG_IDX(id)]; +} + +static int __modify_kvm_id_reg(struct kvm *kvm, u32 id, u64 val, + u64 preserve_mask) +{ + u64 old, new; + + lockdep_assert_held(&kvm->lock); + + old = kvm->arch.id_regs[IDREG_IDX(id)]; + + /* Preserve the value at the bit position set in preserve_mask */ + new = old & preserve_mask; + new |= (val & ~preserve_mask); + + /* Don't allow to modify ID register value after KVM_RUN on any vCPUs */ + if (kvm->arch.ran_once && new != old) + return -EBUSY; + + WRITE_ONCE(kvm->arch.id_regs[IDREG_IDX(id)], new); + + return 0; +} + +static int modify_kvm_id_reg(struct kvm *kvm, u32 id, u64 val, + u64 preserve_mask) +{ + int ret; + + mutex_lock(&kvm->lock); + ret = __modify_kvm_id_reg(kvm, id, val, preserve_mask); + mutex_unlock(&kvm->lock); + + return ret; +} + +static int write_kvm_id_reg(struct kvm *kvm, u32 id, u64 val) +{ + return modify_kvm_id_reg(kvm, id, val, 0); +} + +/* + * KVM basically forces all vCPUs of the guest to have a uniform value for + * each ID register (it means KVM_SET_ONE_REG for a vCPU affects all + * the vCPUs of the guest), and the id_regs[] of kvm_arch holds values + * of ID registers for the guest. However, there is an exception for + * ID register fields corresponding to CPU features that can be + * configured per vCPU by KVM_ARM_VCPU_INIT, or etc (e.g. PMUv3, SVE, etc). + * For such fields, all vCPUs that have the feature will have a non-zero + * uniform value, which can be updated by userspace, but the vCPUs that + * don't have the feature will have zero for the fields. + * Values that @id_regs holds are for vCPUs that have such features. So, + * to get the ID register value for a vCPU that doesn't have those features, + * the corresponding fields in id_regs[] needs to be cleared. + * A bitmask of the fields are provided by id_reg_desc's vcpu_mask(), and + * __write_id_reg() and __read_id_reg() take care of those fields using + * the bitmask. + */ +static int __write_id_reg(struct kvm_vcpu *vcpu, + struct id_reg_desc *id_reg, u64 val) +{ + u64 mask = 0; + u32 id = reg_to_encoding(&id_reg->reg_desc); + + if (id_reg->vcpu_mask) + mask = id_reg->vcpu_mask(vcpu, id_reg); + + /* + * Update the ID register for the guest with @val, except for fields + * that are set in the mask, which indicates fields for opt-in + * features that are not configured for the vCPU. + */ + return modify_kvm_id_reg(vcpu->kvm, id, val, mask); +} + +static u64 __read_id_reg(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg) +{ + u32 id = reg_to_encoding(&id_reg->reg_desc); + u64 val = read_kvm_id_reg(vcpu->kvm, id); + + if (id_reg && id_reg->vcpu_mask) + /* Clear fields for opt-in features that are not configured. */ + val &= ~(id_reg->vcpu_mask(vcpu, id_reg)); + + return val; +} + static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) { - u64 val = vcpu->kvm->arch.id_regs[IDREG_IDX(id)]; + u64 val; + const struct id_reg_desc *id_reg = get_id_reg_desc(id); + if (id_reg) + return __read_id_reg(vcpu, id_reg); + + val = read_kvm_id_reg(vcpu->kvm, id); switch (id) { case SYS_ID_AA64PFR0_EL1: if (!vcpu_has_sve(vcpu)) @@ -1123,9 +1313,7 @@ static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r, bool raz) { - u32 id = reg_to_encoding(r); - - return raz ? 0 : read_id_reg_with_encoding(vcpu, id); + return raz ? 0 : read_id_reg_with_encoding(vcpu, reg_to_encoding(r)); } static unsigned int id_visibility(const struct kvm_vcpu *vcpu, @@ -1229,12 +1417,7 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, return 0; } -/* - * cpufeature ID register user accessors - * - * For now, these registers are immutable for userspace, so for set_id_reg() - * we don't allow the effective value to be changed. - */ +/* cpufeature ID register user accessors */ static int __get_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) @@ -1245,11 +1428,32 @@ static int __get_id_reg(const struct kvm_vcpu *vcpu, return reg_to_user(uaddr, &val, id); } -static int __set_id_reg(const struct kvm_vcpu *vcpu, +/* + * Check if the given id indicates AArch32 ID register encoding. + */ +static bool is_aarch32_id_reg(u32 id) +{ + u32 crm, op2; + + if (!is_id_reg(id)) + return false; + + crm = sys_reg_CRm(id); + op2 = sys_reg_Op2(id); + if (crm == 1 || crm == 2 || (crm == 3 && (op2 != 3 && op2 != 7))) + /* AArch32 ID register */ + return true; + + return false; +} + +static int __set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { const u64 id = sys_reg_to_index(rd); + u32 encoding = reg_to_encoding(rd); + struct id_reg_desc *id_reg; int err; u64 val; @@ -1257,11 +1461,33 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu, if (err) return err; - /* This is what we mean by invariant: you can't change it. */ - if (val != read_id_reg(vcpu, rd, raz)) + if (val == read_id_reg(vcpu, rd, raz)) + /* The value is same as the current value. Nothing to do. */ + return 0; + + /* Don't allow to modify the register's value if the register is raz. */ + if (raz) return -EINVAL; - return 0; + /* + * Don't allow to modify the register's value if the register doesn't + * have the id_reg_desc. + */ + id_reg = get_id_reg_desc(encoding); + if (!id_reg) + return -EINVAL; + + /* + * Skip the validation of AArch32 ID registers if the system doesn't + * 32bit EL0 (their value are UNKNOWN). + */ + if (system_supports_32bit_el0() || !is_aarch32_id_reg(encoding)) { + err = validate_id_reg(vcpu, id_reg, val); + if (err) + return err; + } + + return __write_id_reg(vcpu, id_reg, val); } static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, @@ -2823,6 +3049,8 @@ int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) return write_demux_regids(uindices); } +static void id_reg_desc_init_all(void); + void kvm_sys_reg_table_init(void) { unsigned int i; @@ -2857,6 +3085,43 @@ void kvm_sys_reg_table_init(void) break; /* Clear all higher bits. */ cache_levels &= (1 << (i*3))-1; + + id_reg_desc_init_all(); +} + +/* + * Update the ID register's field with @fval for the guest. + * The caller is expected to hold the kvm->lock. + * This will not fail unless any vCPUs in the guest have started. + */ +int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval) +{ + u64 val = ((u64)fval & ARM64_FEATURE_FIELD_MASK) << field_shift; + u64 preserve_mask = ~(ARM64_FEATURE_FIELD_MASK << field_shift); + + return __modify_kvm_id_reg(kvm, id, val, preserve_mask); +} + +/* A table for ID registers's information. */ +static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = {}; + +static inline struct id_reg_desc *get_id_reg_desc(u32 id) +{ + return id_reg_desc_table[IDREG_IDX(id)]; +} + +static void id_reg_desc_init_all(void) +{ + int i; + struct id_reg_desc *id_reg; + + for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { + id_reg = (struct id_reg_desc *)id_reg_desc_table[i]; + if (!id_reg) + continue; + + id_reg_desc_init(id_reg); + } } /* @@ -2869,6 +3134,7 @@ void set_default_id_regs(struct kvm *kvm) u32 id; const struct sys_reg_desc *rd; u64 val; + struct id_reg_desc *idr; for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) { rd = &sys_reg_descs[i]; @@ -2881,7 +3147,8 @@ void set_default_id_regs(struct kvm *kvm) /* Shouldn't happen */ continue; - val = read_sanitised_ftr_reg(id); - kvm->arch.id_regs[IDREG_IDX(id)] = val; + idr = get_id_reg_desc(id); + val = idr ? idr->vcpu_limit_val : read_sanitised_ftr_reg(id); + WARN_ON_ONCE(write_kvm_id_reg(kvm, id, val)); } } From patchwork Fri Mar 11 04:47:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777399 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id B8F75C433F5 for ; Fri, 11 Mar 2022 04:51:46 +0000 (UTC) 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=aI6b1SZEVGCSkch0ZHwyJGwCpo4CZTWeakfNEsh49Cw=; b=Z9K9wlMcHELrdoBX8GZ0Lx2Sb3 5XeNsLEN2KcVLE2+KdFrEPckNZ9xk3Cx34S/aG/08bUbtmEZOiCr3F9GsOUxnh/B4KWqBBU7rOXU/ BTccwKsaBp3vLhyHRxO8RNtGlAt1IOAqNd8auRuob7er8tQBSjacOodTqRkADgvBQz2qQo0ZGZvw8 GMEHLRewON1x+1mzYzPk7o1cMamAxkz8wJhV8ib8rc5lLuiG5iPI2QGjBQ8HOoaQYJeT9jFMJMawX sQy2CR2v52Xa5osb+3VcA9cl/BKlboKS6e9rm3SIvDyi5pE/niMfSU6eNg05Wfc0nRQ+xffMaaLhv sOPSn6Sw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDi-00F08N-SZ; Fri, 11 Mar 2022 04:49:43 +0000 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCh-00EzXL-UF for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:43 +0000 Received: by mail-pf1-x449.google.com with SMTP id h69-20020a628348000000b004f769e5b4bdso2740008pfe.10 for ; Thu, 10 Mar 2022 20:48:38 -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=IfOAE6MJtteJteQ/p4KBnqsn47ZknQ3Y2Evrog9PWzk=; b=aNHErz1fYG8L0XyouO5mJBzMVcDScmn3AExGM23ftL0XruZGC91v4Z7iTti8nYELwg TvJIHEa3l3pYL4CpUFwU2UpL6reUMmGozwyazWND4VVEqUC1L4ekPA0PiWJAJNKVFFiL TfTCLIVX1j0OXgn/v1UYMqcdKHDV874Cp6bbF79E8aQS4lMHxo5CgRR1et7IWse/sqll xVXHIAP18Y+a8wt9Mq/J5Fc8K7ghc4n8aicZ6Wxm98tU3oNBnPGVCDFCVzG7NPSPDnlt e09PKH72PObKpRmRsfp03zTR2TL7gtDYQbgcit8V5KzeQ+VvrBLdOsTRto1Wf0Sc5K+Z 08IA== 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=IfOAE6MJtteJteQ/p4KBnqsn47ZknQ3Y2Evrog9PWzk=; b=62Zx9y92oQExd/1bQhn6EqV+fzvhMxaA7/91o3samkHkLe2ao4er59xVum9Ockf1cH CH/E1RWOa+L1nqnH6b3yQe9fmm/nd++5MFEnwY9dBdHHFbvBzKNHLXEc+Zx+lSHVd20V C0F5RBRN/Uht9eTitKTA/I4W1zdKrRRNczEyBMUh2dGmremK5PPfZpJ7scHWTLw3JMkk VpjKvdRx13Feum89ZJiQYyODWJ7XlZVPmRMLluBSwavIC3SvSvTqDEN7SzXvdorxF7aP Ed/SAmzX4XvEXAsb7rtGlM93GOjEORl5AU/vIsqhdlMW3iRmWBhOKgn2pC7T1wPWEOdn m0QQ== X-Gm-Message-State: AOAM530EDlmZJn4bfv2MhiafvyNNXWxkAOSMjqbHOZJWq+hvwdvp+dZ4 uidhzww5HLoGswFMwVAxCHx+2E9xr1Q= X-Google-Smtp-Source: ABdhPJwzfMcbrbgEtWV/95s64C/nKBD98oj5MQcWhr+sUPoX7DU0Px+/aQ/WIu8v7SyVMjKEcawv73k42YE= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:3a91:b0:1bf:261e:7773 with SMTP id om17-20020a17090b3a9100b001bf261e7773mr19724859pjb.155.1646974118011; Thu, 10 Mar 2022 20:48:38 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:50 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-5-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 04/25] 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 , Fuad Tabba , 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-20220310_204840_005478_64779164 X-CRM114-Status: GOOD ( 24.92 ) 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_desc for ID_AA64PFR0_EL1 to make it writable by userspace. 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/include/asm/sysreg.h | 1 + arch/arm64/kvm/sys_regs.c | 156 ++++++++++++++++++++------------ arch/arm64/kvm/vgic/vgic-init.c | 9 ++ 3 files changed, 107 insertions(+), 59 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 2c9d8c0a3b75..84edc87f0005 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -813,6 +813,7 @@ #define ID_AA64PFR0_ASIMD_SUPPORTED 0x0 #define ID_AA64PFR0_ELx_64BIT_ONLY 0x1 #define ID_AA64PFR0_ELx_32BIT_64BIT 0x2 +#define ID_AA64PFR0_GIC3 0x1 /* id_aa64pfr1 */ #define ID_AA64PFR1_MPAMFRAC_SHIFT 16 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 6305c2622c32..9e9fa90afb82 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -330,6 +330,87 @@ static void id_reg_desc_init(struct id_reg_desc *id_reg) WARN_ON_ONCE(arm64_check_features_kvm(id, id_reg->vcpu_limit_val, val)); } +static int validate_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + int fp, simd; + unsigned int gic; + bool vcpu_has_sve = vcpu_has_sve(vcpu); + bool pfr0_has_sve = id_aa64pfr0_sve(val); + + simd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); + /* AdvSIMD field must have the same value as FP field */ + 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; + + if ((irqchip_in_kernel(vcpu->kvm) && + vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)) { + gic = cpuid_feature_extract_unsigned_field(val, + ID_AA64PFR0_GIC_SHIFT); + if (gic == 0) + return -EPERM; + + if (gic > ID_AA64PFR0_GIC3) + return -E2BIG; + } else { + u32 id = reg_to_encoding(&id_reg->reg_desc); + u64 mask = ARM64_FEATURE_MASK(ID_AA64PFR0_GIC); + int r = arm64_check_features_kvm(id, val & mask, + id_reg->vcpu_limit_val & mask); + + if (r) + return r; + } + + return 0; +} + +static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *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), ID_AA64PFR0_GIC3); + } + id_reg->vcpu_limit_val = limit; +} + +static u64 vcpu_mask_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *idr) +{ + return vcpu_has_sve(vcpu) ? 0 : ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); +} + static int validate_id_reg(struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg, u64 val) { @@ -1263,20 +1344,6 @@ static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) val = read_kvm_id_reg(vcpu->kvm, id); 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); - } - break; case SYS_ID_AA64PFR1_EL1: if (!kvm_has_mte(vcpu->kvm)) val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_MTE); @@ -1375,48 +1442,6 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu, return REG_HIDDEN; } -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, @@ -1736,8 +1761,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), @@ -3102,8 +3126,22 @@ int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval) return __modify_kvm_id_reg(kvm, id, val, preserve_mask); } +static struct id_reg_desc id_aa64pfr0_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64PFR0_EL1), + .ignore_mask = ARM64_FEATURE_MASK(ID_AA64PFR0_GIC), + .init = init_id_aa64pfr0_el1_desc, + .validate = validate_id_aa64pfr0_el1, + .vcpu_mask = vcpu_mask_id_aa64pfr0_el1, +}; + +#define ID_DESC(id_reg_name, id_reg_desc) \ + [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) + /* A table for ID registers's information. */ -static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = {}; +static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { + /* CRm=4 */ + ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), +}; static inline struct id_reg_desc *get_id_reg_desc(u32 id) { diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index fc00304fe7d8..f0632b46fbf9 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -117,6 +117,15 @@ int kvm_vgic_create(struct kvm *kvm, u32 type) else INIT_LIST_HEAD(&kvm->arch.vgic.rd_regions); + if (type == KVM_DEV_TYPE_ARM_VGIC_V3) + /* + * Set ID_AA64PFR0_EL1.GIC to 1. This shouldn't fail unless + * any vCPU in the guest have started. + */ + WARN_ON_ONCE(kvm_set_id_reg_feature(kvm, SYS_ID_AA64PFR0_EL1, + ID_AA64PFR0_GIC3, + ID_AA64PFR0_GIC_SHIFT)); + out_unlock: unlock_all_vcpus(kvm); return ret; From patchwork Fri Mar 11 04:47:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777400 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 74266C433F5 for ; Fri, 11 Mar 2022 04:52:00 +0000 (UTC) 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=mGQRPrDXkDMdKSUug8zTkZbZYL6ZClRLqIBKnErDKgQ=; b=wSqni7eI5nFacuiVdPCqcijUCy +kT+T/zskVWYepHXBrqWmok9TAyggEMrDrw8KGwr6dIQcKZa11SP2AQ4NQjGMJg1AqgXKhM+cVlLZ +UT/F3AX8/3EQN8nv7UNavCWBZTiF4EO0XjX1laQhZEvq55wG3s3CG26A2X6LQ0zGjevHG4Uv0f6U 9I/VH0KwagHCBIuAHTYnKyLhYMj4AGiDY2XMZigYiOJNwFuw9By3ghA/ZPNlZ00r+sznglqqPPOT+ hRSaXYsi4m8e9FS7f1apDipTHWvmBaeEqFNog1GYzfe37M1vaSrpaE7G1lGdVtOmSGVceU59HtdnT 2Zdr9ECw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXE6-00F0Ja-1K; Fri, 11 Mar 2022 04:50:06 +0000 Received: from mail-pl1-x649.google.com ([2607:f8b0:4864:20::649]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCj-00EzZE-GL for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:45 +0000 Received: by mail-pl1-x649.google.com with SMTP id i7-20020a170902cf0700b0015163eb319eso3901732plg.18 for ; Thu, 10 Mar 2022 20:48:40 -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=uBoyKzZk3Qtv9aZ00wbOXF/ba3q4Fu49o+9bq2Th1Ww=; b=WaOEzQ3J63TTZvIp5H/lnZK5BcWK/0Md7Gxah9ozJWTjDdZZC9UvfdGXYgP9LilqU+ sGSsV8EwJD/Ug/h0cTRJGvN5EVdPxOfsDaM8dgkcFQgh7GUeQPrPuRXPfGZnswqjU9m1 o1aNriRRHMPgy57Zbt1IjI9BeXj+A7Zks11gx9CDeya7BSM1y2OljGQgFMP+jYUajo4z jfHlLPscsINpYKG94NQSEfftScLI6kNjHMPt5RzTcza0jhZaoHOSstIAnzTEcGfIm5C8 fxw014HKohpMkivmaWj3BFqjDArfo3Ei2h4NN+Bh31LZo7Wkkjgj2wZ0rKcuzVoHHhw8 JO3Q== 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=uBoyKzZk3Qtv9aZ00wbOXF/ba3q4Fu49o+9bq2Th1Ww=; b=KiCSXbCOOQrW4UCG4BrkuqobJx8qJ1q2/wD2HXRv4+kDJkpEI+5DrgAVBzREWq142/ ZTm5tId+PPGZyPJ81tvVj5BQtuK7Vu7HDInd9jal/253dV+qBWGxoFWkTHUHZRXgvBRN Bd9fjb/+R7sWaHf2LK+bzlcecHk7p5VQsXYpr55aGzGxeBUu8NSmBJp32pYzmIgRbSJ1 IhkxOoyBvHH6JktgHk0afPfMYBLNbNxf2IWIjuUVmjcW3OZffPEUeH1jpWwLJb3DGZv2 N562bvwJ9A0XyU8bDR7vvoUBroGqAfUPzI/fTOZqU3G2VJTjKAfx/4Iu1H3ybcfwnq7J 60bQ== X-Gm-Message-State: AOAM532kZuFnf7zSff/t1EygkmLGIT9lNOV7vA6YsvwwirFFJVEs17fU n8uH6QIRKcm2niQkwpZpVn0tgIvr66w= X-Google-Smtp-Source: ABdhPJyOxSYFndroMYYb/thCoU6B1JaiKrgug4u+QvotKZqS7wBgDmUI8tVODpRPXtY1pGqD5AxfCVCODJs= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:e811:b0:151:f486:a32f with SMTP id u17-20020a170902e81100b00151f486a32fmr8570545plg.141.1646974119624; Thu, 10 Mar 2022 20:48:39 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:51 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-6-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 05/25] KVM: arm64: Make ID_AA64PFR1_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 , Fuad Tabba , 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-20220310_204841_593098_F2E3DC53 X-CRM114-Status: GOOD ( 18.59 ) 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_desc for ID_AA64PFR1_EL1 to make it writable by userspace. Return an error if userspace tries to set MTE field of the register to a value that conflicts with KVM_CAP_ARM_MTE configuration for the guest. Skip fractional feature fields validation at present and they will be handled by the following patches. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/sysreg.h | 1 + arch/arm64/kvm/sys_regs.c | 42 +++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 84edc87f0005..249f1fdc1f59 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -816,6 +816,7 @@ #define ID_AA64PFR0_GIC3 0x1 /* id_aa64pfr1 */ +#define ID_AA64PFR1_CSV2FRAC_SHIFT 32 #define ID_AA64PFR1_MPAMFRAC_SHIFT 16 #define ID_AA64PFR1_RASFRAC_SHIFT 12 #define ID_AA64PFR1_MTE_SHIFT 8 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 9e9fa90afb82..4294dbfd8fd4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -374,6 +374,21 @@ static int validate_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, return 0; } +static int validate_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + bool kvm_mte = kvm_has_mte(vcpu->kvm); + unsigned int mte; + + mte = cpuid_feature_extract_unsigned_field(val, ID_AA64PFR1_MTE_SHIFT); + + /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT. */ + if (kvm_mte ^ (mte > 0)) + return -EPERM; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -405,12 +420,24 @@ static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) id_reg->vcpu_limit_val = limit; } +static void init_id_aa64pfr1_el1_desc(struct id_reg_desc *id_reg) +{ + if (!system_supports_mte()) + id_reg->vcpu_limit_val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_MTE); +} + static u64 vcpu_mask_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, const struct id_reg_desc *idr) { return vcpu_has_sve(vcpu) ? 0 : ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); } +static u64 vcpu_mask_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *idr) +{ + return kvm_has_mte(vcpu->kvm) ? 0 : (ARM64_FEATURE_MASK(ID_AA64PFR1_MTE)); +} + static int validate_id_reg(struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg, u64 val) { @@ -1344,10 +1371,6 @@ static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) val = read_kvm_id_reg(vcpu->kvm, id); switch (id) { - case SYS_ID_AA64PFR1_EL1: - if (!kvm_has_mte(vcpu->kvm)) - val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_MTE); - break; case SYS_ID_AA64ISAR1_EL1: if (!vcpu_has_ptrauth(vcpu)) val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) | @@ -3134,6 +3157,16 @@ static struct id_reg_desc id_aa64pfr0_el1_desc = { .vcpu_mask = vcpu_mask_id_aa64pfr0_el1, }; +static struct id_reg_desc id_aa64pfr1_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64PFR1_EL1), + .ignore_mask = ARM64_FEATURE_MASK(ID_AA64PFR1_RASFRAC) | + ARM64_FEATURE_MASK(ID_AA64PFR1_MPAMFRAC) | + ARM64_FEATURE_MASK(ID_AA64PFR1_CSV2FRAC), + .init = init_id_aa64pfr1_el1_desc, + .validate = validate_id_aa64pfr1_el1, + .vcpu_mask = vcpu_mask_id_aa64pfr1_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) @@ -3141,6 +3174,7 @@ static struct id_reg_desc id_aa64pfr0_el1_desc = { static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), + ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) From patchwork Fri Mar 11 04:47:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777401 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id A6BB9C433FE for ; Fri, 11 Mar 2022 04:52:15 +0000 (UTC) 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=LeFZE71uGX6Ksp+TQyJLDSlMwci4V9tao4jXCnxezAM=; b=p5Cb1KzzzO1rHPsOKnfm4t4aGp gfmyOMDHPyjQu9wlq+/LgS8pd0zgZyEZfNo0Tq6tw9PhXtED38cu9PyxXgsM1EZ/8lKLCof6P3v9o WbaLHijYey8FySpybfuLdtdYFsCGhJm8ZlooRB9meI0hIubTRbyD5Z/92v034eymuZdtTjww7m3rU IpOYzJqWvcYkPEyOqF1LNkksDIVAzbYOP3H0ms+SBFIjR1DKaPt8kAZ4RvTnQq36iHdcYQkZf0vW8 FpxwKlNm79DrUQ4/OKyVhB02LtjcY6ceS1j/5vpsTSgcPh9Ip26Z1rZb1NIqvuT+XZq6TdRp3RHbt ImgXXa4A==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXEN-00F0PS-07; Fri, 11 Mar 2022 04:50:23 +0000 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCk-00Ezaf-Gn for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:47 +0000 Received: by mail-pj1-x104a.google.com with SMTP id m14-20020a17090a4d8e00b001bf2d4926c5so7186379pjh.3 for ; Thu, 10 Mar 2022 20:48:41 -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=i1Q8oMVcIDawwcpspY0YFzmCHnlNLuWjVrH+1Iwojj8=; b=jVLOPO1C6Ge6K9MG6QbzCVTmnGDbg8jZOD1sL0KvfQwDeSvvbXuCxHIh9stqZKw7o7 m0BVY3IxNn55nzY/Tq9XLu/IiOng74LRlvqo6E6T1rr/98gS9IDg8BpcnCjATjov5so9 PtUgvUnGTNwMTLRZG1vo1oh9KTI7T9CSS/aHcKZjuFkCJ9JZVO64cqoNqredM66vA/hu LDihsicff+dxFB7+dRK10RK6CIvs3oKpyaKUMhvuJF+tGg1wBRtAiAjJsXrcLaiqZLXy E+wRlPN8J8Sn7I3xE/U1ZPoYGH5asekcZGHH0u4dk9Xg3hj2WMXVj+HaHl48qqjp7Abo 0pWQ== 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=i1Q8oMVcIDawwcpspY0YFzmCHnlNLuWjVrH+1Iwojj8=; b=fFfwOdAIVkRpe4aY9Gvb4tc3rAqdlKlDwpHhQP9tNUUPU0+zbBz8oCSOjmMVC7YD09 fPqYPt10zuvVycoUk2YTzVI2xYWxO/Xuf8XOwiWYyh9JhjdC3kz8xrRyesQ2wh+yJjki bxl2vtTIjQIKiGGlTAWXi/7OzwQU8wy+Xb1XfJHrdbycHGBgZVIpaFOls0bXWY0qP28J SgTJsuqswbK8vm7Ppjf5pZ8jckcLW/paLtTxBAOfvJOlUAuq3bY6U8o9KRZLFVHDp8y/ R0JXhsc8FhPjbddrLs0Fn3xJDNHSZh+VyOPLKt+8JC7zmVRlU0BCK1nmhxLZ644YSXvJ QgwA== X-Gm-Message-State: AOAM530CEbixL46TVwdm0tNg4Al5ys1vgEBl+HvIE4FGXjaRGyn+G/ar ZRlJckm5aMNpzofzcL4mfnvqOBMBbPA= X-Google-Smtp-Source: ABdhPJyqzZBFBrLfDZqJ/MEY5oQH2n+E2ImHCp7e6LaNBlZdtcnXcxrMItVl9Ayaa8AX1b+4PjFrf3CrT4s= 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:11c7:b0:151:7290:ccc with SMTP id q7-20020a17090311c700b0015172900cccmr8717277plh.95.1646974121195; Thu, 10 Mar 2022 20:48:41 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:52 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-7-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 06/25] KVM: arm64: Make ID_AA64ISAR0_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 , Fuad Tabba , 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-20220310_204842_597120_2C652C87 X-CRM114-Status: GOOD ( 12.40 ) 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_desc for ID_AA64ISAR0_EL1 to make it writable by userspace. Updating sm3, sm4, sha1, sha2 and sha3 fields are allowed only if values of those fields follow Arm ARM. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4294dbfd8fd4..378777238c68 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -389,6 +389,29 @@ static int validate_id_aa64pfr1_el1(struct kvm_vcpu *vcpu, return 0; } +static int validate_id_aa64isar0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + unsigned int sm3, sm4, sha1, sha2, sha3; + + /* Run consistency checkings according to Arm ARM */ + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); + if (sm3 != sm4) + return -EINVAL; + + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); + if ((sha1 == 0) ^ (sha2 == 0)) + return -EINVAL; + + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); + if (((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) + return -EINVAL; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -3167,6 +3190,11 @@ static struct id_reg_desc id_aa64pfr1_el1_desc = { .vcpu_mask = vcpu_mask_id_aa64pfr1_el1, }; +static struct id_reg_desc id_aa64isar0_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64ISAR0_EL1), + .validate = validate_id_aa64isar0_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) @@ -3175,6 +3203,9 @@ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), + + /* CRm=6 */ + ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) From patchwork Fri Mar 11 04:47:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777402 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 9378BC433F5 for ; Fri, 11 Mar 2022 04:52:15 +0000 (UTC) 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=033huXvrrz3AUhlHMuyAUwSzc/bmiFy21AXx5nrsHpE=; b=FghI9lCG/qc6/LCR/2215JBYXr 0B6wMiu0l1eMIIwdwyrfKo8ngzoWpZVcHbGBfeRofGCd6W4fXkNzae3PaDlm6VxQ4w6AwnkQzhpnN VgB4QauRPYtvhKN1dbGx2UVACk7YwjsuQUeAN0cX3wBXaBdIwIL8YVQ9UUVcWfXTSnWeCzxCxcs/c NO7guvN5w2w+0+0+jBgFEAlga9ZdGfcSSlvFHd2+DhOLr9BkR/BCC10WIld4265rYyEjThHQT3grd 7UiKF3ocVJV67Pq0X5qRXfqcCHgD1t8thfQBBOsqi+8nP7hwLLaGXdlAWXJtkSTqxhkaomDyaTwXJ 4B9ekfDA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXEb-00F0UT-DD; Fri, 11 Mar 2022 04:50:37 +0000 Received: from mail-pl1-x64a.google.com ([2607:f8b0:4864:20::64a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCm-00EzcB-H0 for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:49 +0000 Received: by mail-pl1-x64a.google.com with SMTP id n11-20020a170902d2cb00b0015331a5d02fso910207plc.12 for ; Thu, 10 Mar 2022 20:48:43 -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=SyiktOhTmpvn5pUXgZ6ePXJwo088/NYFSXX6m5o3kNU=; b=KJMufFI/Ev7ysa5LfXFLsD0SOX2mvAf73GWs7q9u/9Qc5u5WPoGirh3w/EL7Rs2CIA OLZErGZeZqomLw4Y0ZzS1F0y7JHHTkbrMFATvNlt985dBbt65XhGTyxHmWdVQPCH9C5i kJCtyoKu/jojlkfR42kEvSUKJBE95teKIfisH4ipKfYBExi+JdXWM0cmDOkxVuS8ZBf3 EHdUF0oKp8U3A5k22XlwTLYW7z0SWt1LkfW+aUT3tQiy0/wYZOseUgBBcqnkpV584Pmg oTz3D4H1QR6Dcs8Ybn7nUfq9Obtc5rde944/zFIQz2c4YxO8OQytTQ7zF8Vk6Wdv3Uyz YbhQ== 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=SyiktOhTmpvn5pUXgZ6ePXJwo088/NYFSXX6m5o3kNU=; b=QOSw9GxhOX5lobXVu8xcgjnzKkqOqHbyauvZYQA8bJySJvA2Le054VvNy7CZ4b/KB1 B1J2mfxwxZEsSu/mOgkb4l1mAl/kCqZamxmfzN6Pb5ELSdtx50FWBrLX4mJuEGwpSeYm R7WC01fUAKBxxshliO1sSrOyWuhdnPXsz+7uOzM/PrVTGnonYLaQHvkOEG+8DLVyM2ej 4uCLxQmZ+4rkiq+iMoFwd5XiM56iCmBlsCTibFgzCr7GtycmAsP7XDMOS0lxq+va/NMv yDUDiU6rKHNRBqtErfd0h9PC9zhD10G8OlS/cN2df851uhzn9saIQPfxP40PFhX4b/Mi VnSg== X-Gm-Message-State: AOAM532uLPbxCl3RzlCZJnMIxU4xPXG9+EOqgB0JlK4mjNOWPurGiAHW WJs5HoFqvRd4ptzS/ZjQAtiTtQjFg/s= X-Google-Smtp-Source: ABdhPJzsMwYr79WYoTXq+KdrvGlSJ5KAZHFBXJrD5JWF+5hgF5n5lPrdLA7d+8Kv+nNzW7PCSxybrp6sdys= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90a:6b48:b0:1be:d73c:f6c6 with SMTP id x8-20020a17090a6b4800b001bed73cf6c6mr8766134pjl.81.1646974122814; Thu, 10 Mar 2022 20:48:42 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:53 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-8-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 07/25] KVM: arm64: Make ID_AA64ISAR1_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 , Fuad Tabba , 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-20220310_204844_642934_32606B45 X-CRM114-Status: GOOD ( 18.08 ) 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_desc for ID_AA64ISAR1_EL1 to make it writable by userspace. Return an error if userspace tries to set PTRAUTH related fields of the register to values that conflict with PTRAUTH configuration, which was configured by KVM_ARM_VCPU_INIT, for the guest. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 77 +++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 378777238c68..33b4918109b7 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -266,6 +266,24 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, return read_zero(vcpu, p); } +#define PTRAUTH_MASK (ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) | \ + ARM64_FEATURE_MASK(ID_AA64ISAR1_API) | \ + ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) | \ + ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI)) + +#define aa64isar1_has_apa(val) \ + (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT) >= \ + ID_AA64ISAR1_APA_ARCHITECTED) +#define aa64isar1_has_api(val) \ + (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT) >= \ + ID_AA64ISAR1_API_IMP_DEF) +#define aa64isar1_has_gpa(val) \ + (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT) >= \ + ID_AA64ISAR1_GPA_ARCHITECTED) +#define aa64isar1_has_gpi(val) \ + (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT) >= \ + ID_AA64ISAR1_GPI_IMP_DEF) + struct id_reg_desc { const struct sys_reg_desc reg_desc; @@ -412,6 +430,36 @@ static int validate_id_aa64isar0_el1(struct kvm_vcpu *vcpu, return 0; } +static int validate_id_aa64isar1_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + bool has_gpi, has_gpa, has_api, has_apa; + bool generic, address; + + has_gpi = aa64isar1_has_gpi(val); + has_gpa = aa64isar1_has_gpa(val); + has_api = aa64isar1_has_api(val); + has_apa = aa64isar1_has_apa(val); + if ((has_gpi && has_gpa) || (has_api && has_apa)) + return -EINVAL; + + generic = has_gpi || has_gpa; + address = has_api || has_apa; + /* + * Since the current KVM guest implementation works by enabling + * both address/generic pointer authentication features, + * return an error if they conflict. + */ + if (generic ^ address) + return -EPERM; + + /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT */ + if (vcpu_has_ptrauth(vcpu) ^ (generic && address)) + return -EPERM; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -449,8 +497,14 @@ static void init_id_aa64pfr1_el1_desc(struct id_reg_desc *id_reg) id_reg->vcpu_limit_val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_MTE); } +static void init_id_aa64isar1_el1_desc(struct id_reg_desc *id_reg) +{ + if (!system_has_full_ptr_auth()) + id_reg->vcpu_limit_val &= ~PTRAUTH_MASK; +} + static u64 vcpu_mask_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, - const struct id_reg_desc *idr) + const struct id_reg_desc *idr) { return vcpu_has_sve(vcpu) ? 0 : ARM64_FEATURE_MASK(ID_AA64PFR0_SVE); } @@ -461,6 +515,12 @@ static u64 vcpu_mask_id_aa64pfr1_el1(const struct kvm_vcpu *vcpu, return kvm_has_mte(vcpu->kvm) ? 0 : (ARM64_FEATURE_MASK(ID_AA64PFR1_MTE)); } +static u64 vcpu_mask_id_aa64isar1_el1(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *idr) +{ + return vcpu_has_ptrauth(vcpu) ? 0 : PTRAUTH_MASK; +} + static int validate_id_reg(struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg, u64 val) { @@ -1394,13 +1454,6 @@ static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) val = read_kvm_id_reg(vcpu->kvm, id); switch (id) { - case SYS_ID_AA64ISAR1_EL1: - if (!vcpu_has_ptrauth(vcpu)) - val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_API) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) | - ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI)); - break; case SYS_ID_AA64DFR0_EL1: /* Limit debug to ARMv8.0 */ val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER); @@ -3195,6 +3248,13 @@ static struct id_reg_desc id_aa64isar0_el1_desc = { .validate = validate_id_aa64isar0_el1, }; +static struct id_reg_desc id_aa64isar1_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64ISAR1_EL1), + .init = init_id_aa64isar1_el1_desc, + .validate = validate_id_aa64isar1_el1, + .vcpu_mask = vcpu_mask_id_aa64isar1_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) @@ -3206,6 +3266,7 @@ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=6 */ ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), + ID_DESC(ID_AA64ISAR1_EL1, &id_aa64isar1_el1_desc), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) From patchwork Fri Mar 11 04:47:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777403 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 48088C433F5 for ; Fri, 11 Mar 2022 04:52:28 +0000 (UTC) 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=DM6Mt9eLPvMoiURMoByDorFND8p8d8Dq8OrOo7ANlzk=; b=xX3p5WJAUMrGbLlNVNAEcvN8xg XN4Rzu+oB+slnSn2pgrmwbs0l7oKwXfixwvA3jBKwQbVz32XS24yKN63gseCJwyavuGQAd/VC4m5P J3AzG6ycJ8LJPqC+h7ADFuF7AnZcSzFT2Hn8D0gEDezBn1zPpKrkTfXnItqQZdmTlo94TEMXvP5cD qCkIlwZRvt1afdht8pBNCyH4jRzSG/PZt6HcJqzDk8pVm7oWB6qmY8GyYMGQic2xD5Qbzbyx+IvXJ 5ByD5dGTtyLJQAdPhgIiIaGehvmoc4LYTUNRYAlb2jW9kSY+ICo66e6YJMCWtk5bfkRFkH/AkZXoF RhUKJoYw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXEv-00F0ef-18; Fri, 11 Mar 2022 04:50:57 +0000 Received: from mail-pj1-x1049.google.com ([2607:f8b0:4864:20::1049]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCo-00Ezdl-EL for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:51 +0000 Received: by mail-pj1-x1049.google.com with SMTP id t10-20020a17090a5d8a00b001bed9556134so7172898pji.5 for ; Thu, 10 Mar 2022 20:48:45 -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=BC/RhHZyQh20zJ4o/L/jR6ipTx5n23zl8pNE5Kswitk=; b=lI34I92LM8QIflRlzMT6EfFDAy+1YBmg8eJPRcNsFzEaEHoumYH1WYQw3kZilJENyE dtWeXXFAxTSqdv6eyxMvE18sw4WTaQ4u+k27UeLSOvKMERLk3ZLePx+v277Oe1qsJXYQ 7+uAAFCSeWx6QKH9g83hOq1SvSKcgRbGcq+cZzbbNje8nDQc0SGt6qhcF52YSZrY76dS oi01m32m6XMrD5Z0yPlgmWJaII/TA04eC2vsOcXCvc0/uM7A56Rcu5U1W6D9UZhCWCEp K2ezwCf1YL3aXhgj4GAumNh4az0xH1pC2aP5o1bDxEB3KWvsPJGWIIPIqiwg/kM5BNDZ IlPg== 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=BC/RhHZyQh20zJ4o/L/jR6ipTx5n23zl8pNE5Kswitk=; b=OYfSmudG4Z0QvbLIGd43OLq58trAfL0W+9G8V31/oquKHN1tLOWlICIWYz8FbQcyTo RGqFEs59kJk8X03rsnBlFRWQnpiflVUxIwdE7a0VtZegGUNFUJu46m8qSyLAh8+YZjcE H6blmsF758kpP5r8izrO+h1we21IeSc7ShEy05F5q+OCWTk8RCR5a46AkjUhGZg9nBKr jxvl1w+maEAe5/cTU5PRZFnrFYkxYsOP9um3nhDy48grKw7MqSRz8+0QeN1XM9bocSn3 5riJVc4sRjUTQHjlweazIo3PZxP3J0DH0V/uSmrK1np+MUxo0pEXxP+0UL7r2ZOHVX21 nnYA== X-Gm-Message-State: AOAM533FL9r+xoyAWblGPiU8CxYlV9DPqyiX3JBsAn3s1Me5lnXJwzHA AjVfldD9qCY5aZzx1cFIAfc86PZ4cFQ= X-Google-Smtp-Source: ABdhPJy7JXTk0HnRt/o3W8puG08ezjtccoA9tPMKC2datbpeXgEETraGwWU0YIdJv6KUiq8OPkEUw6kaylo= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:7246:b0:151:49e7:d4fc with SMTP id c6-20020a170902724600b0015149e7d4fcmr8872189pll.88.1646974124662; Thu, 10 Mar 2022 20:48:44 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:54 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-9-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 08/25] KVM: arm64: Make ID_AA64MMFR0_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 , Fuad Tabba , 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-20220310_204846_562840_78CCE834 X-CRM114-Status: GOOD ( 21.48 ) 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_desc for ID_AA64MMFR0_EL1 to make it writable by userspace. Since ID_AA64MMFR0_EL1 stage 2 granule size fields don't follow the standard ID scheme, we need a special handling to validate those fields. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 129 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 33b4918109b7..ad23361d3a3b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -460,6 +460,118 @@ static int validate_id_aa64isar1_el1(struct kvm_vcpu *vcpu, return 0; } +/* + * Check if the requested stage2 translation granule size indicated in + * @mmfr0 is also indicated in @mmfr0_lim. + * If TGranX_2 field is zero, the value must be validated based on TGranX + * field because that indicates the feature support is identified in + * TGranX field. + * This function relies on the fact TGranX fields are validated before + * through arm64_check_features_kvm. + */ +static int aa64mmfr0_tgran2_check(int field, u64 mmfr0, u64 mmfr0_lim) +{ + s64 tgran2, lim_tgran2, rtgran1; + int f1; + bool is_signed; + + tgran2 = cpuid_feature_extract_unsigned_field(mmfr0, field); + lim_tgran2 = cpuid_feature_extract_unsigned_field(mmfr0_lim, field); + if (tgran2 && lim_tgran2) + /* + * We don't need to check TGranX field. We can simply + * compare tgran2 and lim_tgran2. + */ + return (tgran2 > lim_tgran2) ? -E2BIG : 0; + + if (tgran2 == lim_tgran2) + /* + * Both of them are zero. Since TGranX in @mmfr0 is already + * validated by arm64_check_features_kvm, tgran2 must be fine. + */ + return 0; + + /* + * Either tgran2 or lim_tgran2 is zero. + * Need stage1 granule size to validate tgran2. + */ + + /* + * Get TGranX's bit position by subtracting 12 from TGranX_2's bit + * position. + */ + f1 = field - 12; + + /* TGran4/TGran64 is signed and TGran16 is unsigned field. */ + is_signed = (f1 == ID_AA64MMFR0_TGRAN16_SHIFT) ? false : true; + + /* + * If tgran2 == 0 (&& lim_tgran2 != 0), the requested stage2 granule + * size is indicated in the stage1 granule size field of @mmfr0. + * So, validate the stage1 granule size against the stage2 limit + * granule size. + * If lim_tgran2 == 0 (&& tgran2 != 0), the stage2 limit granule size + * is indicated in the stage1 granule size field of @mmfr0_lim. + * So, validate the requested stage2 granule size against the stage1 + * limit granule size. + */ + + /* Get the relevant stage1 granule size to validate tgran2 */ + if (tgran2 == 0) + /* The requested stage1 granule size */ + rtgran1 = cpuid_feature_extract_field(mmfr0, f1, is_signed); + else /* lim_tgran2 == 0 */ + /* The stage1 limit granule size */ + rtgran1 = cpuid_feature_extract_field(mmfr0_lim, f1, is_signed); + + /* + * Adjust the value of rtgran1 to compare with stage2 granule size, + * which indicates: 1: Not supported, 2: Supported, etc. + */ + if (is_signed) + /* For signed, -1: Not supported, 0: Supported, etc. */ + rtgran1 += 0x2; + else + /* For unsigned, 0: Not supported, 1: Supported, etc. */ + rtgran1 += 0x1; + + if ((tgran2 == 0) && (rtgran1 > lim_tgran2)) + /* + * The requested stage1 granule size (== the requested stage2 + * granule size) is larger than the stage2 limit granule size. + */ + return -E2BIG; + else if ((lim_tgran2 == 0) && (tgran2 > rtgran1)) + /* + * The requested stage2 granule size is larger than the stage1 + * limit granulze size (== the stage2 limit granule size). + */ + return -E2BIG; + + return 0; +} + +static int validate_id_aa64mmfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + u64 limit = id_reg->vcpu_limit_val; + int ret; + + ret = aa64mmfr0_tgran2_check(ID_AA64MMFR0_TGRAN4_2_SHIFT, val, limit); + if (ret) + return ret; + + ret = aa64mmfr0_tgran2_check(ID_AA64MMFR0_TGRAN64_2_SHIFT, val, limit); + if (ret) + return ret; + + ret = aa64mmfr0_tgran2_check(ID_AA64MMFR0_TGRAN16_2_SHIFT, val, limit); + if (ret) + return ret; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -3255,6 +3367,20 @@ static struct id_reg_desc id_aa64isar1_el1_desc = { .vcpu_mask = vcpu_mask_id_aa64isar1_el1, }; +static struct id_reg_desc id_aa64mmfr0_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64MMFR0_EL1), + /* + * When TGranX_2 value is 0, validity of the value depend on TGranX + * value, and TGranX_2 value must be validated against TGranX value, + * which is done by validate_id_aa64mmfr0_el1. + * So, skip the regular validity checking for TGranX_2 fields. + */ + .ignore_mask = ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN4_2) | + ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN64_2) | + ARM64_FEATURE_MASK(ID_AA64MMFR0_TGRAN16_2), + .validate = validate_id_aa64mmfr0_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) @@ -3267,6 +3393,9 @@ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=6 */ ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), ID_DESC(ID_AA64ISAR1_EL1, &id_aa64isar1_el1_desc), + + /* CRm=7 */ + ID_DESC(ID_AA64MMFR0_EL1, &id_aa64mmfr0_el1_desc), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) From patchwork Fri Mar 11 04:47:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777404 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 187D0C433EF for ; Fri, 11 Mar 2022 04:53:09 +0000 (UTC) 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=itibnTUaxnWCOL7pXq3n9keXJUrMkO70vAuygy2KcRo=; b=0LGx/JC2aKnPQQrC3RDYPGRYja HM5NkVd5iy6R5wXON59Lj2GD3zsatrhA4mFF55c3TpVbkTcY2oyrcPw4Q/s0o2dsp9Nl4S6Aq/QqU aYAz8I5vzkeIAx+tN1NU+bk4pqTRJ/CjAx1IQ6sYGXYB2eH/1rd03D8IC/lim8zIotvr5ZZN4sLGV wtW7UIlitfQUL6WdbTQtIbbmdFeKmuPXjcozW2n17Lax842JXLLgE2HXvpzyzEId+c2PvzQjlu3yZ NGR85AO2zTIkwKsRwSo1ARubOo+5HJsg5KEJf0efHFnET1db1qxUmkizRPiCu2KJsSG038P/h/kWw +VDq028g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXFV-00F0xk-RS; Fri, 11 Mar 2022 04:51:35 +0000 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCq-00EzfQ-7b for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:52 +0000 Received: by mail-pf1-x44a.google.com with SMTP id x205-20020a627cd6000000b004f6e1b97b45so4503898pfc.18 for ; Thu, 10 Mar 2022 20:48:46 -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=U4vObHr07JOA9r35Oli1yvQZsMPbxDR2eZHL3vHOgIc=; b=nrWVcz4xkbY4HLXt4miecw5Dd7wLv/8Qw3R+jAAFN9fhmzj+Km0AqV2L7X/z/fTo4T fL7e+zIuPCBBSuik+Y7SuRFNxJX8kJONi/D+iLHDUdfxxWsmDVi52r5r/Vym9Py4ZnJb DUCrq+Sdrh98urXQ+qN9CRfIcyQkvloyBr6QCXiGRFJqN4UZQr4afAx+MJeWbodDBWE0 9Otebs4TqewY0HE8AACw4s05zVtk6BylH/FuCffghUfJynHdzDYur70qlhqiFHCAnl1A JjqvLUoI5yAiAsPtMAdXC0XcXOqKyZqOzkDoHrUYhTOWkN+45sZZLPY4e7c5pXI+D3De VnTA== 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=U4vObHr07JOA9r35Oli1yvQZsMPbxDR2eZHL3vHOgIc=; b=I/qt9i6aLcJPrqoYi314H/L/lPU0wI2XcTt9maCR78t77cNaS09A6fHE31WUpRu9KS OnBXhXRdAflfc8T62Sg3EkJf/ETY2RyN4Krk5+8XqbaxrdQgLhWTs/vOcSPcmWi5PUoA A4tbVPmnHtNaN4ntCsXd2HrAGi6DjYfcolfWPVbs+WsaPG0NJzlyr1VD5MelR+153wEa fZajX6xb0P7EgUiKftqsVRUsSL0bix14D5dqwomtCGFg0YLw1i4NyXqtt2wttDHEYcye XHI3Wq/unkodA/2u+3ykf6tIpSxdgP1Mz/cd/T7Y3G/vfqmZ7XfM4PpQcbfSvayEH4yz /ryg== X-Gm-Message-State: AOAM5313twdrsjOFQUC6VDzIA+MiPO2py+qvGeEhqHIpPJ3vorFf8ug9 GvMKtcbvopT++3TVQqaIs3zGQ8kkttA= X-Google-Smtp-Source: ABdhPJz02TnbQPY0kPnlOASS0GWIbEagDC4DxiLpCYD0ZfEPttap+gCUxytayfCPG35mVswRACXJk9ILkN8= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:8e82:b0:151:6f68:7088 with SMTP id bg2-20020a1709028e8200b001516f687088mr8972609plb.11.1646974126310; Thu, 10 Mar 2022 20:48:46 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:55 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-10-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 09/25] KVM: arm64: Make ID_AA64DFR0_EL1/ID_DFR0_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 , Fuad Tabba , 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-20220310_204848_328859_620D3B66 X-CRM114-Status: GOOD ( 22.31 ) 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_desc for ID_AA64DFR0_EL1 and ID_DFR0_EL1 to make them writable by userspace. Return an error if userspace tries to set PMUVER/PerfMon field of ID_AA64DFR0_EL1/ID_DFR0_EL1 to a value that conflicts with the PMU configuration. When a value of ID_AA64DFR0_EL1.PMUVER or ID_DFR0_EL1.PERFMON on the host is 0xf, which means IMPLEMENTATION DEFINED PMU supported, KVM erroneously expose the value for the guest as it is even though KVM doesn't support it for the guest. In that case, since KVM should expose 0x0 (PMU is not implemented), change the initial value of ID_AA64DFR0_EL1.PMUVER and ID_DFR0_EL1.PERFMON for the guest to 0x0. If userspace requests KVM to set them to 0xf, which shouldn't be allowed as KVM doesn't support IMPLEMENTATION DEFINED PMU for the guest, ignore the request (set the fields to 0x0 instead) so that a live migration from the older kernel works fine. Since number of context-aware breakpoints must be no more than number of supported breakpoints according to Arm ARM, return an error if userspace tries to set CTX_CMPS field to such value. Fixes: 8e35aa642ee4 ("arm64: cpufeature: Extract capped perfmon fields") Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/cpufeature.h | 2 +- arch/arm64/kvm/sys_regs.c | 143 +++++++++++++++++++++++----- 2 files changed, 122 insertions(+), 23 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index a9edf1ca7dcb..375c9cd0123c 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -553,7 +553,7 @@ cpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap) /* Treat IMPLEMENTATION DEFINED functionality as unimplemented */ if (val == ID_AA64DFR0_PMUVER_IMP_DEF) - val = 0; + return (features & ~mask); if (val > cap) { features &= ~mask; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index ad23361d3a3b..46d95626f4d5 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -572,6 +572,66 @@ static int validate_id_aa64mmfr0_el1(struct kvm_vcpu *vcpu, return 0; } +static bool id_reg_has_pmu(u64 val, u64 shift, unsigned int min) +{ + unsigned int pmu = cpuid_feature_extract_unsigned_field(val, shift); + + /* + * Treat IMPLEMENTATION DEFINED functionality as unimplemented for + * ID_AA64DFR0_EL1.PMUVer/ID_DFR0_EL1.PerfMon. + */ + if (pmu == 0xf) + pmu = 0; + + return (pmu >= min); +} + +static int validate_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + unsigned int brps, ctx_cmps; + bool vcpu_pmu, dfr0_pmu; + + brps = cpuid_feature_extract_unsigned_field(val, ID_AA64DFR0_BRPS_SHIFT); + ctx_cmps = cpuid_feature_extract_unsigned_field(val, ID_AA64DFR0_CTX_CMPS_SHIFT); + + /* + * Number of context-aware breakpoints can be no more than number of + * supported breakpoints. + */ + if (ctx_cmps > brps) + return -EINVAL; + + vcpu_pmu = kvm_vcpu_has_pmu(vcpu); + dfr0_pmu = id_reg_has_pmu(val, ID_AA64DFR0_PMUVER_SHIFT, ID_AA64DFR0_PMUVER_8_0); + /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT */ + if (vcpu_pmu ^ dfr0_pmu) + return -EPERM; + + return 0; +} + +static int validate_id_dfr0_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + bool vcpu_pmu, dfr0_pmu; + unsigned int perfmon; + + perfmon = cpuid_feature_extract_unsigned_field(val, ID_DFR0_PERFMON_SHIFT); + if (perfmon == 1 || perfmon == 2) + /* PMUv1 or PMUv2 is not allowed on ARMv8. */ + return -EINVAL; + + vcpu_pmu = kvm_vcpu_has_pmu(vcpu); + dfr0_pmu = id_reg_has_pmu(val, ID_DFR0_PERFMON_SHIFT, ID_DFR0_PERFMON_8_0); + + /* Check if there is a conflict with a request via KVM_ARM_VCPU_INIT */ + if (vcpu_pmu ^ dfr0_pmu) + return -EPERM; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -615,6 +675,32 @@ static void init_id_aa64isar1_el1_desc(struct id_reg_desc *id_reg) id_reg->vcpu_limit_val &= ~PTRAUTH_MASK; } +static void init_id_aa64dfr0_el1_desc(struct id_reg_desc *id_reg) +{ + u64 limit = id_reg->vcpu_limit_val; + + /* Limit guests to PMUv3 for ARMv8.4 */ + limit = cpuid_feature_cap_perfmon_field(limit, ID_AA64DFR0_PMUVER_SHIFT, + ID_AA64DFR0_PMUVER_8_4); + /* Limit debug to ARMv8.0 */ + limit &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER); + limit |= (FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER), 6)); + + /* Hide SPE from guests */ + limit &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_PMSVER); + + id_reg->vcpu_limit_val = limit; +} + +static void init_id_dfr0_el1_desc(struct id_reg_desc *id_reg) +{ + /* Limit guests to PMUv3 for ARMv8.4 */ + id_reg->vcpu_limit_val = + cpuid_feature_cap_perfmon_field(id_reg->vcpu_limit_val, + ID_DFR0_PERFMON_SHIFT, + ID_DFR0_PERFMON_8_4); +} + static u64 vcpu_mask_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, const struct id_reg_desc *idr) { @@ -633,6 +719,18 @@ static u64 vcpu_mask_id_aa64isar1_el1(const struct kvm_vcpu *vcpu, return vcpu_has_ptrauth(vcpu) ? 0 : PTRAUTH_MASK; } +static u64 vcpu_mask_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *idr) +{ + return kvm_vcpu_has_pmu(vcpu) ? 0 : ARM64_FEATURE_MASK(ID_AA64DFR0_PMUVER); +} + +static u64 vcpu_mask_id_dfr0_el1(const struct kvm_vcpu *vcpu, + const struct id_reg_desc *idr) +{ + return kvm_vcpu_has_pmu(vcpu) ? 0 : ARM64_FEATURE_MASK(ID_DFR0_PERFMON); +} + static int validate_id_reg(struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg, u64 val) { @@ -1562,28 +1660,9 @@ static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) const struct id_reg_desc *id_reg = get_id_reg_desc(id); if (id_reg) - return __read_id_reg(vcpu, id_reg); - - val = read_kvm_id_reg(vcpu->kvm, id); - switch (id) { - case SYS_ID_AA64DFR0_EL1: - /* Limit debug to ARMv8.0 */ - val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER); - val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER), 6); - /* Limit guests to PMUv3 for ARMv8.4 */ - val = cpuid_feature_cap_perfmon_field(val, - ID_AA64DFR0_PMUVER_SHIFT, - kvm_vcpu_has_pmu(vcpu) ? ID_AA64DFR0_PMUVER_8_4 : 0); - /* Hide SPE from guests */ - val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_PMSVER); - break; - case SYS_ID_DFR0_EL1: - /* Limit guests to PMUv3 for ARMv8.4 */ - val = cpuid_feature_cap_perfmon_field(val, - ID_DFR0_PERFMON_SHIFT, - kvm_vcpu_has_pmu(vcpu) ? ID_DFR0_PERFMON_8_4 : 0); - break; - } + val = __read_id_reg(vcpu, id_reg); + else + val = read_kvm_id_reg(vcpu->kvm, id); return val; } @@ -3381,15 +3460,35 @@ static struct id_reg_desc id_aa64mmfr0_el1_desc = { .validate = validate_id_aa64mmfr0_el1, }; +static struct id_reg_desc id_aa64dfr0_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64DFR0_EL1), + .init = init_id_aa64dfr0_el1_desc, + .validate = validate_id_aa64dfr0_el1, + .vcpu_mask = vcpu_mask_id_aa64dfr0_el1, +}; + +static struct id_reg_desc id_dfr0_el1_desc = { + .reg_desc = ID_SANITISED(ID_DFR0_EL1), + .init = init_id_dfr0_el1_desc, + .validate = validate_id_dfr0_el1, + .vcpu_mask = vcpu_mask_id_dfr0_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) /* A table for ID registers's information. */ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { + /* CRm=1 */ + ID_DESC(ID_DFR0_EL1, &id_dfr0_el1_desc), + /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), + /* CRm=5 */ + ID_DESC(ID_AA64DFR0_EL1, &id_aa64dfr0_el1_desc), + /* CRm=6 */ ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), ID_DESC(ID_AA64ISAR1_EL1, &id_aa64isar1_el1_desc), From patchwork Fri Mar 11 04:47:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777424 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 88726C433EF for ; Fri, 11 Mar 2022 04:54:25 +0000 (UTC) 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=8KTn/mSy1I2a/cWIP/oux5/k6ydxQIqTJtKpFstdpkA=; b=iFX+C94QVRT6IkBUVPuS2YAZ1N FOSeRcrv5Sgv4Bwh7QxocjZULaoAsXIL3AOtmIDdDz4bSm/mDAlPcYTty6aPK+g76tJiHDOLuaZdZ Jizy5Mb0kY9TYcHJbxUm6jway4OdUrvahPa00zm+spGtLPiZw3ofvQFcRkrkqmGIDRrXiD5q7dYvi w60t3ArfnJgafMmYEnSA18hiIEi5Fe0Iirorha5ruNeN2kzVBHO4L4GJLDsUVd4eADsYdt+dt5Rh0 rnlGFPVTj4nO/auZCXGHbM4kKkZSjCJtEqJTnv5vY3Q7PIrQVAc0zYLu/YcHRWsICQLpA5hIfSJYq wAR9NsGQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXGI-00F1Ms-4N; Fri, 11 Mar 2022 04:52:22 +0000 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCr-00EzgA-Fb for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:53 +0000 Received: by mail-pf1-x44a.google.com with SMTP id y27-20020aa7943b000000b004f6decccdb5so4550407pfo.1 for ; Thu, 10 Mar 2022 20:48:48 -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=uoX+Y+G6xoHPXp4kqnfSVmpfMNJMZgMHDhyE0auL83Q=; b=YNltLUs0JQ2gFkvqzjAXUoHgAi9ZfaLM/L+GHykWnnLtUkQPfLjXODJYzEL9TwOD6t KT525jlPQqr6DC8/EAKJleLT4RIABEucKJ5u44URo1HHUaVsuoJY+jybtXEexOHuofJ6 wCj0ICOlApK+2jJbRNw4N3p1WM8pFyr4Ubpf6Pt8qMqU0jlcXMYsJZjx35tteE0y5NUY qnS6lOa6QbzS4qN2M5utqKhbabagUFrSOdlffYrSdoPd8AZqgRpu5tPA0ERglZjeaJ5R 1E63LdOlRt9IhJ41HAwVfOJRFHL9oVsIcfQZg6j8+/BIPZmoEh1N4r0YC/zkS2bMai5t aVag== 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=uoX+Y+G6xoHPXp4kqnfSVmpfMNJMZgMHDhyE0auL83Q=; b=DR5yXjayr4PIdmq3LLwlqtEsGYzeSM+E2P1Cda1FFsK0QDW//RLsP41BiyPPl9TNUI tVAkLLPKIIOloDFHA6ea6AC5NSF/MFJifayyFT3IqPr8D2rbeQAY0U8YNGT5v3PHZKlk Hod10s1tUmUYgC4OlOg8jvlUa3Lk3vR0bQXKiEITpOVHHUL36g6vXoYUSJ/9R2y99LZH ErGDfHvV4m0ilBIijah5QCB+QEorfBe12x9BkXazRolHu3UcdFklunjjTkmI0k1sFfYw PNDobEIHLzUzh2R2FeHeyFG7cVvIwgSfPh5RsHZ8JqwXxyJZRqAzJpS8QlJ4WcWO3NZw i9pQ== X-Gm-Message-State: AOAM5313WZOuZOJ68B5meBzX84N3bcDI0UFBjBYKYsfMgD9fu2kwDyls d6PAPnEeyrTyI/I94qqS/TnifrLBoHM= X-Google-Smtp-Source: ABdhPJzlEs8FIbA8U2Dis881SY2f6s+kkp+46U11VGjc7k6FSU9t7G0DvVjrYGujHVyxJSa56LXMGJhejwU= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:1a47:b0:4e1:5bc7:840d with SMTP id h7-20020a056a001a4700b004e15bc7840dmr8455437pfv.10.1646974127983; Thu, 10 Mar 2022 20:48:47 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:56 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-11-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 10/25] KVM: arm64: Make MVFR1_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 , Fuad Tabba , 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-20220310_204849_595626_BD6A1431 X-CRM114-Status: GOOD ( 16.59 ) 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_desc for MVFR1_EL1 to make it writable by userspace. There are only a few valid combinations of values that can be set for FPHP and SIMDHP fields according to Arm ARM. Return an error when userspace tries to set those fields to values that don't match any of the valid combinations. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 46d95626f4d5..45d22b9e0d40 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -632,6 +632,36 @@ static int validate_id_dfr0_el1(struct kvm_vcpu *vcpu, return 0; } +static int validate_mvfr1_el1(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg, u64 val) +{ + unsigned int fphp, simdhp; + struct fphp_simdhp { + unsigned int fphp; + unsigned int simdhp; + }; + /* Permitted fphp/simdhp value combinations according to Arm ARM */ + struct fphp_simdhp valid_fphp_simdhp[3] = {{0, 0}, {2, 1}, {3, 2}}; + int i; + bool is_valid_fphp_simdhp = false; + + fphp = cpuid_feature_extract_unsigned_field(val, MVFR1_FPHP_SHIFT); + simdhp = cpuid_feature_extract_unsigned_field(val, MVFR1_SIMDHP_SHIFT); + + for (i = 0; i < ARRAY_SIZE(valid_fphp_simdhp); i++) { + if (valid_fphp_simdhp[i].fphp == fphp && + valid_fphp_simdhp[i].simdhp == simdhp) { + is_valid_fphp_simdhp = true; + break; + } + } + + if (!is_valid_fphp_simdhp) + return -EINVAL; + + return 0; +} + static void init_id_aa64pfr0_el1_desc(struct id_reg_desc *id_reg) { u64 limit = id_reg->vcpu_limit_val; @@ -3474,6 +3504,11 @@ static struct id_reg_desc id_dfr0_el1_desc = { .vcpu_mask = vcpu_mask_id_dfr0_el1, }; +static struct id_reg_desc mvfr1_el1_desc = { + .reg_desc = ID_SANITISED(MVFR1_EL1), + .validate = validate_mvfr1_el1, +}; + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) @@ -3482,6 +3517,9 @@ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=1 */ ID_DESC(ID_DFR0_EL1, &id_dfr0_el1_desc), + /* CRm=3 */ + ID_DESC(MVFR1_EL1, &mvfr1_el1_desc), + /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), From patchwork Fri Mar 11 04:47:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777426 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 08C63C433F5 for ; Fri, 11 Mar 2022 04:55:06 +0000 (UTC) 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=j74bohmz/cZGUR+ROkSHQYWpQBBs4L+yVfATm63h5XE=; b=Abe5FY/1FyuvoUTfLWMYc8+Qwz S3fHWjqBxy7hLqjYeyGneKxmoYCPQuoXu0TvonvMvMej8qfVbapR+2UMyE8yqtJ6yCEjXz2eIV6VO wi/vnPhFCOXwh1AnSokeKu0yeVP/h1itU+s1ttw6QxwlRNmQCUvnlWpERR/QmXQD8B6Cb25Iimkvy CdwXFOjS8lOERkNSEUHCloAUXe70wWW5xG5Ctj96tVbKo/3+Z/4rxPDlvA8jh1AYKAiYdt9+zD7A4 J+MqmSzL8JH4j3Mi2fPpTWJtRNV5UBJPmMPpERjc883f3ocri39Jynhmf1ntYjtgp5mPjs0PHx7/a 2q7mjBDA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXGq-00F1ba-2A; Fri, 11 Mar 2022 04:52:56 +0000 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCs-00EzhP-Vj for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:54 +0000 Received: by mail-pf1-x449.google.com with SMTP id d145-20020a621d97000000b004f7285f67e8so4539316pfd.2 for ; Thu, 10 Mar 2022 20:48:50 -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=sBS0GPRrbiWgeVNZb+9UNH7PQVRywzH/+pUDODbMZ1g=; b=ENpayKBmfeMK+Uq+f7lTV/mKRuXOdPZr6mTDUvWd+uAPU+KZk0izLdEguLYuIuauLM N0WLJyDNbdzroBnPwDIbJSsVmV7p0FNDRujmdbz0kuz2j8Dk1Ch6rAe7jApHzRPecewZ /zkDyEZZMllmc3VuiLdVg1ge5BCnpZC7ODpi91HC2Msz23yqldvH9XYpnI9FqGVxDgEP jA/4LCoyfsavGVedZcFh6hWz/NUuYfyxNKy4kSxRbKmbIiT4FiLhwmH812Y2QdatN014 JBPE8d0E4jZg3dAHRfEFOMda+Ip5JeEI4wmWALk7bTkpcQNd8bP6K8cNuXyhmXAyYuOw 2BcA== 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=sBS0GPRrbiWgeVNZb+9UNH7PQVRywzH/+pUDODbMZ1g=; b=k8qSQlekypDXEtO3gM12J48MIe/2EK57B9NRqn/ElBclU/LlVu8XXQjq829XaH3BGF dRkk3z0XT1KA5K0t/6zh2zL8XhH3OOVNPY+8zYIwcE28Ng8pc/Rf+qSTWiLQ4kPmeQ5N 4HCSRsRXCCaeJM19G6GwQMNMj+ZPhdaSu6StRHugwYWcniiRWd/bq52Os/1XyHPedNIZ VTytfG8h9aHxUz7dA7sQMwOWZAb84QwFqv50ISxXWSG41BO3l2sHadoMp9DmQGGeOinQ MIkA3ynbpOlzWozbE+Z1urNcfN5pQMuDn/ztJqg53zilwZrDSoZQXumjNywbxoaojMfR xcjA== X-Gm-Message-State: AOAM530O/W+hMkvhPCm73WDGGaZ2Ilpnvy9zvroain3gmJ/6Je3Byxen hq/imXrX+NoxuvpVb0vNRlHp+lk6xRo= X-Google-Smtp-Source: ABdhPJwvo+MlpuYLsqLclXrIHZ70iMCXv6C4gJL27oO/w0gInxEG7NIHVVmbw30zKgrbMrTj7EgvpKtQd4E= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:350b:b0:1bf:c563:f0c7 with SMTP id ls11-20020a17090b350b00b001bfc563f0c7mr8762325pjb.157.1646974129584; Thu, 10 Mar 2022 20:48:49 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:57 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-12-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 11/25] KVM: arm64: Add remaining ID registers to id_reg_desc_table 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 , Fuad Tabba , 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-20220310_204851_078342_E3FC11B6 X-CRM114-Status: GOOD ( 16.71 ) 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 Add hidden or reserved ID registers, and remaining ID registers, which don't require special handling, to id_reg_desc_table. Add 'flags' field to id_reg_desc, which is used to indicates hiddden or reserved registers. Since now id_reg_desc_init() is called even for hidden/reserved registers, change it to not do anything for them. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 89 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 45d22b9e0d40..fe2a4de2b8f3 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -284,6 +284,10 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT) >= \ ID_AA64ISAR1_GPI_IMP_DEF) +/* id_reg_desc flags field values */ +#define ID_DESC_REG_UNALLOC (1UL << 0) +#define ID_DESC_REG_HIDDEN (1UL << 1) + struct id_reg_desc { const struct sys_reg_desc reg_desc; @@ -297,6 +301,9 @@ struct id_reg_desc { /* Fields that are not validated by arm64_check_features_kvm. */ u64 ignore_mask; + /* Miscellaneous flags */ + u64 flags; + /* An optional initialization function of the id_reg_desc */ void (*init)(struct id_reg_desc *id_reg); @@ -333,8 +340,13 @@ struct id_reg_desc { static void id_reg_desc_init(struct id_reg_desc *id_reg) { u32 id = reg_to_encoding(&id_reg->reg_desc); - u64 val = read_sanitised_ftr_reg(id); + u64 val; + + if (id_reg->flags & (ID_DESC_REG_HIDDEN | ID_DESC_REG_UNALLOC)) + /* Nothing to do for a hidden/unalloc ID register */ + return; + val = read_sanitised_ftr_reg(id); id_reg->vcpu_limit_val = val; if (id_reg->init) id_reg->init(id_reg); @@ -3509,30 +3521,103 @@ static struct id_reg_desc mvfr1_el1_desc = { .validate = validate_mvfr1_el1, }; +#define ID_DESC_DEFAULT(name) \ + [IDREG_IDX(SYS_##name)] = &(struct id_reg_desc) { \ + .reg_desc = ID_SANITISED(name), \ + } + +#define ID_DESC_HIDDEN(name) \ + [IDREG_IDX(SYS_##name)] = &(struct id_reg_desc) { \ + .reg_desc = ID_HIDDEN(name), \ + .flags = ID_DESC_REG_HIDDEN, \ + } + +#define ID_DESC_UNALLOC(crm, op2) \ + [crm << 3 | op2] = &(struct id_reg_desc) { \ + .reg_desc = ID_UNALLOCATED(crm, op2), \ + .flags = ID_DESC_REG_UNALLOC, \ + } + #define ID_DESC(id_reg_name, id_reg_desc) \ [IDREG_IDX(SYS_##id_reg_name)] = (id_reg_desc) -/* A table for ID registers's information. */ +/* + * A table for ID registers's information. + * All entries in the table except ID_DESC_HIDDEN and ID_DESC_UNALLOC + * must have corresponding entries in arm64_ftr_regs[] in + * arch/arm64/kernel/cpufeature.c because read_sanitised_ftr_reg() is + * called for each of the ID registers. + */ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=1 */ + ID_DESC_DEFAULT(ID_PFR0_EL1), + ID_DESC_DEFAULT(ID_PFR1_EL1), ID_DESC(ID_DFR0_EL1, &id_dfr0_el1_desc), + ID_DESC_HIDDEN(ID_AFR0_EL1), + ID_DESC_DEFAULT(ID_MMFR0_EL1), + ID_DESC_DEFAULT(ID_MMFR1_EL1), + ID_DESC_DEFAULT(ID_MMFR2_EL1), + ID_DESC_DEFAULT(ID_MMFR3_EL1), + + /* CRm=2 */ + ID_DESC_DEFAULT(ID_ISAR0_EL1), + ID_DESC_DEFAULT(ID_ISAR1_EL1), + ID_DESC_DEFAULT(ID_ISAR2_EL1), + ID_DESC_DEFAULT(ID_ISAR3_EL1), + ID_DESC_DEFAULT(ID_ISAR4_EL1), + ID_DESC_DEFAULT(ID_ISAR5_EL1), + ID_DESC_DEFAULT(ID_MMFR4_EL1), + ID_DESC_DEFAULT(ID_ISAR6_EL1), /* CRm=3 */ + ID_DESC_DEFAULT(MVFR0_EL1), ID_DESC(MVFR1_EL1, &mvfr1_el1_desc), + ID_DESC_DEFAULT(MVFR2_EL1), + ID_DESC_UNALLOC(3, 3), + ID_DESC_DEFAULT(ID_PFR2_EL1), + ID_DESC_HIDDEN(ID_DFR1_EL1), + ID_DESC_DEFAULT(ID_MMFR5_EL1), + ID_DESC_UNALLOC(3, 7), /* CRm=4 */ ID_DESC(ID_AA64PFR0_EL1, &id_aa64pfr0_el1_desc), ID_DESC(ID_AA64PFR1_EL1, &id_aa64pfr1_el1_desc), + ID_DESC_UNALLOC(4, 2), + ID_DESC_UNALLOC(4, 3), + ID_DESC_DEFAULT(ID_AA64ZFR0_EL1), + ID_DESC_UNALLOC(4, 5), + ID_DESC_UNALLOC(4, 6), + ID_DESC_UNALLOC(4, 7), /* CRm=5 */ ID_DESC(ID_AA64DFR0_EL1, &id_aa64dfr0_el1_desc), + ID_DESC_DEFAULT(ID_AA64DFR1_EL1), + ID_DESC_UNALLOC(5, 2), + ID_DESC_UNALLOC(5, 3), + ID_DESC_HIDDEN(ID_AA64AFR0_EL1), + ID_DESC_HIDDEN(ID_AA64AFR1_EL1), + ID_DESC_UNALLOC(5, 6), + ID_DESC_UNALLOC(5, 7), /* CRm=6 */ ID_DESC(ID_AA64ISAR0_EL1, &id_aa64isar0_el1_desc), ID_DESC(ID_AA64ISAR1_EL1, &id_aa64isar1_el1_desc), + ID_DESC_DEFAULT(ID_AA64ISAR2_EL1), + ID_DESC_UNALLOC(6, 3), + ID_DESC_UNALLOC(6, 4), + ID_DESC_UNALLOC(6, 5), + ID_DESC_UNALLOC(6, 6), + ID_DESC_UNALLOC(6, 7), /* CRm=7 */ ID_DESC(ID_AA64MMFR0_EL1, &id_aa64mmfr0_el1_desc), + ID_DESC_DEFAULT(ID_AA64MMFR1_EL1), + ID_DESC_DEFAULT(ID_AA64MMFR2_EL1), + ID_DESC_UNALLOC(7, 3), + ID_DESC_UNALLOC(7, 4), + ID_DESC_UNALLOC(7, 5), + ID_DESC_UNALLOC(7, 6), + ID_DESC_UNALLOC(7, 7), }; static inline struct id_reg_desc *get_id_reg_desc(u32 id) From patchwork Fri Mar 11 04:47:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777425 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 2F8FDC433F5 for ; Fri, 11 Mar 2022 04:54:43 +0000 (UTC) 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=pBZeqAYljxRDfzoAwC97CtQXs9c40a3IH4icKDmlcTc=; b=fijg1Gw0l/xzG+IcZMqG5hrauO dskEpIPCcHlB36Yx6Zui2SHn+ut9NdQiG0g5q368rch17jlRc7AOny/4mfydnFDf4NjF7THfW/l9f IRhtjfC5i0Sa5K722cZ03F/WmYnvvUTXn4Rh6huDeTNaJgso8SRLzIYDzrAfZCKdncNDF6lmzyG1v uGyFnsG1ZnP3OaZq4CpIML7mbUjEH7/y2ekGICIXRJ83lpHB3X9k5tnJsfVewATYMsRH8iAQtkptz tE5Toz/tvml8bEF0fnfUeTdD38o5D/1qiMH2pqSkdaF8Jtf4jw8h38iZ19gInU9jTcpEXeuAQNdFn RWD41WqQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXHA-00F1kV-PD; Fri, 11 Mar 2022 04:53:17 +0000 Received: from mail-pl1-x649.google.com ([2607:f8b0:4864:20::649]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCu-00EziA-UJ for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:55 +0000 Received: by mail-pl1-x649.google.com with SMTP id y3-20020a1709029b8300b0014c8bcb70a1so3936043plp.3 for ; Thu, 10 Mar 2022 20:48:52 -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=a5NZVbIGTYSicQYzOe725Txq1lABLpfJECv3sjtkGuU=; b=rZWabE3/DjqFkZZ9yem9BCkI5hKWm8VfpXefmCQaPcTs14QvUZ0vcayO45kMleKK29 GMp09uKACG3tWlNHVh3GPHV2J0SwJPZCeNrIONstfq05qxdkbiLxCVXxS/XrIwKo4WnA AeHEt3sWNHx3yld+TIk/OJY6tevxKHjWwYOQ7AjpX2hbpmhAnpy7wBO2QmW1uQa7QIbs OpK+PLPBOAIEvTVYxTTjye4f7GxhrytGEIbBeTpAEaoW3VyZBxElnQ0cYInZQYvlCN2O tY3S0V0dkRY4PvNVsk3du41C01mZyzMVDQ4fwQChOKSbCTqvCx4/AWIpb0mUwmpAtiKc HsMg== 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=a5NZVbIGTYSicQYzOe725Txq1lABLpfJECv3sjtkGuU=; b=rNiaOq4LsG0ryRi8cKE3O77rS+XlHvmfJL8Bgb45wBsR5rYPI6WFSe9p+Ta8Za67XV q877hC30ARgUREKyA9+GGiFOWqG+GUll0PjnlWAmCJfC4Nry7YLjAthfM1l7V6mZw100 g3hQoozieQdDhfd4z0wtY7HM+xGguw2zE9P2jkC6zGYLcZD5C7DOdAnaAd+2jCl5zG0i HcDA5oxWMU+ukGyWfriAJSKvAf+n3wtSepqmEsf/oBJR5oc/MtJWSRy2YrQmo3Bu9QKY XR7xnvPSz2CFvZFoa8cB6Rv8Zbewqmc61zKo2uTbXy3tPimFv2qVbcTqC8xPjovZbQyq ZOtw== X-Gm-Message-State: AOAM5300GSimCa8QzQJ0UkHQSsrzl9DbOdTB0x/7u8Hz4TIMU0c1AIvP yKvvQ+X76yjAtWgHKMB/1q1Kmv5EP7A= X-Google-Smtp-Source: ABdhPJzvkmL3IM37HsTGDKBcNfNxa8ZQ40eJ1UsQa3PnTHm4qaAZLEQpv/Muf4haE6tVZuP1eE4Yz/InSqM= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:4d81:b0:1bf:8ce4:4f51 with SMTP id oj1-20020a17090b4d8100b001bf8ce44f51mr435697pjb.0.1646974131159; Thu, 10 Mar 2022 20:48:51 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:58 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-13-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 12/25] KVM: arm64: Use id_reg_desc_table for ID registers 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 , Fuad Tabba , 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-20220310_204853_055693_93222335 X-CRM114-Status: GOOD ( 23.49 ) 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 Use id_reg_desc_table for ID registers instead of sys_reg_descs as id_reg_desc_table has all ID register entries that sys_reg_descs has, and remove the ID register entries from sys_reg_descs, which are no longer used. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 201 +++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 109 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index fe2a4de2b8f3..ba851de6486d 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -337,6 +337,11 @@ struct id_reg_desc { const struct id_reg_desc *id_reg); }; +static inline struct id_reg_desc *sys_to_id_desc(const struct sys_reg_desc *r) +{ + return container_of(r, struct id_reg_desc, reg_desc); +} + static void id_reg_desc_init(struct id_reg_desc *id_reg) { u32 id = reg_to_encoding(&id_reg->reg_desc); @@ -1696,23 +1701,15 @@ static u64 __read_id_reg(const struct kvm_vcpu *vcpu, return val; } -static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 id) +static u64 read_id_reg_with_encoding(const struct kvm_vcpu *vcpu, u32 encoding) { - u64 val; - const struct id_reg_desc *id_reg = get_id_reg_desc(id); - - if (id_reg) - val = __read_id_reg(vcpu, id_reg); - else - val = read_kvm_id_reg(vcpu->kvm, id); - - return val; + return __read_id_reg(vcpu, get_id_reg_desc(encoding)); } static u64 read_id_reg(const struct kvm_vcpu *vcpu, struct sys_reg_desc const *r, bool raz) { - return raz ? 0 : read_id_reg_with_encoding(vcpu, reg_to_encoding(r)); + return raz ? 0 : __read_id_reg(vcpu, sys_to_id_desc(r)); } static unsigned int id_visibility(const struct kvm_vcpu *vcpu, @@ -1826,13 +1823,7 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, if (raz) return -EINVAL; - /* - * Don't allow to modify the register's value if the register doesn't - * have the id_reg_desc. - */ - id_reg = get_id_reg_desc(encoding); - if (!id_reg) - return -EINVAL; + id_reg = sys_to_id_desc(rd); /* * Skip the validation of AArch32 ID registers if the system doesn't @@ -2055,83 +2046,6 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 }, - /* - * ID regs: all ID_SANITISED() entries here must have corresponding - * entries in arm64_ftr_regs[]. - */ - - /* AArch64 mappings of the AArch32 ID registers */ - /* CRm=1 */ - ID_SANITISED(ID_PFR0_EL1), - ID_SANITISED(ID_PFR1_EL1), - ID_SANITISED(ID_DFR0_EL1), - ID_HIDDEN(ID_AFR0_EL1), - ID_SANITISED(ID_MMFR0_EL1), - ID_SANITISED(ID_MMFR1_EL1), - ID_SANITISED(ID_MMFR2_EL1), - ID_SANITISED(ID_MMFR3_EL1), - - /* CRm=2 */ - ID_SANITISED(ID_ISAR0_EL1), - ID_SANITISED(ID_ISAR1_EL1), - ID_SANITISED(ID_ISAR2_EL1), - ID_SANITISED(ID_ISAR3_EL1), - ID_SANITISED(ID_ISAR4_EL1), - ID_SANITISED(ID_ISAR5_EL1), - ID_SANITISED(ID_MMFR4_EL1), - ID_SANITISED(ID_ISAR6_EL1), - - /* CRm=3 */ - ID_SANITISED(MVFR0_EL1), - ID_SANITISED(MVFR1_EL1), - ID_SANITISED(MVFR2_EL1), - ID_UNALLOCATED(3,3), - ID_SANITISED(ID_PFR2_EL1), - ID_HIDDEN(ID_DFR1_EL1), - ID_SANITISED(ID_MMFR5_EL1), - ID_UNALLOCATED(3,7), - - /* AArch64 ID registers */ - /* CRm=4 */ - ID_SANITISED(ID_AA64PFR0_EL1), - ID_SANITISED(ID_AA64PFR1_EL1), - ID_UNALLOCATED(4,2), - ID_UNALLOCATED(4,3), - ID_SANITISED(ID_AA64ZFR0_EL1), - ID_UNALLOCATED(4,5), - ID_UNALLOCATED(4,6), - ID_UNALLOCATED(4,7), - - /* CRm=5 */ - ID_SANITISED(ID_AA64DFR0_EL1), - ID_SANITISED(ID_AA64DFR1_EL1), - ID_UNALLOCATED(5,2), - ID_UNALLOCATED(5,3), - ID_HIDDEN(ID_AA64AFR0_EL1), - ID_HIDDEN(ID_AA64AFR1_EL1), - ID_UNALLOCATED(5,6), - ID_UNALLOCATED(5,7), - - /* CRm=6 */ - ID_SANITISED(ID_AA64ISAR0_EL1), - ID_SANITISED(ID_AA64ISAR1_EL1), - ID_SANITISED(ID_AA64ISAR2_EL1), - ID_UNALLOCATED(6,3), - ID_UNALLOCATED(6,4), - ID_UNALLOCATED(6,5), - ID_UNALLOCATED(6,6), - ID_UNALLOCATED(6,7), - - /* CRm=7 */ - ID_SANITISED(ID_AA64MMFR0_EL1), - ID_SANITISED(ID_AA64MMFR1_EL1), - ID_SANITISED(ID_AA64MMFR2_EL1), - ID_UNALLOCATED(7,3), - ID_UNALLOCATED(7,4), - ID_UNALLOCATED(7,5), - ID_UNALLOCATED(7,6), - ID_UNALLOCATED(7,7), - { SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 }, { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 }, { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 }, @@ -2946,12 +2860,38 @@ static bool is_imp_def_sys_reg(struct sys_reg_params *params) return params->Op0 == 3 && (params->CRn & 0b1011) == 0b1011; } +static inline const struct sys_reg_desc * +find_id_reg(const struct sys_reg_params *params) +{ + u32 id = reg_to_encoding(params); + struct id_reg_desc *idr; + + if (!is_id_reg(id)) + return NULL; + + idr = get_id_reg_desc(id); + + return idr ? &idr->reg_desc : NULL; +} + +static const struct sys_reg_desc * +find_sys_reg(const struct sys_reg_params *params) +{ + const struct sys_reg_desc *r = NULL; + + r = find_id_reg(params); + if (!r) + r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); + + return r; +} + static int emulate_sys_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *params) { const struct sys_reg_desc *r; - r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); + r = find_sys_reg(params); if (likely(r)) { perform_access(vcpu, params, r); @@ -2966,6 +2906,8 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu, return 1; } +static void kvm_reset_id_regs(struct kvm_vcpu *vcpu); + /** * kvm_reset_sys_regs - sets system registers to reset value * @vcpu: The VCPU pointer @@ -2980,6 +2922,8 @@ void kvm_reset_sys_regs(struct kvm_vcpu *vcpu) for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) if (sys_reg_descs[i].reset) sys_reg_descs[i].reset(vcpu, &sys_reg_descs[i]); + + kvm_reset_id_regs(vcpu); } /** @@ -3063,7 +3007,7 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu, if (!index_to_params(id, ¶ms)) return NULL; - r = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); + r = find_sys_reg(¶ms); /* Not saved in the sys_reg array and not otherwise accessible? */ if (r && !(r->reg || r->get_user)) @@ -3360,6 +3304,8 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu, return 0; } +static int walk_id_regs(struct kvm_vcpu *vcpu, u64 __user *uind); + /* Assumed ordered tables, see kvm_sys_reg_table_init. */ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) { @@ -3375,6 +3321,12 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) if (err) return err; } + + err = walk_id_regs(vcpu, uind); + if (err < 0) + return err; + + total += err; return total; } @@ -3625,6 +3577,25 @@ static inline struct id_reg_desc *get_id_reg_desc(u32 id) return id_reg_desc_table[IDREG_IDX(id)]; } +static int walk_id_regs(struct kvm_vcpu *vcpu, u64 __user *uind) +{ + const struct sys_reg_desc *sys_reg; + int err, i; + unsigned int total = 0; + + for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { + if (!id_reg_desc_table[i]) + continue; + + sys_reg = &id_reg_desc_table[i]->reg_desc; + err = walk_one_sys_reg(vcpu, sys_reg, &uind, &total); + if (err) + return err; + } + + return total; +} + static void id_reg_desc_init_all(void) { int i; @@ -3647,23 +3618,35 @@ void set_default_id_regs(struct kvm *kvm) { int i; u32 id; - const struct sys_reg_desc *rd; - u64 val; struct id_reg_desc *idr; - for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) { - rd = &sys_reg_descs[i]; - if (rd->access != access_id_reg) - /* Not ID register, or hidden/reserved ID register */ + for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { + idr = id_reg_desc_table[i]; + if (!idr) + continue; + + if (idr->flags & (ID_DESC_REG_HIDDEN | ID_DESC_REG_UNALLOC)) + /* Nothing to do for hidden/unalloc registers */ continue; - id = reg_to_encoding(rd); - if (WARN_ON_ONCE(!is_id_reg(id))) - /* Shouldn't happen */ + id = reg_to_encoding(&idr->reg_desc); + WARN_ON_ONCE(write_kvm_id_reg(kvm, id, idr->vcpu_limit_val)); + } +} + +static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) +{ + int i; + const struct sys_reg_desc *r; + struct id_reg_desc *id_reg; + + for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { + id_reg = (struct id_reg_desc *)id_reg_desc_table[i]; + if (!id_reg) continue; - idr = get_id_reg_desc(id); - val = idr ? idr->vcpu_limit_val : read_sanitised_ftr_reg(id); - WARN_ON_ONCE(write_kvm_id_reg(kvm, id, val)); + r = &id_reg->reg_desc; + if (r->reset) + r->reset(vcpu, r); } } From patchwork Fri Mar 11 04:47:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777427 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 6BE6AC433F5 for ; Fri, 11 Mar 2022 04:55:36 +0000 (UTC) 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=LRQ4pCIKLQInP50W1aNaGj1sCXBIbeqhlF4Lzbp3wO0=; b=JoKK8ECQh1FRfdNHz4lZy9lvz7 OQ8HV5m08LmNlbCrENXjbb87G0US1PXLvNIbRjauZPvoG0ZpZJHPWaD41RXxyz7solWN0SP51e12j ynoeEaaf3HPc8yy3LlaKSCJQbbcX6AbloFs+2h8rbpRNQtkLlT1Petv5PxRi62+Qow7EtxeKO2bza TyNUVXUvYtZ0xkUo5bQwgdKTwL4FOHuZyBduNKOiqZ2F/meqQzgLleCCaPlePuNfJxcfP2qcCM8Oh OW84ExjzhZ/BzHF402o2p1l7L178Jszke6uM7grw9DBrUsdbRS1j7YOEjT+nUFKgMKiMXnqcaCvrH 8qqZxqYA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXHa-00F1uE-Pl; Fri, 11 Mar 2022 04:53:43 +0000 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCw-00Ezir-Td for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:56 +0000 Received: by mail-pf1-x449.google.com with SMTP id z194-20020a627ecb000000b004f6db380a59so4508532pfc.19 for ; Thu, 10 Mar 2022 20:48:53 -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=DltmKg7opwhIQvsCwmEx6qs3h14xPlDqswCiLBq3BvI=; b=N39NQTTkdbZnRTzSRZEqZFrgTaFi2lK42y1/qZ1pn8Pbr5yj0p9nYTSuhihb/Lu7sN dcVYmv/4AvKdLQy0RzMJr/m5lgP/QBuf9FWhQU5tcKmJLEpCItk3qaBIYUuyaqVenVRb QPqY7gVLWPRDfezgK4RqFc7luPzOknbDAl0I0mtaKwd/XlEWy/XLC2GGb8aWgsnsZ/ld DT+bSp2hAUW+34+S4eKwqMNUNcpyxVHKM97cmvbV3wBjdQJNAzCQTistKsISe5uLVoZz 8//fO4tniGmbUOmnQGpOVgylJluO75sgWNrifgjIbTlzAefKYxlH7Fi09jTmhfkjfLl6 r6rQ== 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=DltmKg7opwhIQvsCwmEx6qs3h14xPlDqswCiLBq3BvI=; b=nlH+dWXXhLIeTaPzN4StF5ifMZDVa/xQBtyo5sSKhWdUHzsO1gc6Kb+dylJ1b1BGPY rYw+mgDzs+WcPNrK0Quo2no4N79Y6Cu/ponwqXMfXUvsu+562Rmv+ZzFWLKoO0tvR4qm vzvmttArUmRJVtm+ZIColI5mtj4I1edESx/5KVkZ7qE1jWBicE4UTaZtCiXxiJMua9Ar ruJkGHG1K5d0AtAD7vC+2jXh+hmF3WtMCP3vNoCBKJIHVzqBEg0+QPcKUp2XmwnuA9Ib BpnfM+40U1gcC2+uaHnF+AjaoHE3GwGes4fHIvGBlQ2T+9yvrcQlT85p/Mg3F/R4fRxG 4JxQ== X-Gm-Message-State: AOAM530JuHQNVxlRKOzPalthkEDbuBs1rC7O6N0vBPto6Zs7ZarZ7Jtg 63AkcggZqY+JCAT2vCsRsFYHBuD+AmA= X-Google-Smtp-Source: ABdhPJwFRwT5Fgamh4l+5MQdfg7BYHp05vvdFwuVRvSeFNzp6LJbqoSWM+rN32ZUxVO+QSRSMIPfjJ4nruM= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:10cf:b0:4f6:5834:aefb with SMTP id d15-20020a056a0010cf00b004f65834aefbmr8229183pfu.77.1646974132762; Thu, 10 Mar 2022 20:48:52 -0800 (PST) Date: Thu, 10 Mar 2022 20:47:59 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-14-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 13/25] KVM: arm64: Add consistency checking for frac fields of ID registers 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 , Fuad Tabba , 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-20220310_204855_044532_542EA9EA X-CRM114-Status: GOOD ( 20.57 ) 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 Feature fractional field of an ID register cannot be simply validated at KVM_SET_ONE_REG because its validity depends on its (main) feature field value, which could be in a different ID register (and might be set later). Validate fractional fields at the first KVM_RUN instead. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sys_regs.c | 112 ++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 9ffe6604a58a..5e53102a1ac1 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -748,6 +748,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, void set_default_id_regs(struct kvm *kvm); int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval); +int kvm_id_regs_check_frac_fields(const struct kvm_vcpu *vcpu); /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 91110d996ed6..e7dcc7704302 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -599,6 +599,9 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) if (likely(vcpu_has_run_once(vcpu))) return 0; + if (!kvm_vm_is_protected(kvm) && kvm_id_regs_check_frac_fields(vcpu)) + return -EPERM; + kvm_arm_vcpu_init_debug(vcpu); if (likely(irqchip_in_kernel(kvm))) { diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index ba851de6486d..3805b69ed23e 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3397,6 +3397,102 @@ void kvm_sys_reg_table_init(void) id_reg_desc_init_all(); } +/* ID register's fractional field information with its feature field. */ +struct feature_frac { + u32 id; + u32 shift; + u32 frac_id; + u32 frac_shift; +}; + +static struct feature_frac feature_frac_table[] = { + { + .frac_id = SYS_ID_AA64PFR1_EL1, + .frac_shift = ID_AA64PFR1_RASFRAC_SHIFT, + .id = SYS_ID_AA64PFR0_EL1, + .shift = ID_AA64PFR0_RAS_SHIFT, + }, + { + .frac_id = SYS_ID_AA64PFR1_EL1, + .frac_shift = ID_AA64PFR1_MPAMFRAC_SHIFT, + .id = SYS_ID_AA64PFR0_EL1, + .shift = ID_AA64PFR0_MPAM_SHIFT, + }, + { + .frac_id = SYS_ID_AA64PFR1_EL1, + .frac_shift = ID_AA64PFR1_CSV2FRAC_SHIFT, + .id = SYS_ID_AA64PFR0_EL1, + .shift = ID_AA64PFR0_CSV2_SHIFT, + }, +}; + +/* + * Return non-zero if the feature/fractional fields pair are not + * supported. Return zero otherwise. + * This function validates only the fractional feature field, + * and relies on the fact the feature field is validated before + * through arm64_check_features_kvm. + */ +static int vcpu_id_reg_feature_frac_check(const struct kvm_vcpu *vcpu, + const struct feature_frac *ftr_frac) +{ + const struct id_reg_desc *id_reg; + u32 id; + u64 val, lim, mask; + + /* Check if the feature field value is same as the limit */ + id = ftr_frac->id; + id_reg = get_id_reg_desc(id); + + mask = (u64)ARM64_FEATURE_FIELD_MASK << ftr_frac->shift; + val = __read_id_reg(vcpu, id_reg) & mask; + lim = id_reg ? id_reg->vcpu_limit_val : read_sanitised_ftr_reg(id); + lim &= mask; + + if (val != lim) + /* + * The feature level is lower than the limit. + * Any fractional version should be fine. + */ + return 0; + + /* Check the fractional feature field */ + id = ftr_frac->frac_id; + id_reg = get_id_reg_desc(id); + + mask = (u64)ARM64_FEATURE_FIELD_MASK << ftr_frac->frac_shift; + val = __read_id_reg(vcpu, id_reg) & mask; + lim = id_reg ? id_reg->vcpu_limit_val : read_sanitised_ftr_reg(id); + lim &= mask; + + if (val == lim) + /* + * Both the feature and fractional fields are the same + * as limit. + */ + return 0; + + return arm64_check_features_kvm(id, val, lim); +} + +int kvm_id_regs_check_frac_fields(const struct kvm_vcpu *vcpu) +{ + int i, err; + const struct feature_frac *frac; + + /* + * Check ID registers' fractional fields, which aren't checked + * at KVM_SET_ONE_REG. + */ + for (i = 0; i < ARRAY_SIZE(feature_frac_table); i++) { + frac = &feature_frac_table[i]; + err = vcpu_id_reg_feature_frac_check(vcpu, frac); + if (err) + return err; + } + return 0; +} + /* * Update the ID register's field with @fval for the guest. * The caller is expected to hold the kvm->lock. @@ -3600,6 +3696,8 @@ static void id_reg_desc_init_all(void) { int i; struct id_reg_desc *id_reg; + struct feature_frac *frac; + u64 ftr_mask = ARM64_FEATURE_FIELD_MASK; for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { id_reg = (struct id_reg_desc *)id_reg_desc_table[i]; @@ -3608,6 +3706,20 @@ static void id_reg_desc_init_all(void) id_reg_desc_init(id_reg); } + + /* + * Update ignore_mask of ID registers based on fractional fields + * information. Any ID register that have fractional fields + * is expected to have its own id_reg_desc. + */ + for (i = 0; i < ARRAY_SIZE(feature_frac_table); i++) { + frac = &feature_frac_table[i]; + id_reg = get_id_reg_desc(frac->frac_id); + if (WARN_ON_ONCE(!id_reg)) + continue; + + id_reg->ignore_mask |= ftr_mask << frac->frac_shift; + } } /* From patchwork Fri Mar 11 04:48:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777428 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 3A3C5C433EF for ; Fri, 11 Mar 2022 04:55:38 +0000 (UTC) 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=jQFKBDK2sT3RXaawBtbPlq8uij4OAfjKydLv+rmZT68=; b=J749H22Ps/y3e8nuGf96R43yfV aPKpeFij4ZgT70Qi02mTY9cemmSQ5FjqW9EGqb4nggyeNohaygC1Czn319KbGfCY9iYGIM+CK78ij h36uGY9XZEDs2Pjx6n65qr6fNhsEYOBEXRgml/d79XKcaJAEplR65l5YNWcc5SdKO3sJKAiqhUdHD WE8APiL0rzjQitMP5Fng8icXbK6GEtQBq4BxDtUywJtNiu2bwdLWYZPNualGAdkBP5f/SkEtNmFw5 tmbzTjd3w3ERf2NImauS+aBnZHvXOvnMi47EJSgotLGOlz1dgfwfHnnJibjppMJi0wdPbkhxQ3412 RNDlC4nA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXI8-00F26L-Si; Fri, 11 Mar 2022 04:54:17 +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 1nSXCy-00Ezjk-CE for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:48:57 +0000 Received: by mail-pg1-x549.google.com with SMTP id z10-20020a634c0a000000b0036c5eb39076so4120996pga.18 for ; Thu, 10 Mar 2022 20:48: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=YvkdLZdpcr97EpSsUi5adIM71O6zx1+CVaghTM2lKQc=; b=WW9mUBlAXTHtpKEr3Ay7NmT20frRkus2LqacrMY+0B0b1ZhuU3tEvhK6b3wZU/ORFt sa55nV3ZrgY5MgtjlQVBpdtqyFbjZppWQCm2l0cVBWAqi1VDRVbjrjB/uu1VrUXHsT3v JTQv7fegNAfQHGW26cOwiExvl2UWjMKnpBMAexNgf8VDKqrGSfZLt3A33jk7p/97Cfn4 9+3/YGnvvaatyDI8WqBeDbkRQt/2eHQO/TObdfaHNMTWEOnV/efpI33e3RpcIgKOFDFS ++uMr4ZigfVe97viZ9lx3iiQPIXSsluL57ZzBOGYES5FDwrFO0ILP8RZ5oAwpA43s2IW Abzw== 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=YvkdLZdpcr97EpSsUi5adIM71O6zx1+CVaghTM2lKQc=; b=7LWMuCxr1RVYPy3jNKTAVQaVdw696GTje5RsQMz66bm5cgUSVtd8732c0fp+7MJTmI XD6CNkvBIPnE/MLtq3gv8j+K3ZHAwbnbKvD1tC4Tlfc8lZaurd2uz1glppcgMLMpm7ug QJi6YzNZadG6kJi7+DjwFX/RnyNJc7GMs7Cmtr89ocGh2WGHYS9ODcU18/CA2f5ZTklU vbaZo2JaWixJY0oZze/RGAMI8bZ4bMcW02uEFM/ptdCj6WTYNVtZrplNYaReFanQUQBT YWlRyR2N3H9aeG086NeW80QEFMBZtId+iWlCV1aGJ3YVvIgotSn3RPfQCvdLcHpOZ6EA GZoA== X-Gm-Message-State: AOAM530QdqxsK2lxxf/LCYWSvvBlIKqBNABB3/bZ9Gd/N7xn0VSnwsFE /AcvIbydNv9BdQfKalY3paNtzx0k7O0= X-Google-Smtp-Source: ABdhPJyXnNci0fOzvDdVKJf4gcHvVbtR1SLTxJuXYaGJpVy9F9SwRVGou9JVMngVfwiQy4DD8uTH1DNToK8= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:c96:b0:4f7:203a:e8de with SMTP id a22-20020a056a000c9600b004f7203ae8demr8180188pfv.32.1646974134582; Thu, 10 Mar 2022 20:48:54 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:00 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-15-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 14/25] KVM: arm64: Introduce KVM_CAP_ARM_ID_REG_CONFIGURABLE capability 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 , Fuad Tabba , 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-20220310_204856_469585_058B1C8B X-CRM114-Status: GOOD ( 11.43 ) 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 Introduce a new capability KVM_CAP_ARM_ID_REG_CONFIGURABLE to indicate that ID registers are writable by userspace. Signed-off-by: Reiji Watanabe --- Documentation/virt/kvm/api.rst | 12 ++++++++++++ arch/arm64/kvm/arm.c | 1 + include/uapi/linux/kvm.h | 1 + 3 files changed, 14 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 9f3172376ec3..d2cd404d74c2 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -2607,6 +2607,10 @@ EINVAL. After the vcpu's SVE configuration is finalized, further attempts to write this register will fail with EPERM. +The arm64 ID registers (where Op0=3, Op1=0, CRn=0, 0<=CRm<8, 0<=Op2<8) +are allowed to set by userspace if KVM_CAP_ARM_ID_REG_CONFIGURABLE is +available. They become immutable after calling KVM_RUN on any of the +vcpus in the guest (modifying values of those registers will fail). MIPS registers are mapped using the lower 32 bits. The upper 16 of that is the register group type: @@ -7575,3 +7579,11 @@ The argument to KVM_ENABLE_CAP is also a bitmask, and must be a subset of the result of KVM_CHECK_EXTENSION. KVM will forward to userspace the hypercalls whose corresponding bit is in the argument, and return ENOSYS for the others. + +8.35 KVM_CAP_ARM_ID_REG_CONFIGURABLE +------------------------------------ + +:Architectures: arm64 + +This capability indicates that userspace can modify the ID registers +via KVM_SET_ONE_REG ioctl. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e7dcc7704302..68ffced5b09e 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -210,6 +210,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_SET_GUEST_DEBUG: case KVM_CAP_VCPU_ATTRIBUTES: case KVM_CAP_PTP_KVM: + case KVM_CAP_ARM_ID_REG_CONFIGURABLE: r = 1; break; case KVM_CAP_SET_GUEST_DEBUG2: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 507ee1f2aa96..a9351727a7aa 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1135,6 +1135,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_XSAVE2 208 #define KVM_CAP_SYS_ATTRIBUTES 209 #define KVM_CAP_PPC_AIL_MODE_3 210 +#define KVM_CAP_ARM_ID_REG_CONFIGURABLE 211 #ifdef KVM_CAP_IRQ_ROUTING From patchwork Fri Mar 11 04:48:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777430 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 474A5C433F5 for ; Fri, 11 Mar 2022 04:57:14 +0000 (UTC) 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=BkFxJ4ffmeIp5Np4IiLKIWIT9V6j9XrctOWU/klpMmQ=; b=bYe9TJIGj9FF7pXbAhjRNYOTE2 sRTvXydL8VDh96d6hBCkgFakDrHKUVQbrCGX+a8V7P9vk0OnLP0vdivZIVe3Vy7qMbVg2YVYNo9vQ vhQIky3mKbqYcDf9V00PAthk7KbY17jBQZhPocphCvtX/U5oKZpHJWTt6MlCz+/MxV9MyQEAR4s54 MtrFrPo3HmDM2fZkCn7+4XUf7cZ+IyeVaUa5v7PF5LgzBsQuYxHWcd4bHB841Twq7B0C836KvGXes PEvrAwjVCBXwp9Nik+oamkKezsb0BPtF9N6IuXZRJjzEJh/si1DTYewnU+PsulwxgwkXNXhcyFtVy nE7mJ/4Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXJP-00F2gO-0A; Fri, 11 Mar 2022 04:55:36 +0000 Received: from mail-pj1-x1049.google.com ([2607:f8b0:4864:20::1049]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXCz-00Ezkl-At for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:02 +0000 Received: by mail-pj1-x1049.google.com with SMTP id m9-20020a17090ade0900b001bedf2d1d4cso7193675pjv.2 for ; Thu, 10 Mar 2022 20:48:56 -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=jfOH2015965eWLFEWQQye3bOrg7hJCS3oXcPyaL1nbU=; b=sG/c9gU4wM5zOhcrJieLoUIYWMfGBw/6exm9gIixl0aHC/kj6Dondr0Q7x3JYLM5vj R+ouNeyO2pn4b8bqk26LJaw3qWh63XOGLBQGFRtfPQOGjMQGABhwNsPUJk2ibi4EdKsR Gh7N1QezxcHNaJDjznAmAaNUb0U+ztqg1Pop0QeeSpU1lkmFKB+Z0XHK2ZfxGGpuwZYE Xd2YMpJZz0vlUUMTOOee9epkA98ryHEi30vIxXfCc64v8DXtTFL/q2E49MyY4FdbbWHB E0kg9EIRb89GBwOu83gU2io4RwiRV1zIZeiJcErZuO4mORkz8WxSLkh4u0nH5xJsCjMn ig9w== 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=jfOH2015965eWLFEWQQye3bOrg7hJCS3oXcPyaL1nbU=; b=p5Hyr6gjk2ZdAA7FPEWMeKUwJ0U5laD4J+qpj7bYu0e8wHuLkaTNKYtImZQGGqLasH Zpuj6BEJ5b/50T7FKTLtuNhEaVwMruFpOWYKECf0fUNrznocL8dNQaMmhPV6xmjnn7XG uV95UPwCw8oEqSpibiLcJ6f5Dkz3fIz/rLTDwUF/zdVXLuNffYLCHlNVhI80xXVbIkpG DOFMhtrHVWmXPW8mzqED2N0UT9cfts/U0IR4KsMGEKqshCiVJj7h5i7q9ZpMgCHEgh9p Ff7F4bwrAWXiJIkCHoWCu/9T9TV+eWNyv0/I2IdbYah/AspOc1rlfh52Jj1hr9MFGtEF /cqw== X-Gm-Message-State: AOAM533glMYRU67UZGWQJ0bhCYcdSsqE8J3OMxmOctIiZukqirv43y7V pxWKpNJ4EmNX07slrQFoy5aYTLd6m1w= X-Google-Smtp-Source: ABdhPJw/8c0fXAUEpUFmm96pA3F7939672imxM0ZO6QIV+mfM91xCKyGQlgMwUOKKPrD09erGPx81DXak9I= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:4d88:b0:1bf:793:7134 with SMTP id oj8-20020a17090b4d8800b001bf07937134mr19865544pjb.112.1646974136161; Thu, 10 Mar 2022 20:48:56 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:01 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-16-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 15/25] KVM: arm64: Add kunit test for ID register validation 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 , Fuad Tabba , 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-20220310_204857_447584_8CDE116F X-CRM114-Status: GOOD ( 25.71 ) 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 Add kunit tests for functions that are used for validation of ID registers, CONFIG_KVM_KUNIT_TEST option to enable the tests, and .kunitconfig to run the kunit tests. One line change below is needed in the default arm64.py to fully run all of those kunit tests. ----------------------------------------------------------------------- $ diff tools/testing/kunit/qemu_configs/arm64.py arm64_kvm_min.py 12c12 < extra_qemu_params=['-machine virt', '-cpu cortex-a57']) --- > extra_qemu_params=['-M virt,virtualization=on,mte=on', '-cpu max,sve=on']) ----------------------------------------------------------------------- The outputs from the tests are: ----------------------------------------------------------------------- $ tools/testing/kunit/kunit.py run --timeout=60 --jobs=`nproc --all` \ --arch=arm64 --cross_compile=aarch64-linux-gnu- \ --qemu_config arm64_kvm_min.py \ --kunitconfig=arch/arm64/kvm/.kunitconfig [20:02:52] Configuring KUnit Kernel ... [20:02:52] Building KUnit Kernel ... Populating config with: $ make ARCH=arm64 olddefconfig CROSS_COMPILE=aarch64-linux-gnu- O=.kunit Building with: $ make ARCH=arm64 --jobs=96 CROSS_COMPILE=aarch64-linux-gnu- O=.kunit [20:02:59] Starting KUnit Kernel (1/1)... [20:02:59] ============================================================ Running tests with: $ qemu-system-aarch64 -nodefaults -m 1024 -kernel .kunit/arch/arm64/boot/Image.gz -append 'mem=1G console=tty kunit_shutdown=halt console=ttyAMA0 kunit_shutdown=reboot' -no-reboot -nographic -serial stdio -M virt,virtualization=on,mte=on -cpu max,sve=on [20:03:00] ========== kvm-sys-regs-test-suite (14 subtests) =========== [20:03:00] [PASSED] vcpu_id_reg_feature_frac_check_test [20:03:00] [PASSED] validate_id_aa64mmfr0_tgran2_test [20:03:01] [PASSED] validate_id_aa64mmfr0_tgran2_test [20:03:01] [PASSED] validate_id_aa64mmfr0_tgran2_test [20:03:01] [PASSED] validate_id_aa64pfr0_el1_test [20:03:01] [PASSED] validate_id_aa64pfr1_el1_test [20:03:01] [PASSED] validate_id_aa64isar0_el1_test [20:03:01] [PASSED] validate_id_aa64isar1_el1_test [20:03:01] [PASSED] validate_id_aa64mmfr0_el1_test [20:03:01] [PASSED] validate_id_aa64mmfr1_el1_test [20:03:01] [PASSED] validate_id_aa64dfr0_el1_test [20:03:01] [PASSED] validate_id_dfr0_el1_test [20:03:01] [PASSED] validate_mvfr1_el1_test [20:03:01] [PASSED] validate_id_reg_test [20:03:01] ============= [PASSED] kvm-sys-regs-test-suite ============= [20:03:01] ============================================================ [20:03:01] Testing complete. Passed: 14, Failed: 0, Crashed: 0, Skipped: 0, Errors: 0 [20:03:01] Elapsed time: 8.534s total, 0.003s configuring, 6.962s building, 1.569s running ----------------------------------------------------------------------- Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/.kunitconfig | 4 + arch/arm64/kvm/Kconfig | 11 + arch/arm64/kvm/sys_regs.c | 4 + arch/arm64/kvm/sys_regs_test.c | 983 +++++++++++++++++++++++++++++++++ 4 files changed, 1002 insertions(+) create mode 100644 arch/arm64/kvm/.kunitconfig create mode 100644 arch/arm64/kvm/sys_regs_test.c diff --git a/arch/arm64/kvm/.kunitconfig b/arch/arm64/kvm/.kunitconfig new file mode 100644 index 000000000000..c564c98fc319 --- /dev/null +++ b/arch/arm64/kvm/.kunitconfig @@ -0,0 +1,4 @@ +CONFIG_KUNIT=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_KVM_KUNIT_TEST=y diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 8a5fbbf084df..0d628d0e7dd5 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -56,4 +56,15 @@ config NVHE_EL2_DEBUG If unsure, say N. +config KVM_KUNIT_TEST + bool "KUnit tests for KVM on ARM64 processors" if !KUNIT_ALL_TESTS + depends on KVM && KUNIT + default KUNIT_ALL_TESTS + help + Say Y here to enable KUnit tests for the KVM on ARM64. + Only useful for KVM/ARM development and are not for inclusion into + a production build. + + If unsure, say N. + endif # VIRTUALIZATION diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 3805b69ed23e..b44a3bf488c1 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -3762,3 +3762,7 @@ static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) r->reset(vcpu, r); } } + +#if IS_ENABLED(CONFIG_KVM_KUNIT_TEST) +#include "sys_regs_test.c" +#endif diff --git a/arch/arm64/kvm/sys_regs_test.c b/arch/arm64/kvm/sys_regs_test.c new file mode 100644 index 000000000000..954c01876977 --- /dev/null +++ b/arch/arm64/kvm/sys_regs_test.c @@ -0,0 +1,983 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for arch/arm64/kvm/sys_regs.c. + */ + +#include +#include +#include +#include +#include +#include "asm/sysreg.h" + +/* + * Create a vcpu with the minimum fields required for testing in this file + * including the struct kvm. Any resources that are allocated by this + * function must be allocated by kunit_* so that we don't need to explicitly + * free them. + */ +static struct kvm_vcpu *test_kvm_vcpu_init(struct kunit *test) +{ + struct kvm_vcpu *vcpu; + struct kvm *kvm; + + kvm = kunit_kzalloc(test, sizeof(struct kvm), GFP_KERNEL); + if (!kvm) + return NULL; + + vcpu = kunit_kzalloc(test, sizeof(struct kvm_vcpu), GFP_KERNEL); + if (!vcpu) { + kunit_kfree(test, kvm); + return NULL; + } + + vcpu->cpu = -1; + vcpu->kvm = kvm; + vcpu->vcpu_id = 0; + + return vcpu; +} + +static void test_kvm_vcpu_fini(struct kunit *test, struct kvm_vcpu *vcpu) +{ + if (vcpu->kvm) + kunit_kfree(test, vcpu->kvm); + + kunit_kfree(test, vcpu); +} + +/* Test parameter information to test arm64_check_features */ +struct check_features_test { + u64 check_types; + u64 value; + u64 limit; + int expected; +}; + + +/* Used to define test parameters of vcpu_id_reg_feature_frac_check_test() */ +struct feat_info { + u32 id; + u32 shift; + u32 value; + u32 limit; +}; + +struct frac_check_test { + struct feat_info feat; + struct feat_info frac_feat; + int ret; +}; + +#define FRAC_FEAT(id, shift, value, limit) {id, shift, value, limit} + +/* Tests parameters of vcpu_id_reg_feature_frac_check_test() */ +struct frac_check_test frac_params[] = { + { + /* + * The feature value is smaller than its limit. + * Expect no error regardless of the frac value. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 2), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 1, 1), + 0, + }, + { + /* + * The feature value is smaller than its limit. + * Expect no error regardless of the frac value. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 2), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 1, 2), + 0, + }, + { + /* + * The feature value is smaller than its limit. + * Expect no error regardless of the frac value. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 2), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 2, 1), + 0, + }, + { + /* + * Both the feature and frac values are same as their limits. + * Expect no error. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 1), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 1, 1), + 0, + }, + { + /* + * The feature value is same as its limit, and the frac value + * is smaller than its limit. Expect no error. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 1), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 1, 2), + 0, + }, + { + /* + * The feature value is same as its limit, and the frac value + * is larger than its limit. Expect an error. + */ + FRAC_FEAT(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_RAS_SHIFT, 1, 1), + FRAC_FEAT(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_RASFRAC_SHIFT, 2, 1), + -E2BIG, + }, + +}; + +static void frac_case_to_desc(struct frac_check_test *t, char *desc) +{ + struct feat_info *feat = &t->feat; + struct feat_info *frac = &t->frac_feat; + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "feat - shift:%d, val:%d, lim:%d, frac - shift:%d, val:%d, lim:%d\n", + feat->shift, feat->value, feat->limit, + frac->shift, frac->value, frac->limit); +} + +KUNIT_ARRAY_PARAM(frac, frac_params, frac_case_to_desc); + +/* Tests for vcpu_id_reg_feature_frac_check(). */ +static void vcpu_id_reg_feature_frac_check_test(struct kunit *test) +{ + struct kvm_vcpu *vcpu; + u32 id, frac_id; + struct id_reg_desc id_data, frac_id_data; + struct id_reg_desc *idr, *frac_idr; + struct feature_frac frac_data, *frac = &frac_data; + const struct frac_check_test *frct = test->param_value; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + id = frct->feat.id; + frac_id = frct->frac_feat.id; + + frac->id = id; + frac->shift = frct->feat.shift; + frac->frac_id = frac_id; + frac->frac_shift = frct->frac_feat.shift; + + idr = get_id_reg_desc(id); + frac_idr = get_id_reg_desc(frac_id); + + /* Save the original id_reg_desc (and restore later) */ + memcpy(&id_data, idr, sizeof(id_data)); + memcpy(&frac_id_data, frac_idr, sizeof(frac_id_data)); + + /* The id could be same as the frac_id */ + idr->vcpu_limit_val = (u64)frct->feat.limit << frac->shift; + frac_idr->vcpu_limit_val |= + (u64)frct->frac_feat.limit << frac->frac_shift; + + write_kvm_id_reg(vcpu->kvm, id, (u64)frct->feat.value << frac->shift); + write_kvm_id_reg(vcpu->kvm, frac_id, + (u64)frct->frac_feat.value << frac->frac_shift); + + KUNIT_EXPECT_EQ(test, + vcpu_id_reg_feature_frac_check(vcpu, frac), + frct->ret); + + /* Restore id_reg_desc */ + memcpy(idr, &id_data, sizeof(id_data)); + memcpy(frac_idr, &frac_id_data, sizeof(frac_id_data)); +} + +/* + * Test parameter information to test validate_id_aa64mmfr0_tgran2 + * and validate_id_aa64mmfr0_el1_test. + */ +struct tgran_test { + int gran2_field; + int gran2; + int gran2_lim; + int gran1; + int gran1_lim; + int ret; +}; + +/* + * Test parameters of validate_id_aa64mmfr0_tgran2_test() for TGran4_2. + * Defined values for the field are: + * 0x0: Support for 4KB granule at stage 2 is identified in TGran4. + * 0x1: 4KB granule not supported at stage 2. + * 0x2: 4KB granule supported at stage 2. + * 0x3: 4KB granule at stage 2 supports 52-bit input and output addresses. + * + * Defined values for the TGran4 are: + * 0x0: 4KB granule supported. + * 0x1: 4KB granule supports 52-bit input and output addresses. + * 0xf: 4KB granule not supported. + */ +struct tgran_test tgran4_2_test_params[] = { + /* Enable 4KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 2, 2, 0, 0, 0}, + /* Enable 4KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 2, 1, 0, 0, -E2BIG}, + /* Disable 4KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 1, 2, 0, 0, 0}, + /* Enable 4KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 0, 0, 0, 0, 0}, + /* Disable 4KB granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 0, 1, 0xf, 0, 0}, + /* Enable 4KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 0, 1, 0, 0, -E2BIG}, + /* Disable 4KB granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 0, 2, 0xf, 0, 0}, + /* + * Enable 4KB granule with 52 bit address on the host that doesn't + * support it. + */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 0, 2, 1, 0, -E2BIG}, + /* Disable 4KB granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 1, 0, 0, 0xf, 0}, + /* Disable 4KB granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 1, 0, 0, 0, 0}, + /* Enable 4KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 2, 0, 0xf, 0xf, -E2BIG}, + /* Enable 4KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN4_2_SHIFT, 2, 0, 0, 0, 0}, +}; + +/* + * Test parameters of validate_id_aa64mmfr0_tgran2_test() for TGran64_2. + * Defined values for the field are: + * 0x0: Support for 64KB granule at stage 2 is identified in TGran64. + * 0x1: 64KB granule not supported at stage 2. + * 0x2: 64KB granule supported at stage 2. + * 0x3: 64KB granule at stage 2 supports 52-bit input and output addresses. + * + * Defined values for the TGran64 are: + * 0x0: 64KB granule supported. + * 0xf: 64KB granule not supported. + */ +struct tgran_test tgran64_2_test_params[] = { + /* Enable 64KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 2, 2, 0, 0, 0}, + /* Enable 64KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 2, 1, 0, 0, -E2BIG}, + /* Enable 64KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 1, 2, 0, 0, 0}, + /* Enable 64KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 0, 0, 0, 0, 0}, + /* Disable 64KB granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 0, 1, 0xf, 0, 0}, + /* Enable 64KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 0, 1, 0, 0, -E2BIG}, + /* Disable 64KB granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 0, 2, 0xf, 0, 0}, + /* Disable 64KB granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 1, 0, 0, 0xf, 0}, + /* Disable 64KB granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 1, 0, 0, 0, 0}, + /* Enable 64KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 2, 0, 0xf, 0xf, -E2BIG}, + /* Enable 64KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN64_2_SHIFT, 2, 0, 0, 0, 0}, +}; + +/* + * Test parameters of validate_id_aa64mmfr0_tgran2_test() for TGran16_2 + * Defined values for the field are: + * 0x0: Support for 16KB granule at stage 2 is identified in TGran16. + * 0x1: 16KB granule not supported at stage 2. + * 0x2: 16KB granule supported at stage 2. + * 0x3: 16KB granule at stage 2 supports 52-bit input and output addresses. + * + * Defined values for the TGran16 are: + * 0x0: 16KB granule not supported. + * 0x1: 16KB granule supported. + * 0x2: 16KB granule supports 52-bit input and output addresses. + */ +struct tgran_test tgran16_2_test_params[] = { + /* Enable 16KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 2, 2, 0, 0, 0}, + /* Enable 16KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 2, 1, 0, 0, -E2BIG}, + /* Disable 16KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 1, 2, 0, 0, 0}, + /* Disable 16KB granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 0, 0, 0, 0, 0}, + /* Disable 16KB granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 0, 1, 0, 0, 0}, + /* Enable 16KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 0, 1, 1, 0, -E2BIG}, + /* Disable 16KB granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 0, 2, 0, 0, 0}, + /* + * Enable 16KB granule with 52 bit address on the host that doesn't + * support it. + */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 0, 2, 2, 2, -E2BIG}, + /* Disable 16KB granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 1, 0, 0, 0, 0}, + /* Disable 16KB granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 1, 0, 0, 1, 0}, + /* Enable 16KB granule on the host that doesn't support the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 2, 0, 0, 0, -E2BIG}, + /* Enable 16KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 2, 0, 0, 1, 0}, + /* Enable 16KB granule on the host that supports the granule */ + {ID_AA64MMFR0_TGRAN16_2_SHIFT, 2, 0, 0, 2, 0}, +}; + +static void tgran2_case_to_desc(struct tgran_test *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "gran2(field=%d): val=%d, lim=%d gran1: val=%d limit=%d\n", + t->gran2_field, t->gran2, t->gran2_lim, + t->gran1, t->gran1_lim); +} + +KUNIT_ARRAY_PARAM(tgran4_2, tgran4_2_test_params, tgran2_case_to_desc); +KUNIT_ARRAY_PARAM(tgran64_2, tgran64_2_test_params, tgran2_case_to_desc); +KUNIT_ARRAY_PARAM(tgran16_2, tgran16_2_test_params, tgran2_case_to_desc); + +#define MAKE_MMFR0_TGRAN(shift1, gran1, shift2, gran2) \ + (((u64)((gran1) & 0xf) << (shift1)) | \ + ((u64)((gran2) & 0xf) << (shift2))) + +/* Return the bit position of TGranX field for the given TGranX_2 field. */ +static int tgran2_to_tgran1_shift(int tgran2_shift) +{ + int tgran1_shift = -1; + + switch (tgran2_shift) { + case ID_AA64MMFR0_TGRAN4_2_SHIFT: + tgran1_shift = ID_AA64MMFR0_TGRAN4_SHIFT; + break; + case ID_AA64MMFR0_TGRAN64_2_SHIFT: + tgran1_shift = ID_AA64MMFR0_TGRAN64_SHIFT; + break; + case ID_AA64MMFR0_TGRAN16_2_SHIFT: + tgran1_shift = ID_AA64MMFR0_TGRAN16_SHIFT; + break; + default: + break; + } + + return tgran1_shift; +} + +/* Tests for validate_id_aa64mmfr0_el1(). */ +static void validate_id_aa64mmfr0_tgran2_test(struct kunit *test) +{ + const struct tgran_test *t = test->param_value; + int shift1, shift2; + u64 v, lim; + + shift2 = t->gran2_field; + shift1 = tgran2_to_tgran1_shift(shift2); + v = MAKE_MMFR0_TGRAN(shift1, t->gran1, shift2, t->gran2); + lim = MAKE_MMFR0_TGRAN(shift1, t->gran1_lim, shift2, t->gran2_lim); + + KUNIT_EXPECT_EQ(test, aa64mmfr0_tgran2_check(shift2, v, lim), t->ret); +} + +/* Tests for validate_id_aa64pfr0_el1(). */ +static void validate_id_aa64pfr0_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + id_reg = get_id_reg_desc(SYS_ID_AA64PFR0_EL1); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + /* + * Tests for GIC. + * GIC must be 1 when vGIC3 is configured. + */ + v = 0x0000000; /* GIC = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + /* Test with VGIC_V2 */ + vcpu->kvm->arch.vgic.in_kernel = true; + vcpu->kvm->arch.vgic.vgic_model = KVM_DEV_TYPE_ARM_VGIC_V2; + + v = 0x0000000; /* GIC = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + /* Test with VGIC_V3 */ + vcpu->kvm->arch.vgic.vgic_model = KVM_DEV_TYPE_ARM_VGIC_V3; + + v = 0x0000000; /* GIC = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + v = 0x1000000; /* GIC = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + /* Restore the original VGIC state */ + vcpu->kvm->arch.vgic.in_kernel = false; + vcpu->kvm->arch.vgic.vgic_model = 0; + + /* + * Tests for AdvSIMD/FP. + * AdvSIMD must have the same value as FP. + */ + + /* Tests with SVE disabled */ + v = 0x000010000; /* AdvSIMD = 0, FP = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + v = 0x000100000; /* AdvSIMD = 1, FP = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + v = 0x000ff0000; /* AdvSIMD = 0xf, FP = 0xf */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + v = 0x100000000; /* SVE =1, AdvSIMD = 0, FP = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + if (!system_supports_sve()) { + kunit_skip(test, "No SVE support. Partial skip)"); + /* Not reached */ + } + + /* Tests with SVE enabled */ + vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE; + + v = 0x100000000; /* SVE =1, AdvSIMD = 0, FP = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + v = 0x100ff0000; /* SVE =1, AdvSIMD = 0, FP = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr0_el1(vcpu, id_reg, v), 0); + + vcpu->arch.flags &= ~KVM_ARM64_GUEST_HAS_SVE; +} + +/* Tests for validate_id_aa64pfr1_el1() */ +static void validate_id_aa64pfr1_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + id_reg = get_id_reg_desc(SYS_ID_AA64PFR1_EL1); + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr1_el1(vcpu, id_reg, v), 0); + + /* Tests for MTE */ + + /* Tests with MTE disabled */ + KUNIT_EXPECT_FALSE(test, vcpu->kvm->arch.mte_enabled); + + v = 0x000; /* MTE = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr1_el1(vcpu, id_reg, v), 0); + + v = 0x100; /* MTE = 1*/ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr1_el1(vcpu, id_reg, v), 0); + + if (!system_supports_mte()) { + kunit_skip(test, "(No MTE support. Partial skip)"); + /* Not reached */ + } + + /* Tests with MTE enabled */ + vcpu->kvm->arch.mte_enabled = true; + + v = 0x100; /* MTE = 1*/ + KUNIT_EXPECT_EQ(test, validate_id_aa64pfr1_el1(vcpu, id_reg, v), 0); + + v = 0x0; /* MTE = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64pfr1_el1(vcpu, id_reg, v), 0); +} + +/* Tests for validate_id_aa64isar0_el1(). */ +static void validate_id_aa64isar0_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + id_reg = get_id_reg_desc(SYS_ID_AA64ISAR0_EL1); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + /* + * Tests for SM3/SM4. + * Arm ARM says SM3 must have the same value as SM4. + */ + + v = 0x01000000000; /* SM4 = 0, SM3 = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x10000000000; /* SM4 = 1, SM3 = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x11000000000; /* SM3 = SM4 = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + + /* + * Tests for SHA1/SHA2/SHA3. Arm ARM says: + * If SHA1 is 0x0, both SHA2 and SHA3 must be 0x0. + * If SHA2 is 0x0, SHA1 must be 0x0. + * If SHA2 is 0x2, SHA3 must be 0x1. + * If SHA3 is 0x1, SHA2 msut be 0x2. + */ + + v = 0x000000100; /* SHA2 = 0, SHA1 = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x000001000; /* SHA2 = 1, SHA1 = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x000001100; /* SHA2 = 1, SHA1 = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x100002000; /* SHA3 = 1, SHA2 = 2 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x000002000; /* SHA3 = 0, SHA2 = 2 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x100001000; /* SHA3 = 1, SHA2 = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x200000000; /* SHA3 = 2, SHA1 = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x200001100; /* SHA3 = 2, SHA2= 1, SHA1 = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); + + v = 0x300003300; /* SHA3 = 3, SHA2 = 3, SHA1 = 3 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar0_el1(vcpu, id_reg, v), 0); +} + +/* Tests for validate_id_aa64isar1_el1() */ +static void validate_id_aa64isar1_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + id_reg = get_id_reg_desc(SYS_ID_AA64ISAR1_EL1); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + /* + * Tests for GPI/GPA/API/APA. + * Arm ARM says: + * If GPA is non-zero, GPI must be zero. + * If GPI is non-zero, GPA must be zero. + * If APA is non-zero, API must be zero. + * If API is non-zero, APA must be zero. + */ + + /* Tests with PTRAUTH disabled */ + v = 0x11000110; /* GPI = 1, GPA = 1, API = 1, APA = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x11000100; /* GPI = 1, GPA = 1, API = 1, APA = 0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x11000010; /* GPI = 1, GPA = 1, API = 0, APA = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x10000110; /* GPI = 1, GPA = 0, API = 1, APA = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x01000110; /* GPI = 0, GPA = 1, API = 1, APA = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + if (!system_has_full_ptr_auth()) { + kunit_skip(test, "(No PTRAUTH support. Partial skip)"); + /* Not reached */ + } + + /* Tests with PTRAUTH enabled */ + vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_PTRAUTH; + + v = 0x10000100; /* GPI = 1, GPA = 0, API = 1, APA = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x10000010; /* GPI = 1, GPA = 0, API = 0, APA = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x01000100; /* GPI = 0, GPA = 1, API = 1, APA = 0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0x01000010; /* GPI = 0, GPA = 1, API = 0, APA = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); + + v = 0; + KUNIT_EXPECT_NE(test, validate_id_aa64isar1_el1(vcpu, id_reg, v), 0); +} + +/* Tests for validate_id_aa64mmfr0_el1() */ +static void validate_id_aa64mmfr0_el1_test(struct kunit *test) +{ + struct id_reg_desc id_data, *id_reg; + const struct tgran_test *t4, *t64, *t16; + struct kvm_vcpu *vcpu; + int field4, field4_2, field64, field64_2, field16, field16_2; + u64 v, v4, lim4, v64, lim64, v16, lim16; + int i, j, ret; + + id_reg = get_id_reg_desc(SYS_ID_AA64MMFR0_EL1); + + /* Save the original id_reg_desc (and restore later) */ + memcpy(&id_data, id_reg, sizeof(id_data)); + + vcpu = test_kvm_vcpu_init(test); + + t4 = test->param_value; + field4_2 = t4->gran2_field; + field4 = tgran2_to_tgran1_shift(field4_2); + v4 = MAKE_MMFR0_TGRAN(field4, t4->gran1, field4_2, t4->gran2); + lim4 = MAKE_MMFR0_TGRAN(field4, t4->gran1_lim, field4_2, t4->gran2_lim); + + /* + * For each given gran4_2 params, test validate_id_aa64mmfr0_el1 + * with each of tgran64_2 and tgran16_2 params. + */ + for (i = 0; i < ARRAY_SIZE(tgran64_2_test_params); i++) { + t64 = &tgran64_2_test_params[i]; + field64_2 = t64->gran2_field; + field64 = tgran2_to_tgran1_shift(field64_2); + v64 = MAKE_MMFR0_TGRAN(field64, t64->gran1, + field64_2, t64->gran2); + lim64 = MAKE_MMFR0_TGRAN(field64, t64->gran1_lim, + field64_2, t64->gran2_lim); + + for (j = 0; j < ARRAY_SIZE(tgran16_2_test_params); j++) { + t16 = &tgran16_2_test_params[j]; + + field16_2 = t16->gran2_field; + field16 = tgran2_to_tgran1_shift(field16_2); + v16 = MAKE_MMFR0_TGRAN(field16, t16->gran1, + field16_2, t16->gran2); + lim16 = MAKE_MMFR0_TGRAN(field16, t16->gran1_lim, + field16_2, t16->gran2_lim); + + /* Build id_aa64mmfr0_el1 from tgran16/64/4 values */ + v = v16 | v64 | v4; + id_reg->vcpu_limit_val = lim16 | lim64 | lim4; + + ret = t4->ret ? t4->ret : t64->ret; + ret = ret ? ret : t16->ret; + KUNIT_EXPECT_EQ(test, + validate_id_aa64mmfr0_el1(vcpu, id_reg, v), + ret); + } + } + + /* Restore id_reg_desc */ + memcpy(id_reg, &id_data, sizeof(id_data)); +} + +/* Tests for validate_id_aa64dfr0_el1() */ +static void validate_id_aa64dfr0_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + id_reg = get_id_reg_desc(SYS_ID_AA64DFR0_EL1); + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + /* + * Tests for CTX_CMPS/BRPS. + * Number of context-aware breakpoints can be no more than number + * of supported breakpoints. + */ + v = 0x10001000; /* CTX_CMPS = 1, BRPS = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x20001000; /* CTX_CMPS = 2, BRPS = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + /* Tests for PMUVer */ + + /* Tests with PMUv3 disabled. */ + + v = 0x000; /* PMUVER = 0x0 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + v = 0xf00; /* PMUVER = 0xf */ + KUNIT_EXPECT_EQ(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x100; /* PMUVER = 1 */ + KUNIT_EXPECT_NE(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + /* Tests with PMUv3 enabled */ + set_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features); + + v = 0x000; /* PMUVER = 0x0 */ + KUNIT_EXPECT_NE(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x000; /* PMUVER = 0xf */ + KUNIT_EXPECT_NE(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x100; /* PMUVER = 1 */ + KUNIT_EXPECT_EQ(test, validate_id_aa64dfr0_el1(vcpu, id_reg, v), 0); +} + +/* Tests for validate_id_dfr0_el1() */ +static void validate_id_dfr0_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + id_reg = get_id_reg_desc(SYS_ID_DFR0_EL1); + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + /* Tests for PERFMON */ + + /* Tests with PMUv3 disabled */ + + v = 0x0000000; /* PERFMON = 0x0 */ + KUNIT_EXPECT_EQ(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0xf000000; /* PERFMON = 0xf */ + KUNIT_EXPECT_EQ(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x1000000; /* PERFMON = 1 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x2000000; /* PERFMON = 2 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x3000000; /* PERFMON = 3 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + + /* Tests with PMUv3 enabled */ + set_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features); + + v = 0x0000000; /* PERFMON = 0x0 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0xf000000; /* PERFMON = 0xf */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x1000000; /* PERFMON = 1 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x2000000; /* PERFMON = 2 */ + KUNIT_EXPECT_NE(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); + + v = 0x3000000; /* PERFMON = 3 */ + KUNIT_EXPECT_EQ(test, validate_id_dfr0_el1(vcpu, id_reg, v), 0); +} + +/* Tests for validate_mvfr1_el1(). */ +static void validate_mvfr1_el1_test(struct kunit *test) +{ + struct id_reg_desc *id_reg; + struct kvm_vcpu *vcpu; + u64 v; + + id_reg = get_id_reg_desc(SYS_MVFR1_EL1); + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + v = 0; + KUNIT_EXPECT_EQ(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + /* + * Tests for FPHP/SIMDHP. + * Arm ARM says the level of support indicated by FPHP must be + * equivalent to the level of support indicated by the SIMDHP, + * meaning the permitted values are: + * FPHP = 0x0, SIMDHP = 0x0 + * FPHP = 0x2, SIMDHP = 0x1 + * FPHP = 0x3, SIMDHP = 0x2 + */ + v = 0x0000000; /* FPHP = 0, SIMDHP = 0 */ + KUNIT_EXPECT_EQ(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = 0x2100000; /* FPHP = 2, SIMDHP = 1 */ + KUNIT_EXPECT_EQ(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = 0x3200000; /* FPHP = 3, SIMDHP = 2 */ + KUNIT_EXPECT_EQ(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = 0x1100000; /* FPHP = 1, SIMDHP = 1 */ + KUNIT_EXPECT_NE(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = 0x2200000; /* FPHP = 2, SIMDHP = 2 */ + KUNIT_EXPECT_NE(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = 0x3300000; /* FPHP = 3, SIMDHP = 3 */ + KUNIT_EXPECT_NE(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); + + v = (u64)-1; + KUNIT_EXPECT_NE(test, validate_mvfr1_el1(vcpu, id_reg, v), 0); +} + +/* + * Helper function for validate_id_reg_test(). + * We don't use KUNIT_ASSERT or kunit_skip because this is a helper test + * function and we are not sure if it's safe to exist from the test case. + */ +static void validate_id_reg_test_one_field(struct kunit *test, + u32 id, int pos, int fval, int flimit, + bool is_signed, struct id_reg_desc *idr) +{ + struct kvm_vcpu *vcpu; + int fmin = is_signed ? -1 : 0; + int fmax = is_signed ? 7 : 15; + u64 fmask = ARM64_FEATURE_FIELD_MASK; + u64 val; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + if (flimit > fmax) { + /* Shouldn't happen. Make the test failure. */ + KUNIT_EXPECT_FALSE(test, flimit > fmax); + kunit_err(test, "%s: flimit(%d) > fmax(%d). Must be test bug", + __func__, flimit, fmax); + return; + } + + if (fval > fmin) { + /* Set the field to a smaller value */ + val = ((u64)(fval - 1) & fmask) << pos; + KUNIT_EXPECT_EQ(test, validate_id_reg(vcpu, idr, val), 0); + } + + if (fval < flimit) { + /* Set the field to a larger value, but smaller than flimit */ + val = ((u64)(fval + 1) & fmask) << pos; + KUNIT_EXPECT_EQ(test, validate_id_reg(vcpu, idr, val), 0); + + /* Set the field to the flimit */ + val = ((u64)flimit & fmask) << pos; + KUNIT_EXPECT_EQ(test, validate_id_reg(vcpu, idr, val), 0); + } + + if (flimit < fmax) { + /* Set the field to a larger value than flimit */ + val = ((u64)(flimit + 1) & fmask) << pos; + KUNIT_EXPECT_NE(test, validate_id_reg(vcpu, idr, val), 0); + + /* Test with ignore_mask */ + if (idr) { + idr->ignore_mask = fmask << pos; + KUNIT_EXPECT_EQ(test, validate_id_reg(vcpu, idr, val), 0); + } + } + test_kvm_vcpu_fini(test, vcpu); +} + +static void set_sys_desc(struct sys_reg_desc *rd, u32 encoding) +{ + rd->Op0 = sys_reg_Op0(encoding); + rd->Op1 = sys_reg_Op1(encoding); + rd->CRn = sys_reg_CRn(encoding); + rd->CRm = sys_reg_CRm(encoding); + rd->Op2 = sys_reg_Op2(encoding); +} + +/* + * Test for validate_id_reg(). + */ +static void validate_id_reg_test(struct kunit *test) +{ + struct id_reg_desc idr_data, *idr, *original_idr; + u32 id; + int fval, flim, pos; + u64 val; + bool sign; + + /* Use AA64PFR0_EL1 because it includes both sign/unsigned fields */ + id = SYS_ID_AA64PFR0_EL1; + + /* Test with a temporary id_reg_desc for testing */ + idr = &idr_data; + + fval = 0x1; + flim = 0x2; + + /* Test with unsigned field */ + pos = ID_AA64PFR0_RAS_SHIFT; + + /* Set up id_reg_desc for testing */ + memset(idr, 0, sizeof(*idr)); + set_sys_desc((struct sys_reg_desc *)&idr->reg_desc, id); + idr->vcpu_limit_val = (u64)flim << pos; + validate_id_reg_test_one_field(test, id, pos, fval, flim, false, idr); + + /* Test with signed field */ + pos = ID_AA64PFR0_FP_SHIFT; + + /* Set up id_reg_desc for testing */ + memset(idr, 0, sizeof(*idr)); + set_sys_desc((struct sys_reg_desc *)&idr->reg_desc, id); + idr->vcpu_limit_val = (u64)flim << pos; + validate_id_reg_test_one_field(test, id, pos, fval, flim, true, idr); + + /* Test with the original limit val */ + original_idr = get_id_reg_desc(id); + val = original_idr->vcpu_limit_val; + idr->vcpu_limit_val = val; + + for (pos = 0; pos < 64; pos += 4) { + if (pos == ID_AA64PFR0_FP_SHIFT || + pos == ID_AA64PFR0_ASIMD_SHIFT) + sign = true; + else + sign = false; + + fval = cpuid_feature_extract_field(val, pos, sign); + validate_id_reg_test_one_field(test, id, pos, fval, fval, + sign, idr); + } +} + +static struct kunit_case kvm_sys_regs_test_cases[] = { + KUNIT_CASE_PARAM(vcpu_id_reg_feature_frac_check_test, frac_gen_params), + KUNIT_CASE_PARAM(validate_id_aa64mmfr0_tgran2_test, tgran4_2_gen_params), + KUNIT_CASE_PARAM(validate_id_aa64mmfr0_tgran2_test, tgran64_2_gen_params), + KUNIT_CASE_PARAM(validate_id_aa64mmfr0_tgran2_test, tgran16_2_gen_params), + KUNIT_CASE(validate_id_aa64pfr0_el1_test), + KUNIT_CASE(validate_id_aa64pfr1_el1_test), + KUNIT_CASE(validate_id_aa64isar0_el1_test), + KUNIT_CASE(validate_id_aa64isar1_el1_test), + KUNIT_CASE_PARAM(validate_id_aa64mmfr0_el1_test, tgran4_2_gen_params), + KUNIT_CASE(validate_id_aa64dfr0_el1_test), + KUNIT_CASE(validate_id_dfr0_el1_test), + KUNIT_CASE(validate_mvfr1_el1_test), + KUNIT_CASE(validate_id_reg_test), + {} +}; + +static struct kunit_suite kvm_sys_regs_test_suite = { + .name = "kvm-sys-regs-test-suite", + .test_cases = kvm_sys_regs_test_cases, +}; + +kunit_test_suites(&kvm_sys_regs_test_suite); +MODULE_LICENSE("GPL"); From patchwork Fri Mar 11 04:48:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777429 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 93A5BC433F5 for ; Fri, 11 Mar 2022 04:56:32 +0000 (UTC) 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=AdMd/ggoY5vqglGE3tTxSe4DMAh58qeJDUXO1m6C90A=; b=vFjqrLq6CmToCqNuijHvobmEJI R5MVIe7FrWfWm2OVuAjE4Y+nGtdiRSxB+IU/9B6OlyY8TqNMTZZUyY/SXlPUEtp6ahZc4uBDKWGVu zsvV2r3UvmG1B4ziA7cKGAes/SvOhr2xatDaK3me70fzlYKDlLeDhsydaaWqi/YuZAbw+PX4jN4bG oJNeMycZVMuNSZqU8nWVEgKXHxynN/EqAdfh1FuhBjVtCtf9S+WOoCeZDT9j4W2z5NxeGANzByCTB PUTFuX5VlTmY7h6P9v89PYQ1XtINAmqofkCjSpwSPbKmKSc05lmYaDaFX8914cQ3WjVDz0dvirrye cddqyHwg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXIj-00F2Lp-Ml; Fri, 11 Mar 2022 04:54:54 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXD2-00Ezm5-2S for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:01 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id o70-20020a25d749000000b006291c691122so6456059ybg.1 for ; Thu, 10 Mar 2022 20:48:58 -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=1ZpB7mebk52BK64Fn+qIRSBhSlLqEoMEpcPywkyCKcc=; b=NcRxYPwj2+VJwWIDxJ8QU7cH/MEOcvTG9RCmDwi7VST9esRYax47/OXHiPlRblN8Ae 9fKOVLuosVmhOf/l+df7afRZsT6gGWjgW83MCX+lwU2lG2otC9e775RRch7FcS9GeSqN KuyyAeXR/hMI5w3o8SvqgeFIhARrqNPZeN5VW9qeUwFD0AUFa1knUKy/M3HwzIQtQCE2 u202fRZnfiVB3dr23WflyyeoRtW8UFXhI7gPLgvT6AzgkoRFpIEei+FOUfTsQUbanFYF YKopSsPjdQwYSLIhj8M9KoESG8UpDSvvQ8163zohYCofTn/t6t7xTkkWy9ePSR/O+QJ6 4DNw== 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=1ZpB7mebk52BK64Fn+qIRSBhSlLqEoMEpcPywkyCKcc=; b=RTTvul9M/pTpbn3MWaf54Egouzt2awK0mMapYky3rI2zf4Yl9zviI0tkR2spg2NKam CNMleXB7WdHYWSXqOHjAh/5mPOpr3McYdLgATImnejmgV0jdJ8sVne1na8iT7Bm5pBcY SbFAI+HzukNaCPxQukxX9wPcWk04Xo4ZyVQY2GYXaxOXaV9graEEnCNXLtb0Ag1oo9vJ qF0qnvH7YERc7FVNx3sldSodHTTdz4ukNGm2SEjk/YeAUZp6f3y0gPcA3SeYxZdEpPCA aHcZ5g5qRVmF8UBIkwETsK3EbRk591+cyBLZOKLy86nLgkdyDaf3WgTHzuK2vfrufIsJ 2WBw== X-Gm-Message-State: AOAM533sTeJLlHM69RVYdRPEqjMTNFwONqAca0oOjeEmXciUBhfiSDDc 71z7Inb3JkveFmvRBKJb5lDXbvZ8bDY= X-Google-Smtp-Source: ABdhPJwqyGbkCoXNBO8RHFsHa21/AIWr/xnZ505liPIsQwWTnrbY6VfhBIkHNw8pgzOAvveF0hEdH/m72OE= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a0d:dd85:0:b0:2dc:5589:763a with SMTP id g127-20020a0ddd85000000b002dc5589763amr6951575ywe.278.1646974137632; Thu, 10 Mar 2022 20:48:57 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:02 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-17-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 16/25] KVM: arm64: Use vcpu->arch cptr_el2 to track value of cptr_el2 for VHE 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 , Fuad Tabba , 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-20220310_204900_174538_F5DD3791 X-CRM114-Status: GOOD ( 16.38 ) 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 Track the baseline guest value for cptr_el2 in struct kvm_vcpu_arch for VHE. Use this value when setting cptr_el2 for the guest. Currently this value is unchanged, but the following patches will set trapping bits based on features supported for the guest. No functional change intended. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_arm.h | 16 ++++++++++++++++ arch/arm64/kvm/arm.c | 5 ++++- arch/arm64/kvm/hyp/vhe/switch.c | 14 ++------------ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 01d47c5886dc..8ab6ea038721 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -288,6 +288,22 @@ GENMASK(19, 14) | \ BIT(11)) +/* + * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to + * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2, + * except for some missing controls, such as TAM. + * In this case, CPTR_EL2.TAM has the same position with or without + * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM + * shift value for trapping the AMU accesses. + */ +#define CPTR_EL2_VHE_GUEST_DEFAULT (CPACR_EL1_TTA | CPTR_EL2_TAM) + +/* + * Bits that are copied from vcpu->arch.cptr_el2 to set cptr_el2 for + * guest with VHE. + */ +#define CPTR_EL2_VHE_GUEST_TRACKED_MASK (CPACR_EL1_TTA | CPTR_EL2_TAM) + /* Hyp Debug Configuration Register bits */ #define MDCR_EL2_E2TB_MASK (UL(0x3)) #define MDCR_EL2_E2TB_SHIFT (UL(24)) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 68ffced5b09e..7bb744bb23ce 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1182,7 +1182,10 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, } vcpu_reset_hcr(vcpu); - vcpu->arch.cptr_el2 = CPTR_EL2_DEFAULT; + if (has_vhe()) + vcpu->arch.cptr_el2 = CPTR_EL2_VHE_GUEST_DEFAULT; + else + vcpu->arch.cptr_el2 = CPTR_EL2_DEFAULT; /* * Handle the "start in power-off" case. diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 11d053fdd604..ed01c4ee9953 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -37,20 +37,10 @@ static void __activate_traps(struct kvm_vcpu *vcpu) ___activate_traps(vcpu); val = read_sysreg(cpacr_el1); - val |= CPACR_EL1_TTA; + val &= ~CPTR_EL2_VHE_GUEST_TRACKED_MASK; + val |= (vcpu->arch.cptr_el2 & CPTR_EL2_VHE_GUEST_TRACKED_MASK); val &= ~CPACR_EL1_ZEN; - /* - * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to - * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2, - * except for some missing controls, such as TAM. - * In this case, CPTR_EL2.TAM has the same position with or without - * VHE (HCR.E2H == 1) which allows us to use here the CPTR_EL2.TAM - * shift value for trapping the AMU accesses. - */ - - val |= CPTR_EL2_TAM; - if (update_fp_enabled(vcpu)) { if (vcpu_has_sve(vcpu)) val |= CPACR_EL1_ZEN; From patchwork Fri Mar 11 04:48:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777431 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 2A50EC433EF for ; Fri, 11 Mar 2022 04:57:54 +0000 (UTC) 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=7EnihVbqNoGiBjxlSZZmlRriKexL8naLux5G5lWy6lI=; b=pFsWj+LaN8nsE1w6Rg77ne0sm5 +rebgc95+Ko729dFiPx7l+xD1LnrcJyLsrxQua/RoYBHb5pHiYkcsjXYuxpKVxXFYKq9W20d9WuhK bomFgFdjfqQ1RNM0KI9fLSKz0BWpBkfYtlHolSizUxPpvPFa04EmjlIKF4ROidGppfZporZWoF0+B kVRQ1AAVkLQi3YI0mPONJja+wX2Dcbtpbp3TVRsAeJxaIdTclDno209J/433n+G10E6dKRSeT7gef wi9SfL5WbSxHCKr6whcBbFE1mhNitCOn1fITbPEOUaEcqktMWkuS4v03MMtVWaNSSg9RavWqOED3u yA4FhZJw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXKF-00F34L-Is; Fri, 11 Mar 2022 04:56:29 +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 1nSXD3-00EzmR-6m for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:03 +0000 Received: by mail-pg1-x549.google.com with SMTP id v8-20020a654608000000b0037d5ef9cfa0so4138887pgq.8 for ; Thu, 10 Mar 2022 20:49:00 -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=1OjK12i8EHB/xwmjswIl10AW6opGSFSXfAnin19ncrs=; b=Tdy0kI2iOENeYBXZpnjdLxKm/NPobNxKkPJR9u/6q42CzYhQZEaE/LQc/5FRsQ3FfG ojeXDADTFgC8S8KFlBe/K02Y6o5Byrfy9ta14+clKCipnKNi/fezer13gf4ZqtnGW79f tQJXvO22EdVEL9lz3gTA5pNvXZ/AlfGLHG3v2+PEtGUFEMU9j/6EvuzOrnK80WvJSmKp S60X842JGTTlJs/1/myvyVspgbxKE+t+CO6r7Ld/qWojdNI2V6fLiCC0iheIfup1T+/7 mlAyd8Y8YOGikoxV4P24cz0jvIL03rl/pI5kltxUzJZVay8x0/qyIY5Uhb3S4/ZJHmw9 VcWg== 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=1OjK12i8EHB/xwmjswIl10AW6opGSFSXfAnin19ncrs=; b=6py1tFCJTQdfs0BNQE3eF/V+a22rkEBJujYPCYWMzKzSw4x5VdC+IGOgO5z//hi1m+ D3uPHD7vhGawV0ymZ+eMBBU/1KOiyVMERFQcX0EngPLzk4TTOgDHShgbmUSDPqIut67T DoDbi4duKjmCSP6THkb5WrFzIo7wQqR9ScVf1VgTRYwC1G+E/mVWX8blDDm7bEq6knDl uFzAdEriFukNSST+laZW9GDwpAozTMxIFgb4AMufAibviwda5R74HdNCSd8qmzkkzPOF oV14beYXK46O1X2gXz+Pb5kmrTLnkGuJ7L1j1niVNP91K+nQfbcxes3tHwqfvd2cIZGT dG0g== X-Gm-Message-State: AOAM532SA6tIQmIoFG22HSs16Wqt2TVFmDJPq8wOqPQTLYU+WqQn9RDY mfZf8GgJD0AWKmQHQJvM91PDbTMkSPo= X-Google-Smtp-Source: ABdhPJwcy43pnB6CMBNwp379nzYspjgrnPnrO7sxcJb9fAltkiOVzV8VIs9j+AIeZj6u7qs/OCe8irdFCCg= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:1e10:b0:1bf:6c78:54a9 with SMTP id pg16-20020a17090b1e1000b001bf6c7854a9mr434960pjb.1.1646974139406; Thu, 10 Mar 2022 20:48:59 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:03 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-18-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 17/25] KVM: arm64: Use vcpu->arch.mdcr_el2 to track value of mdcr_el2 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 , Fuad Tabba , 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-20220310_204901_315464_0A9443B9 X-CRM114-Status: GOOD ( 15.41 ) 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 Track the baseline guest value for mdcr_el2 in struct kvm_vcpu_arch. Use this value when setting mdcr_el2 for the guest. Currently this value is unchanged, but the following patches will set trapping bits based on features supported for the guest. No functional change intended. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_arm.h | 16 ++++++++++++++++ arch/arm64/kvm/arm.c | 1 + arch/arm64/kvm/debug.c | 13 ++++--------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index 8ab6ea038721..4b2ac9e32a36 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -333,6 +333,22 @@ BIT(18) | \ GENMASK(16, 15)) +/* + * The default value for the guest below also clears MDCR_EL2_E2PB_MASK + * and MDCR_EL2_E2TB_MASK to disable guest access to the profiling and + * trace buffers. + */ +#define MDCR_GUEST_FLAGS_DEFAULT \ + (MDCR_EL2_TPM | MDCR_EL2_TPMS | MDCR_EL2_TTRF | \ + MDCR_EL2_TPMCR | MDCR_EL2_TDRA | MDCR_EL2_TDOSA) + +/* Bits that are copied from vcpu->arch.mdcr_el2 to set mdcr_el2 for guest. */ +#define MDCR_GUEST_FLAGS_TRACKED_MASK \ + (MDCR_EL2_TPM | MDCR_EL2_TPMS | MDCR_EL2_TTRF | \ + MDCR_EL2_TPMCR | MDCR_EL2_TDRA | MDCR_EL2_TDOSA | \ + (MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT)) + + /* For compatibility with fault code shared with 32-bit */ #define FSC_FAULT ESR_ELx_FSC_FAULT #define FSC_ACCESS ESR_ELx_FSC_ACCESS diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 7bb744bb23ce..ce7229010a78 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1182,6 +1182,7 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, } vcpu_reset_hcr(vcpu); + vcpu->arch.mdcr_el2 = MDCR_GUEST_FLAGS_DEFAULT; if (has_vhe()) vcpu->arch.cptr_el2 = CPTR_EL2_VHE_GUEST_DEFAULT; else diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index db9361338b2a..83330968a411 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -84,16 +84,11 @@ void kvm_arm_init_debug(void) static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu) { /* - * This also clears MDCR_EL2_E2PB_MASK and MDCR_EL2_E2TB_MASK - * to disable guest access to the profiling and trace buffers + * Keep the vcpu->arch.mdcr_el2 bits that are specified by + * MDCR_GUEST_FLAGS_TRACKED_MASK. */ - vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; - vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | - MDCR_EL2_TPMS | - MDCR_EL2_TTRF | - MDCR_EL2_TPMCR | - MDCR_EL2_TDRA | - MDCR_EL2_TDOSA); + vcpu->arch.mdcr_el2 &= MDCR_GUEST_FLAGS_TRACKED_MASK; + vcpu->arch.mdcr_el2 |= __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; /* Is the VM being debugged by userspace? */ if (vcpu->guest_debug) From patchwork Fri Mar 11 04:48:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777432 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 8BB29C433F5 for ; Fri, 11 Mar 2022 04:58:48 +0000 (UTC) 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=XtjwuEl0L0rSHgkIXHox/63l/aDaOCfDK/paXxOliSk=; b=squhPauerZbYYikzZfy2h9OgTk J9CSGTE/ueVk+p4PKJy7WZf6yHKpRA4jeX4zhWX9DV5AAWrSD7c/xupJjdp0Q2j/mRTnsHlANxW84 6+Ugacys68va3szEtpuG+tBWITsfE6npWDL70QzDql2w8VfdRT0W/LGWgBgva8YRp1/3G9z95DaQa Xy5Y0zviGWVDwg8VDyEf8MaArwSk4rba90jPdTtd8PH98Zt8eo5+sjDZH94G0xPn7sBHb/zT8hUJN vaQF4A9EB4HK5Rdg+0lqKiVCbr81wKJhPsAFNUh1kivjueNn+KaMVjRxbWpAEGfYaz0QJw3WUCRWm SDhUEScA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXL1-00F3Ol-FT; Fri, 11 Mar 2022 04:57:16 +0000 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXD4-00Eznb-Bo for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:04 +0000 Received: by mail-pj1-x104a.google.com with SMTP id mm2-20020a17090b358200b001bf529127dfso4510698pjb.6 for ; Thu, 10 Mar 2022 20:49:01 -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=P6w9BVvAXiEumM7YPj7nhW02oDd+02fdwpSOhJH2kYw=; b=QVWaTn/U/hi+unViUFh9VLttYMSUf6cDc/FxUCXGkEl5EOtX3tjwK3KjdtPgHgt57a 2nLGHdqHReQ3NkV7bpq4OmqCpeJgr/OMmPjlnVPYMJvIi/nxZwOay0M09Bvd8nrLodDN kUuBQRV7QPS5YPu1XY0pCwlTP4Ayg7ryZNTmlfrxeTExwLwbyaW/iqMat80nqOpwtmhX ERIiwVNtBI7kYgwnYjKhFvRTgiJ7bUP4UWqo877BRXCl7VSc6A2DqZ2JAU61883oAJx/ UaJjKTKW4YgIEvRd6AheikMzCYTkvL2XhtfvINICgbBq7MY3INyR/b46s7pEnQ260GHc rqGg== 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=P6w9BVvAXiEumM7YPj7nhW02oDd+02fdwpSOhJH2kYw=; b=WXfln61bywzh5xcLO4oLQuiGysGLKCfQ2LVo8RJQflDps631xOMFBKneHylfAt4OWm vErtuPeRMH/zVHMYmP13MNNrEtcarHqsK2GbIeH//pp5TeAZT7/q6agsGzbAnpAChebo BMd/6waimaMbphIS4X5TgOXDuIMcDWbMPkDz8UdYLMWDOOrIjeNFdF4fzIieO9//B1Vr WFMokM1lnW1nKs+OfZGRaeoG5l90e8a9B0U6+ZMsUsj3zfiKhcaTR0rQolNMhwXXeQ/H LHUKOm3xPN13VMCN5E++60RNTKsOjCx3F8nFVeyOlIMuNek7hJE0aBRRrfTTAOUne93+ vx6g== X-Gm-Message-State: AOAM533ZEbYWv+JvM+K8F4lyC3NEG+dZIC4SvzAJYisn/KrAnpZziwwu XXaNp1I/mNZpkDksxdqz18iXdiW74ks= X-Google-Smtp-Source: ABdhPJzhh1U7y5CL8ltfYwY4d+qtiQiox0IYx4/Dpt56merG9aO2FQSKi2C7GJaXW+1lU89FVH7aAQfnGfw= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:902:d482:b0:153:12b0:60b5 with SMTP id c2-20020a170902d48200b0015312b060b5mr8606210plg.105.1646974140996; Thu, 10 Mar 2022 20:49:00 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:04 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-19-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 18/25] KVM: arm64: Introduce framework to trap disabled features 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 , Fuad Tabba , 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-20220310_204902_458642_A0125536 X-CRM114-Status: GOOD ( 31.17 ) 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 When a CPU feature that is supported on the host is not exposed to its guest, emulating a real CPU's behavior (by trapping or disabling guest's using the feature) is generally a desirable behavior (when it's possible without any or little side effect). Introduce feature_config_ctrl structure, which manages feature information to program configuration register to trap or disable the feature when the feature is not exposed to the guest, and functions that uses the structure to activate the vcpu's trapping the feature. Those codes don't update trap configuration registers themselves (HCR_EL2, etc) but values for the registers in kvm_vcpu_arch at the first KVM_RUN. At present, no feature has feature_config_ctrl yet and the following patches will add the feature_config_ctrl for some features. Signed-off-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 13 ++-- arch/arm64/kvm/sys_regs.c | 111 ++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 5e53102a1ac1..9b7fad07fcb0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -749,6 +749,7 @@ long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm, void set_default_id_regs(struct kvm *kvm); int kvm_set_id_reg_feature(struct kvm *kvm, u32 id, u8 field_shift, u8 fval); int kvm_id_regs_check_frac_fields(const struct kvm_vcpu *vcpu); +void kvm_vcpu_init_traps(struct kvm_vcpu *vcpu); /* Guest/host FPSIMD coordination helpers */ int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index ce7229010a78..dfd247d2746f 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -631,13 +631,16 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) static_branch_inc(&userspace_irqchip_in_use); } - /* - * Initialize traps for protected VMs. - * NOTE: Move to run in EL2 directly, rather than via a hypercall, once - * the code is in place for first run initialization at EL2. - */ + /* Initialize traps for the guest. */ if (kvm_vm_is_protected(kvm)) + /* + * NOTE: Move to run in EL2 directly, rather than via a + * hypercall, once the code is in place for first run + * initialization at EL2. + */ kvm_call_hyp_nvhe(__pkvm_vcpu_init_traps, vcpu); + else + kvm_vcpu_init_traps(vcpu); mutex_lock(&kvm->lock); kvm->arch.ran_once = true; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index b44a3bf488c1..a754099d2a73 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -284,6 +284,27 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT) >= \ ID_AA64ISAR1_GPI_IMP_DEF) +/* + * Feature information to program configuration register to trap or disable + * guest's using a feature when the feature is not exposed to the guest. + */ +struct feature_config_ctrl { + /* ID register/field for the feature */ + u32 ftr_reg; /* ID register */ + bool ftr_signed; /* Is the feature field signed ? */ + u8 ftr_shift; /* Field of ID register for the feature */ + s8 ftr_min; /* Min value that indicate the feature */ + + /* + * Function to check trapping is needed. This is used when the above + * fields are not enough to determine if trapping is needed. + */ + bool (*ftr_need_trap)(struct kvm_vcpu *vcpu); + + /* Function to activate trapping the feature. */ + void (*trap_activate)(struct kvm_vcpu *vcpu); +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -291,6 +312,9 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, struct id_reg_desc { const struct sys_reg_desc reg_desc; + /* Sanitized system value */ + u64 sys_val; + /* * Limit value of the register for a vcpu. The value is the sanitized * system value with bits set/cleared for unsupported features for the @@ -335,6 +359,9 @@ struct id_reg_desc { */ u64 (*vcpu_mask)(const struct kvm_vcpu *vcpu, const struct id_reg_desc *id_reg); + + /* Information to trap features that are disabled for the guest */ + const struct feature_config_ctrl *(*trap_features)[]; }; static inline struct id_reg_desc *sys_to_id_desc(const struct sys_reg_desc *r) @@ -352,6 +379,7 @@ static void id_reg_desc_init(struct id_reg_desc *id_reg) return; val = read_sanitised_ftr_reg(id); + id_reg->sys_val = val; id_reg->vcpu_limit_val = val; if (id_reg->init) id_reg->init(id_reg); @@ -807,6 +835,24 @@ static int validate_id_reg(struct kvm_vcpu *vcpu, return err; } +static inline bool feature_avail(const struct feature_config_ctrl *ctrl, + u64 id_val) +{ + int field_val = cpuid_feature_extract_field(id_val, + ctrl->ftr_shift, ctrl->ftr_signed); + + return (field_val >= ctrl->ftr_min); +} + +static inline bool vcpu_feature_is_available(struct kvm_vcpu *vcpu, + const struct feature_config_ctrl *ctrl) +{ + u64 val; + + val = read_id_reg_with_encoding(vcpu, ctrl->ftr_reg); + return feature_avail(ctrl, val); +} + /* * ARMv8.1 mandates at least a trivial LORegion implementation, where all the * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0 @@ -1761,6 +1807,46 @@ static int reg_from_user(u64 *val, const void __user *uaddr, u64 id); static int reg_to_user(void __user *uaddr, const u64 *val, u64 id); static u64 sys_reg_to_index(const struct sys_reg_desc *reg); +static void id_reg_features_trap_activate(struct kvm_vcpu *vcpu, + const struct id_reg_desc *id_reg) +{ + u64 val; + int i = 0; + const struct feature_config_ctrl **ctrlp_array, *ctrl; + + if (!id_reg->trap_features) + /* No information to trap a feature */ + return; + + val = __read_id_reg(vcpu, id_reg); + if (val == id_reg->sys_val) + /* No feature needs to be trapped (no feature is disabled). */ + return; + + ctrlp_array = *id_reg->trap_features; + while ((ctrl = ctrlp_array[i++]) != NULL) { + if (WARN_ON_ONCE(!ctrl->trap_activate)) + /* Shouldn't happen */ + continue; + + if (ctrl->ftr_need_trap && ctrl->ftr_need_trap(vcpu)) { + ctrl->trap_activate(vcpu); + continue; + } + + if (!feature_avail(ctrl, id_reg->sys_val)) + /* The feature is not supported on the host. */ + continue; + + if (feature_avail(ctrl, val)) + /* The feature is enabled for the guest. */ + continue; + + /* The feature is supported but disabled. */ + ctrl->trap_activate(vcpu); + } +} + /* Visibility overrides for SVE-specific control registers */ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd) @@ -3763,6 +3849,31 @@ static void kvm_reset_id_regs(struct kvm_vcpu *vcpu) } } +/* + * This function activates vcpu's trapping of features that are included in + * trap_features[] of id_reg_desc if the features are supported on the + * host, but are hidden from the guest (i.e. values of ID registers for + * the guest are modified to not show the features' availability). + * This function just updates values for trap configuration registers (e.g. + * HCR_EL2, etc) in kvm_vcpu_arch, which will be restored before switching + * to the guest, but doesn't update the registers themselves. + * This function should be called once at the first KVM_RUN (ID registers + * are immutable after the first KVM_RUN). + */ +void kvm_vcpu_init_traps(struct kvm_vcpu *vcpu) +{ + int i; + struct id_reg_desc *idr; + + for (i = 0; i < ARRAY_SIZE(id_reg_desc_table); i++) { + idr = (struct id_reg_desc *)id_reg_desc_table[i]; + if (!idr) + continue; + + id_reg_features_trap_activate(vcpu, idr); + } +} + #if IS_ENABLED(CONFIG_KVM_KUNIT_TEST) #include "sys_regs_test.c" #endif From patchwork Fri Mar 11 04:48:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777433 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id F25BFC433EF for ; Fri, 11 Mar 2022 04:59:37 +0000 (UTC) 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=EYSPkHdJu3ceEvACoPttUHbbP2Rbfzi7ahpbM7D0d8c=; b=gMOcA7TGv+RHQLmasyEPv2LmuX bprndBJwISaN5stSQnzgSaWgtIYCsHideDzJAFPRidyXnO0KH5zVjmQczlLOqMGig/1pz98tt+eJC wNN8Owbq4tYEfadQfAlNK0cWc1uF64hT08hhnjAboey2gS4y+CK52BJx5t0RKuXFna78/tYk6Fz7C LDd7M75ughfr14bKkVjBEewKqcR2x+kJXynKE6i6Oh4mq1dhDXZBFbfMPGv/nB6qLS42H0kd0ka1N dlRMjAYzWASg5hY5a1a0j4jgu5c7mHaOyrE1cZeddCSO2fgF1l5OM559H//Rcm9bN3yyXzlUbvVHw ZE051O8g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXLj-00F3hG-W6; Fri, 11 Mar 2022 04:58:02 +0000 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXD6-00EzoE-6O for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:05 +0000 Received: by mail-pf1-x44a.google.com with SMTP id h69-20020a628348000000b004f769e5b4bdso2740424pfe.10 for ; Thu, 10 Mar 2022 20:49:03 -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=zv2nragi6VCMhrP9RIAZluYZ3kaqdgQBPPUgqdiA67k=; b=k2wcaxfjBN7e1gGyczyvGVZ5SRaRU/0+Cfw8qqRRc3LBRLiBiCZ4K9wmtGmryGqlUT MJUDo6l42Sonpc3K9YzDGcB8YAZCCTWjQkgLJpx8HTuqRULTZaJlPB1DrG3gJNQlt4ec 6eaU7Y6j4KlvVHHQZFMSea1vXO4Dmq7i2nALxJX9wqCItMdaz/E615qkKCfjIxNG7RDb 004H2hCXVL6Jwn/mXpWt4SySzKVNlZfg/0/H0tU2c4n4QybMerW+QnDtQGJY3Qr8SETn hyLqPJvj2SrbSuFucjnfEg4/UKXFBBEtQZHl/rp5gj6ryg66qqAzCSvIqXzztynjM5Sr StiQ== 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=zv2nragi6VCMhrP9RIAZluYZ3kaqdgQBPPUgqdiA67k=; b=YepmVCmpWBhzAbjYK6rYxaXabkK4AsWORDwbBHD6HXsjInOD9QxEU33qkd3dlSEcBA lFFLJkYxlotUqTTkehCgWAPwsP3opjBPEUnP2GvEhzLh9eieUJJMpDunX8DxuzhzZvA8 hqb26I1dA/wJcS7zPzMmldecMbUgMadUfMHPdFcfy/IBeExGfLllBDTt99JlkiE59Lyi L/3aNhohjC7CEz8Yp9rXyB0+g70eyERYsBx+u7NZC1yQ/srxvwB+AG32S02StSWF0exJ jTT30sYalZmxl2EE+uXtuNorFB2Bsj4LQ9AIOuOfJxi263UeRB/kOLUDCXOyg2jXhTzl 8NQw== X-Gm-Message-State: AOAM531A37WenTfuysnLidFy3E4lIOkCpiSP2mX2IPO7WzVq6t0PLqn4 oHVNNQmBsQZD8H1YAI3SsCcYkLQjPXc= X-Google-Smtp-Source: ABdhPJxgt3wVmNEP7Hp+XFmZZ6kh7g5UV/GpW30zYhq2KR8GWwKyrVydsF3qaN7mryevseZDC1NDCvbjms0= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:808:b0:4f7:765c:7606 with SMTP id m8-20020a056a00080800b004f7765c7606mr6390477pfk.57.1646974142570; Thu, 10 Mar 2022 20:49:02 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:05 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-20-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 19/25] KVM: arm64: Trap disabled features of ID_AA64PFR0_EL1 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 , Fuad Tabba , 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-20220310_204904_313153_D6F19755 X-CRM114-Status: GOOD ( 17.23 ) 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 Add feature_config_ctrl for RAS and AMU, which are indicated in ID_AA64PFR0_EL1, to program configuration registers to trap guest's using those features when they are not exposed to the guest. Introduce trap_ras_regs() to change a behavior of guest's access to the registers, which is currently raz/wi, depending on the feature's availability for the guest (and inject undefined instruction exception when guest's RAS register access are trapped and RAS is not exposed to the guest). In order to keep the current visibility of the RAS registers from userspace (always visible), a visibility function for RAS registers is not added. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 90 +++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a754099d2a73..3f3f2800ff8b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -305,6 +305,63 @@ struct feature_config_ctrl { void (*trap_activate)(struct kvm_vcpu *vcpu); }; +enum vcpu_config_reg { + VCPU_HCR_EL2 = 1, + VCPU_MDCR_EL2, + VCPU_CPTR_EL2, +}; + +static void feature_trap_activate(struct kvm_vcpu *vcpu, + enum vcpu_config_reg cfg_reg, + u64 cfg_set, u64 cfg_clear) +{ + u64 *reg_ptr, reg_val; + + switch (cfg_reg) { + case VCPU_HCR_EL2: + reg_ptr = &vcpu->arch.hcr_el2; + break; + case VCPU_MDCR_EL2: + reg_ptr = &vcpu->arch.mdcr_el2; + break; + case VCPU_CPTR_EL2: + reg_ptr = &vcpu->arch.cptr_el2; + break; + } + + /* Clear/Set fields that are indicated by cfg_clear/cfg_set. */ + reg_val = (*reg_ptr & ~cfg_clear); + reg_val |= cfg_set; + *reg_ptr = reg_val; +} + +static void feature_ras_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, HCR_TERR | HCR_TEA, HCR_FIEN); +} + +static void feature_amu_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_CPTR_EL2, CPTR_EL2_TAM, 0); +} + +/* For ID_AA64PFR0_EL1 */ +static struct feature_config_ctrl ftr_ctrl_ras = { + .ftr_reg = SYS_ID_AA64PFR0_EL1, + .ftr_shift = ID_AA64PFR0_RAS_SHIFT, + .ftr_min = ID_AA64PFR0_RAS_V1, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_ras_trap_activate, +}; + +static struct feature_config_ctrl ftr_ctrl_amu = { + .ftr_reg = SYS_ID_AA64PFR0_EL1, + .ftr_shift = ID_AA64PFR0_AMU_SHIFT, + .ftr_min = ID_AA64PFR0_AMU, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_amu_trap_activate, +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -853,6 +910,18 @@ static inline bool vcpu_feature_is_available(struct kvm_vcpu *vcpu, return feature_avail(ctrl, val); } +static bool trap_ras_regs(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + if (!vcpu_feature_is_available(vcpu, &ftr_ctrl_ras)) { + kvm_inject_undefined(vcpu); + return false; + } + + return trap_raz_wi(vcpu, p, r); +} + /* * ARMv8.1 mandates at least a trivial LORegion implementation, where all the * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0 @@ -2155,14 +2224,14 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 }, { SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 }, - { SYS_DESC(SYS_ERRIDR_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERRSELR_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXFR_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXCTLR_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXSTATUS_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXADDR_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi }, - { SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi }, + { SYS_DESC(SYS_ERRIDR_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERRSELR_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXFR_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXCTLR_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXSTATUS_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXADDR_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXMISC0_EL1), trap_ras_regs }, + { SYS_DESC(SYS_ERXMISC1_EL1), trap_ras_regs }, MTE_REG(TFSR_EL1), MTE_REG(TFSRE0_EL1), @@ -3598,6 +3667,11 @@ static struct id_reg_desc id_aa64pfr0_el1_desc = { .init = init_id_aa64pfr0_el1_desc, .validate = validate_id_aa64pfr0_el1, .vcpu_mask = vcpu_mask_id_aa64pfr0_el1, + .trap_features = &(const struct feature_config_ctrl *[]) { + &ftr_ctrl_ras, + &ftr_ctrl_amu, + NULL, + }, }; static struct id_reg_desc id_aa64pfr1_el1_desc = { From patchwork Fri Mar 11 04:48:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777434 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id C3D7EC433EF for ; Fri, 11 Mar 2022 05:00:51 +0000 (UTC) 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=XiWivz9u0IqvALPBYf7eamnBCczphzO5ztdWulfH9x8=; b=vi/+zGXvFtqippVld5zRqIHNV3 kxqbuoOqQ+FYNBFYjPYNiICS6QKViEHKZvUk95EtT8eEFXc7Nu6GP8x3mDZpYWxgHECM87nONnQTA AqMhxyHCDbJxcnlIaRPqwSDvvV8Fox/Vg9ZbZlJRv2gfKZlnsWnGABs0RdZ8MJzy08keZnD9H+rLA 4qnlY3zqXbyyJXm0sXh/r8BKBy3Ph2jaGHa8xHoKwX1qYD5g0pn1ZO2nrocLT8Q95w0E5OmQJNuWj Aru59MgPhamAA95gbaGadBhClalW7O/HYPcbSGEtZ5Tn5BDMLHeKVL6g3lz7y91IRa3VtqHBpG9Hb KSQhiSgA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXMz-00F4E4-Br; Fri, 11 Mar 2022 04:59:17 +0000 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXD7-00EzpN-Eq for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:06 +0000 Received: by mail-pf1-x44a.google.com with SMTP id z194-20020a627ecb000000b004f6db380a59so4508743pfc.19 for ; Thu, 10 Mar 2022 20:49:04 -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=xLUCA41gdz7FCF8bUZA9Zti+AcGuAvR0DZ5YiMSov0E=; b=Vc1EayLhrOzYdEvO5XuG7Sgh7TZEmWxNUoLCYTfidCSdg7vSpbf5BcKDmMUiZl0R4L CcNTXxUh+KYp/iwYE1FVJOkNwuRBUIRgJJ06rfIze0sumJqVgeVADx0lWC6ZegwQwGV7 rZd7qnPTxFexvkYJpVgyrh7VoKI38Vw+/6Bm4wxZxwbL3oSfWGHOr/oXFkcox9o4aOZR qoWOPG2Lg6D7YwkNu6abWchaG/BHS0j5K51sVIMGZUvWrCud0I3x3dG9lgbSG7VoE/Pf sFKHEuec5XVRta/06pVQrd8by8u3oAeYEkNBzh0/2/duFKN4qLtp8pYOEcYBHEztNXJm FwoQ== 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=xLUCA41gdz7FCF8bUZA9Zti+AcGuAvR0DZ5YiMSov0E=; b=tsGEokLr7Z6GRZqhl/+vTxO5GIAPPCP9amS+cgTh9ftcCgWRJIYOG7oeiAwqnHjY1L x9oG7WNSIFuB/ZPUnqCZ6lVITEll0Ar7Kf8Cv9bmHoAaxvStucyGcH6koXiAl4ScR5R+ e4+FjpIfK8Z2Qtih7DYlxsL4xXl5OC2IgAmdJJr1PjSEB+P8naVb6mAcUIlMEeVs2KWV U9c5AsfahZwNSTBmrMA+p4ZhMr/+lavJTiisDRElg24DD8HyUuBvghcj6Q1QGPavKRSI hMdITij2XwvYL7Ffw6KEv8KxdWsIc8M7hf661N5VsE4olQn0JtFAdBr84SVTSsfGb/1/ zUiw== X-Gm-Message-State: AOAM532g5QdMd0rOi3riPs4pz4+j3zE33vO9DYU8M9hnN3TpaRV+tXaj H3R/o9lun/yYjE0vW3JGvRrQAiPLMUU= X-Google-Smtp-Source: ABdhPJwyRNt8QZSL25MhBfqeOrj7itaUKc+bzv73Qi9m6d1fIbeodfC9ndqspbZ/YEChD2vpQA5YzFqEYxw= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:b92:b0:4f6:dfe0:9abb with SMTP id g18-20020a056a000b9200b004f6dfe09abbmr8235033pfj.68.1646974144149; Thu, 10 Mar 2022 20:49:04 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:06 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-21-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 20/25] KVM: arm64: Trap disabled features of ID_AA64PFR1_EL1 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 , Fuad Tabba , 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-20220310_204905_573118_9BFF189B X-CRM114-Status: GOOD ( 11.93 ) 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 Add feature_config_ctrl for MTE, which is indicated in ID_AA64PFR1_EL1, to program configuration register to trap the guest's using the feature when it is not exposed to the guest. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 3f3f2800ff8b..924ffedf4b05 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -345,6 +345,11 @@ static void feature_amu_trap_activate(struct kvm_vcpu *vcpu) feature_trap_activate(vcpu, VCPU_CPTR_EL2, CPTR_EL2_TAM, 0); } +static void feature_mte_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, HCR_TID5, HCR_DCT | HCR_ATA); +} + /* For ID_AA64PFR0_EL1 */ static struct feature_config_ctrl ftr_ctrl_ras = { .ftr_reg = SYS_ID_AA64PFR0_EL1, @@ -362,6 +367,15 @@ static struct feature_config_ctrl ftr_ctrl_amu = { .trap_activate = feature_amu_trap_activate, }; +/* For ID_AA64PFR1_EL1 */ +static struct feature_config_ctrl ftr_ctrl_mte = { + .ftr_reg = SYS_ID_AA64PFR1_EL1, + .ftr_shift = ID_AA64PFR1_MTE_SHIFT, + .ftr_min = ID_AA64PFR1_MTE_EL0, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_mte_trap_activate, +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -3682,6 +3696,10 @@ static struct id_reg_desc id_aa64pfr1_el1_desc = { .init = init_id_aa64pfr1_el1_desc, .validate = validate_id_aa64pfr1_el1, .vcpu_mask = vcpu_mask_id_aa64pfr1_el1, + .trap_features = &(const struct feature_config_ctrl *[]) { + &ftr_ctrl_mte, + NULL, + }, }; static struct id_reg_desc id_aa64isar0_el1_desc = { From patchwork Fri Mar 11 04:48:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777435 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id D7FC3C433F5 for ; Fri, 11 Mar 2022 05:02:12 +0000 (UTC) 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=AQfhLdIN/iz+hjNj8UOazJjQZazEcUUXPupNNqtjmTY=; b=mwc1qZqzphOHN/nm7i5sMu6J5A 6DZHjpc4jOdv9N9UfsC0gC4cv74u16+CpM9hayKoj+1he+/sGytTbYKipwWwkc9FnrYS2uVhZQcxH /c1zJDCCOiONGCs+5QhVjStp03KJpA5ijhgsFI+e1rdjdF8zvlMvQEU88j1tRDlJSxuhNGTPS/Buy O9JetNaHqzPxM6Z+htauoHIbWoYPkuRXdJn1iJETHvDYhYaJkOSI70nWmi7lArdaqipDTjZWNyb1Q AhTv2aF5tOr0yFbv97kKUB6ul5NtraoWR7QjlcKnWNAAO8VxvupqU+p+5fe7sKELDbR0MD07HpJOu CIUw+qeA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXNm-00F4WG-Vv; Fri, 11 Mar 2022 05:00:07 +0000 Received: from mail-ot1-x34a.google.com ([2607:f8b0:4864:20::34a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDA-00EzqR-86 for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:09 +0000 Received: by mail-ot1-x34a.google.com with SMTP id q18-20020a05683022d200b005b23730dc8eso5361479otc.19 for ; Thu, 10 Mar 2022 20:49:06 -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=BOtqtDPmFVbXSVQplJqqHWzAUqxe06WK8Hgp5xswEjo=; b=hjhU16IsuclGFWjBCSbzTVlbAwlKDoX+LoOaMMapNL8w6ClETZtePMebhWY3wK5qIK RZEHvgJmeqic7DauveyRHrogrFXjjQ85aC3eM8tEEZDRQgwFFdu1DoR7i7O5ksFs8Txt svGWTqmO2+IXkKE0AZ43wyFmymaBBq/gDGxMFfrjh4/l3akP8lAMWo204hbl6MV1Zg/k qKMoVz0evWLjjaVKZeDfsnMMG9pfgq7OYNe+xMFlARUmlTiBUCwPaIpoYMUuftn6NsV/ Baw2+PpEMVAYvXavy87vEyU6/Fx6J3KYqq0/epl8LhXllOnBkt2+UKcqAlmAixhzde6Z pHWA== 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=BOtqtDPmFVbXSVQplJqqHWzAUqxe06WK8Hgp5xswEjo=; b=f8BOBi8cj+//eYgvV+tOE5lQm97t8za5BbIuOfKyL2sn8mFN0o9mUHw/81zyBel1Nr spjExAgUJPmXT8TWzHILg74BvmnoTwPtu8uPXYmzvOrDvAu6VX0AqrwIcrjTSClBmtoq /SUPtO+xGXWofQwcOkMFFQGOYYx5Ajb+bf4agMcc8XBNkHXQdpxiV4LRm5gUFgj6Kcx/ BCfsUQAwny4s2tZDuxD7STcFQkSV5WIEK8bZLcHEynHm13I3jdBbTNz7dpX3tmxFFP8Q 2InKbRMSJRFCzhkRQX8l3gy0uUrvuMNjJYyWOTkeICUYrdkMsZ3THiw0cJhfErqIMu2L ngHQ== X-Gm-Message-State: AOAM530gxLCcXS6HBQ8zHB0kFlvSmtBWOqizFbWh6k3JfKdttKD+Ichy 5S+gHsgPHuwYWE762PgKyTHvlzw0VPc= X-Google-Smtp-Source: ABdhPJwxlwQXx8fxZeLKU4n6nbDbzjRmOlYI/0f1fj5lPlt6ZBH1yo0WCK5jePLAp870++wELV/pob1U/z4= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6870:c588:b0:da:3d88:de58 with SMTP id ba8-20020a056870c58800b000da3d88de58mr10499144oab.32.1646974145880; Thu, 10 Mar 2022 20:49:05 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:07 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-22-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 21/25] KVM: arm64: Trap disabled features of ID_AA64DFR0_EL1 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 , Fuad Tabba , 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-20220310_204908_324263_2F97CCC0 X-CRM114-Status: GOOD ( 11.69 ) 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 Add feature_config_ctrl for PMUv3, PMS and TraceFilt, which are indicated in ID_AA64DFR0_EL1, to program configuration registers to trap guest's using those features when they are not exposed to the guest. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 924ffedf4b05..677815030d44 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -350,6 +350,30 @@ static void feature_mte_trap_activate(struct kvm_vcpu *vcpu) feature_trap_activate(vcpu, VCPU_HCR_EL2, HCR_TID5, HCR_DCT | HCR_ATA); } +static void feature_trace_trap_activate(struct kvm_vcpu *vcpu) +{ + if (has_vhe()) + feature_trap_activate(vcpu, VCPU_CPTR_EL2, CPACR_EL1_TTA, 0); + else + feature_trap_activate(vcpu, VCPU_CPTR_EL2, CPTR_EL2_TTA, 0); +} + +static void feature_pmuv3_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_MDCR_EL2, MDCR_EL2_TPM, 0); +} + +static void feature_pms_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_MDCR_EL2, MDCR_EL2_TPMS, + MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT); +} + +static void feature_tracefilt_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_MDCR_EL2, MDCR_EL2_TTRF, 0); +} + /* For ID_AA64PFR0_EL1 */ static struct feature_config_ctrl ftr_ctrl_ras = { .ftr_reg = SYS_ID_AA64PFR0_EL1, @@ -376,6 +400,39 @@ static struct feature_config_ctrl ftr_ctrl_mte = { .trap_activate = feature_mte_trap_activate, }; +/* For ID_AA64DFR0_EL1 */ +static struct feature_config_ctrl ftr_ctrl_trace = { + .ftr_reg = SYS_ID_AA64DFR0_EL1, + .ftr_shift = ID_AA64DFR0_TRACEVER_SHIFT, + .ftr_min = 1, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_trace_trap_activate, +}; + +static struct feature_config_ctrl ftr_ctrl_pmuv3 = { + .ftr_reg = SYS_ID_AA64DFR0_EL1, + .ftr_shift = ID_AA64DFR0_PMUVER_SHIFT, + .ftr_min = ID_AA64DFR0_PMUVER_8_0, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_pmuv3_trap_activate, +}; + +static struct feature_config_ctrl ftr_ctrl_pms = { + .ftr_reg = SYS_ID_AA64DFR0_EL1, + .ftr_shift = ID_AA64DFR0_PMSVER_SHIFT, + .ftr_min = ID_AA64DFR0_PMSVER_8_2, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_pms_trap_activate, +}; + +static struct feature_config_ctrl ftr_ctrl_tracefilt = { + .ftr_reg = SYS_ID_AA64DFR0_EL1, + .ftr_shift = ID_AA64DFR0_TRACE_FILT_SHIFT, + .ftr_min = 1, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_tracefilt_trap_activate, +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -3733,6 +3790,13 @@ static struct id_reg_desc id_aa64dfr0_el1_desc = { .init = init_id_aa64dfr0_el1_desc, .validate = validate_id_aa64dfr0_el1, .vcpu_mask = vcpu_mask_id_aa64dfr0_el1, + .trap_features = &(const struct feature_config_ctrl *[]) { + &ftr_ctrl_trace, + &ftr_ctrl_pmuv3, + &ftr_ctrl_pms, + &ftr_ctrl_tracefilt, + NULL, + }, }; static struct id_reg_desc id_dfr0_el1_desc = { From patchwork Fri Mar 11 04:48:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777436 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 9F659C433F5 for ; Fri, 11 Mar 2022 05:03:26 +0000 (UTC) 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=Wn5WfI7trWchXxjK6EUudHsf5WJUEWAs8Y2mB2p3ciA=; b=J6N3cvbpT6f3Ic7HZcxaKWS5gV t0+DXeF+uepZSPQ9bbAy+FMuBAIR9b3wQjQr/93dnOwjS23Hn4uNQcwfrtOSzZEsHsOAf/HXVEqx+ aigifQVzOmt7rESZ2ZfJEXiirdlPUeCJK9DXmHOlm/qjWqeYnjsgc1ZWLNhFcET+3zQOMhamaaHuV xJHLZwswchfbh6TaEXiaZNdefjDFExBVFW/NoQ/inNxeoHbAgvSfZ+6KYyWjvH4JoSs0SIK2AzpTa 4f+r2QWvXYmwlEESIAjcMDFbLY+XSYl6nKwxEIu/k9hW6w6peGXj+rCdGPuKwZ9kGmr23fWit44lg r0lkz8nA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXP6-00F4vK-5y; Fri, 11 Mar 2022 05:01:31 +0000 Received: from mail-pf1-x44a.google.com ([2607:f8b0:4864:20::44a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDB-00EzrK-41 for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:11 +0000 Received: by mail-pf1-x44a.google.com with SMTP id y7-20020a626407000000b004f6d39f1b0fso4539460pfb.5 for ; Thu, 10 Mar 2022 20:49:08 -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=46qXeSpi4Sz/Cxmd+kiVveMfXndYTJmQfut6cp7XrW4=; b=CPA2eRLxteZJs71CJ0dQUl7ireq+1W+7rl/oRTYFYRyGUMOlkRpx2xNk/s4nJt0A5r 2C238ZfVTpkE8Ujii9v29Vnk3ITgwjUnaK5PZZcdRWiOcqwYYB1AfVnxYQDJqGFhu/IJ 4XJ2k1wjuss+Kvd7Au27jIRjPf3JHrzenFHb9knbYT8bjBzl7Glg6u4TzmchCCtHmDo5 xQwJVTxMcZqLGgRxDvWHsAJvBNogJqoy9TP687htkO+JtIaYO9W+v/vnOaPs9OWplpPv mu4BnmDtCuFN7vZQ5agxRAstLL9+XA9aErEQiU7EXruF8IhFID8v76gHBJml9H2eG3Rm aVGQ== 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=46qXeSpi4Sz/Cxmd+kiVveMfXndYTJmQfut6cp7XrW4=; b=ObCbA4muVvKnH7M3Rex9Ddp6l0GJ/h12VB8nnaiuj3Ml8BBWfmNKVgwyabdqBDPWlf PK9lRBjN8nnYwkfHb2y6cZMaSP8FEgn4cjo7xxZaW/k+2e56V9D6ephDp+3eBjNfUf/m quLJBH1mmA3sDHOAIPwTNacn77OZDUxUYrq2l+cKEhebJyeH6l/FkZEVWHhI/d0M0I1n QbemwlEbZ+P5Cj/kMcgNoANdFFb6A46V5Z8E9GIaK70zwzbl06+mDNkV53/NLJaqdyRO XXhDm3XPbz17+OqNiL4Rct048dmCO5D/f0OXIzuE/HQb3R1Uyvz9MtA+svF7pgqKiRJ3 Qb1w== X-Gm-Message-State: AOAM530KO1/CzrUC1aPrlLj5en0gCr1flGLGGQaj4YOdcfEa7QnLKUpH 9p00DxlDYmSN0s9fC4ygqvOZop7I+MY= X-Google-Smtp-Source: ABdhPJwSHuu2+YqzR0IJLcSfz4UuQFLPxAgOKQjBnghAqNzp2YYPCYKHN+sp+/U5r8Ffe0yVzT7zWbBDzAU= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90b:1e10:b0:1bf:6c78:54a9 with SMTP id pg16-20020a17090b1e1000b001bf6c7854a9mr434986pjb.1.1646974147365; Thu, 10 Mar 2022 20:49:07 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:08 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-23-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 22/25] KVM: arm64: Trap disabled features of ID_AA64MMFR1_EL1 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 , Fuad Tabba , 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-20220310_204909_197937_44227B3C X-CRM114-Status: GOOD ( 13.96 ) 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 Add feature_config_ctrl for LORegions, which is indicated in ID_AA64MMFR1_EL1, to program configuration register to trap guest's using the feature when it is not exposed to the guest. Change trap_loregion() to use vcpu_feature_is_available() to simplify checking of the feature's availability. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 677815030d44..f3661881cbed 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -374,6 +374,11 @@ static void feature_tracefilt_trap_activate(struct kvm_vcpu *vcpu) feature_trap_activate(vcpu, VCPU_MDCR_EL2, MDCR_EL2_TTRF, 0); } +static void feature_lor_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, HCR_TLOR, 0); +} + /* For ID_AA64PFR0_EL1 */ static struct feature_config_ctrl ftr_ctrl_ras = { .ftr_reg = SYS_ID_AA64PFR0_EL1, @@ -433,6 +438,15 @@ static struct feature_config_ctrl ftr_ctrl_tracefilt = { .trap_activate = feature_tracefilt_trap_activate, }; +/* For ID_AA64MMFR1_EL1 */ +static struct feature_config_ctrl ftr_ctrl_lor = { + .ftr_reg = SYS_ID_AA64MMFR1_EL1, + .ftr_shift = ID_AA64MMFR1_LOR_SHIFT, + .ftr_min = 1, + .ftr_signed = FTR_UNSIGNED, + .trap_activate = feature_lor_trap_activate, +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -1003,10 +1017,9 @@ static bool trap_loregion(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { - u64 val = read_id_reg_with_encoding(vcpu, SYS_ID_AA64MMFR1_EL1); u32 sr = reg_to_encoding(r); - if (!(val & (0xfUL << ID_AA64MMFR1_LOR_SHIFT))) { + if (!vcpu_feature_is_available(vcpu, &ftr_ctrl_lor)) { kvm_inject_undefined(vcpu); return false; } @@ -3785,6 +3798,14 @@ static struct id_reg_desc id_aa64mmfr0_el1_desc = { .validate = validate_id_aa64mmfr0_el1, }; +static struct id_reg_desc id_aa64mmfr1_el1_desc = { + .reg_desc = ID_SANITISED(ID_AA64MMFR1_EL1), + .trap_features = &(const struct feature_config_ctrl *[]) { + &ftr_ctrl_lor, + NULL, + }, +}; + static struct id_reg_desc id_aa64dfr0_el1_desc = { .reg_desc = ID_SANITISED(ID_AA64DFR0_EL1), .init = init_id_aa64dfr0_el1_desc, @@ -3901,7 +3922,7 @@ static struct id_reg_desc *id_reg_desc_table[KVM_ARM_ID_REG_MAX_NUM] = { /* CRm=7 */ ID_DESC(ID_AA64MMFR0_EL1, &id_aa64mmfr0_el1_desc), - ID_DESC_DEFAULT(ID_AA64MMFR1_EL1), + ID_DESC(ID_AA64MMFR1_EL1, &id_aa64mmfr1_el1_desc), ID_DESC_DEFAULT(ID_AA64MMFR2_EL1), ID_DESC_UNALLOC(7, 3), ID_DESC_UNALLOC(7, 4), From patchwork Fri Mar 11 04:48:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777437 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 2EB33C433F5 for ; Fri, 11 Mar 2022 05:05:12 +0000 (UTC) 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=6fLTqFx2OS9gSfBK7fHZOl+w1i4i0XDieU9e6AfPXig=; b=MUX12B9PvV1n9SC+k+U1sj531K 2Yo7Xt25+gToaerU6PKrgJpoF9mQFu4JuTvukaCtCabP8bwFTBfcyg9bI5zcEc3IDMp0BorTrHqqP up3ptFSFBHkiHLHbFqUg/dfdnLl5VBU82F3hsGlhKgvES8e2Da3+SNtLEnOFtbKqBaHEVdtVmPH9v 46FdR5oxX/8FQUg6KUSFtY1MXmWEKQWUwpX8f3wKiFgYeqH5udxWg5n2CDOwTo0dQ2ebJaf39whL2 kp/ymRiwrE1fCjI8uou/As8zG/Jo8CjuqfjZKPZHC3b1WFgXwYg7tzVwMr+XzSDdEjGjdGg1jXH42 DVJ+didw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXR4-00F5kF-4k; Fri, 11 Mar 2022 05:03:32 +0000 Received: from mail-pf1-x449.google.com ([2607:f8b0:4864:20::449]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDC-00EzsI-UN for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:12 +0000 Received: by mail-pf1-x449.google.com with SMTP id w68-20020a62dd47000000b004f6aa5e4824so4533864pff.4 for ; Thu, 10 Mar 2022 20:49:09 -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=7z5Uw2gRXSzvSWZCDvr7dARcE7XtDS3gb33aMNuIZp0=; b=LgvVZuqBFOS0jJKhiMC7n9409cSkdsgPrFen1ZDgAcy8XvbK5y7SuNyF2yj99Gs50X 8ctQndJnSgLFIAP995LFH9A9CyErl47PF5oJfFOu37jmWeQMiZlViWMsQEMouVLx2FId uw+L8ae+yJG3jRPydLz99/TREejGMtYarMr2/rXAq8Tn5lS+SPhVzfCJotveG3TIQZiQ DNxTGJan0vG2MDqBnZuRXt5+Wgx/DkcsUZfeBOe9WM466Bhc6ShUyRX9yyMHE0vpZlP+ hIit8D51RNTa1Bc+lf1P3YK4GXsm1D6MV0qYFKb+lJ2vdpvDXYmqaRka0xVr+4UriKpe d/7g== 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=7z5Uw2gRXSzvSWZCDvr7dARcE7XtDS3gb33aMNuIZp0=; b=GBieFZLzGMVgzY247UNLuqGZlb2i22rOjab+BrzimNiVWJLEufEx3eKNFqFfex9hnE a/CgW4U9p/h+3re16PRDessvRr4I99zVnvz+ZnKwygD4nMbtf3xFWh7qDfKpF4qGAzR9 qJbdlWpYHFAoMG1shLPQXbuCihuHNCXYhkyXzwyGh8uyeewnxl/+BqOPkzQ28ir/sFIe WKVROjTgS4gJOGDXflsPJgTVHx3Sj+FTCyQ7OrX9ClVWW8AdNh9pM2JWPPO0oQfh+8/j D/E4TANL5LtukqFAkSZeBNQeaqrATgTuncBdx2T5Aq3HQCGfID2mzmXV9Rjv4XQqlOh8 zZwA== X-Gm-Message-State: AOAM5336EKzWyNxMr6w2QEtbSAcVlkeBUDaKyCUi8bz6KVs2DahedeZ5 BADdepvLSBmTmbLHxcKXedtB25JpUpM= X-Google-Smtp-Source: ABdhPJw61zM8eXq9A5LGOH7Lc1dcnB3i8F9/nsnO0WTPLudzhQ0Ew+bphYaAwCUfdiwvwCU4sgAbzOAPE+w= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:228b:b0:4f7:9155:b685 with SMTP id f11-20020a056a00228b00b004f79155b685mr208604pfe.61.1646974149257; Thu, 10 Mar 2022 20:49:09 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:09 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-24-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 23/25] KVM: arm64: Trap disabled features of ID_AA64ISAR1_EL1 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 , Fuad Tabba , 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-20220310_204911_044378_D780A08E X-CRM114-Status: GOOD ( 15.22 ) 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 Add feature_config_ctrl for PTRAUTH, which is indicated in ID_AA64ISAR1_EL1, to program configuration register to trap guest's using the feature when it is not exposed to the guest. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index f3661881cbed..881e8879a48b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -284,6 +284,30 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu, (cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT) >= \ ID_AA64ISAR1_GPI_IMP_DEF) +/* + * Return true if ptrauth needs to be trapped. + * (i.e. if ptrauth is supported on the host but not exposed to the guest) + */ +static bool vcpu_need_trap_ptrauth(struct kvm_vcpu *vcpu) +{ + u64 val; + bool generic, address; + + if (!system_has_full_ptr_auth()) + /* The feature is not supported. */ + return false; + + val = read_id_reg_with_encoding(vcpu, SYS_ID_AA64ISAR1_EL1); + generic = aa64isar1_has_gpi(val) || aa64isar1_has_gpa(val); + address = aa64isar1_has_api(val) || aa64isar1_has_apa(val); + if (generic && address) + /* The feature is available. */ + return false; + + /* The feature is supported but hidden. */ + return true; +} + /* * Feature information to program configuration register to trap or disable * guest's using a feature when the feature is not exposed to the guest. @@ -379,6 +403,11 @@ static void feature_lor_trap_activate(struct kvm_vcpu *vcpu) feature_trap_activate(vcpu, VCPU_HCR_EL2, HCR_TLOR, 0); } +static void feature_ptrauth_trap_activate(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, 0, HCR_API | HCR_APK); +} + /* For ID_AA64PFR0_EL1 */ static struct feature_config_ctrl ftr_ctrl_ras = { .ftr_reg = SYS_ID_AA64PFR0_EL1, @@ -447,6 +476,12 @@ static struct feature_config_ctrl ftr_ctrl_lor = { .trap_activate = feature_lor_trap_activate, }; +/* For SYS_ID_AA64ISAR1_EL1 */ +static struct feature_config_ctrl ftr_ctrl_ptrauth = { + .ftr_need_trap = vcpu_need_trap_ptrauth, + .trap_activate = feature_ptrauth_trap_activate, +}; + /* id_reg_desc flags field values */ #define ID_DESC_REG_UNALLOC (1UL << 0) #define ID_DESC_REG_HIDDEN (1UL << 1) @@ -3782,6 +3817,10 @@ static struct id_reg_desc id_aa64isar1_el1_desc = { .init = init_id_aa64isar1_el1_desc, .validate = validate_id_aa64isar1_el1, .vcpu_mask = vcpu_mask_id_aa64isar1_el1, + .trap_features = &(const struct feature_config_ctrl *[]) { + &ftr_ctrl_ptrauth, + NULL, + }, }; static struct id_reg_desc id_aa64mmfr0_el1_desc = { From patchwork Fri Mar 11 04:48:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777438 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 189C5C433EF for ; Fri, 11 Mar 2022 05:06:22 +0000 (UTC) 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=Esc8rNPbgEeG/TXY2PaT/EDRVWD8mV6ncVhKDScz6e8=; b=qdHA9wZ9W40uSdLkZrOCThF9Mm BujoNUxh7ckzn6pkNjhfNmXFBUTBlGzyCYzO9wO6MkoTaVTANhb2AuwMZhZO999hCZszUNy9iAJUP +6Mqz2J57o4WM+HRVc5UrA55APyh9x+rV4zgs4M0pS5RyrjXtr5BCeOv77ZbdfGwpm8fZ4VkBxh+E BC72yc6QpXZQdxXAUmMqXzjbGfMVErv2heWXy03LY23zN33B+PQJNXltMSHoV2bkn984gpBcEqxLx QT6yiSb3f2Yk1z1unJ0jvowWGWjicjdeW+pQVR8EnbdOLCtSYXph1TVgTQDM5CCPj30liEwrhFCwC qxIPKAHA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXSD-00F67g-AT; Fri, 11 Mar 2022 05:04:42 +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 1nSXDE-00Ezt5-0v for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:14 +0000 Received: by mail-pg1-x549.google.com with SMTP id q7-20020a63e207000000b003801b9bb18dso4137850pgh.15 for ; Thu, 10 Mar 2022 20:49:11 -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=tYsa4GwK5vHvXOLU4hy5whTfg5+Nu58Qitdxi9Dv5NM=; b=siMDqo3ZOE6cYuiG6VHlGle1pdvc/FiPB5gq7bTUIJzm66A6cikgiKmWGaJ2+c/T6j oBcwLDfZXs25lfhx3I1inzwalmPnVDxjo58UdPOgiAcjNcwZ2cw/Q1vhLya+iFxAJBO7 8pW7Y8rcgNqZGmLbSRpm3kQZ3giYJ1/asU7Fb3iRSQdd9YQejweehGzYDxx7Zxy3EJgv WSPD8LLXL4x1zKq5kguPhs8hmzOhuliLLL/WsEgzrF364RiKeikfjW9OUPXcQT6BCZs2 VaAebMEMs9KgXV34yUEBhSX74es6t+6Zzgejs8KqAHrKVWvFgE9hgXhaMz92qLK7zLh/ DBxw== 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=tYsa4GwK5vHvXOLU4hy5whTfg5+Nu58Qitdxi9Dv5NM=; b=qgKayjHlX66fk6zqePJ1okpDWJ9uOSSoDIBZiNi1BtYmvT09fPNmT1L/sIjM49rSQ4 /g+KgCE7yVPe0gW/XG6bxP98xxJkDj3+898rZ13jHDBtade6dkeFr6qIaLkrwwpv7aFQ 2QisrEtWfUFCPhP9b5sDGJxDbJEj4FpdYZvttTHbPtEKsb9h3hN/LMvftBxFSWDnjiCl unvgcHqxahgPSrwXaZS9MVhR7OtFi3RLSAgTPIX0x/0JsgL2YbToiaxu+d7LUxFpChiN eZTaRlXA7B8Dar6J3Zg3WNfLtIxnFvp5+/iG3iChE74Z5ZuurEPhB9Eche0l3QchyLgq 36Jg== X-Gm-Message-State: AOAM533bYVY0vFBiJXm+VOGwAV0ZzTaHKgVpAZ/M/PWyQGTi0rVOtf5j lb+Ioxd5/Utv06XO99O2wNmwtpCedkc= X-Google-Smtp-Source: ABdhPJwwtBuATxtUAkCdD6djUtwNzadoHy3qN0OijrF6sB7z1qriiPYEkLLfTp8OdqSMGoAAN9AQgIQ6O0k= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a17:90a:c504:b0:1bf:6d9f:65a6 with SMTP id k4-20020a17090ac50400b001bf6d9f65a6mr9038972pjt.204.1646974150722; Thu, 10 Mar 2022 20:49:10 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:10 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-25-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 24/25] KVM: arm64: Add kunit test for trap initialization 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 , Fuad Tabba , 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-20220310_204912_133763_8CE33BA1 X-CRM114-Status: GOOD ( 17.30 ) 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 Add KUnit tests for functions in arch/arm64/kvm/sys_regs_test.c that activates traps for disabled features. Signed-off-by: Reiji Watanabe --- arch/arm64/kvm/sys_regs_test.c | 255 +++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/arch/arm64/kvm/sys_regs_test.c b/arch/arm64/kvm/sys_regs_test.c index 954c01876977..d26c589cbb93 100644 --- a/arch/arm64/kvm/sys_regs_test.c +++ b/arch/arm64/kvm/sys_regs_test.c @@ -957,6 +957,258 @@ static void validate_id_reg_test(struct kunit *test) } } +struct trap_config_test { + u64 set; + u64 clear; + u64 prev_val; + u64 expect_val; +}; + +struct trap_config_test trap_params[] = { + {0x30000800000, 0, 0, 0x30000800000}, + {0, 0x30000800000, 0, 0}, + {0x30000800000, 0, (u64)-1, (u64)-1}, + {0, 0x30000800000, (u64)-1, (u64)0xfffffcffff7fffff}, +}; + +static void trap_case_to_desc(struct trap_config_test *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "trap - set:0x%llx, clear:0x%llx, prev_val:0x%llx\n", + t->set, t->clear, t->prev_val); +} + +KUNIT_ARRAY_PARAM(trap, trap_params, trap_case_to_desc); + +/* Tests for feature_trap_activate(). */ +static void feature_trap_activate_test(struct kunit *test) +{ + struct kvm_vcpu *vcpu; + const struct trap_config_test *trap = test->param_value; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_ASSERT_TRUE(test, vcpu); + + /* Test for HCR_EL2 */ + vcpu->arch.hcr_el2 = trap->prev_val; + feature_trap_activate(vcpu, VCPU_HCR_EL2, trap->set, trap->clear); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2, trap->expect_val); + + /* Test for MDCR_EL2 */ + vcpu->arch.mdcr_el2 = trap->prev_val; + feature_trap_activate(vcpu, VCPU_MDCR_EL2, trap->set, trap->clear); + KUNIT_EXPECT_EQ(test, vcpu->arch.mdcr_el2, trap->expect_val); + + /* Test for CPTR_EL2 */ + vcpu->arch.cptr_el2 = trap->prev_val; + feature_trap_activate(vcpu, VCPU_CPTR_EL2, trap->set, trap->clear); + KUNIT_EXPECT_EQ(test, vcpu->arch.cptr_el2, trap->expect_val); +} + +static u64 test_trap_set0; +static u64 test_trap_clear0; +static void test_trap_activate0(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, + test_trap_set0, test_trap_clear0); +} + +static u64 test_trap_set1; +static u64 test_trap_clear1; +static void test_trap_activate1(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, + test_trap_set1, test_trap_clear1); +} + +static u64 test_trap_set2; +static u64 test_trap_clear2; +static void test_trap_activate2(struct kvm_vcpu *vcpu) +{ + feature_trap_activate(vcpu, VCPU_HCR_EL2, + test_trap_set2, test_trap_clear2); +} + + +static void setup_feature_config_ctrl(struct feature_config_ctrl *config, + u32 id, int shift, int min, bool sign, + void *fn) +{ + memset(config, 0, sizeof(*config)); + config->ftr_reg = id; + config->ftr_shift = shift; + config->ftr_min = min; + config->ftr_signed = sign; + config->trap_activate = fn; +} + +/* + * Tests for id_reg_features_trap_activate. + * Setup a id_reg_desc with three entries in id_reg_desc->trap_features[]. + * Check if the config register is updated to enable trap for the disabled + * features. + */ +static void id_reg_features_trap_activate_test(struct kunit *test) +{ + struct kvm_vcpu *vcpu; + u32 id; + u64 cfg_set, cfg_clear, id_reg_sys_val, id_reg_val; + struct id_reg_desc id_reg_data = {}; + struct feature_config_ctrl config0, config1, config2; + struct feature_config_ctrl *trap_features[] = { + &config0, &config1, &config2, NULL, + }; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_EXPECT_TRUE(test, vcpu); + if (!vcpu) + return; + + /* Setup id_reg_desc */ + id_reg_sys_val = 0x7777777777777777; + id = SYS_ID_AA64DFR0_EL1; + set_sys_desc((struct sys_reg_desc *)&id_reg_data.reg_desc, id); + id_reg_data.sys_val = id_reg_sys_val; + id_reg_data.vcpu_limit_val = (u64)-1; + id_reg_data.trap_features = + (const struct feature_config_ctrl *(*)[])trap_features; + + /* Setup the 1st feature_config_ctrl */ + test_trap_set0 = 0x3; + test_trap_clear0 = 0x0; + setup_feature_config_ctrl(&config0, id, 60, 2, FTR_UNSIGNED, + &test_trap_activate0); + + /* Setup the 2nd feature_config_ctrl */ + test_trap_set1 = 0x30000040; + test_trap_clear1 = 0x40000000; + setup_feature_config_ctrl(&config1, id, 0, 1, FTR_UNSIGNED, + &test_trap_activate1); + + /* Setup the 3rd feature_config_ctrl */ + test_trap_set2 = 0x30000000800; + test_trap_clear2 = 0x40000000000; + setup_feature_config_ctrl(&config2, id, 4, 0, FTR_SIGNED, + &test_trap_activate2); + +#define ftr_dis(cfg) \ + ((u64)(((cfg)->ftr_min - 1) & 0xf) << (cfg)->ftr_shift) + +#define ftr_en(cfg) \ + ((u64)(cfg)->ftr_min << (cfg)->ftr_shift) + + /* Test with features enabled for config0, 1 and 2 */ + id_reg_val = ftr_en(&config0) | ftr_en(&config1) | ftr_en(&config2); + write_kvm_id_reg(vcpu->kvm, id, id_reg_val); + vcpu->arch.hcr_el2 = 0; + id_reg_features_trap_activate(vcpu, &id_reg_data); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2, 0); + + + /* Test with features disabled for config0 only */ + id_reg_val = ftr_dis(&config0) | ftr_en(&config1) | ftr_en(&config2); + write_kvm_id_reg(vcpu->kvm, id, id_reg_val); + vcpu->arch.hcr_el2 = 0; + cfg_set = test_trap_set0; + cfg_clear = test_trap_clear0; + + id_reg_features_trap_activate(vcpu, &id_reg_data); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_set, cfg_set); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_clear, 0); + + + /* Test with features disabled for config0 and config1 */ + id_reg_val = ftr_dis(&config0) | ftr_dis(&config1) | ftr_en(&config2); + write_kvm_id_reg(vcpu->kvm, id, id_reg_val); + vcpu->arch.hcr_el2 = 0; + + cfg_set = test_trap_set0 | test_trap_set1; + cfg_clear = test_trap_clear0 | test_trap_clear1; + + id_reg_features_trap_activate(vcpu, &id_reg_data); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_set, cfg_set); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_clear, 0); + + + /* Test with features disabled for config0, config1, and config2 */ + id_reg_val = ftr_dis(&config0) | ftr_dis(&config1) | ftr_dis(&config2); + write_kvm_id_reg(vcpu->kvm, id, id_reg_val); + vcpu->arch.hcr_el2 = 0; + + cfg_set = test_trap_set0 | test_trap_set1 | test_trap_set2; + cfg_clear = test_trap_clear0 | test_trap_clear1 | test_trap_clear2; + + id_reg_features_trap_activate(vcpu, &id_reg_data); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_set, cfg_set); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2 & cfg_clear, 0); + + + /* Test with id_reg_data.trap_features = NULL */ + id_reg_data.trap_features = NULL; + vcpu->arch.hcr_el2 = 0; + id_reg_features_trap_activate(vcpu, &id_reg_data); + KUNIT_EXPECT_EQ(test, vcpu->arch.hcr_el2, 0); +} + +/* Tests for vcpu_need_trap_ptrauth(). */ +static void vcpu_need_trap_ptrauth_test(struct kunit *test) +{ + struct kvm_vcpu *vcpu; + u32 id = SYS_ID_AA64ISAR1_EL1; + + vcpu = test_kvm_vcpu_init(test); + KUNIT_EXPECT_TRUE(test, vcpu); + if (!vcpu) + return; + + if (system_has_full_ptr_auth()) { + /* Tests with PTRAUTH disabled vCPU */ + write_kvm_id_reg(vcpu->kvm, id, 0x0); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPI = 1, API = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x10000100); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPI = 1, APA = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x10000010); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPA = 1, API = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x01000100); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPA = 1, APA = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x01000010); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + + /* Tests with PTRAUTH enabled vCPU */ + vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_PTRAUTH; + + write_kvm_id_reg(vcpu->kvm, id, 0x0); + KUNIT_EXPECT_TRUE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPI = 1, API = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x10000100); + KUNIT_EXPECT_FALSE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPI = 1, APA = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x10000010); + KUNIT_EXPECT_FALSE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPA = 1, API = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x01000100); + KUNIT_EXPECT_FALSE(test, vcpu_need_trap_ptrauth(vcpu)); + + /* GPA = 1, APA = 1 */ + write_kvm_id_reg(vcpu->kvm, id, 0x01000010); + KUNIT_EXPECT_FALSE(test, vcpu_need_trap_ptrauth(vcpu)); + } else { + KUNIT_EXPECT_FALSE(test, vcpu_need_trap_ptrauth(vcpu)); + } +} + static struct kunit_case kvm_sys_regs_test_cases[] = { KUNIT_CASE_PARAM(vcpu_id_reg_feature_frac_check_test, frac_gen_params), KUNIT_CASE_PARAM(validate_id_aa64mmfr0_tgran2_test, tgran4_2_gen_params), @@ -971,6 +1223,9 @@ static struct kunit_case kvm_sys_regs_test_cases[] = { KUNIT_CASE(validate_id_dfr0_el1_test), KUNIT_CASE(validate_mvfr1_el1_test), KUNIT_CASE(validate_id_reg_test), + KUNIT_CASE(vcpu_need_trap_ptrauth_test), + KUNIT_CASE_PARAM(feature_trap_activate_test, trap_gen_params), + KUNIT_CASE(id_reg_features_trap_activate_test), {} }; From patchwork Fri Mar 11 04:48:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reiji Watanabe X-Patchwork-Id: 12777439 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id D7F3EC433F5 for ; Fri, 11 Mar 2022 05:07:53 +0000 (UTC) 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=5MFR9jfxcbNCb2sm+9EISKP1zFzXkWs98BBrMSXpIyc=; b=UKm2YqtwpgDE5GuGKJUJoY05LK 1bqWWpiTEfs0KBqKla/k+cRy4q+Xr5O6PLsZvkofTPaMkS4aNjMffJVUJkhMyQwHTcpUV2bsW2LPi BSw7ZHcq7gBTumhQg0oCGZnFEGR3NJpZ+e+WrutapqzxnS4T+Kv/rHDNVRNu1zmPQ4UP89ZY0dzdU CFajH5ZqufKXY41mLtVPwC/AD6eHtvyek5NdqnxKI68IF0qcNHsMw07mjtIEZjvsUfB8qm1L1ClbC KhT74J5MSaZvLLahCMcoEm0YR6Oc2sberpROHJFdoaQtgVfr0QbFUX+hf0Ql9+2ueGejbhn3tfLXa as+SCZIQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXTQ-00F6X4-Oc; Fri, 11 Mar 2022 05:05:58 +0000 Received: from mail-pj1-x104a.google.com ([2607:f8b0:4864:20::104a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSXDF-00EzuB-Tg for linux-arm-kernel@lists.infradead.org; Fri, 11 Mar 2022 04:49:18 +0000 Received: by mail-pj1-x104a.google.com with SMTP id c14-20020a17090a674e00b001bf1c750f9bso7161519pjm.9 for ; Thu, 10 Mar 2022 20:49:12 -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=2VzJ5bbyA7Dksa2KQg5LK+2SEJqfJMZXQQHf/Kgd4lU=; b=AV0WoRrX6tf+MScGlKd0qf721x1teQwMQzw5EcjCQvEun66l37qDNH4+4hUSHqPzhY 7JJmEf3xR9gpY3JJKkoixvBlkbNy3+CQvuNwWQN13vRYJ8MQRHHsoagbbZEdoV4SRM94 pr+JbZzgFprByPIERTpHkzsOFnR3PhNip4SS3mrcntgdmgNe0qHHOICrEeQiOO5aopdq tSIvTHMPudve+VW+em72biz5hR6OdB4wMjpxpuKem6LppmPV1DaXfkJ9Wr4XL2ZxqDt0 Z/8KlaMlrbbpPMVKXkp35OCI0AKfE3K+hv7csJrA6jiWmNIEitQOutSj8xQOL4SI5Qct vsSA== 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=2VzJ5bbyA7Dksa2KQg5LK+2SEJqfJMZXQQHf/Kgd4lU=; b=1p5bo+n75CSkwIQra0N4b+6Qx1Ofg5MqYva1M0vq1rtxmQpU8m/EuL0zFtlgeYfIi5 fCbRkZ7MFeMMOwy+Q2IwC2BOd7NPcODWMU3EwQCxQD0Yqc9nKw4U8DJftE6GzHw+ZvtS ZxWI1yvS2FT13ndTI4qbonAw6gVncRemnK3uCNbyvjJ/enXNd5L6I4L9Zx4ZYHv8Vyqh h1yu1RmikoWfDQS9NTEkz0dzQNDXwjS5puxdaG7ftrwW3lcdK7m6NIKqoNjKQNYkJtDp AwkJI5+2cDrQPgcNg/+HKbDYU8sQBZ3lqvzpyEKE7CgfN8Ui6MI55N6Dp17SIikzuyXK EXjQ== X-Gm-Message-State: AOAM532tV1OvqkeufDOjhGrkGbq8G32IeRVBI3jqeT2da4YlX4QBY4fJ KbC1QPUMWP/NtIxM8BfebfSIameHVd0= X-Google-Smtp-Source: ABdhPJwD5YtuyER4VqF/KXNPQtcIFb60qbyjqRAlITHTEsEkqxHYo2VRYZKUymYmlTn6lMzRjEwKIAraX5c= X-Received: from reiji-vws-sp.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3d59]) (user=reijiw job=sendgmr) by 2002:a05:6a00:2481:b0:4f6:b71f:3330 with SMTP id c1-20020a056a00248100b004f6b71f3330mr8246328pfv.47.1646974152362; Thu, 10 Mar 2022 20:49:12 -0800 (PST) Date: Thu, 10 Mar 2022 20:48:11 -0800 In-Reply-To: <20220311044811.1980336-1-reijiw@google.com> Message-Id: <20220311044811.1980336-26-reijiw@google.com> Mime-Version: 1.0 References: <20220311044811.1980336-1-reijiw@google.com> X-Mailer: git-send-email 2.35.1.723.g4982287a31-goog Subject: [PATCH v6 25/25] KVM: arm64: selftests: Introduce id_reg_test 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 , Fuad Tabba , 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-20220310_204914_042442_C402E6C9 X-CRM114-Status: GOOD ( 21.76 ) 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 Introduce a test for aarch64 to validate basic behavior of KVM_GET_ONE_REG and KVM_SET_ONE_REG for ID registers. This test runs only when KVM_CAP_ARM_ID_REG_CONFIGURABLE is supported. Signed-off-by: Reiji Watanabe --- tools/arch/arm64/include/asm/sysreg.h | 1 + tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/aarch64/id_reg_test.c | 1300 +++++++++++++++++ 4 files changed, 1303 insertions(+) create mode 100644 tools/testing/selftests/kvm/aarch64/id_reg_test.c diff --git a/tools/arch/arm64/include/asm/sysreg.h b/tools/arch/arm64/include/asm/sysreg.h index 7640fa27be94..be3947c125f1 100644 --- a/tools/arch/arm64/include/asm/sysreg.h +++ b/tools/arch/arm64/include/asm/sysreg.h @@ -793,6 +793,7 @@ #define ID_AA64PFR0_ELx_32BIT_64BIT 0x2 /* id_aa64pfr1 */ +#define ID_AA64PFR1_CSV2FRAC_SHIFT 32 #define ID_AA64PFR1_MPAMFRAC_SHIFT 16 #define ID_AA64PFR1_RASFRAC_SHIFT 12 #define ID_AA64PFR1_MTE_SHIFT 8 diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index dce7de7755e6..c82c1978d5bb 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -2,6 +2,7 @@ /aarch64/arch_timer /aarch64/debug-exceptions /aarch64/get-reg-list +/aarch64/id_reg_test /aarch64/psci_cpu_on_test /aarch64/vgic_init /aarch64/vgic_irq diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 17c3f0749f05..aa05a142994a 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -102,6 +102,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test TEST_GEN_PROGS_aarch64 += aarch64/arch_timer TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list +TEST_GEN_PROGS_aarch64 += aarch64/id_reg_test TEST_GEN_PROGS_aarch64 += aarch64/psci_cpu_on_test TEST_GEN_PROGS_aarch64 += aarch64/vgic_init TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq diff --git a/tools/testing/selftests/kvm/aarch64/id_reg_test.c b/tools/testing/selftests/kvm/aarch64/id_reg_test.c new file mode 100644 index 000000000000..e4f353323d68 --- /dev/null +++ b/tools/testing/selftests/kvm/aarch64/id_reg_test.c @@ -0,0 +1,1300 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * id_reg_test.c - Tests reading/writing the aarch64's ID registers + * + * The test validates KVM_SET_ONE_REG/KVM_GET_ONE_REG ioctl for ID + * registers as well as reading ID register from the guest works fine. + * + * Copyright (c) 2022, Google LLC. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" +#include "vgic.h" + +/* Reserved ID registers */ +#define SYS_ID_REG_3_3_EL1 sys_reg(3, 0, 0, 3, 3) +#define SYS_ID_REG_3_7_EL1 sys_reg(3, 0, 0, 3, 7) + +#define SYS_ID_REG_4_2_EL1 sys_reg(3, 0, 0, 4, 2) +#define SYS_ID_REG_4_3_EL1 sys_reg(3, 0, 0, 4, 3) +#define SYS_ID_REG_4_5_EL1 sys_reg(3, 0, 0, 4, 5) +#define SYS_ID_REG_4_6_EL1 sys_reg(3, 0, 0, 4, 6) +#define SYS_ID_REG_4_7_EL1 sys_reg(3, 0, 0, 4, 7) + +#define SYS_ID_REG_5_2_EL1 sys_reg(3, 0, 0, 5, 2) +#define SYS_ID_REG_5_3_EL1 sys_reg(3, 0, 0, 5, 3) +#define SYS_ID_REG_5_6_EL1 sys_reg(3, 0, 0, 5, 6) +#define SYS_ID_REG_5_7_EL1 sys_reg(3, 0, 0, 5, 7) + +#define SYS_ID_REG_6_2_EL1 sys_reg(3, 0, 0, 6, 2) +#define SYS_ID_REG_6_3_EL1 sys_reg(3, 0, 0, 6, 3) +#define SYS_ID_REG_6_4_EL1 sys_reg(3, 0, 0, 6, 4) +#define SYS_ID_REG_6_5_EL1 sys_reg(3, 0, 0, 6, 5) +#define SYS_ID_REG_6_6_EL1 sys_reg(3, 0, 0, 6, 6) +#define SYS_ID_REG_6_7_EL1 sys_reg(3, 0, 0, 6, 7) + +#define SYS_ID_REG_7_3_EL1 sys_reg(3, 0, 0, 7, 3) +#define SYS_ID_REG_7_4_EL1 sys_reg(3, 0, 0, 7, 4) +#define SYS_ID_REG_7_5_EL1 sys_reg(3, 0, 0, 7, 5) +#define SYS_ID_REG_7_6_EL1 sys_reg(3, 0, 0, 7, 6) +#define SYS_ID_REG_7_7_EL1 sys_reg(3, 0, 0, 7, 7) + +#define READ_ID_REG_FN(name) read_## name ## _EL1 + +#define DEFINE_READ_SYS_REG(reg_name) \ +uint64_t read_##reg_name(void) \ +{ \ + return read_sysreg_s(SYS_##reg_name); \ +} + +#define DEFINE_READ_ID_REG(name) \ + DEFINE_READ_SYS_REG(name ## _EL1) + +#define __ID_REG(reg_name) \ + .name = #reg_name, \ + .id = SYS_## reg_name ##_EL1, \ + .read_reg = READ_ID_REG_FN(reg_name), + +#define ID_REG_ENT(reg_name) \ + [ID_IDX(reg_name)] = { __ID_REG(reg_name) } + +/* Functions to read each ID register */ +/* CRm=1 */ +DEFINE_READ_ID_REG(ID_PFR0) +DEFINE_READ_ID_REG(ID_PFR1) +DEFINE_READ_ID_REG(ID_DFR0) +DEFINE_READ_ID_REG(ID_AFR0) +DEFINE_READ_ID_REG(ID_MMFR0) +DEFINE_READ_ID_REG(ID_MMFR1) +DEFINE_READ_ID_REG(ID_MMFR2) +DEFINE_READ_ID_REG(ID_MMFR3) + +/* CRm=2 */ +DEFINE_READ_ID_REG(ID_ISAR0) +DEFINE_READ_ID_REG(ID_ISAR1) +DEFINE_READ_ID_REG(ID_ISAR2) +DEFINE_READ_ID_REG(ID_ISAR3) +DEFINE_READ_ID_REG(ID_ISAR4) +DEFINE_READ_ID_REG(ID_ISAR5) +DEFINE_READ_ID_REG(ID_MMFR4) +DEFINE_READ_ID_REG(ID_ISAR6) + +/* CRm=3 */ +DEFINE_READ_ID_REG(MVFR0) +DEFINE_READ_ID_REG(MVFR1) +DEFINE_READ_ID_REG(MVFR2) +DEFINE_READ_ID_REG(ID_REG_3_3) +DEFINE_READ_ID_REG(ID_PFR2) +DEFINE_READ_ID_REG(ID_DFR1) +DEFINE_READ_ID_REG(ID_MMFR5) +DEFINE_READ_ID_REG(ID_REG_3_7) + +/* CRm=4 */ +DEFINE_READ_ID_REG(ID_AA64PFR0) +DEFINE_READ_ID_REG(ID_AA64PFR1) +DEFINE_READ_ID_REG(ID_REG_4_2) +DEFINE_READ_ID_REG(ID_REG_4_3) +DEFINE_READ_ID_REG(ID_AA64ZFR0) +DEFINE_READ_ID_REG(ID_REG_4_5) +DEFINE_READ_ID_REG(ID_REG_4_6) +DEFINE_READ_ID_REG(ID_REG_4_7) + +/* CRm=5 */ +DEFINE_READ_ID_REG(ID_AA64DFR0) +DEFINE_READ_ID_REG(ID_AA64DFR1) +DEFINE_READ_ID_REG(ID_REG_5_2) +DEFINE_READ_ID_REG(ID_REG_5_3) +DEFINE_READ_ID_REG(ID_AA64AFR0) +DEFINE_READ_ID_REG(ID_AA64AFR1) +DEFINE_READ_ID_REG(ID_REG_5_6) +DEFINE_READ_ID_REG(ID_REG_5_7) + +/* CRm=6 */ +DEFINE_READ_ID_REG(ID_AA64ISAR0) +DEFINE_READ_ID_REG(ID_AA64ISAR1) +DEFINE_READ_ID_REG(ID_REG_6_2) +DEFINE_READ_ID_REG(ID_REG_6_3) +DEFINE_READ_ID_REG(ID_REG_6_4) +DEFINE_READ_ID_REG(ID_REG_6_5) +DEFINE_READ_ID_REG(ID_REG_6_6) +DEFINE_READ_ID_REG(ID_REG_6_7) + +/* CRm=7 */ +DEFINE_READ_ID_REG(ID_AA64MMFR0) +DEFINE_READ_ID_REG(ID_AA64MMFR1) +DEFINE_READ_ID_REG(ID_AA64MMFR2) +DEFINE_READ_ID_REG(ID_REG_7_3) +DEFINE_READ_ID_REG(ID_REG_7_4) +DEFINE_READ_ID_REG(ID_REG_7_5) +DEFINE_READ_ID_REG(ID_REG_7_6) +DEFINE_READ_ID_REG(ID_REG_7_7) + +#define ID_IDX(name) REG_IDX_## name + +enum id_reg_idx { + /* CRm=1 */ + ID_IDX(ID_PFR0) = 0, + ID_IDX(ID_PFR1), + ID_IDX(ID_DFR0), + ID_IDX(ID_AFR0), + ID_IDX(ID_MMFR0), + ID_IDX(ID_MMFR1), + ID_IDX(ID_MMFR2), + ID_IDX(ID_MMFR3), + + /* CRm=2 */ + ID_IDX(ID_ISAR0), + ID_IDX(ID_ISAR1), + ID_IDX(ID_ISAR2), + ID_IDX(ID_ISAR3), + ID_IDX(ID_ISAR4), + ID_IDX(ID_ISAR5), + ID_IDX(ID_MMFR4), + ID_IDX(ID_ISAR6), + + /* CRm=3 */ + ID_IDX(MVFR0), + ID_IDX(MVFR1), + ID_IDX(MVFR2), + ID_IDX(ID_REG_3_3), + ID_IDX(ID_PFR2), + ID_IDX(ID_DFR1), + ID_IDX(ID_MMFR5), + ID_IDX(ID_REG_3_7), + + /* CRm=4 */ + ID_IDX(ID_AA64PFR0), + ID_IDX(ID_AA64PFR1), + ID_IDX(ID_REG_4_2), + ID_IDX(ID_REG_4_3), + ID_IDX(ID_AA64ZFR0), + ID_IDX(ID_REG_4_5), + ID_IDX(ID_REG_4_6), + ID_IDX(ID_REG_4_7), + + /* CRm=5 */ + ID_IDX(ID_AA64DFR0), + ID_IDX(ID_AA64DFR1), + ID_IDX(ID_REG_5_2), + ID_IDX(ID_REG_5_3), + ID_IDX(ID_AA64AFR0), + ID_IDX(ID_AA64AFR1), + ID_IDX(ID_REG_5_6), + ID_IDX(ID_REG_5_7), + + /* CRm=6 */ + ID_IDX(ID_AA64ISAR0), + ID_IDX(ID_AA64ISAR1), + ID_IDX(ID_REG_6_2), + ID_IDX(ID_REG_6_3), + ID_IDX(ID_REG_6_4), + ID_IDX(ID_REG_6_5), + ID_IDX(ID_REG_6_6), + ID_IDX(ID_REG_6_7), + + /* CRm=7 */ + ID_IDX(ID_AA64MMFR0), + ID_IDX(ID_AA64MMFR1), + ID_IDX(ID_AA64MMFR2), + ID_IDX(ID_REG_7_3), + ID_IDX(ID_REG_7_4), + ID_IDX(ID_REG_7_5), + ID_IDX(ID_REG_7_6), + ID_IDX(ID_REG_7_7), +}; + +struct id_reg_test_info { + char *name; + uint32_t id; + /* Indicates the register can be set to 0 */ + bool can_clear; + uint64_t initial_value; + uint64_t current_value; + uint64_t (*read_reg)(void); +}; + +#define ID_REG_INFO(name) (&id_reg_list[ID_IDX(name)]) +static struct id_reg_test_info id_reg_list[] = { + /* CRm=1 */ + ID_REG_ENT(ID_PFR0), + ID_REG_ENT(ID_PFR1), + ID_REG_ENT(ID_DFR0), + ID_REG_ENT(ID_AFR0), + ID_REG_ENT(ID_MMFR0), + ID_REG_ENT(ID_MMFR1), + ID_REG_ENT(ID_MMFR2), + ID_REG_ENT(ID_MMFR3), + + /* CRm=2 */ + ID_REG_ENT(ID_ISAR0), + ID_REG_ENT(ID_ISAR1), + ID_REG_ENT(ID_ISAR2), + ID_REG_ENT(ID_ISAR3), + ID_REG_ENT(ID_ISAR4), + ID_REG_ENT(ID_ISAR5), + ID_REG_ENT(ID_MMFR4), + ID_REG_ENT(ID_ISAR6), + + /* CRm=3 */ + ID_REG_ENT(MVFR0), + ID_REG_ENT(MVFR1), + ID_REG_ENT(MVFR2), + ID_REG_ENT(ID_REG_3_3), + ID_REG_ENT(ID_PFR2), + ID_REG_ENT(ID_DFR1), + ID_REG_ENT(ID_MMFR5), + ID_REG_ENT(ID_REG_3_7), + + /* CRm=4 */ + ID_REG_ENT(ID_AA64PFR0), + ID_REG_ENT(ID_AA64PFR1), + ID_REG_ENT(ID_REG_4_2), + ID_REG_ENT(ID_REG_4_3), + ID_REG_ENT(ID_AA64ZFR0), + ID_REG_ENT(ID_REG_4_5), + ID_REG_ENT(ID_REG_4_6), + ID_REG_ENT(ID_REG_4_7), + + /* CRm=5 */ + ID_REG_ENT(ID_AA64DFR0), + ID_REG_ENT(ID_AA64DFR1), + ID_REG_ENT(ID_REG_5_2), + ID_REG_ENT(ID_REG_5_3), + ID_REG_ENT(ID_AA64AFR0), + ID_REG_ENT(ID_AA64AFR1), + ID_REG_ENT(ID_REG_5_6), + ID_REG_ENT(ID_REG_5_7), + + /* CRm=6 */ + ID_REG_ENT(ID_AA64ISAR0), + ID_REG_ENT(ID_AA64ISAR1), + ID_REG_ENT(ID_REG_6_2), + ID_REG_ENT(ID_REG_6_3), + ID_REG_ENT(ID_REG_6_4), + ID_REG_ENT(ID_REG_6_5), + ID_REG_ENT(ID_REG_6_6), + ID_REG_ENT(ID_REG_6_7), + + /* CRm=7 */ + ID_REG_ENT(ID_AA64MMFR0), + ID_REG_ENT(ID_AA64MMFR1), + ID_REG_ENT(ID_AA64MMFR2), + ID_REG_ENT(ID_REG_7_3), + ID_REG_ENT(ID_REG_7_4), + ID_REG_ENT(ID_REG_7_5), + ID_REG_ENT(ID_REG_7_6), + ID_REG_ENT(ID_REG_7_7), +}; + +static bool aarch32_support = true; + +/* Utilities to get a feature field from ID register value */ +static inline int +cpuid_signed_field_width(uint64_t id_val, int field, int width) +{ + return (s64)(id_val << (64 - width - field)) >> (64 - width); +} + +static unsigned int +cpuid_unsigned_field_width(uint64_t id_val, int field, int width) +{ + return (uint64_t)(id_val << (64 - width - field)) >> (64 - width); +} + +static inline int __attribute_const__ +cpuid_extract_field_width(uint64_t id_val, int field, int width, bool sign) +{ + return (sign) ? cpuid_signed_field_width(id_val, field, width) : + cpuid_unsigned_field_width(id_val, field, width); +} + +#define is_id_reg(id) \ + (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && \ + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 0 && \ + sys_reg_CRm(id) < 8) + +#define GET_ID_FIELD(regval, shift, is_signed) \ + cpuid_extract_field_width(regval, shift, 4, is_signed) + +#define GET_ID_UFIELD(regval, shift) \ + cpuid_unsigned_field_width(regval, shift, 4) + +#define UPDATE_ID_UFIELD(regval, shift, fval) \ + (((regval) & ~(0xfULL << (shift))) | \ + (((uint64_t)((fval) & 0xf)) << (shift))) + +void pmu_init(struct kvm_vm *vm, uint32_t vcpu) +{ + struct kvm_device_attr attr = { + .group = KVM_ARM_VCPU_PMU_V3_CTRL, + .attr = KVM_ARM_VCPU_PMU_V3_INIT, + }; + vcpu_ioctl(vm, vcpu, KVM_SET_DEVICE_ATTR, &attr); +} + +void sve_init(struct kvm_vm *vm, uint32_t vcpu) +{ + int feature = KVM_ARM_VCPU_SVE; + + vcpu_ioctl(vm, vcpu, KVM_ARM_VCPU_FINALIZE, &feature); +} + +#define GICD_BASE_GPA 0x8000000ULL +#define GICR_BASE_GPA 0x80A0000ULL + +void test_vgic_init(struct kvm_vm *vm, uint32_t vcpu) +{ + /* We jsut need to configure gic v3 (we don't use it though) */ + vgic_v3_setup(vm, 1, 64, GICD_BASE_GPA, GICR_BASE_GPA); +} + +static bool is_aarch32_id_reg(uint32_t id) +{ + uint32_t crm, op2; + + if (!is_id_reg(id)) + return false; + + crm = sys_reg_CRm(id); + op2 = sys_reg_Op2(id); + if (crm == 1 || crm == 2 || (crm == 3 && (op2 != 3 && op2 != 7))) + /* AArch32 ID register */ + return true; + + return false; +} + +#define MAX_CAPS 2 +struct feature_test_info { + char *name; /* Feature Name (Debug information) */ + + /* ID register that identifies the presence of the feature */ + struct id_reg_test_info *sreg; + + /* + * Bit position of the ID register field that identifies + * the presence of the feature. + */ + int shift; + + /* Min value of the field that indicates the presence of the feature. */ + int min; + bool is_sign; /* Is the field signed or unsigned ? */ + int ncaps; /* Number of valid Capabilities in caps[] */ + + /* KVM_CAP_* Capabilities to indicates that KVM supports this feature */ + long caps[MAX_CAPS]; + + /* struct kvm_enable_cap to use the capability if needed */ + struct kvm_enable_cap *opt_in_cap; + + /* Should the guest check the ID register for this feature ? */ + bool run_test; + + /* + * Extra initialization function to enable the feature if needed. + * (e.g. KVM_ARM_VCPU_FINALIZE for SVE) + */ + void (*init_feature)(struct kvm_vm *vm, uint32_t vcpuid); + + /* struct kvm_vcpu_init to opt-in the feature if needed */ + struct kvm_vcpu_init *vcpu_init; + + /* Extra feature specific tests */ + void (*test_feature)(struct feature_test_info *finfo); +}; + +static void pmu_test(struct feature_test_info *finfo); + +/* Information for opt-in CPU features */ +static struct feature_test_info feature_test_info_table[] = { + { + .name = "SVE", + .sreg = ID_REG_INFO(ID_AA64PFR0), + .shift = ID_AA64PFR0_SVE_SHIFT, + .min = 1, + .caps = {KVM_CAP_ARM_SVE}, + .ncaps = 1, + .init_feature = sve_init, + .vcpu_init = &(struct kvm_vcpu_init) { + .features = {1ULL << KVM_ARM_VCPU_SVE}, + }, + }, + { + .name = "GIC", + .sreg = ID_REG_INFO(ID_AA64PFR0), + .shift = ID_AA64PFR0_GIC_SHIFT, + .min = 1, + .caps = {KVM_CAP_IRQCHIP}, + .ncaps = 1, + .init_feature = test_vgic_init, + }, + { + .name = "MTE", + .sreg = ID_REG_INFO(ID_AA64PFR1), + .shift = ID_AA64PFR1_MTE_SHIFT, + .min = 2, + .caps = {KVM_CAP_ARM_MTE}, + .ncaps = 1, + .opt_in_cap = &(struct kvm_enable_cap) { + .cap = KVM_CAP_ARM_MTE, + }, + }, + { + .name = "PMUV3", + .sreg = ID_REG_INFO(ID_AA64DFR0), + .shift = ID_AA64DFR0_PMUVER_SHIFT, + .min = 1, + .init_feature = pmu_init, + .test_feature = pmu_test, + .caps = {KVM_CAP_ARM_PMU_V3}, + .ncaps = 1, + .vcpu_init = &(struct kvm_vcpu_init) { + .features = {1ULL << KVM_ARM_VCPU_PMU_V3}, + }, + }, + { + .name = "PERFMON", + .sreg = ID_REG_INFO(ID_DFR0), + .shift = ID_DFR0_PERFMON_SHIFT, + .min = 3, + .init_feature = pmu_init, + .test_feature = pmu_test, + .caps = {KVM_CAP_ARM_PMU_V3}, + .ncaps = 1, + .vcpu_init = &(struct kvm_vcpu_init) { + .features = {1ULL << KVM_ARM_VCPU_PMU_V3}, + }, + }, +}; + +static void walk_id_reg_list(void (*fn)(struct id_reg_test_info *r, void *arg), + void *arg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(id_reg_list); i++) + fn(&id_reg_list[i], arg); +} + +static void guest_code_id_reg_check_one(struct id_reg_test_info *idr, void *arg) +{ + uint64_t v = idr->read_reg(); + + GUEST_ASSERT_2(v == idr->current_value, idr->name, idr->current_value); +} + +static void guest_code_id_reg_check_all(uint32_t cpu) +{ + walk_id_reg_list(guest_code_id_reg_check_one, NULL); + GUEST_DONE(); +} + +static void guest_code_do_nothing(uint32_t cpu) +{ + GUEST_DONE(); +} + +static void guest_code_feature_check(uint32_t cpu) +{ + int i; + struct feature_test_info *finfo; + + for (i = 0; i < ARRAY_SIZE(feature_test_info_table); i++) { + finfo = &feature_test_info_table[i]; + if (finfo->run_test) + guest_code_id_reg_check_one(finfo->sreg, NULL); + } + + GUEST_DONE(); +} + +static void guest_code_ptrauth_check(uint32_t cpuid) +{ + struct id_reg_test_info *sreg = ID_REG_INFO(ID_AA64ISAR1); + uint64_t val = sreg->read_reg(); + + GUEST_ASSERT_2(val == sreg->current_value, "PTRAUTH", val); + GUEST_DONE(); +} + +static void reset_id_reg_info_current_value(struct id_reg_test_info *info, + void *arg) +{ + info->current_value = info->initial_value; +} + +/* Reset current_value field of each id_reg_test_info */ +static void reset_id_reg_info(void) +{ + walk_id_reg_list(reset_id_reg_info_current_value, NULL); +} + +static struct kvm_vm *test_vm_create(uint32_t nvcpus, + void (*guest_code)(uint32_t), struct kvm_vcpu_init *init, + struct kvm_enable_cap *cap) +{ + struct kvm_vm *vm; + uint32_t cpuid; + uint64_t mem_pages; + + mem_pages = DEFAULT_GUEST_PHY_PAGES + DEFAULT_STACK_PGS * nvcpus; + mem_pages += mem_pages / (PTES_PER_MIN_PAGE * 2); + mem_pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, mem_pages); + + vm = vm_create(VM_MODE_DEFAULT, mem_pages, O_RDWR); + if (cap) + vm_enable_cap(vm, cap); + + kvm_vm_elf_load(vm, program_invocation_name); + + if (init && init->target == -1) { + struct kvm_vcpu_init preferred; + + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred); + init->target = preferred.target; + } + + vm_init_descriptor_tables(vm); + for (cpuid = 0; cpuid < nvcpus; cpuid++) { + aarch64_vcpu_add_default(vm, cpuid, init, guest_code); + vcpu_init_descriptor_tables(vm, cpuid); + } + + ucall_init(vm, NULL); + return vm; +} + +static void test_vm_free(struct kvm_vm *vm) +{ + ucall_uninit(vm); + kvm_vm_free(vm); +} + +#define TEST_RUN(vm, cpu) \ + (test_vcpu_run(__func__, __LINE__, vm, cpu, true)) + +#define TEST_RUN_NO_SYNC_DATA(vm, cpu) \ + (test_vcpu_run(__func__, __LINE__, vm, cpu, false)) + +static int test_vcpu_run(const char *test_name, int line, + struct kvm_vm *vm, uint32_t vcpuid, bool sync_data) +{ + struct ucall uc; + int ret; + + if (sync_data) { + sync_global_to_guest(vm, id_reg_list); + sync_global_to_guest(vm, feature_test_info_table); + } + + vcpu_args_set(vm, vcpuid, 1, vcpuid); + + ret = _vcpu_run(vm, vcpuid); + if (ret) { + ret = errno; + goto sync_exit; + } + + switch (get_ucall(vm, vcpuid, &uc)) { + case UCALL_SYNC: + case UCALL_DONE: + ret = 0; + break; + case UCALL_ABORT: + TEST_FAIL( + "%s (%s) at line %d (user %s at line %d), args[3]=0x%lx", + (char *)uc.args[0], (char *)uc.args[2], (int)uc.args[1], + test_name, line, uc.args[3]); + break; + default: + TEST_FAIL("Unexpected guest exit\n"); + } + +sync_exit: + if (sync_data) { + sync_global_from_guest(vm, id_reg_list); + sync_global_from_guest(vm, feature_test_info_table); + } + return ret; +} + +/* + * Test KVM's special handling for ID_AA64DFR0.PMUVER/DFR0.PERFMON, which + * is ignoring userspace's request to set the fields to 0xf (IMPLEMENTATION + * DEFINED PMU) and setting the field to 0 instead. This KVM's implementation + * is to make live migration work from the older KVM, which erroneously sets + * those fields to 0xf for the guest when their host sanitized value are + * 0xf (it should have been set to 0x0 as the KVM doesn't support + * IMPLEMENTATION DEFINED PMU for the guest). + */ +static void pmu_test(struct feature_test_info *finfo) +{ + struct id_reg_test_info *sreg = finfo->sreg; + struct kvm_one_reg one_reg; + struct kvm_vm *vm; + int64_t fval, reg_val; + uint32_t vcpu = 0; + int ret; + + reset_id_reg_info(); + finfo->run_test = 1; + + vm = test_vm_create(1, guest_code_feature_check, NULL, NULL); + + /* Make sure that ID_AA64DFR0.PMUVER/DFR0.PERFMON is 0. */ + one_reg.addr = (uint64_t)®_val; + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + fval = GET_ID_FIELD(reg_val, finfo->shift, finfo->is_sign); + TEST_ASSERT(fval == 0, "%s field of %s should be initially 0 but %ld", + finfo->name, sreg->name, fval); + + /* Try to set ID_AA64DFR0.PMUVER/DFR0.PERFMON to -1 (0xf). */ + fval = -1; + reg_val = UPDATE_ID_UFIELD(reg_val, finfo->shift, fval); + ret = _vcpu_ioctl(vm, vcpu, KVM_SET_ONE_REG, &one_reg); + TEST_ASSERT(ret == 0, "Setting %s field of %s to %ld failed (%d)\n", + finfo->name, sreg->name, fval, ret); + + /* Check if ID_AA64DFR0.PMUVER/DFR0.PERFMON is still 0. */ + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + fval = GET_ID_FIELD(reg_val, finfo->shift, finfo->is_sign); + TEST_ASSERT(fval == 0, "%s field of %s should be 0 but %ld", + finfo->name, sreg->name, fval); + + sreg->current_value = reg_val; + ret = TEST_RUN(vm, vcpu); + finfo->run_test = 0; + test_vm_free(vm); +} + +struct vm_vcpu_arg { + struct kvm_vm *vm; + uint32_t vcpuid; + bool after_run; +}; + +/* + * Test if KVM_SET_ONE_REG can work with the value KVM_GET_ONE_REG returns, + * KVM_SET_ONE_REG with zero works before KVM_RUN (and fails after KVM_RUN), + * and KVM_GET_ONE_REG returns the value KVM_SET_ONE_REG sets. + */ +static void test_get_set_id_reg(struct id_reg_test_info *sreg, void *arg) +{ + struct kvm_vm *vm = ((struct vm_vcpu_arg *)arg)->vm; + uint32_t vcpuid = ((struct vm_vcpu_arg *)arg)->vcpuid; + bool after_run = ((struct vm_vcpu_arg *)arg)->after_run; + struct kvm_one_reg one_reg; + uint64_t reg_val, tval; + int ret; + + one_reg.addr = (uint64_t)®_val; + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + + /* Check the current register value */ + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg); + TEST_ASSERT(reg_val == sreg->current_value, + "GET(%s) didn't return 0x%lx but 0x%lx", + sreg->name, sreg->current_value, reg_val); + tval = reg_val; + + /* Try to clear the register that should be able to be cleared. */ + if ((reg_val != 0) && (sreg->can_clear)) { + reg_val = 0; + ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg); + if (after_run) { + /* Expect an error after KVM_RUN */ + TEST_ASSERT(ret, + "Clearing %s unexpectedly worked\n", + sreg->name); + } else { + TEST_ASSERT(!ret, + "Clearing %s didn't work\n", sreg->name); + /* + * Make sure that KVM_GET_ONE_REG provides the value + * we set. + */ + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg); + TEST_ASSERT(reg_val == 0, + "GET(%s) didn't return 0x%lx but 0x%lx", + sreg->name, (uint64_t)0, reg_val); + } + } + + /* Check if KVM_SET_ONE_REG works with the original value. */ + reg_val = tval; + ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg); + TEST_ASSERT(ret == 0, "Setting the same ID reg value should work\n"); + + /* Make sure that KVM_GET_ONE_REG provides the value we set. */ + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg); + TEST_ASSERT(reg_val == tval, + "GET(%s) didn't return 0x%lx but 0x%lx", + sreg->name, sreg->current_value, reg_val); +} + +/* + * Test if KVM_SET_ONE_REG with the current value works before KVM_RUN, + * values of ID registers the guest sees are consistent with the ones + * userspace sees, and KVM_SET_ONE_REG after KVM_RUN works when the + * specified value is the same as the current one (fails otherwise). + */ +static void test_id_regs_basic(void) +{ + struct kvm_vm *vm; + struct vm_vcpu_arg arg = { .vcpuid = 0 }; + int ret; + + reset_id_reg_info(); + + vm = test_vm_create(1, guest_code_id_reg_check_all, NULL, NULL); + + arg.vm = vm; + walk_id_reg_list(test_get_set_id_reg, &arg); + + ret = TEST_RUN(vm, 0); + assert(!ret); + + arg.after_run = true; + walk_id_reg_list(test_get_set_id_reg, &arg); + + test_vm_free(vm); +} + +static bool caps_are_supported(long *caps, int ncaps) +{ + int i; + + for (i = 0; i < ncaps; i++) { + if (kvm_check_cap(caps[i]) <= 0) + return false; + } + return true; +} + +#define NCAPS_PTRAUTH 2 + +/* + * Test if the ID register value reflects the ptrauth feature configuration. + * KVM_SET_ONE_REG should work as long as the requested value is consistent + * with the ptrauth feature configuration. + */ +static void test_feature_ptrauth(void) +{ + struct kvm_one_reg one_reg; + struct kvm_vcpu_init init; + struct kvm_vm *vm = NULL; + struct id_reg_test_info *sreg = ID_REG_INFO(ID_AA64ISAR1); + uint32_t vcpu = 0; + int64_t rval; + int ret; + int apa, api, gpa, gpi; + char *name = "PTRAUTH"; + long caps[NCAPS_PTRAUTH] = {KVM_CAP_ARM_PTRAUTH_ADDRESS, + KVM_CAP_ARM_PTRAUTH_GENERIC}; + + reset_id_reg_info(); + one_reg.addr = (uint64_t)&rval; + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + + if (caps_are_supported(caps, NCAPS_PTRAUTH)) { + + /* Test with feature enabled */ + memset(&init, 0, sizeof(init)); + init.target = -1; + init.features[0] = (1ULL << KVM_ARM_VCPU_PTRAUTH_ADDRESS | + 1ULL << KVM_ARM_VCPU_PTRAUTH_GENERIC); + vm = test_vm_create(1, guest_code_ptrauth_check, &init, NULL); + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + + /* Make sure values of apa/api/gpa/gpi fields are expected */ + apa = GET_ID_UFIELD(rval, ID_AA64ISAR1_APA_SHIFT); + api = GET_ID_UFIELD(rval, ID_AA64ISAR1_API_SHIFT); + gpa = GET_ID_UFIELD(rval, ID_AA64ISAR1_GPA_SHIFT); + gpi = GET_ID_UFIELD(rval, ID_AA64ISAR1_GPI_SHIFT); + + TEST_ASSERT((apa > 0) || (api > 0), + "Either apa(0x%x) or api(0x%x) must be available", + apa, gpa); + TEST_ASSERT((gpa > 0) || (gpi > 0), + "Either gpa(0x%x) or gpi(0x%x) must be available", + gpa, gpi); + + TEST_ASSERT((apa > 0) ^ (api > 0), + "Both apa(0x%x) and api(0x%x) must not be available", + apa, api); + TEST_ASSERT((gpa > 0) ^ (gpi > 0), + "Both gpa(0x%x) and gpi(0x%x) must not be available", + gpa, gpi); + + sreg->current_value = rval; + + pr_debug("%s: Test with %s enabled (%s: 0x%lx)\n", + __func__, name, sreg->name, sreg->current_value); + + /* Make sure that the guest sees the same ID register value. */ + ret = TEST_RUN(vm, vcpu); + + TEST_ASSERT(!ret, "%s:KVM_RUN failed with %s enabled", + __func__, name); + test_vm_free(vm); + } + + reset_id_reg_info(); + + /* Test with feature disabled */ + vm = test_vm_create(1, guest_code_feature_check, NULL, NULL); + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + + apa = GET_ID_UFIELD(rval, ID_AA64ISAR1_APA_SHIFT); + api = GET_ID_UFIELD(rval, ID_AA64ISAR1_API_SHIFT); + gpa = GET_ID_UFIELD(rval, ID_AA64ISAR1_GPA_SHIFT); + gpi = GET_ID_UFIELD(rval, ID_AA64ISAR1_GPI_SHIFT); + TEST_ASSERT(!apa && !api && !gpa && !gpi, + "apa(0x%x), api(0x%x), gpa(0x%x), gpi(0x%x) must be zero", + apa, api, gpa, gpi); + + pr_debug("%s: Test with %s disabled (%s: 0x%lx)\n", + __func__, name, sreg->name, sreg->current_value); + + /* Make sure that the guest sees the same ID register value. */ + ret = TEST_RUN(vm, vcpu); + TEST_ASSERT(!ret, "%s TEST_RUN failed with %s enabled, ret=0x%x", + __func__, name, ret); + + test_vm_free(vm); +} + +static bool feature_caps_are_available(struct feature_test_info *finfo) +{ + return ((finfo->ncaps > 0) && + caps_are_supported(finfo->caps, finfo->ncaps)); +} + +/* + * Test if the ID register value reflects the feature configuration. + * KVM_SET_ONE_REG should work as long as the requested value is + * consistent with the feature configuration. + */ +static void test_feature(struct feature_test_info *finfo) +{ + struct id_reg_test_info *sreg = finfo->sreg; + struct kvm_one_reg one_reg; + struct kvm_vcpu_init init, *initp = NULL; + struct kvm_vm *vm = NULL; + int64_t fval, reg_val; + uint32_t vcpu = 0; + bool is_sign = finfo->is_sign; + int min = finfo->min; + int shift = finfo->shift; + int ret; + + pr_debug("%s: %s (reg %s)\n", __func__, finfo->name, sreg->name); + + reset_id_reg_info(); + + if (is_aarch32_id_reg(sreg->id) && !aarch32_support) + /* + * AArch32 is not supported. Skip testing with the AArch32 + * ID register. + */ + return; + + /* Indicate that guest runs the test for the feature */ + finfo->run_test = 1; + one_reg.addr = (uint64_t)®_val; + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + + /* + * Test with feature enabled if the feature is exposed in the default + * ID register value or the capabilities are supported at KVM level. + */ + if ((GET_ID_FIELD(sreg->initial_value, shift, is_sign) >= min) || + feature_caps_are_available(finfo)) { + if (finfo->vcpu_init) { + /* Need to enable the feature via KVM_ARM_VCPU_INIT. */ + memset(&init, 0, sizeof(init)); + init = *finfo->vcpu_init; + init.target = -1; + initp = &init; + } + + vm = test_vm_create(1, guest_code_feature_check, initp, + finfo->opt_in_cap); + if (finfo->init_feature) + /* Run any required extra process to use the feature */ + finfo->init_feature(vm, vcpu); + + /* Check if the ID register value indicates the feature */ + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + fval = GET_ID_FIELD(reg_val, shift, is_sign); + TEST_ASSERT(fval >= min, "%s field of %s is too small (%ld)", + finfo->name, sreg->name, fval); + sreg->current_value = reg_val; + + pr_debug("%s: Test with %s enabled (%s: 0x%lx)\n", __func__, + finfo->name, sreg->name, sreg->current_value); + + /* Make sure that the guest sees the same ID register value. */ + ret = TEST_RUN(vm, vcpu); + TEST_ASSERT(!ret, "%s:TEST_RUN failed with %s enabled", + __func__, finfo->name); + + test_vm_free(vm); + } + + reset_id_reg_info(); + + /* Test with feature disabled */ + vm = test_vm_create(1, guest_code_feature_check, NULL, NULL); + vcpu_ioctl(vm, vcpu, KVM_GET_ONE_REG, &one_reg); + fval = GET_ID_FIELD(reg_val, shift, is_sign); + if (finfo->vcpu_init || finfo->opt_in_cap) { + /* + * If the feature needs to be enabled with KVM_ARM_VCPU_INIT + * or opt-in capabilities, the default value of the ID register + * shouldn't indicate the feature. + */ + TEST_ASSERT(fval < min, "%s field of %s is too big (%ld)", + finfo->name, sreg->name, fval); + } else { + /* Update the relevant field to hide the feature. */ + fval = is_sign ? 0xf : 0x0; + reg_val = UPDATE_ID_UFIELD(reg_val, shift, fval); + ret = _vcpu_ioctl(vm, vcpu, KVM_SET_ONE_REG, &one_reg); + TEST_ASSERT(ret == 0, "Disabling %s failed %d\n", + finfo->name, ret); + sreg->current_value = reg_val; + } + + pr_debug("%s: Test with %s disabled (%s: 0x%lx)\n", + __func__, finfo->name, sreg->name, sreg->current_value); + + /* Make sure that the guest sees the same ID register value. */ + ret = TEST_RUN(vm, vcpu); + TEST_ASSERT(!ret, "%s:TEST_RUN failed with %s disabled", + __func__, finfo->name); + finfo->run_test = 0; + test_vm_free(vm); + + /* Run extra feature specific tests, if any */ + if (finfo->test_feature) + finfo->test_feature(finfo); +} + +/* + * For each opt-in feature in feature_test_info_table[], + * test if KVM_GET_ONE_REG/KVM_SET_ONE_REG works appropriately according + * to the feature configuration. See test_feature's comment for more detail. + */ +static void test_feature_all(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(feature_test_info_table); i++) + test_feature(&feature_test_info_table[i]); +} + +int set_id_reg(struct kvm_vm *vm, uint32_t vcpu, struct id_reg_test_info *sreg, + uint64_t new_val) +{ + int ret; + uint64_t reg_val; + struct kvm_one_reg one_reg; + + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + one_reg.addr = (uint64_t)®_val; + + reg_val = new_val; + ret = _vcpu_ioctl(vm, vcpu, KVM_SET_ONE_REG, &one_reg); + if (!ret) + sreg->current_value = new_val; + + return ret; +} + + +/* + * Create a new VM with one vCPU, set the ID register to @new_val. + */ +int set_id_reg_vm(struct id_reg_test_info *sreg, uint64_t new_val) +{ + struct kvm_vm *vm; + int ret; + uint32_t vcpu = 0; + + reset_id_reg_info(); + + vm = test_vm_create(1, guest_code_id_reg_check_all, NULL, NULL); + ret = set_id_reg(vm, vcpu, sreg, new_val); + test_vm_free(vm); + + return ret; +} + +struct frac_info { + char *name; + struct id_reg_test_info *sreg; + struct id_reg_test_info *frac_sreg; + int shift; + int frac_shift; +}; + +struct frac_info frac_info_table[] = { + { + .name = "RAS", + .sreg = ID_REG_INFO(ID_AA64PFR0), + .shift = ID_AA64PFR0_RAS_SHIFT, + .frac_sreg = ID_REG_INFO(ID_AA64PFR1), + .frac_shift = ID_AA64PFR1_RASFRAC_SHIFT, + }, + { + .name = "MPAM", + .sreg = ID_REG_INFO(ID_AA64PFR0), + .shift = ID_AA64PFR0_MPAM_SHIFT, + .frac_sreg = ID_REG_INFO(ID_AA64PFR1), + .frac_shift = ID_AA64PFR1_MPAMFRAC_SHIFT, + }, + { + .name = "CSV2", + .sreg = ID_REG_INFO(ID_AA64PFR0), + .shift = ID_AA64PFR0_CSV2_SHIFT, + .frac_sreg = ID_REG_INFO(ID_AA64PFR1), + .frac_shift = ID_AA64PFR1_CSV2FRAC_SHIFT, + }, +}; + + +/* + * Make sure that we can set the fractional reg field even before setting + * the feature reg field. + */ +int test_feature_frac_vm(struct frac_info *frac, uint64_t new_val, + uint64_t frac_new_val) +{ + struct kvm_vm *vm; + uint32_t vcpu = 0; + struct id_reg_test_info *sreg, *frac_sreg; + int ret; + + sreg = frac->sreg; + frac_sreg = frac->frac_sreg; + reset_id_reg_info(); + + vm = test_vm_create(1, guest_code_id_reg_check_all, NULL, NULL); + + /* Set fractional reg field */ + ret = set_id_reg(vm, vcpu, frac_sreg, frac_new_val); + TEST_ASSERT(!ret, "SET_REG(%s=0x%lx) failed, ret=0x%x", + frac_sreg->name, frac_new_val, ret); + + /* Set feature reg field */ + ret = set_id_reg(vm, vcpu, sreg, new_val); + TEST_ASSERT(!ret, "SET_REG(%s=0x%lx) failed, ret=0x%x", + sreg->name, new_val, ret); + + ret = TEST_RUN(vm, vcpu); + test_vm_free(vm); + + return ret; +} + +/* + * Test for setting the feature fractional field of the ID register. + * When the (main) feature field of the ID register is the same as the host's, + * the fractional field value cannot be larger than the host's. + * (KVM_SET_ONE_REG should work but KVM_RUN with the larger value will fail) + * When the (main) feature field of the ID register is smaler than the host's, + * the fractional field can be any values. + * The function tests those behaviors. + */ +void test_feature_frac_one(struct frac_info *frac) +{ + uint64_t ftr_val, ftr_fval, frac_val, frac_fval; + int ret, shift, frac_shift; + struct id_reg_test_info *sreg, *frac_sreg; + + reset_id_reg_info(); + + sreg = frac->sreg; + shift = frac->shift; + frac_sreg = frac->frac_sreg; + frac_shift = frac->frac_shift; + + pr_debug("%s(%s Frac) reg:%s(shift:%d) frac reg:%s(shift:%d)\n", + __func__, frac->name, sreg->name, shift, frac_sreg->name, + frac_shift); + + /* + * Use the host's feature value for the guest. + * KVM_RUN with a larger frac value than the host's should fail. + * Otherwise, it should work. + */ + + frac_fval = GET_ID_UFIELD(frac_sreg->initial_value, frac_shift); + if (frac_fval > 0) { + /* Test with smaller frac value */ + frac_val = UPDATE_ID_UFIELD(frac_sreg->initial_value, + frac_shift, frac_fval - 1); + ret = test_feature_frac_vm(frac, sreg->initial_value, frac_val); + TEST_ASSERT(!ret, "Test smaller %s frac (val:%lx) failed(%d)", + frac->name, frac_val, ret); + } + + reset_id_reg_info(); + + if (frac_fval != 0xf) { + /* Test with larger frac value */ + frac_val = UPDATE_ID_UFIELD(frac_sreg->initial_value, + frac_shift, frac_fval + 1); + + /* Setting larger frac shouldn't fail at ioctl */ + ret = set_id_reg_vm(frac_sreg, frac_val); + TEST_ASSERT(!ret, + "SET larger %s frac (%s org:%lx, val:%lx) failed(%d)", + frac->name, frac_sreg->name, frac_sreg->initial_value, + frac_val, ret); + + /* KVM_RUN with larger frac should fail */ + ret = test_feature_frac_vm(frac, sreg->initial_value, frac_val); + TEST_ASSERT(ret, + "Test with larger %s frac (%s org:%lx, val:%lx) worked", + frac->name, frac_sreg->name, frac_sreg->initial_value, + frac_val); + } + + reset_id_reg_info(); + + /* + * Test with a smaller (main) feature value than the host's. + */ + ftr_fval = GET_ID_UFIELD(sreg->initial_value, shift); + if (ftr_fval == 0) + /* Cannot set it to the smaller value */ + return; + + ftr_val = UPDATE_ID_UFIELD(sreg->initial_value, shift, ftr_fval - 1); + ret = test_feature_frac_vm(frac, ftr_val, frac_sreg->initial_value); + TEST_ASSERT(!ret, "Test with smaller %s (val:%lx) failed(%d)", + frac->name, ftr_val, ret); + + if (frac_fval > 0) { + /* Test with smaller frac value */ + frac_val = UPDATE_ID_UFIELD(frac_sreg->initial_value, + frac_shift, frac_fval - 1); + ret = test_feature_frac_vm(frac, ftr_val, frac_val); + TEST_ASSERT(!ret, + "Test with smaller %s and frac (val:%lx) failed(%d)", + frac->name, ftr_val, ret); + } + + if (frac_fval != 0xf) { + /* Test with larger frac value */ + frac_val = UPDATE_ID_UFIELD(frac_sreg->initial_value, + frac_shift, frac_fval + 1); + ret = test_feature_frac_vm(frac, ftr_val, frac_val); + TEST_ASSERT(!ret, + "Test with smaller %s and larger frac (val:%lx) failed(%d)", + frac->name, ftr_val, ret); + } +} + +/* + * Test for setting feature fractional fields of ID registers. + * See test_feature_frac_one's comments for more detail. + */ +void test_feature_frac_all(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(frac_info_table); i++) + test_feature_frac_one(&frac_info_table[i]); +} + +void run_test(void) +{ + test_id_regs_basic(); + test_feature_all(); + test_feature_ptrauth(); + test_feature_frac_all(); +} + +static void init_id_reg_info_one(struct id_reg_test_info *sreg, void *arg) +{ + struct kvm_one_reg one_reg; + uint64_t reg_val; + struct kvm_vm *vm = ((struct vm_vcpu_arg *)arg)->vm; + uint32_t vcpuid = ((struct vm_vcpu_arg *)arg)->vcpuid; + int ret; + + one_reg.addr = (uint64_t)®_val; + one_reg.id = KVM_ARM64_SYS_REG(sreg->id); + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg); + sreg->current_value = reg_val; + + /* Keep the initial value to reset the register value later */ + sreg->initial_value = reg_val; + + /* Check if the register can be set to 0 */ + reg_val = 0; + ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg); + if (!ret) + sreg->can_clear = true; + + pr_debug("%s (0x%x): 0x%lx%s\n", sreg->name, sreg->id, + sreg->initial_value, sreg->can_clear ? ", can clear" : ""); +} + +/* + * Check if aarch32 is supported, and initialize id_reg_test_info for all + * the ID registers. Loop over the idreg list and populates each id_reg + * info with the initial value, current value, and can_clear value. + */ +static void init_test_info(void) +{ + uint64_t reg_val; + int fval; + struct kvm_vm *vm; + struct kvm_one_reg one_reg; + struct vm_vcpu_arg arg = { .vcpuid = 0 }; + + vm = test_vm_create(1, guest_code_do_nothing, NULL, NULL); + + /* Get ID_AA64PFR0_EL1 to check if AArch32 is supported */ + one_reg.addr = (uint64_t)®_val; + one_reg.id = KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1); + vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, &one_reg); + fval = GET_ID_UFIELD(reg_val, ID_AA64PFR0_EL0_SHIFT); + if (fval == 0x1) + /* No AArch32 support */ + aarch32_support = false; + + /* Initialize id_reg_test_info */ + arg.vm = vm; + walk_id_reg_list(init_id_reg_info_one, &arg); + test_vm_free(vm); +} + +int main(void) +{ + + setbuf(stdout, NULL); + + if (kvm_check_cap(KVM_CAP_ARM_ID_REG_CONFIGURABLE) <= 0) { + print_skip("KVM_CAP_ARM_ID_REG_CONFIGURABLE is not supported"); + exit(KSFT_SKIP); + } + + init_test_info(); + run_test(); + return 0; +}