From: Oliver Upton <oliver.upton@linux.dev>
To: Jing Zhang <jingzhangos@google.com>
Cc: KVM <kvm@vger.kernel.org>, KVMARM <kvmarm@lists.linux.dev>,
ARMLinux <linux-arm-kernel@lists.infradead.org>,
Marc Zyngier <maz@kernel.org>, Will Deacon <will@kernel.org>,
Paolo Bonzini <pbonzini@redhat.com>,
James Morse <james.morse@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Fuad Tabba <tabba@google.com>, Reiji Watanabe <reijiw@google.com>,
Raghavendra Rao Ananta <rananta@google.com>,
Suraj Jitindar Singh <surajjs@amazon.com>,
Cornelia Huck <cohuck@redhat.com>
Subject: Re: [PATCH v7 10/10] KVM: arm64: selftests: Test for setting ID register from usersapce
Date: Wed, 2 Aug 2023 17:27:58 +0000 [thread overview]
Message-ID: <ZMqSHhFe/4nSN4US@linux.dev> (raw)
In-Reply-To: <20230801152007.337272-11-jingzhangos@google.com>
Hi Jing,
On Tue, Aug 01, 2023 at 08:20:06AM -0700, Jing Zhang wrote:
> Add tests to verify setting ID registers from userapce is handled
> correctly by KVM. Also add a test case to use ioctl
> KVM_ARM_GET_FEATURE_ID_WRITABLE_MASKS to get writable masks.
>
> Signed-off-by: Jing Zhang <jingzhangos@google.com>
> ---
> tools/arch/arm64/include/uapi/asm/kvm.h | 25 +++
> tools/include/uapi/linux/kvm.h | 2 +
Why is this diff needed? I thought we wound up using the latest headers
from the kernel.
> tools/testing/selftests/kvm/Makefile | 1 +
Need to add your file to .gitignore too.
> .../selftests/kvm/aarch64/set_id_regs.c | 191 ++++++++++++++++++
> 4 files changed, 219 insertions(+)
> create mode 100644 tools/testing/selftests/kvm/aarch64/set_id_regs.c
[...]
> diff --git a/tools/testing/selftests/kvm/aarch64/set_id_regs.c b/tools/testing/selftests/kvm/aarch64/set_id_regs.c
> new file mode 100644
> index 000000000000..9c8f439ac7b3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/aarch64/set_id_regs.c
> @@ -0,0 +1,191 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * set_id_regs - Test for setting ID register from usersapce.
> + *
> + * Copyright (c) 2023 Google LLC.
> + *
> + *
> + * Test that KVM supports setting ID registers from userspace and handles the
> + * feature set correctly.
> + */
> +
> +#include <stdint.h>
> +#include "kvm_util.h"
> +#include "processor.h"
> +#include "test_util.h"
> +#include <linux/bitfield.h>
> +
> +#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffsl(_mask) - 1))
> +#define field_prep(_mask, _val) (((_val) << (ffsl(_mask) - 1)) & (_mask))
> +
Shadowing the naming of the kernel's own FIELD_{GET,PREP}() is a bit
awkward. I'm guessing that you're working around @_mask not being a
compile-time constant?
> +struct reg_feature {
> + uint64_t reg;
> + uint64_t ftr_mask;
> +};
> +
> +static void guest_code(void)
> +{
> + for (;;)
> + GUEST_SYNC(0);
> +}
The test should check that the written values are visible both from the
guest as well as userspace.
> +static struct reg_feature lower_safe_reg_ftrs[] = {
> + { KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), ARM64_FEATURE_MASK(ID_AA64DFR0_WRPS) },
> + { KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), ARM64_FEATURE_MASK(ID_AA64PFR0_EL3) },
> + { KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1), ARM64_FEATURE_MASK(ID_AA64MMFR0_FGT) },
> + { KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR1_EL1), ARM64_FEATURE_MASK(ID_AA64MMFR1_PAN) },
> + { KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR2_EL1), ARM64_FEATURE_MASK(ID_AA64MMFR2_FWB) },
> +};
My preference would be to organize the field descriptors by register
rather than the policy. This matches what the kernel does in cpufeature.c
quite closely and allows us to easily reason about which fields are/aren't
tested.
> +static void test_user_set_lower_safe(struct kvm_vcpu *vcpu)
> +{
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(lower_safe_reg_ftrs); i++) {
> + struct reg_feature *reg_ftr = lower_safe_reg_ftrs + i;
> + uint64_t val, new_val, ftr;
> +
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ftr = field_get(reg_ftr->ftr_mask, val);
> +
> + /* Set a safe value for the feature */
> + if (ftr > 0)
> + ftr--;
> +
> + val &= ~reg_ftr->ftr_mask;
> + val |= field_prep(reg_ftr->ftr_mask, ftr);
> +
> + vcpu_set_reg(vcpu, reg_ftr->reg, val);
> + vcpu_get_reg(vcpu, reg_ftr->reg, &new_val);
> + ASSERT_EQ(new_val, val);
> + }
> +}
> +
> +static void test_user_set_fail(struct kvm_vcpu *vcpu)
> +{
> + int i, r;
> +
> + for (i = 0; i < ARRAY_SIZE(lower_safe_reg_ftrs); i++) {
> + struct reg_feature *reg_ftr = lower_safe_reg_ftrs + i;
> + uint64_t val, old_val, ftr;
> +
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ftr = field_get(reg_ftr->ftr_mask, val);
> +
> + /* Set a invalid value (too big) for the feature */
> + if (ftr >= GENMASK_ULL(ARM64_FEATURE_FIELD_BITS - 1, 0))
> + continue;
This assumes that the fields in the register are unsigned, but there are
several which are not.
> + ftr++;
> +
> + old_val = val;
> + val &= ~reg_ftr->ftr_mask;
> + val |= field_prep(reg_ftr->ftr_mask, ftr);
> +
> + r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
> + TEST_ASSERT(r < 0 && errno == EINVAL,
> + "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
> +
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ASSERT_EQ(val, old_val);
> + }
> +}
> +
> +static struct reg_feature exact_reg_ftrs[] = {
> + /* Items will be added when there is appropriate field of type
> + * FTR_EXACT enabled writing from userspace later.
> + */
> +};
> +
> +static void test_user_set_exact(struct kvm_vcpu *vcpu)
> +{
> + int i, r;
> +
> + for (i = 0; i < ARRAY_SIZE(exact_reg_ftrs); i++) {
> + struct reg_feature *reg_ftr = exact_reg_ftrs + i;
> + uint64_t val, old_val, ftr;
> +
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ftr = field_get(reg_ftr->ftr_mask, val);
> + old_val = val;
> +
> + /* Exact match */
> + vcpu_set_reg(vcpu, reg_ftr->reg, val);
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ASSERT_EQ(val, old_val);
> +
> + /* Smaller value */
> + if (ftr > 0) {
> + ftr--;
> + val &= ~reg_ftr->ftr_mask;
> + val |= field_prep(reg_ftr->ftr_mask, ftr);
> + r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
> + TEST_ASSERT(r < 0 && errno == EINVAL,
> + "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ASSERT_EQ(val, old_val);
> + ftr++;
> + }
> +
> + /* Bigger value */
> + ftr++;
> + val &= ~reg_ftr->ftr_mask;
> + val |= field_prep(reg_ftr->ftr_mask, ftr);
> + r = __vcpu_set_reg(vcpu, reg_ftr->reg, val);
> + TEST_ASSERT(r < 0 && errno == EINVAL,
> + "Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
> + vcpu_get_reg(vcpu, reg_ftr->reg, &val);
> + ASSERT_EQ(val, old_val);
> + }
> +}
Don't add dead code, this can be added when we actually test FTR_EXACT
fields. Are there not any in the registers exposed by this series?
> +static uint32_t writable_regs[] = {
> + SYS_ID_DFR0_EL1,
> + SYS_ID_AA64DFR0_EL1,
> + SYS_ID_AA64PFR0_EL1,
> + SYS_ID_AA64MMFR0_EL1,
> + SYS_ID_AA64MMFR1_EL1,
> + SYS_ID_AA64MMFR2_EL1,
> +};
> +
> +void test_user_get_writable_masks(struct kvm_vm *vm)
> +{
> + struct feature_id_writable_masks masks;
> +
> + vm_ioctl(vm, KVM_ARM_GET_FEATURE_ID_WRITABLE_MASKS, &masks);
> +
> + for (int i = 0; i < ARRAY_SIZE(writable_regs); i++) {
> + uint32_t reg = writable_regs[i];
> + int idx = ARM64_FEATURE_ID_SPACE_IDX(sys_reg_Op0(reg),
> + sys_reg_Op1(reg), sys_reg_CRn(reg),
> + sys_reg_CRm(reg), sys_reg_Op2(reg));
> +
> + ASSERT_EQ(masks.mask[idx], GENMASK_ULL(63, 0));
> + }
> +}
The more robust test would be to check that every field this test knows
is writable is actually advertised as such in the ioctl. So you could
fetch this array at the start of the entire test and pass it through to
the routines that do granular checks against the fields of every
register.
It'd also be good to see basic sanity tests on the ioctl (i.e. call
fails if ::rsvd is nonzero), since KVM has screwed that up on several
occasions in past.
> +int main(void)
> +{
> + struct kvm_vcpu *vcpu;
> + struct kvm_vm *vm;
> +
> + vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> +
> + ksft_print_header();
> + ksft_set_plan(4);
> +
> + test_user_get_writable_masks(vm);
> + ksft_test_result_pass("test_user_get_writable_masks\n");
> +
> + test_user_set_exact(vcpu);
> + ksft_test_result_pass("test_user_set_exact\n");
> +
> + test_user_set_fail(vcpu);
> + ksft_test_result_pass("test_user_set_fail\n");
> +
> + test_user_set_lower_safe(vcpu);
> + ksft_test_result_pass("test_user_set_lower_safe\n");
> +
> + kvm_vm_free(vm);
> +
> + ksft_finished();
> +}
> --
> 2.41.0.585.gd2178a4bd4-goog
>
--
Thanks,
Oliver
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2023-08-02 17:28 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-01 15:19 [PATCH v7 00/10] Enable writable for idregs DFR0,PFR0, MMFR{0,1,2,3} Jing Zhang
2023-08-01 15:19 ` [PATCH v7 01/10] KVM: arm64: Allow userspace to get the writable masks for feature ID registers Jing Zhang
2023-08-02 0:04 ` Oliver Upton
2023-08-02 15:55 ` Jing Zhang
2023-08-02 17:04 ` Oliver Upton
2023-08-02 17:48 ` Jing Zhang
2023-08-03 13:20 ` Cornelia Huck
2023-08-08 17:02 ` Oliver Upton
2023-08-10 4:27 ` Shaoqin Huang
2023-08-10 4:57 ` Jing Zhang
2023-08-01 15:19 ` [PATCH v7 02/10] KVM: arm64: Document KVM_ARM_GET_FEATURE_ID_WRITABLE_MASKS Jing Zhang
2023-08-01 15:19 ` [PATCH v7 03/10] KVM: arm64: Use guest ID register values for the sake of emulation Jing Zhang
2023-08-01 15:20 ` [PATCH v7 04/10] KVM: arm64: Reject attempts to set invalid debug arch version Jing Zhang
2023-08-01 15:20 ` [PATCH v7 05/10] KVM: arm64: Enable writable for ID_AA64DFR0_EL1 and ID_DFR0_EL1 Jing Zhang
2023-08-01 15:20 ` [PATCH v7 06/10] KVM: arm64: Bump up the default KVM sanitised debug version to v8p8 Jing Zhang
2023-08-01 15:20 ` [PATCH v7 07/10] KVM: arm64: Enable writable for ID_AA64PFR0_EL1 Jing Zhang
2023-08-01 15:20 ` [PATCH v7 08/10] KVM: arm64: Refactor helper Macros for idreg desc Jing Zhang
2023-08-01 15:20 ` [PATCH v7 09/10] KVM: arm64: Enable writable for ID_AA64MMFR{0, 1, 2, 3}_EL1 Jing Zhang
2023-08-01 15:20 ` [PATCH v7 10/10] KVM: arm64: selftests: Test for setting ID register from usersapce Jing Zhang
2023-08-02 17:27 ` Oliver Upton [this message]
2023-08-03 23:42 ` Jing Zhang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZMqSHhFe/4nSN4US@linux.dev \
--to=oliver.upton@linux.dev \
--cc=alexandru.elisei@arm.com \
--cc=cohuck@redhat.com \
--cc=james.morse@arm.com \
--cc=jingzhangos@google.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=maz@kernel.org \
--cc=pbonzini@redhat.com \
--cc=rananta@google.com \
--cc=reijiw@google.com \
--cc=surajjs@amazon.com \
--cc=suzuki.poulose@arm.com \
--cc=tabba@google.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).