kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Auger <eauger@redhat.com>
To: Reiji Watanabe <reijiw@google.com>
Cc: Marc Zyngier <maz@kernel.org>,
	kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	James Morse <james.morse@arm.com>,
	Alexandru Elisei <alexandru.elisei@arm.com>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Will Deacon <will@kernel.org>, Andrew Jones <drjones@redhat.com>,
	Peng Liang <liangpeng10@huawei.com>,
	Peter Shier <pshier@google.com>,
	Ricardo Koller <ricarkol@google.com>,
	Oliver Upton <oupton@google.com>,
	Jing Zhang <jingzhangos@google.com>,
	Raghavendra Rao Anata <rananta@google.com>
Subject: Re: [RFC PATCH v3 29/29] KVM: arm64: selftests: Introduce id_reg_test
Date: Mon, 22 Nov 2021 15:17:46 +0100	[thread overview]
Message-ID: <8dfa692e-5aa1-c6b3-55f8-3c2bb83df9cd@redhat.com> (raw)
In-Reply-To: <CAAeT=FwmmLJCR-WumnvxjiRuafD_7gr3JjHZWWO5O=jedh2daQ@mail.gmail.com>

Hi Reiji,
On 11/20/21 7:39 AM, Reiji Watanabe wrote:
>  Hi Eric,
> 
> On Thu, Nov 18, 2021 at 12:34 PM Eric Auger <eauger@redhat.com> wrote:
>>
>> Hi Reiji,
>>
>> On 11/17/21 7:43 AM, Reiji Watanabe wrote:
>>> 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.
>>
>> That's great to get those tests along with the series.
>>
>> There are several tests actually. I would encourage you to drop a short
>> comment along with the each main test to summarize what it does.
> 
> Thank you for the review !
> Yes, I will add short comments for the main test to summarize what it does.
> 
> 
>>> +struct id_reg_test_info {
>>> +     char            *name;
>>> +     uint32_t        id;
>>> +     bool            can_clear;
>>> +     uint64_t        fixed_mask;
>>> +     uint64_t        org_val;
>> nit: original_val? or default_val?
> 
> That is an original (or initial) value that is set by KVM.
> I will change it to original_val.
> 
> 
>>> +void test_pmu_init(struct kvm_vm *vm, uint32_t vcpu)
>> I would remove the test_ prefix as it does not test anything but
>> enhances the initialization instead
> 
> Yes, I agree.
> I will remove test_ prefix from those names.
> 
>>> +{
>>> +     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 test_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, GICD_BASE_GPA, GICR_BASE_GPA);
>>> +}
>>> +
>>> +#define      MAX_CAPS        2
>>> +struct feature_test_info {
>>> +     char    *name;  /* Feature Name (Debug information) */
>>> +     struct id_reg_test_info *sreg;  /* ID register for the feature */
>> ID register comprising the feature?
>>> +     int     shift;  /* Field of the ID register for the feature */
>> I guess you mean feature field bit shift
>>> +     int     min;    /* Min value to indicate the feature */
>> Min value that can be assigned to the feature field?
>>> +     bool    is_sign;        /* Is the field signed or unsigned ? */
>>> +     int     ncaps;          /* Number of valid Capabilities in caps[] */
>>> +     long    caps[MAX_CAPS]; /* Capabilities to indicate this feature */
>> I suggest: KVM_CAP_* capabilities requested to test this feature
>>> +     /* struct kvm_enable_cap to use the capability if needed */
>>> +     struct kvm_enable_cap   *opt_in_cap;
>>> +     bool    run_test;       /* Does guest run test for this feature ? */
>> s/run_test/guest_run?
>>> +     /* Initialization function for the feature as needed */
>> extra init sequence needed besides KVM CAP setting?
>>> +     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;
>>> +};
> 
> I am going to fix the comments as follows.
> (Or are any of them still unclear ?)
> 
>     /* ID register that identifies the presence of the feature */
>     struct id_reg_test_info *sreg;
> 
>     /* Bit shift for the field that identifies the presence of the feature */
>     int     shift;
> 
>     /* Min value of the field that indicates the presence of the feature */
>     int     min;    /* Min value to indicate the feature */
> 
>     /* KVM_CAP_* Capabilities to indicates that KVM supports this feature */
>     long    caps[MAX_CAPS]; /* Capabilities to indicate this feature */
> 
>     /* Should the guest check the ID register for this feature ? */
>     bool    run_test;
> 
>     /*
>      * Any extra function to configure the feature if needed.
>      * (e.g. KVM_ARM_VCPU_FINALIZE for SVE)
>      */
>     void    (*init_feature)(struct kvm_vm *vm, uint32_t vcpuid);
> 
>>> +
>>> +/* Test for optin CPU features */
>> opt-in?
> 
> I will fix it.
> 
>>> +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 = test_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 = test_pmu_init,
>>> +             .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 = test_pmu_init,
>>> +             .caps = {KVM_CAP_ARM_PMU_V3},
>>> +             .ncaps = 1,
>>> +             .vcpu_init = &(struct kvm_vcpu_init) {
>>> +                     .features = {1ULL << KVM_ARM_VCPU_PMU_V3},
>>> +             },
>>> +     },
>>> +};
>>> +
>>> +static int walk_id_reg_list(int (*fn)(struct id_reg_test_info *sreg, void *arg),
>>> +                         void *arg)
>>> +{
>>> +     int ret = 0, i;
>>> +
>>> +     for (i = 0; i < ARRAY_SIZE(id_reg_list); i++) {
>>> +             ret = fn(&id_reg_list[i], arg);
>>> +             if (ret)
>>> +                     break;
>> none of your fn() function does return something != 0
> 
> I will change the callback function to return void instead of int.
> 
>>> +     }
>>> +     return ret;
>>> +}
>>> +
>>> +static int guest_code_id_reg_check_one(struct id_reg_test_info *sreg, void *arg)
>>> +{
>>> +     uint64_t val = sreg->read_reg();
>>> +
>>> +     GUEST_ASSERT_2(val == sreg->user_val, sreg->name, sreg->user_val);
>>> +     return 0;
>>> +}
>>> +
>>> +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->user_val, "PTRAUTH", val);
>>> +     GUEST_DONE();
>>> +}
>>> +
>>> +static int reset_id_reg_info_one(struct id_reg_test_info *sreg, void *arg)
>> reset_id_reg_user_val_one()?
> 
> Thanks for the suggestion. I will fix that.
> 
>>> +{
>>> +     sreg->user_val = sreg->org_val;
>>> +     return 0;
>>> +}
>>> +
>>> +static void reset_id_reg_info(void)
>> reset_id_reg_user_val()?
> 
>  I will fix that.
> 
>>> +{
>>> +     walk_id_reg_list(reset_id_reg_info_one, NULL);
>>> +}
>>> +
>>> +static struct kvm_vm *test_vm_create_cap(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,
>>> +             DEFAULT_GUEST_PHY_PAGES + (DEFAULT_STACK_PGS * nvcpus),
>>> +             O_RDWR);
>> mem_pages must be used instead
>>
>> augere@virtlab-arm04:~/UPSTREAM/ML/tools/testing/selftests/kvm#
>> ./aarch64/id_reg_test
>> ==== Test Assertion Failure ====
>>   lib/kvm_util.c:825: vm_adjust_num_guest_pages(vm->mode, npages) == npages
>>   pid=11439 tid=11439 errno=0 - Success
>>      1  0x00000000004068cb: vm_userspace_mem_region_add at kvm_util.c:823
>>      2  0x00000000004071af: vm_create at kvm_util.c:319
>>      3  0x0000000000401afb: test_vm_create_cap at id_reg_test.c:508
>>      4  0x00000000004014a3: test_vm_create at id_reg_test.c:541
>>      5   (inlined by) init_id_reg_info at id_reg_test.c:1110
>>      6   (inlined by) main at id_reg_test.c:1125
>>      7  0x000003ffa7220de3: ?? ??:0
>>      8  0x00000000004015eb: _start at :?
>>   Number of guest pages is not compatible with the host. Try npages=528
> 
> Thank you for catching this (It didn't happen in my usual test environment).
> I will fix this.
> 
>>
>>
>> Don't you want to check the cap in a first place using kvm_check_cap and
>> cap->cap
> 
> It is done by the caller before trying to create the vm.
> 
> 
>>> +     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++) {
>>> +             if (init)
>>> +                     aarch64_vcpu_add_default(vm, cpuid, init, guest_code);
>>> +             else
>>> +                     vm_vcpu_add_default(vm, cpuid, guest_code);
>> nit: vm_vcpu_add_default calls aarch64_vcpu_add_default(vm, vcpuid,
>> NULL, guest_code) so you can unconditionnaly call
>> aarch64_vcpu_add_default(vm, cpuid, init, guest_code)
> 
> Oh, thank you ! I will fix that (somehow I overlooked that...).
> 
>>> +
>>> +             vcpu_init_descriptor_tables(vm, cpuid);
>>> +     }
>>> +
>>> +     ucall_init(vm, NULL);
>>> +     return vm;
>>> +}
>>> +
>>> +static struct kvm_vm *test_vm_create(uint32_t nvcpus,
>>> +                                  void (*guest_code)(uint32_t),
>>> +                                  struct kvm_vcpu_init *init)
>>> +{
>>> +     return test_vm_create_cap(nvcpus, guest_code, init, NULL);
>>> +}
>> nit: not sure test_vm_create is needed. By the way it is already called
>> with init = NULL so we can call test_vm_create_cap with 2 NULL args
> 
> I will remove test_vm_create.
> 
> 
>>> +
>>> +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;
>>> +}
>>> +
>>> +static int set_id_regs_after_run_test_one(struct id_reg_test_info *sreg,
>>> +                                       void *arg)
>>> +{
>>> +     struct kvm_vm *vm = arg;
>>> +     struct kvm_one_reg one_reg;
>>> +     uint32_t vcpuid = 0;
>>> +     uint64_t reg_val;
>>> +     int ret;
>>> +
>>> +     one_reg.addr = (uint64_t)&reg_val;
>>> +     one_reg.id = KVM_ARM64_SYS_REG(sreg->id);
>>> +
>>> +     vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg);
>>> +     if ((reg_val != 0) && (sreg->can_clear)) {
>>> +             reg_val = 0;
>>> +             ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg);
>>> +             TEST_ASSERT(ret && errno == EINVAL,
>>> +                         "Changing ID reg value should fail\n");
>>> +     }
>>> +
>>> +     vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg);> +   ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg);
>>> +     TEST_ASSERT(ret == 0, "Setting the same ID reg value should work\n");
>>> +
>>> +     return 0;
>>> +}
>>> +
>>> +static int set_id_regs_test_one(struct id_reg_test_info *sreg, void *arg)
>> if it is a test use test_ prefix
> 
> I will fix this.
> 
> 
>>> +{
>>> +     struct kvm_vm *vm = arg;
>>> +     struct kvm_one_reg one_reg;
>>> +     uint32_t vcpuid = 0;
>>> +     uint64_t reg_val;
>>> +
>>> +     one_reg.addr = (uint64_t)&reg_val;
>>> +     reset_id_reg_info();
>>> +
>>> +     one_reg.id = KVM_ARM64_SYS_REG(sreg->id);
>>> +     if (sreg->can_clear) {
>>> +             /* Change the register to 0 when possible */
>>> +             reg_val = 0;
>>> +             vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg);
>>> +             vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg);
>>> +             TEST_ASSERT(reg_val == 0,
>>> +                 "GET(%s) didn't return 0 but 0x%lx", sreg->name, reg_val);
>>> +     }
>>> +
>>> +     /* Check if we can restore the initial value */
>>> +     reg_val = sreg->org_val;
>>> +     vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &one_reg);
>>> +     vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg);
>>> +     TEST_ASSERT(reg_val == sreg->org_val,
>>> +                 "GET(%s) didn't return 0x%lx but 0x%lx",
>>> +                 sreg->name, sreg->org_val, reg_val);
>>> +     sreg->user_val = sreg->org_val;
>>> +     return 0;
>>> +}
>>> +
>>> +static void set_id_regs_test(void)
>> if it is a test use test_ prefix
> 
> I will fix this.
> 
>>> +{
>>> +     struct kvm_vm *vm;
>>> +     int ret;
>>> +
>>> +     reset_id_reg_info();
>>> +     vm = test_vm_create(1, guest_code_id_reg_check_all, NULL);
>> add test_vm_free()
> 
> I will fix this.
> 
>>> +
>>> +     ret = walk_id_reg_list(set_id_regs_test_one, vm);
>>> +     assert(!ret);
>>> +
>>> +     ret = TEST_RUN(vm, 0);
>>> +     TEST_ASSERT(!ret, "%s TEST_RUN failed, ret=0x%x", __func__, ret);
>>> +
>>> +     ret = walk_id_reg_list(set_id_regs_after_run_test_one, vm);
>>> +     assert(!ret);
>>> +}
>>> +
>>> +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;
>>> +}
>>> +
>>> +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[2] = {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, 2)) {
>>> +
>>> +             /* 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_cap(1, guest_code_ptrauth_check, &init,
>>> +                                     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 > 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->user_val = rval;
>>> +
>>> +             pr_debug("%s: Test with %s enabled (%s: 0x%lx)\n",
>>> +                      __func__, name, sreg->name, sreg->user_val);
>>> +             ret = TEST_RUN(vm, vcpu);
>>> +             TEST_ASSERT(!ret, "%s:KVM_RUN failed with %s enabled",
>>> +                         __func__, name);
>>> +             test_vm_free(vm);
>>> +     }
>>> +
>>> +     /* Test with feature disabled */
>>> +     reset_id_reg_info();
>>> +
>>> +     vm = test_vm_create(1, guest_code_feature_check, 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->user_val);
>>> +
>>> +     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));
>>> +}
>>> +
>> comment with short explanation of what the test does
> 
> Yes, I will add a short explanation for each test.
> 
>>> +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();
>>> +     finfo->run_test = 1;    /* Indicate that guest runs the test on it */
>>> +     one_reg.addr = (uint64_t)&reg_val;
>>> +     one_reg.id = KVM_ARM64_SYS_REG(sreg->id);
>>> +
>>> +     /* Test with feature enabled if the feature is available */
>> s/if the feature is available/if the feature is exposed in the default
>> ID_REG value and if the capabilities are supported at KVM level
> 
> Thank you for the suggestion. I will fix that.
> 
> 
>>> +void run_test(void)
>>> +{
>>> +     set_id_regs_test();
>>> +     test_feature_all();
>>> +     test_feature_ptrauth();
>>> +     test_feature_frac_all();
>>> +}
>>> +
>> basic comment would be helpful: attempts to clear a given id_reg and
>> populate the id_reg with the original value, and can_clear flag?
> 
> I will add some comments.
> 
>>> +static int init_id_reg_info_one(struct id_reg_test_info *sreg, void *arg)
>>> +{
>>> +     uint64_t reg_val;
>>> +     uint32_t vcpuid = 0;
>>> +     int ret;
>>> +     struct kvm_one_reg one_reg;
>>> +     struct kvm_vm *vm = arg;
>>> +
>>> +     one_reg.addr = (uint64_t)&reg_val;
>>> +     one_reg.id = KVM_ARM64_SYS_REG(sreg->id);
>>> +     vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &one_reg);
>>> +     sreg->org_val = reg_val;
>>> +     sreg->user_val = reg_val;
>> nit: add a comment for user_val because it is not obvious why you set it
>> to reg_val.
> 
> I will add a comment for it.
> 
>>> +     if (sreg->org_val) {
>>> +             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->org_val, sreg->can_clear ? ", can clear" : "");
>>> +
>>> +     return 0;
>>> +}
>>> +
>> add a comment? loop over the idreg list and populates each regid info
>> with the default, user and can_clear value
> 
> I will add a comment for the function.
> 
>>> +static void init_id_reg_info(void)
>>> +{
>>> +     struct kvm_vm *vm;
>>> +
>>> +     vm = test_vm_create(1, guest_code_do_nothing, NULL);
>>> +     walk_id_reg_list(init_id_reg_info_one, vm);
>>> +     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\n");
>>> +             exit(KSFT_SKIP);
>>> +     }
>>> +
>>> +     init_id_reg_info();
>>> +     run_test();
>>> +     return 0;
>>> +}
>>>
>>
>> After fixing the mem_pages stuff I get the following error on a cavium
>> machine.
>>
>> augere@virtlab-arm04:~/UPSTREAM/ML/tools/testing/selftests/kvm#
>> ./aarch64/id_reg_test
>> ==== Test Assertion Failure ====
>>   aarch64/id_reg_test.c:814: fval >= min
>>   pid=11692 tid=11692 errno=4 - Interrupted system call
>>      1  0x00000000004028d3: test_feature at id_reg_test.c:813
>>      2   (inlined by) test_feature_all at id_reg_test.c:863
>>      3   (inlined by) run_test at id_reg_test.c:1073
>>      4  0x000000000040156f: main at id_reg_test.c:1124
>>      5  0x000003ffa9420de3: ?? ??:0
>>      6  0x00000000004015eb: _start at :?
>>   PERFMON field of ID_DFR0 is too small (0)
>>
>> Fails on
>> test_feature: PERFMON (reg ID_DFR0)
>>
>> I will do my utmost to further debug
> 
> Thank you for running it in your environment and reporting this !
> This is very interesting...
> 
> It implies that the host's ID_DFR0_EL1.PerfMon is zero or 0xf
> (meaning FEAT_PMUv3 is not implemented) even though the host's
> ID_AA64DFR0_EL1.PMUVer indicates that FEAT_PMUv3 is implemented.
> 
> Would it be possible for you to check values of those two
> registers on the host (not on the guest) to see if both of them
> indicate the presence of FEAT_PMUv3 consistently ?

Here are both values printed in armpmu_register()
[   33.320901] armpmu_register perfmon=0x0 pmuver=0x4

        perfmon =
cpuid_feature_extract_unsigned_field(read_cpuid(ID_DFR0_EL1),
                        ID_DFR0_PERFMON_SHIFT);
        pmuver =
cpuid_feature_extract_unsigned_field(read_cpuid(ID_AA64DFR0_EL1),
                        ID_AA64DFR0_PMUVER_SHIFT);
        printk("%s perfmon=0x%x pmuver=0x%x\n", __func__, perfmon, pmuver);

My machine is a Gigabyte R181-T90 (ThunderX2)

Eric


Eric

> 
> Thanks,
> Reiji
> 


  reply	other threads:[~2021-11-22 14:18 UTC|newest]

Thread overview: 109+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-17  6:43 [RFC PATCH v3 00/29] KVM: arm64: Make CPU ID registers writable by userspace Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 01/29] KVM: arm64: Add has_reset_once flag for vcpu Reiji Watanabe
2021-11-21 12:36   ` Marc Zyngier
2021-11-23  0:51     ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 02/29] KVM: arm64: Save ID registers' sanitized value per vCPU Reiji Watanabe
2021-11-18 20:36   ` Eric Auger
2021-11-18 22:00     ` Reiji Watanabe
2021-11-24 18:08       ` Eric Auger
2021-11-21 12:36   ` Marc Zyngier
2021-11-23  4:39     ` Reiji Watanabe
2021-11-23 10:03       ` Marc Zyngier
2021-11-23 17:12         ` Reiji Watanabe
2021-12-02 10:58   ` Eric Auger
2021-12-04  1:45     ` Reiji Watanabe
2021-12-07  9:34       ` Eric Auger
2021-12-08  5:57         ` Reiji Watanabe
2021-12-08  7:09           ` Eric Auger
2021-12-08  7:18             ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 03/29] KVM: arm64: Introduce struct id_reg_info Reiji Watanabe
2021-11-18 20:36   ` Eric Auger
2021-11-19  4:47     ` Reiji Watanabe
2021-11-21 12:37       ` Marc Zyngier
2021-11-23  0:56         ` Reiji Watanabe
2021-11-24 18:22       ` Eric Auger
2021-11-25  6:05         ` Reiji Watanabe
2021-11-21 12:37   ` Marc Zyngier
2021-11-25  5:27     ` Reiji Watanabe
2021-12-01 15:38       ` Alexandru Elisei
2021-12-02  4:32         ` Reiji Watanabe
2021-11-24 21:07   ` Eric Auger
2021-11-25  6:40     ` Reiji Watanabe
2021-12-02 12:51       ` Eric Auger
2021-12-01 15:24   ` Alexandru Elisei
2021-12-02  4:09     ` Reiji Watanabe
2021-12-02 12:51   ` Eric Auger
2021-12-04  4:35     ` Reiji Watanabe
2021-12-07  9:36       ` Eric Auger
2021-11-17  6:43 ` [RFC PATCH v3 04/29] KVM: arm64: Make ID_AA64PFR0_EL1 writable Reiji Watanabe
2021-11-21 12:37   ` Marc Zyngier
2021-11-24  6:11     ` Reiji Watanabe
2021-11-25 15:35   ` Eric Auger
2021-11-30  1:29     ` Reiji Watanabe
2021-12-02 13:02       ` Eric Auger
2021-12-04  7:59         ` Reiji Watanabe
2021-12-07  9:42           ` Eric Auger
2021-11-17  6:43 ` [RFC PATCH v3 05/29] KVM: arm64: Make ID_AA64PFR1_EL1 writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 06/29] KVM: arm64: Make ID_AA64ISAR0_EL1 writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 07/29] KVM: arm64: Make ID_AA64ISAR1_EL1 writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 08/29] KVM: arm64: Make ID_AA64MMFR0_EL1 writable Reiji Watanabe
2021-11-25 15:31   ` Eric Auger
2021-11-30  4:43     ` Reiji Watanabe
2021-11-25 16:06   ` Eric Auger
2021-11-17  6:43 ` [RFC PATCH v3 09/29] KVM: arm64: Hide IMPLEMENTATION DEFINED PMU support for the guest Reiji Watanabe
2021-11-25 20:30   ` Eric Auger
2021-11-30  5:32     ` Reiji Watanabe
2021-12-01 15:53       ` Alexandru Elisei
2021-12-01 16:09         ` Alexandru Elisei
2021-12-02  4:42           ` Reiji Watanabe
2021-12-02 10:57       ` Eric Auger
2021-12-04  1:04         ` Reiji Watanabe
2021-12-04 14:14           ` Eric Auger
2021-12-04 17:39             ` Reiji Watanabe
2021-12-04 23:38               ` Itaru Kitayama
2021-12-06  0:27                 ` Reiji Watanabe
2021-12-06  9:52               ` Alexandru Elisei
2021-12-06 10:25                 ` Eric Auger
2021-12-07  7:07                   ` Reiji Watanabe
2021-12-07  8:10                 ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 10/29] KVM: arm64: Make ID_AA64DFR0_EL1 writable Reiji Watanabe
2021-11-25 20:30   ` Eric Auger
2021-11-30  5:21     ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 11/29] KVM: arm64: Make ID_DFR0_EL1 writable Reiji Watanabe
2021-11-24 13:46   ` Eric Auger
2021-11-25  5:33     ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 12/29] KVM: arm64: Make ID_DFR1_EL1 writable Reiji Watanabe
2021-11-25 20:30   ` Eric Auger
2021-11-30  5:39     ` Reiji Watanabe
2021-12-02 13:11       ` Eric Auger
2021-11-17  6:43 ` [RFC PATCH v3 13/29] KVM: arm64: Make ID_MMFR0_EL1 writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 14/29] KVM: arm64: Make MVFR1_EL1 writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 15/29] KVM: arm64: Make ID registers without id_reg_info writable Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 16/29] KVM: arm64: Add consistency checking for frac fields of ID registers Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 17/29] KVM: arm64: Introduce KVM_CAP_ARM_ID_REG_CONFIGURABLE capability Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 18/29] KVM: arm64: Add kunit test for ID register validation Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 19/29] KVM: arm64: Use vcpu->arch cptr_el2 to track value of cptr_el2 for VHE Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 20/29] KVM: arm64: Use vcpu->arch.mdcr_el2 to track value of mdcr_el2 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 21/29] KVM: arm64: Introduce framework to trap disabled features Reiji Watanabe
2021-11-21 18:46   ` Marc Zyngier
2021-11-23  7:27     ` Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 22/29] KVM: arm64: Trap disabled features of ID_AA64PFR0_EL1 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 23/29] KVM: arm64: Trap disabled features of ID_AA64PFR1_EL1 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 24/29] KVM: arm64: Trap disabled features of ID_AA64DFR0_EL1 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 25/29] KVM: arm64: Trap disabled features of ID_AA64MMFR1_EL1 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 26/29] KVM: arm64: Trap disabled features of ID_AA64ISAR1_EL1 Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 27/29] KVM: arm64: Initialize trapping of disabled CPU features for the guest Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 28/29] KVM: arm64: Add kunit test for trap initialization Reiji Watanabe
2021-11-17  6:43 ` [RFC PATCH v3 29/29] KVM: arm64: selftests: Introduce id_reg_test Reiji Watanabe
2021-11-18 20:34   ` Eric Auger
2021-11-20  6:39     ` Reiji Watanabe
2021-11-22 14:17       ` Eric Auger [this message]
2021-11-23  6:33         ` Reiji Watanabe
2021-11-23 16:00 ` [RFC PATCH v3 00/29] KVM: arm64: Make CPU ID registers writable by userspace Alexandru Elisei
2021-11-24  5:13   ` Reiji Watanabe
2021-11-24 10:50     ` Alexandru Elisei
2021-11-24 17:00       ` Reiji Watanabe
2021-11-23 16:27 ` Alexandru Elisei
2021-11-24  5:49   ` Reiji Watanabe
2021-11-24 10:48     ` Alexandru Elisei
2021-11-24 16:44       ` Reiji Watanabe

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=8dfa692e-5aa1-c6b3-55f8-3c2bb83df9cd@redhat.com \
    --to=eauger@redhat.com \
    --cc=alexandru.elisei@arm.com \
    --cc=drjones@redhat.com \
    --cc=james.morse@arm.com \
    --cc=jingzhangos@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=liangpeng10@huawei.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=maz@kernel.org \
    --cc=oupton@google.com \
    --cc=pbonzini@redhat.com \
    --cc=pshier@google.com \
    --cc=rananta@google.com \
    --cc=reijiw@google.com \
    --cc=ricarkol@google.com \
    --cc=suzuki.poulose@arm.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).