@ -52,6 +52,7 @@
# include "qemu/main-loop.h"
# include "exec/address-spaces.h"
# include "exec/exec-all.h"
# include "exec/gdbstub.h"
# include "sysemu/cpus.h"
# include "sysemu/hvf.h"
# include "sysemu/hvf_int.h"
@ -334,6 +335,8 @@ static int hvf_accel_init(MachineState *ms)
s - > slots [ x ] . slot_id = x ;
}
QTAILQ_INIT ( & s - > hvf_sw_breakpoints ) ;
hvf_state = s ;
memory_listener_register ( & hvf_memory_listener , & address_space_memory ) ;
@ -462,6 +465,108 @@ static void hvf_start_vcpu_thread(CPUState *cpu)
cpu , QEMU_THREAD_JOINABLE ) ;
}
static int hvf_insert_breakpoint ( CPUState * cpu , int type , hwaddr addr , hwaddr len )
{
struct hvf_sw_breakpoint * bp ;
int err ;
if ( type = = GDB_BREAKPOINT_SW ) {
bp = hvf_find_sw_breakpoint ( cpu , addr ) ;
if ( bp ) {
bp - > use_count + + ;
return 0 ;
}
bp = g_new ( struct hvf_sw_breakpoint , 1 ) ;
bp - > pc = addr ;
bp - > use_count = 1 ;
err = hvf_arch_insert_sw_breakpoint ( cpu , bp ) ;
if ( err ) {
g_free ( bp ) ;
return err ;
}
QTAILQ_INSERT_HEAD ( & hvf_state - > hvf_sw_breakpoints , bp , entry ) ;
} else {
err = hvf_arch_insert_hw_breakpoint ( addr , len , type ) ;
if ( err ) {
return err ;
}
}
CPU_FOREACH ( cpu ) {
err = hvf_update_guest_debug ( cpu ) ;
if ( err ) {
return err ;
}
}
return 0 ;
}
static int hvf_remove_breakpoint ( CPUState * cpu , int type , hwaddr addr , hwaddr len )
{
struct hvf_sw_breakpoint * bp ;
int err ;
if ( type = = GDB_BREAKPOINT_SW ) {
bp = hvf_find_sw_breakpoint ( cpu , addr ) ;
if ( ! bp ) {
return - ENOENT ;
}
if ( bp - > use_count > 1 ) {
bp - > use_count - - ;
return 0 ;
}
err = hvf_arch_remove_sw_breakpoint ( cpu , bp ) ;
if ( err ) {
return err ;
}
QTAILQ_REMOVE ( & hvf_state - > hvf_sw_breakpoints , bp , entry ) ;
g_free ( bp ) ;
} else {
err = hvf_arch_remove_hw_breakpoint ( addr , len , type ) ;
if ( err ) {
return err ;
}
}
CPU_FOREACH ( cpu ) {
err = hvf_update_guest_debug ( cpu ) ;
if ( err ) {
return err ;
}
}
return 0 ;
}
static void hvf_remove_all_breakpoints ( CPUState * cpu )
{
struct hvf_sw_breakpoint * bp , * next ;
CPUState * tmpcpu ;
QTAILQ_FOREACH_SAFE ( bp , & hvf_state - > hvf_sw_breakpoints , entry , next ) {
if ( hvf_arch_remove_sw_breakpoint ( cpu , bp ) ! = 0 ) {
/* Try harder to find a CPU that currently sees the breakpoint. */
CPU_FOREACH ( tmpcpu )
{
if ( hvf_arch_remove_sw_breakpoint ( tmpcpu , bp ) = = 0 ) {
break ;
}
}
}
QTAILQ_REMOVE ( & hvf_state - > hvf_sw_breakpoints , bp , entry ) ;
g_free ( bp ) ;
}
hvf_arch_remove_all_hw_breakpoints ( ) ;
CPU_FOREACH ( cpu ) {
hvf_update_guest_debug ( cpu ) ;
}
}
static void hvf_accel_ops_class_init ( ObjectClass * oc , void * data )
{
AccelOpsClass * ops = ACCEL_OPS_CLASS ( oc ) ;
@ -473,6 +578,10 @@ static void hvf_accel_ops_class_init(ObjectClass *oc, void *data)
ops - > synchronize_post_init = hvf_cpu_synchronize_post_init ;
ops - > synchronize_state = hvf_cpu_synchronize_state ;
ops - > synchronize_pre_loadvm = hvf_cpu_synchronize_pre_loadvm ;
ops - > insert_breakpoint = hvf_insert_breakpoint ;
ops - > remove_breakpoint = hvf_remove_breakpoint ;
ops - > remove_all_breakpoints = hvf_remove_all_breakpoints ;
} ;
static const TypeInfo hvf_accel_ops_type = {
. name = ACCEL_OPS_NAME ( " hvf " ) ,