diff options
Diffstat (limited to 'target-arm/kvm64.c')
-rw-r--r-- | target-arm/kvm64.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index d0877946b1..3b3929dc24 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -18,6 +18,7 @@ #include "config-host.h" #include "qemu-common.h" #include "qemu/timer.h" +#include "qemu/error-report.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" #include "kvm_arm.h" @@ -481,3 +482,74 @@ int kvm_arch_get_registers(CPUState *cs) /* TODO: other registers */ return ret; } + +/* C6.6.29 BRK instruction */ +static const uint32_t brk_insn = 0xd4200000; + +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + if (have_guest_debug) { + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) { + return -EINVAL; + } + return 0; + } else { + error_report("guest debug not supported on this kernel"); + return -EINVAL; + } +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ + static uint32_t brk; + + if (have_guest_debug) { + if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) || + brk != brk_insn || + cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) { + return -EINVAL; + } + return 0; + } else { + error_report("guest debug not supported on this kernel"); + return -EINVAL; + } +} + +/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register + * + * To minimise translating between kernel and user-space the kernel + * ABI just provides user-space with the full exception syndrome + * register value to be decoded in QEMU. + */ + +bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit) +{ + int hsr_ec = debug_exit->hsr >> ARM_EL_EC_SHIFT; + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + /* Ensure PC is synchronised */ + kvm_cpu_synchronize_state(cs); + + switch (hsr_ec) { + case EC_AA64_BKPT: + if (kvm_find_sw_breakpoint(cs, env->pc)) { + return true; + } + break; + default: + error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n", + __func__, debug_exit->hsr, env->pc); + } + + /* If we don't handle this it could be it really is for the + guest to handle */ + qemu_log_mask(LOG_UNIMP, + "%s: re-injecting exception not yet implemented" + " (0x%"PRIx32", %"PRIx64")\n", + __func__, hsr_ec, env->pc); + + return false; +} |