mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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>
This commit is contained in:
@@ -250,6 +250,47 @@ static void test_serror(void)
|
||||
kvm_vm_free(vm);
|
||||
}
|
||||
|
||||
static void expect_sea_s1ptw_handler(struct ex_regs *regs)
|
||||
{
|
||||
u64 esr = read_sysreg(esr_el1);
|
||||
|
||||
GUEST_ASSERT_EQ(regs->pc, expected_abort_pc);
|
||||
GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR);
|
||||
GUEST_ASSERT_EQ((esr & ESR_ELx_FSC), ESR_ELx_FSC_SEA_TTW(3));
|
||||
|
||||
GUEST_DONE();
|
||||
}
|
||||
|
||||
static noinline void test_s1ptw_abort_guest(void)
|
||||
{
|
||||
extern char test_s1ptw_abort_insn;
|
||||
|
||||
WRITE_ONCE(expected_abort_pc, (u64)&test_s1ptw_abort_insn);
|
||||
|
||||
asm volatile("test_s1ptw_abort_insn:\n\t"
|
||||
"ldr x0, [%0]\n\t"
|
||||
: : "r" (MMIO_ADDR) : "x0", "memory");
|
||||
|
||||
GUEST_FAIL("Load on S1PTW abort should not retire");
|
||||
}
|
||||
|
||||
static void test_s1ptw_abort(void)
|
||||
{
|
||||
struct kvm_vcpu *vcpu;
|
||||
u64 *ptep, bad_pa;
|
||||
struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_s1ptw_abort_guest,
|
||||
expect_sea_s1ptw_handler);
|
||||
|
||||
ptep = virt_get_pte_hva_at_level(vm, MMIO_ADDR, 2);
|
||||
bad_pa = BIT(vm->pa_bits) - vm->page_size;
|
||||
|
||||
*ptep &= ~GENMASK(47, 12);
|
||||
*ptep |= bad_pa;
|
||||
|
||||
vcpu_run_expect_done(vcpu);
|
||||
kvm_vm_free(vm);
|
||||
}
|
||||
|
||||
static void test_serror_emulated_guest(void)
|
||||
{
|
||||
GUEST_ASSERT(!(read_sysreg(isr_el1) & ISR_EL1_A));
|
||||
@@ -327,4 +368,5 @@ int main(void)
|
||||
test_serror_masked();
|
||||
test_serror_emulated();
|
||||
test_mmio_ease();
|
||||
test_s1ptw_abort();
|
||||
}
|
||||
|
||||
@@ -175,6 +175,7 @@ void vm_install_exception_handler(struct kvm_vm *vm,
|
||||
void vm_install_sync_handler(struct kvm_vm *vm,
|
||||
int vector, int ec, handler_fn handler);
|
||||
|
||||
uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level);
|
||||
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva);
|
||||
|
||||
static inline void cpu_relax(void)
|
||||
|
||||
@@ -185,7 +185,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
|
||||
_virt_pg_map(vm, vaddr, paddr, attr_idx);
|
||||
}
|
||||
|
||||
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
uint64_t *virt_get_pte_hva_at_level(struct kvm_vm *vm, vm_vaddr_t gva, int level)
|
||||
{
|
||||
uint64_t *ptep;
|
||||
|
||||
@@ -195,17 +195,23 @@ uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
|
||||
if (!ptep)
|
||||
goto unmapped_gva;
|
||||
if (level == 0)
|
||||
return ptep;
|
||||
|
||||
switch (vm->pgtable_levels) {
|
||||
case 4:
|
||||
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
|
||||
if (!ptep)
|
||||
goto unmapped_gva;
|
||||
if (level == 1)
|
||||
break;
|
||||
/* fall through */
|
||||
case 3:
|
||||
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8;
|
||||
if (!ptep)
|
||||
goto unmapped_gva;
|
||||
if (level == 2)
|
||||
break;
|
||||
/* fall through */
|
||||
case 2:
|
||||
ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8;
|
||||
@@ -223,6 +229,11 @@ unmapped_gva:
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
{
|
||||
return virt_get_pte_hva_at_level(vm, gva, 3);
|
||||
}
|
||||
|
||||
vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
|
||||
{
|
||||
uint64_t *ptep = virt_get_pte_hva(vm, gva);
|
||||
|
||||
Reference in New Issue
Block a user