-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
KVM: selftests: Add test for AArch32 ID registers
Add a test to assert that KVM handles the AArch64 views of the AArch32 ID registers as RAZ/WI (writable only from userspace). For registers that were already hidden or unallocated, expect RAZ + invariant behavior. Signed-off-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220913094441.3957645-8-oliver.upton@linux.dev
- Loading branch information
Oliver Upton
authored and
Marc Zyngier
committed
Sep 14, 2022
1 parent
d5efec7
commit 797b845
Showing
3 changed files
with
171 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
/* | ||
* aarch32_id_regs - Test for ID register behavior on AArch64-only systems | ||
* | ||
* Copyright (c) 2022 Google LLC. | ||
* | ||
* Test that KVM handles the AArch64 views of the AArch32 ID registers as RAZ | ||
* and WI from userspace. | ||
*/ | ||
|
||
#include <stdint.h> | ||
|
||
#include "kvm_util.h" | ||
#include "processor.h" | ||
#include "test_util.h" | ||
|
||
#define BAD_ID_REG_VAL 0x1badc0deul | ||
|
||
#define GUEST_ASSERT_REG_RAZ(reg) GUEST_ASSERT_EQ(read_sysreg_s(reg), 0) | ||
|
||
static void guest_main(void) | ||
{ | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_PFR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_PFR1_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_DFR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_AFR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR1_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR2_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR3_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR1_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR2_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR3_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR4_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR5_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR4_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_ISAR6_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_MVFR0_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_MVFR1_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_MVFR2_EL1); | ||
GUEST_ASSERT_REG_RAZ(sys_reg(3, 0, 0, 3, 3)); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_PFR2_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_DFR1_EL1); | ||
GUEST_ASSERT_REG_RAZ(SYS_ID_MMFR5_EL1); | ||
GUEST_ASSERT_REG_RAZ(sys_reg(3, 0, 0, 3, 7)); | ||
|
||
GUEST_DONE(); | ||
} | ||
|
||
static void test_guest_raz(struct kvm_vcpu *vcpu) | ||
{ | ||
struct ucall uc; | ||
|
||
vcpu_run(vcpu); | ||
|
||
switch (get_ucall(vcpu, &uc)) { | ||
case UCALL_ABORT: | ||
REPORT_GUEST_ASSERT(uc); | ||
break; | ||
case UCALL_DONE: | ||
break; | ||
default: | ||
TEST_FAIL("Unexpected ucall: %lu", uc.cmd); | ||
} | ||
} | ||
|
||
static uint64_t raz_wi_reg_ids[] = { | ||
KVM_ARM64_SYS_REG(SYS_ID_PFR0_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_PFR1_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_DFR0_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR0_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR1_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR2_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR3_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR0_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR1_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR2_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR3_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR4_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR5_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR4_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_ISAR6_EL1), | ||
KVM_ARM64_SYS_REG(SYS_MVFR0_EL1), | ||
KVM_ARM64_SYS_REG(SYS_MVFR1_EL1), | ||
KVM_ARM64_SYS_REG(SYS_MVFR2_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_PFR2_EL1), | ||
KVM_ARM64_SYS_REG(SYS_ID_MMFR5_EL1), | ||
}; | ||
|
||
static void test_user_raz_wi(struct kvm_vcpu *vcpu) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(raz_wi_reg_ids); i++) { | ||
uint64_t reg_id = raz_wi_reg_ids[i]; | ||
uint64_t val; | ||
|
||
vcpu_get_reg(vcpu, reg_id, &val); | ||
ASSERT_EQ(val, 0); | ||
|
||
/* | ||
* Expect the ioctl to succeed with no effect on the register | ||
* value. | ||
*/ | ||
vcpu_set_reg(vcpu, reg_id, BAD_ID_REG_VAL); | ||
|
||
vcpu_get_reg(vcpu, reg_id, &val); | ||
ASSERT_EQ(val, 0); | ||
} | ||
} | ||
|
||
static uint64_t raz_invariant_reg_ids[] = { | ||
KVM_ARM64_SYS_REG(SYS_ID_AFR0_EL1), | ||
KVM_ARM64_SYS_REG(sys_reg(3, 0, 0, 3, 3)), | ||
KVM_ARM64_SYS_REG(SYS_ID_DFR1_EL1), | ||
KVM_ARM64_SYS_REG(sys_reg(3, 0, 0, 3, 7)), | ||
}; | ||
|
||
static void test_user_raz_invariant(struct kvm_vcpu *vcpu) | ||
{ | ||
int i, r; | ||
|
||
for (i = 0; i < ARRAY_SIZE(raz_invariant_reg_ids); i++) { | ||
uint64_t reg_id = raz_invariant_reg_ids[i]; | ||
uint64_t val; | ||
|
||
vcpu_get_reg(vcpu, reg_id, &val); | ||
ASSERT_EQ(val, 0); | ||
|
||
r = __vcpu_set_reg(vcpu, reg_id, BAD_ID_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_id, &val); | ||
ASSERT_EQ(val, 0); | ||
} | ||
} | ||
|
||
|
||
|
||
static bool vcpu_aarch64_only(struct kvm_vcpu *vcpu) | ||
{ | ||
uint64_t val, el0; | ||
|
||
vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1), &val); | ||
|
||
el0 = (val & ARM64_FEATURE_MASK(ID_AA64PFR0_EL0)) >> ID_AA64PFR0_EL0_SHIFT; | ||
return el0 == ID_AA64PFR0_ELx_64BIT_ONLY; | ||
} | ||
|
||
int main(void) | ||
{ | ||
struct kvm_vcpu *vcpu; | ||
struct kvm_vm *vm; | ||
|
||
vm = vm_create_with_one_vcpu(&vcpu, guest_main); | ||
|
||
TEST_REQUIRE(vcpu_aarch64_only(vcpu)); | ||
|
||
ucall_init(vm, NULL); | ||
|
||
test_user_raz_wi(vcpu); | ||
test_user_raz_invariant(vcpu); | ||
test_guest_raz(vcpu); | ||
|
||
ucall_uninit(vm); | ||
kvm_vm_free(vm); | ||
} |