Skip to content

Commit 00a3727

Browse files
author
Marc Zyngier
committed
KVM: arm64: selftest: Expand external_aborts test to look for TTW levels
Add a basic test corrupting a level-2 table entry to check that the resulting abort is a SEA on a PTW at level-3. Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent 50f77dc commit 00a3727

3 files changed

Lines changed: 55 additions & 1 deletion

File tree

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,47 @@ static void test_serror(void)
250250
kvm_vm_free(vm);
251251
}
252252

253+
static void expect_sea_s1ptw_handler(struct ex_regs *regs)
254+
{
255+
u64 esr = read_sysreg(esr_el1);
256+
257+
GUEST_ASSERT_EQ(regs->pc, expected_abort_pc);
258+
GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR);
259+
GUEST_ASSERT_EQ((esr & ESR_ELx_FSC), ESR_ELx_FSC_SEA_TTW(3));
260+
261+
GUEST_DONE();
262+
}
263+
264+
static noinline void test_s1ptw_abort_guest(void)
265+
{
266+
extern char test_s1ptw_abort_insn;
267+
268+
WRITE_ONCE(expected_abort_pc, (u64)&test_s1ptw_abort_insn);
269+
270+
asm volatile("test_s1ptw_abort_insn:\n\t"
271+
"ldr x0, [%0]\n\t"
272+
: : "r" (MMIO_ADDR) : "x0", "memory");
273+
274+
GUEST_FAIL("Load on S1PTW abort should not retire");
275+
}
276+
277+
static void test_s1ptw_abort(void)
278+
{
279+
struct kvm_vcpu *vcpu;
280+
u64 *ptep, bad_pa;
281+
struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_s1ptw_abort_guest,
282+
expect_sea_s1ptw_handler);
283+
284+
ptep = virt_get_pte_hva_at_level(vm, MMIO_ADDR, 2);
285+
bad_pa = BIT(vm->pa_bits) - vm->page_size;
286+
287+
*ptep &= ~GENMASK(47, 12);
288+
*ptep |= bad_pa;
289+
290+
vcpu_run_expect_done(vcpu);
291+
kvm_vm_free(vm);
292+
}
293+
253294
static void test_serror_emulated_guest(void)
254295
{
255296
GUEST_ASSERT(!(read_sysreg(isr_el1) & ISR_EL1_A));
@@ -327,4 +368,5 @@ int main(void)
327368
test_serror_masked();
328369
test_serror_emulated();
329370
test_mmio_ease();
371+
test_s1ptw_abort();
330372
}

tools/testing/selftests/kvm/include/arm64/processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ void vm_install_exception_handler(struct kvm_vm *vm,
175175
void vm_install_sync_handler(struct kvm_vm *vm,
176176
int vector, int ec, handler_fn handler);
177177

178+
uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level);
178179
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva);
179180

180181
static inline void cpu_relax(void)

tools/testing/selftests/kvm/lib/arm64/processor.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
185185
_virt_pg_map(vm, vaddr, paddr, attr_idx);
186186
}
187187

188-
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
188+
uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level)
189189
{
190190
uint64_t *ptep;
191191

@@ -195,17 +195,23 @@ uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
195195
ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
196196
if (!ptep)
197197
goto unmapped_gva;
198+
if (level == 0)
199+
return ptep;
198200

199201
switch (vm->pgtable_levels) {
200202
case 4:
201203
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
202204
if (!ptep)
203205
goto unmapped_gva;
206+
if (level == 1)
207+
break;
204208
/* fall through */
205209
case 3:
206210
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8;
207211
if (!ptep)
208212
goto unmapped_gva;
213+
if (level == 2)
214+
break;
209215
/* fall through */
210216
case 2:
211217
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8;
@@ -223,6 +229,11 @@ uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
223229
exit(EXIT_FAILURE);
224230
}
225231

232+
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
233+
{
234+
return virt_get_pte_hva_at_level(vm, gva, 3);
235+
}
236+
226237
vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
227238
{
228239
uint64_t *ptep = virt_get_pte_hva(vm, gva);

0 commit comments

Comments
 (0)