Skip to content

Commit 10fd028

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/selftests-6.18 into kvmarm-master/next
* kvm-arm64/selftests-6.18: : . : KVM/arm64 selftest updates for 6.18: : : - Large update to run EL1 selftests at EL2 when possible : (20250917212044.294760-1-oliver.upton@linux.dev) : : - Work around lack of ID_AA64MMFR4_EL1 trapping on CPUs : without FEAT_FGT : (20250923173006.467455-1-oliver.upton@linux.dev) : : - Additional fixes and cleanups : (20250920-kvm-arm64-id-aa64isar3-el1-v1-0-1764c1c1c96d@kernel.org) : . KVM: arm64: selftests: Cover ID_AA64ISAR3_EL1 in set_id_regs KVM: arm64: selftests: Remove a duplicate register listing in set_id_regs KVM: arm64: selftests: Cope with arch silliness in EL2 selftest KVM: arm64: selftests: Add basic test for running in VHE EL2 KVM: arm64: selftests: Enable EL2 by default KVM: arm64: selftests: Initialize HCR_EL2 KVM: arm64: selftests: Use the vCPU attr for setting nr of PMU counters KVM: arm64: selftests: Use hyp timer IRQs when test runs at EL2 KVM: arm64: selftests: Select SMCCC conduit based on current EL KVM: arm64: selftests: Provide helper for getting default vCPU target KVM: arm64: selftests: Alias EL1 registers to EL2 counterparts KVM: arm64: selftests: Create a VGICv3 for 'default' VMs KVM: arm64: selftests: Add unsanitised helpers for VGICv3 creation KVM: arm64: selftests: Add helper to check for VGICv3 support KVM: arm64: selftests: Initialize VGICv3 only once KVM: arm64: selftests: Provide kvm_arch_vm_post_create() in library code Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents 181ce6b + b02a2c0 commit 10fd028

28 files changed

Lines changed: 422 additions & 176 deletions

tools/testing/selftests/kvm/Makefile.kvm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ TEST_GEN_PROGS_arm64 = $(TEST_GEN_PROGS_COMMON)
156156
TEST_GEN_PROGS_arm64 += arm64/aarch32_id_regs
157157
TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases
158158
TEST_GEN_PROGS_arm64 += arm64/debug-exceptions
159+
TEST_GEN_PROGS_arm64 += arm64/hello_el2
159160
TEST_GEN_PROGS_arm64 += arm64/host_sve
160161
TEST_GEN_PROGS_arm64 += arm64/hypercalls
161162
TEST_GEN_PROGS_arm64 += arm64/external_aborts

tools/testing/selftests/kvm/arm64/arch_timer.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,25 +165,23 @@ static void guest_code(void)
165165
static void test_init_timer_irq(struct kvm_vm *vm)
166166
{
167167
/* Timer initid should be same for all the vCPUs, so query only vCPU-0 */
168-
vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL,
169-
KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq);
170-
vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL,
171-
KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq);
168+
ptimer_irq = vcpu_get_ptimer_irq(vcpus[0]);
169+
vtimer_irq = vcpu_get_vtimer_irq(vcpus[0]);
172170

173171
sync_global_to_guest(vm, ptimer_irq);
174172
sync_global_to_guest(vm, vtimer_irq);
175173

176174
pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);
177175
}
178176

179-
static int gic_fd;
180-
181177
struct kvm_vm *test_vm_create(void)
182178
{
183179
struct kvm_vm *vm;
184180
unsigned int i;
185181
int nr_vcpus = test_args.nr_vcpus;
186182

183+
TEST_REQUIRE(kvm_supports_vgic_v3());
184+
187185
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
188186

189187
vm_init_descriptor_tables(vm);
@@ -204,8 +202,6 @@ struct kvm_vm *test_vm_create(void)
204202
vcpu_init_descriptor_tables(vcpus[i]);
205203

206204
test_init_timer_irq(vm);
207-
gic_fd = vgic_v3_setup(vm, nr_vcpus, 64);
208-
__TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3");
209205

210206
/* Make all the test's cmdline args visible to the guest */
211207
sync_global_to_guest(vm, test_args);
@@ -215,6 +211,5 @@ struct kvm_vm *test_vm_create(void)
215211

216212
void test_vm_cleanup(struct kvm_vm *vm)
217213
{
218-
close(gic_fd);
219214
kvm_vm_free(vm);
220215
}

tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -924,19 +924,15 @@ static void test_run(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
924924

925925
static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
926926
{
927-
vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,
928-
KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq);
929-
vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,
930-
KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq);
927+
ptimer_irq = vcpu_get_ptimer_irq(vcpu);
928+
vtimer_irq = vcpu_get_vtimer_irq(vcpu);
931929

932930
sync_global_to_guest(vm, ptimer_irq);
933931
sync_global_to_guest(vm, vtimer_irq);
934932

935933
pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);
936934
}
937935

938-
static int gic_fd;
939-
940936
static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
941937
enum arch_timer timer)
942938
{
@@ -951,8 +947,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
951947
vcpu_args_set(*vcpu, 1, timer);
952948

953949
test_init_timer_irq(*vm, *vcpu);
954-
gic_fd = vgic_v3_setup(*vm, 1, 64);
955-
__TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3");
956950

957951
sync_global_to_guest(*vm, test_args);
958952
sync_global_to_guest(*vm, CVAL_MAX);
@@ -961,7 +955,6 @@ static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,
961955

962956
static void test_vm_cleanup(struct kvm_vm *vm)
963957
{
964-
close(gic_fd);
965958
kvm_vm_free(vm);
966959
}
967960

@@ -1042,6 +1035,8 @@ int main(int argc, char *argv[])
10421035
/* Tell stdout not to buffer its content */
10431036
setbuf(stdout, NULL);
10441037

1038+
TEST_REQUIRE(kvm_supports_vgic_v3());
1039+
10451040
if (!parse_args(argc, argv))
10461041
exit(KSFT_SKIP);
10471042

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* hello_el2 - Basic KVM selftest for VM running at EL2 with E2H=RES1
4+
*
5+
* Copyright 2025 Google LLC
6+
*/
7+
#include "kvm_util.h"
8+
#include "processor.h"
9+
#include "test_util.h"
10+
#include "ucall.h"
11+
12+
#include <asm/sysreg.h>
13+
14+
static void guest_code(void)
15+
{
16+
u64 mmfr0 = read_sysreg_s(SYS_ID_AA64MMFR0_EL1);
17+
u64 mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
18+
u64 mmfr4 = read_sysreg_s(SYS_ID_AA64MMFR4_EL1);
19+
u8 e2h0 = SYS_FIELD_GET(ID_AA64MMFR4_EL1, E2H0, mmfr4);
20+
21+
GUEST_ASSERT_EQ(get_current_el(), 2);
22+
GUEST_ASSERT(read_sysreg(hcr_el2) & HCR_EL2_E2H);
23+
GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR1_EL1, VH, mmfr1),
24+
ID_AA64MMFR1_EL1_VH_IMP);
25+
26+
/*
27+
* Traps of the complete ID register space are IMPDEF without FEAT_FGT,
28+
* which is really annoying to deal with in KVM describing E2H as RES1.
29+
*
30+
* If the implementation doesn't honor the trap then expect the register
31+
* to return all zeros.
32+
*/
33+
if (e2h0 == ID_AA64MMFR4_EL1_E2H0_IMP)
34+
GUEST_ASSERT_EQ(SYS_FIELD_GET(ID_AA64MMFR0_EL1, FGT, mmfr0),
35+
ID_AA64MMFR0_EL1_FGT_NI);
36+
else
37+
GUEST_ASSERT_EQ(e2h0, ID_AA64MMFR4_EL1_E2H0_NI_NV1);
38+
39+
GUEST_DONE();
40+
}
41+
42+
int main(void)
43+
{
44+
struct kvm_vcpu_init init;
45+
struct kvm_vcpu *vcpu;
46+
struct kvm_vm *vm;
47+
struct ucall uc;
48+
49+
TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_EL2));
50+
51+
vm = vm_create(1);
52+
53+
kvm_get_default_vcpu_target(vm, &init);
54+
init.features[0] |= BIT(KVM_ARM_VCPU_HAS_EL2);
55+
vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
56+
kvm_arch_vm_finalize_vcpus(vm);
57+
58+
vcpu_run(vcpu);
59+
switch (get_ucall(vcpu, &uc)) {
60+
case UCALL_DONE:
61+
break;
62+
case UCALL_ABORT:
63+
REPORT_GUEST_ASSERT(uc);
64+
break;
65+
default:
66+
TEST_FAIL("Unhandled ucall: %ld\n", uc.cmd);
67+
}
68+
69+
kvm_vm_free(vm);
70+
return 0;
71+
}

tools/testing/selftests/kvm/arm64/hypercalls.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ static void guest_test_hvc(const struct test_hvc_info *hc_info)
108108

109109
for (i = 0; i < hvc_info_arr_sz; i++, hc_info++) {
110110
memset(&res, 0, sizeof(res));
111-
smccc_hvc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
111+
do_smccc(hc_info->func_id, hc_info->arg1, 0, 0, 0, 0, 0, 0, &res);
112112

113113
switch (stage) {
114114
case TEST_STAGE_HVC_IFACE_FEAT_DISABLED:

tools/testing/selftests/kvm/arm64/kvm-uuid.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ static void guest_code(void)
2525
{
2626
struct arm_smccc_res res = {};
2727

28-
smccc_hvc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res);
28+
do_smccc(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res);
2929

3030
__GUEST_ASSERT(res.a0 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 &&
3131
res.a1 == ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 &&

tools/testing/selftests/kvm/arm64/no-vgic-v3.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ int main(int argc, char *argv[])
163163
struct kvm_vm *vm;
164164
uint64_t pfr0;
165165

166+
test_disable_default_vgic();
167+
166168
vm = vm_create_with_one_vcpu(&vcpu, NULL);
167169
pfr0 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));
168170
__TEST_REQUIRE(FIELD_GET(ID_AA64PFR0_EL1_GIC, pfr0),

tools/testing/selftests/kvm/arm64/psci_test.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr,
2727
{
2828
struct arm_smccc_res res;
2929

30-
smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id,
30+
do_smccc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id,
3131
0, 0, 0, 0, &res);
3232

3333
return res.a0;
@@ -38,7 +38,7 @@ static uint64_t psci_affinity_info(uint64_t target_affinity,
3838
{
3939
struct arm_smccc_res res;
4040

41-
smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level,
41+
do_smccc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level,
4242
0, 0, 0, 0, 0, &res);
4343

4444
return res.a0;
@@ -48,7 +48,7 @@ static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id)
4848
{
4949
struct arm_smccc_res res;
5050

51-
smccc_hvc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id,
51+
do_smccc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id,
5252
0, 0, 0, 0, 0, &res);
5353

5454
return res.a0;
@@ -58,7 +58,7 @@ static uint64_t psci_system_off2(uint64_t type, uint64_t cookie)
5858
{
5959
struct arm_smccc_res res;
6060

61-
smccc_hvc(PSCI_1_3_FN64_SYSTEM_OFF2, type, cookie, 0, 0, 0, 0, 0, &res);
61+
do_smccc(PSCI_1_3_FN64_SYSTEM_OFF2, type, cookie, 0, 0, 0, 0, 0, &res);
6262

6363
return res.a0;
6464
}
@@ -67,7 +67,7 @@ static uint64_t psci_features(uint32_t func_id)
6767
{
6868
struct arm_smccc_res res;
6969

70-
smccc_hvc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res);
70+
do_smccc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res);
7171

7272
return res.a0;
7373
}
@@ -89,12 +89,13 @@ static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source,
8989

9090
vm = vm_create(2);
9191

92-
vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
92+
kvm_get_default_vcpu_target(vm, &init);
9393
init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);
9494

9595
*source = aarch64_vcpu_add(vm, 0, &init, guest_code);
9696
*target = aarch64_vcpu_add(vm, 1, &init, guest_code);
9797

98+
kvm_arch_vm_finalize_vcpus(vm);
9899
return vm;
99100
}
100101

tools/testing/selftests/kvm/arm64/set_id_regs.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#include "test_util.h"
1616
#include <linux/bitfield.h>
1717

18-
bool have_cap_arm_mte;
19-
2018
enum ftr_type {
2119
FTR_EXACT, /* Use a predefined safe value */
2220
FTR_LOWER_SAFE, /* Smaller value is safe */
@@ -125,6 +123,13 @@ static const struct reg_ftr_bits ftr_id_aa64isar2_el1[] = {
125123
REG_FTR_END,
126124
};
127125

126+
static const struct reg_ftr_bits ftr_id_aa64isar3_el1[] = {
127+
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FPRCVT, 0),
128+
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, LSFE, 0),
129+
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64ISAR3_EL1, FAMINMAX, 0),
130+
REG_FTR_END,
131+
};
132+
128133
static const struct reg_ftr_bits ftr_id_aa64pfr0_el1[] = {
129134
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV3, 0),
130135
REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64PFR0_EL1, CSV2, 0),
@@ -223,6 +228,7 @@ static struct test_feature_reg test_regs[] = {
223228
TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
224229
TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
225230
TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
231+
TEST_REG(SYS_ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
226232
TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
227233
TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
228234
TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
@@ -241,6 +247,7 @@ static void guest_code(void)
241247
GUEST_REG_SYNC(SYS_ID_AA64ISAR0_EL1);
242248
GUEST_REG_SYNC(SYS_ID_AA64ISAR1_EL1);
243249
GUEST_REG_SYNC(SYS_ID_AA64ISAR2_EL1);
250+
GUEST_REG_SYNC(SYS_ID_AA64ISAR3_EL1);
244251
GUEST_REG_SYNC(SYS_ID_AA64PFR0_EL1);
245252
GUEST_REG_SYNC(SYS_ID_AA64MMFR0_EL1);
246253
GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1);
@@ -570,7 +577,9 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
570577
uint64_t mte_frac;
571578
int idx, err;
572579

573-
if (!have_cap_arm_mte) {
580+
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
581+
mte = FIELD_GET(ID_AA64PFR1_EL1_MTE, val);
582+
if (!mte) {
574583
ksft_test_result_skip("MTE capability not supported, nothing to test\n");
575584
return;
576585
}
@@ -595,9 +604,6 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
595604
* from unsupported (0xF) to supported (0).
596605
*
597606
*/
598-
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
599-
600-
mte = FIELD_GET(ID_AA64PFR1_EL1_MTE, val);
601607
mte_frac = FIELD_GET(ID_AA64PFR1_EL1_MTE_frac, val);
602608
if (mte != ID_AA64PFR1_EL1_MTE_MTE2 ||
603609
mte_frac != ID_AA64PFR1_EL1_MTE_frac_NI) {
@@ -752,28 +758,23 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
752758
ksft_test_result_pass("%s\n", __func__);
753759
}
754760

755-
void kvm_arch_vm_post_create(struct kvm_vm *vm)
756-
{
757-
if (vm_check_cap(vm, KVM_CAP_ARM_MTE)) {
758-
vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0);
759-
have_cap_arm_mte = true;
760-
}
761-
}
762-
763761
int main(void)
764762
{
765763
struct kvm_vcpu *vcpu;
766764
struct kvm_vm *vm;
767765
bool aarch64_only;
768766
uint64_t val, el0;
769-
int test_cnt;
767+
int test_cnt, i, j;
770768

771769
TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SUPPORTED_REG_MASK_RANGES));
772770
TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_WRITABLE_IMP_ID_REGS));
773771

772+
test_wants_mte();
773+
774774
vm = vm_create(1);
775775
vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0);
776776
vcpu = vm_vcpu_add(vm, 0, guest_code);
777+
kvm_arch_vm_finalize_vcpus(vm);
777778

778779
/* Check for AARCH64 only system */
779780
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR0_EL1));
@@ -782,13 +783,10 @@ int main(void)
782783

783784
ksft_print_header();
784785

785-
test_cnt = ARRAY_SIZE(ftr_id_aa64dfr0_el1) + ARRAY_SIZE(ftr_id_dfr0_el1) +
786-
ARRAY_SIZE(ftr_id_aa64isar0_el1) + ARRAY_SIZE(ftr_id_aa64isar1_el1) +
787-
ARRAY_SIZE(ftr_id_aa64isar2_el1) + ARRAY_SIZE(ftr_id_aa64pfr0_el1) +
788-
ARRAY_SIZE(ftr_id_aa64pfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr0_el1) +
789-
ARRAY_SIZE(ftr_id_aa64mmfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr2_el1) +
790-
ARRAY_SIZE(ftr_id_aa64mmfr3_el1) + ARRAY_SIZE(ftr_id_aa64zfr0_el1) -
791-
ARRAY_SIZE(test_regs) + 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
786+
test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
787+
for (i = 0; i < ARRAY_SIZE(test_regs); i++)
788+
for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
789+
test_cnt++;
792790

793791
ksft_set_plan(test_cnt);
794792

0 commit comments

Comments
 (0)