hvf: add breakpoint handlers

Required for guest debugging. The code has been structured like the KVM
counterpart.

Signed-off-by: Francesco Cagnin <fcagnin@quarkslab.com>
Message-id: 20230601153107.81955-4-fcagnin@quarkslab.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Francesco Cagnin 2023-06-06 10:19:30 +01:00 committed by Peter Maydell
parent ce799a04b2
commit f41520402c
6 changed files with 236 additions and 0 deletions

View file

@ -31,6 +31,8 @@
#include "trace/trace-target_arm_hvf.h"
#include "migration/vmstate.h"
#include "exec/gdbstub.h"
#define HVF_SYSREG(crn, crm, op0, op1, op2) \
ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP, crn, crm, op0, op1, op2)
#define PL1_WRITE_MASK 0x4
@ -1711,3 +1713,64 @@ int hvf_arch_init(void)
qemu_add_vm_change_state_handler(hvf_vm_state_change, &vtimer);
return 0;
}
static const uint32_t brk_insn = 0xd4200000;
int hvf_arch_insert_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
{
if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
return -EINVAL;
}
return 0;
}
int hvf_arch_remove_sw_breakpoint(CPUState *cpu, struct hvf_sw_breakpoint *bp)
{
static uint32_t brk;
if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&brk, 4, 0) ||
brk != brk_insn ||
cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
return -EINVAL;
}
return 0;
}
int hvf_arch_insert_hw_breakpoint(target_ulong addr, target_ulong len, int type)
{
switch (type) {
case GDB_BREAKPOINT_HW:
return insert_hw_breakpoint(addr);
case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_WRITE:
case GDB_WATCHPOINT_ACCESS:
return insert_hw_watchpoint(addr, len, type);
default:
return -ENOSYS;
}
}
int hvf_arch_remove_hw_breakpoint(target_ulong addr, target_ulong len, int type)
{
switch (type) {
case GDB_BREAKPOINT_HW:
return delete_hw_breakpoint(addr);
case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_WRITE:
case GDB_WATCHPOINT_ACCESS:
return delete_hw_watchpoint(addr, len, type);
default:
return -ENOSYS;
}
}
void hvf_arch_remove_all_hw_breakpoints(void)
{
if (cur_hw_wps > 0) {
g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
}
if (cur_hw_bps > 0) {
g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
}
}