1 // SPDX-License-Identifier: GPL-2.0-only
3 * mmio_abort - Tests for userspace MMIO abort injection
5 * Copyright (c) 2024 Google LLC
10 #define MMIO_ADDR 0x8000000ULL
12 static u64 expected_abort_pc
;
14 static void expect_sea_handler(struct ex_regs
*regs
)
16 u64 esr
= read_sysreg(esr_el1
);
18 GUEST_ASSERT_EQ(regs
->pc
, expected_abort_pc
);
19 GUEST_ASSERT_EQ(ESR_ELx_EC(esr
), ESR_ELx_EC_DABT_CUR
);
20 GUEST_ASSERT_EQ(esr
& ESR_ELx_FSC_TYPE
, ESR_ELx_FSC_EXTABT
);
25 static void unexpected_dabt_handler(struct ex_regs
*regs
)
27 GUEST_FAIL("Unexpected data abort at PC: %lx\n", regs
->pc
);
30 static struct kvm_vm
*vm_create_with_dabt_handler(struct kvm_vcpu
**vcpu
, void *guest_code
,
31 handler_fn dabt_handler
)
33 struct kvm_vm
*vm
= vm_create_with_one_vcpu(vcpu
, guest_code
);
35 vm_init_descriptor_tables(vm
);
36 vcpu_init_descriptor_tables(*vcpu
);
37 vm_install_sync_handler(vm
, VECTOR_SYNC_CURRENT
, ESR_ELx_EC_DABT_CUR
, dabt_handler
);
39 virt_map(vm
, MMIO_ADDR
, MMIO_ADDR
, 1);
44 static void vcpu_inject_extabt(struct kvm_vcpu
*vcpu
)
46 struct kvm_vcpu_events events
= {};
48 events
.exception
.ext_dabt_pending
= true;
49 vcpu_events_set(vcpu
, &events
);
52 static void vcpu_run_expect_done(struct kvm_vcpu
*vcpu
)
57 switch (get_ucall(vcpu
, &uc
)) {
59 REPORT_GUEST_ASSERT(uc
);
64 TEST_FAIL("Unexpected ucall: %lu", uc
.cmd
);
68 extern char test_mmio_abort_insn
;
70 static void test_mmio_abort_guest(void)
72 WRITE_ONCE(expected_abort_pc
, (u64
)&test_mmio_abort_insn
);
74 asm volatile("test_mmio_abort_insn:\n\t"
76 : : "r" (MMIO_ADDR
) : "x0", "memory");
78 GUEST_FAIL("MMIO instruction should not retire");
82 * Test that KVM doesn't complete MMIO emulation when userspace has made an
83 * external abort pending for the instruction.
85 static void test_mmio_abort(void)
87 struct kvm_vcpu
*vcpu
;
88 struct kvm_vm
*vm
= vm_create_with_dabt_handler(&vcpu
, test_mmio_abort_guest
,
90 struct kvm_run
*run
= vcpu
->run
;
93 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_MMIO
);
94 TEST_ASSERT_EQ(run
->mmio
.phys_addr
, MMIO_ADDR
);
95 TEST_ASSERT_EQ(run
->mmio
.len
, sizeof(unsigned long));
96 TEST_ASSERT(!run
->mmio
.is_write
, "Expected MMIO read");
98 vcpu_inject_extabt(vcpu
);
99 vcpu_run_expect_done(vcpu
);
103 extern char test_mmio_nisv_insn
;
105 static void test_mmio_nisv_guest(void)
107 WRITE_ONCE(expected_abort_pc
, (u64
)&test_mmio_nisv_insn
);
109 asm volatile("test_mmio_nisv_insn:\n\t"
110 "ldr x0, [%0], #8\n\t"
111 : : "r" (MMIO_ADDR
) : "x0", "memory");
113 GUEST_FAIL("MMIO instruction should not retire");
117 * Test that the KVM_RUN ioctl fails for ESR_EL2.ISV=0 MMIO aborts if userspace
118 * hasn't enabled KVM_CAP_ARM_NISV_TO_USER.
120 static void test_mmio_nisv(void)
122 struct kvm_vcpu
*vcpu
;
123 struct kvm_vm
*vm
= vm_create_with_dabt_handler(&vcpu
, test_mmio_nisv_guest
,
124 unexpected_dabt_handler
);
126 TEST_ASSERT(_vcpu_run(vcpu
), "Expected nonzero return code from KVM_RUN");
127 TEST_ASSERT_EQ(errno
, ENOSYS
);
133 * Test that ESR_EL2.ISV=0 MMIO aborts reach userspace and that an injected SEA
136 static void test_mmio_nisv_abort(void)
138 struct kvm_vcpu
*vcpu
;
139 struct kvm_vm
*vm
= vm_create_with_dabt_handler(&vcpu
, test_mmio_nisv_guest
,
141 struct kvm_run
*run
= vcpu
->run
;
143 vm_enable_cap(vm
, KVM_CAP_ARM_NISV_TO_USER
, 1);
146 TEST_ASSERT_KVM_EXIT_REASON(vcpu
, KVM_EXIT_ARM_NISV
);
147 TEST_ASSERT_EQ(run
->arm_nisv
.fault_ipa
, MMIO_ADDR
);
149 vcpu_inject_extabt(vcpu
);
150 vcpu_run_expect_done(vcpu
);
158 test_mmio_nisv_abort();