Compare commits
5 Commits
migration-
...
singlestep
Author | SHA1 | Date | |
---|---|---|---|
|
34370ee6ff | ||
|
9953b32e77 | ||
|
0da2fd84e1 | ||
|
b82417e8bf | ||
|
0b72719af8 |
@@ -2267,6 +2267,13 @@ bool kvm_arm_supports_user_irq(void)
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);
|
||||
}
|
||||
|
||||
/* Whether the KVM_SET_GUEST_DEBUG ioctl supports single stepping */
|
||||
int kvm_has_guestdbg_singlestep(void)
|
||||
{
|
||||
/* return kvm_check_extension(kvm_state, KVM_CAP_GUEST_DEBUG_SSTEP); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
|
||||
target_ulong pc)
|
||||
@@ -2316,6 +2323,15 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||
return data.err;
|
||||
}
|
||||
|
||||
void kvm_set_singlestep(CPUState *cs, int enabled)
|
||||
{
|
||||
if (kvm_has_guestdbg_singlestep()) {
|
||||
kvm_update_guest_debug(cs, 0);
|
||||
} else {
|
||||
kvm_arch_set_singlestep(cs, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
|
||||
target_ulong len, int type)
|
||||
{
|
||||
|
@@ -79,6 +79,10 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void kvm_set_singlestep(CPUState *cs, int enabled)
|
||||
{
|
||||
}
|
||||
|
||||
int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
|
||||
target_ulong len, int type)
|
||||
{
|
||||
|
2
exec.c
2
exec.c
@@ -1236,7 +1236,7 @@ void cpu_single_step(CPUState *cpu, int enabled)
|
||||
if (cpu->singlestep_enabled != enabled) {
|
||||
cpu->singlestep_enabled = enabled;
|
||||
if (kvm_enabled()) {
|
||||
kvm_update_guest_debug(cpu, 0);
|
||||
kvm_set_singlestep(cpu, enabled);
|
||||
} else {
|
||||
/* must flush all the translated code to avoid inconsistencies */
|
||||
/* XXX: only flush what is necessary */
|
||||
|
@@ -214,6 +214,7 @@ int kvm_has_pit_state2(void);
|
||||
int kvm_has_many_ioeventfds(void);
|
||||
int kvm_has_gsi_routing(void);
|
||||
int kvm_has_intx_set_mask(void);
|
||||
int kvm_has_guestdbg_singlestep(void);
|
||||
|
||||
int kvm_init_vcpu(CPUState *cpu);
|
||||
int kvm_cpu_exec(CPUState *cpu);
|
||||
@@ -246,6 +247,7 @@ bool kvm_memcrypt_enabled(void);
|
||||
*/
|
||||
int kvm_memcrypt_encrypt_data(uint8_t *ptr, uint64_t len);
|
||||
|
||||
void kvm_arch_set_singlestep(CPUState *cpu, int enabled);
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
#include "cpu.h"
|
||||
@@ -258,6 +260,7 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
|
||||
target_ulong len, int type);
|
||||
void kvm_remove_all_breakpoints(CPUState *cpu);
|
||||
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
|
||||
void kvm_set_singlestep(CPUState *cs, int enabled);
|
||||
|
||||
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
|
||||
int kvm_on_sigbus(int code, void *addr);
|
||||
|
@@ -12,6 +12,7 @@ stub-obj-y += get-vm-name.o
|
||||
stub-obj-y += iothread.o
|
||||
stub-obj-y += iothread-lock.o
|
||||
stub-obj-y += is-daemonized.o
|
||||
stub-obj-y += kvm-arch-set-singlestep.o
|
||||
stub-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
stub-obj-y += machine-init-done.o
|
||||
stub-obj-y += migr-blocker.o
|
||||
|
8
stubs/kvm-arch-set-singlestep.c
Normal file
8
stubs/kvm-arch-set-singlestep.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
void kvm_arch_set_singlestep(CPUState *cpu, int enabled)
|
||||
{
|
||||
warn_report("KVM does not support single stepping");
|
||||
}
|
@@ -1171,6 +1171,11 @@ struct CPUPPCState {
|
||||
uint32_t tm_vscr;
|
||||
uint64_t tm_dscr;
|
||||
uint64_t tm_tar;
|
||||
|
||||
/* Used for software single step */
|
||||
target_ulong sstep_msr;
|
||||
target_ulong sstep_srr0;
|
||||
target_ulong sstep_srr1;
|
||||
};
|
||||
|
||||
#define SET_FIT_PERIOD(a_, b_, c_, d_) \
|
||||
@@ -1266,6 +1271,7 @@ struct PPCVirtualHypervisorClass {
|
||||
OBJECT_GET_CLASS(PPCVirtualHypervisorClass, (obj), \
|
||||
TYPE_PPC_VIRTUAL_HYPERVISOR)
|
||||
|
||||
target_ulong ppc_get_trace_int_handler_addr(CPUState *cs);
|
||||
void ppc_cpu_do_interrupt(CPUState *cpu);
|
||||
bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||
@@ -1281,6 +1287,12 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void ppc_gdb_gen_spr_xml(PowerPCCPU *cpu);
|
||||
const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name);
|
||||
#endif
|
||||
uint32_t ppc_gdb_read_insn(CPUState *cs, target_ulong addr);
|
||||
uint32_t ppc_gdb_get_op(uint32_t insn);
|
||||
uint32_t ppc_gdb_get_xop(uint32_t insn);
|
||||
uint32_t ppc_gdb_get_spr(uint32_t insn);
|
||||
uint32_t ppc_gdb_get_rt(uint32_t insn);
|
||||
|
||||
int ppc64_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
int cpuid, void *opaque);
|
||||
int ppc32_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||
@@ -2227,6 +2239,10 @@ enum {
|
||||
PPC2_ISA300)
|
||||
};
|
||||
|
||||
#define XOP_RFID 18
|
||||
#define XOP_MFMSR 83
|
||||
#define XOP_MTSPR 467
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Memory access type :
|
||||
* may be needed for precise access rights control and precise exceptions.
|
||||
|
@@ -107,6 +107,26 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
|
||||
return POWERPC_EXCP_RESET;
|
||||
}
|
||||
|
||||
static uint64_t ppc_excp_vector_offset(CPUState *cs, int ail)
|
||||
{
|
||||
uint64_t offset = 0;
|
||||
|
||||
switch (ail) {
|
||||
case AIL_NONE:
|
||||
break;
|
||||
case AIL_0001_8000:
|
||||
offset = 0x18000;
|
||||
break;
|
||||
case AIL_C000_0000_0000_4000:
|
||||
offset = 0xc000000000004000ull;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "Invalid AIL combination %d\n", ail);
|
||||
break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Note that this function should be greatly optimized
|
||||
* when called with a constant excp, from ppc_hw_interrupt
|
||||
@@ -708,17 +728,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
/* Handle AIL */
|
||||
if (ail) {
|
||||
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
|
||||
switch(ail) {
|
||||
case AIL_0001_8000:
|
||||
vector |= 0x18000;
|
||||
break;
|
||||
case AIL_C000_0000_0000_4000:
|
||||
vector |= 0xc000000000004000ull;
|
||||
break;
|
||||
default:
|
||||
cpu_abort(cs, "Invalid AIL combination %d\n", ail);
|
||||
break;
|
||||
}
|
||||
vector |= ppc_excp_vector_offset(cs, ail);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
@@ -760,6 +770,17 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
check_tlb_flush(env, false);
|
||||
}
|
||||
|
||||
target_ulong ppc_get_trace_int_handler_addr(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int ail;
|
||||
|
||||
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
|
||||
return env->excp_vectors[POWERPC_EXCP_TRACE] |
|
||||
ppc_excp_vector_offset(cs, ail);
|
||||
}
|
||||
|
||||
void ppc_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
|
@@ -380,3 +380,38 @@ const char *ppc_gdb_get_dynamic_xml(CPUState *cs, const char *xml_name)
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t ppc_gdb_read_insn(CPUState *cs, target_ulong addr)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint32_t insn;
|
||||
|
||||
cpu_memory_rw_debug(cs, addr, (uint8_t *)&insn, sizeof(insn), 0);
|
||||
|
||||
if (msr_le) {
|
||||
return ldl_le_p(&insn);
|
||||
} else {
|
||||
return ldl_be_p(&insn);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ppc_gdb_get_op(uint32_t insn)
|
||||
{
|
||||
return extract32(insn, 26, 6);
|
||||
}
|
||||
|
||||
uint32_t ppc_gdb_get_xop(uint32_t insn)
|
||||
{
|
||||
return extract32(insn, 1, 10);
|
||||
}
|
||||
|
||||
uint32_t ppc_gdb_get_spr(uint32_t insn)
|
||||
{
|
||||
return extract32(insn, 11, 5) << 5 | extract32(insn, 16, 5);
|
||||
}
|
||||
|
||||
uint32_t ppc_gdb_get_rt(uint32_t insn)
|
||||
{
|
||||
return extract32(insn, 21, 5);
|
||||
}
|
||||
|
314
target/ppc/kvm.c
314
target/ppc/kvm.c
@@ -1554,6 +1554,86 @@ void kvm_arch_remove_all_hw_breakpoints(void)
|
||||
nb_hw_breakpoint = nb_hw_watchpoint = 0;
|
||||
}
|
||||
|
||||
void kvm_arch_set_singlestep(CPUState *cs, int enabled)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong trace_handler_addr;
|
||||
uint32_t insn;
|
||||
bool rfid;
|
||||
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
insn = ppc_gdb_read_insn(cs, env->nip);
|
||||
|
||||
/*
|
||||
* rfid needs special handling because it:
|
||||
* - overwrites NIP with SRR0;
|
||||
* - overwrites MSR with SRR1;
|
||||
* - cannot be single stepped.
|
||||
*/
|
||||
rfid = ppc_gdb_get_op(insn) == 19 && ppc_gdb_get_xop(insn) == XOP_RFID;
|
||||
|
||||
if (rfid && kvm_find_sw_breakpoint(cs, env->spr[SPR_SRR0])) {
|
||||
/*
|
||||
* There is a breakpoint at the next instruction address. It
|
||||
* will already cause the vm exit we need for the single step,
|
||||
* so there's nothing to be done.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the registers that will be affected by the single step
|
||||
* mechanism. These will be restored after the step at
|
||||
* kvm_handle_singlestep.
|
||||
*/
|
||||
env->sstep_msr = env->msr;
|
||||
env->sstep_srr0 = env->spr[SPR_SRR0];
|
||||
env->sstep_srr1 = env->spr[SPR_SRR1];
|
||||
|
||||
/*
|
||||
* MSR_SE = 1 will cause a Trace Interrupt in the guest after the
|
||||
* next instruction executes. If this is a rfid, use SRR1 instead
|
||||
* of MSR.
|
||||
*/
|
||||
if (rfid) {
|
||||
if ((env->spr[SPR_SRR1] >> MSR_SE) & 1) {
|
||||
/*
|
||||
* The guest is doing a single step itself. Make sure we
|
||||
* restore it later.
|
||||
*/
|
||||
env->sstep_msr |= (1ULL << MSR_SE);
|
||||
}
|
||||
|
||||
env->spr[SPR_SRR1] |= (1ULL << MSR_SE);
|
||||
} else {
|
||||
env->msr |= (1ULL << MSR_SE);
|
||||
}
|
||||
|
||||
/*
|
||||
* We set a breakpoint at the interrupt handler address so
|
||||
* that the singlestep will be seen by KVM (this is treated by
|
||||
* KVM like an ordinary breakpoint) and control is returned to
|
||||
* QEMU.
|
||||
*/
|
||||
trace_handler_addr = ppc_get_trace_int_handler_addr(cs);
|
||||
|
||||
if (env->nip == trace_handler_addr) {
|
||||
/*
|
||||
* We are trying to step over the interrupt handler
|
||||
* address itself; move the breakpoint to the next
|
||||
* instruction.
|
||||
*/
|
||||
trace_handler_addr += 4;
|
||||
}
|
||||
|
||||
kvm_insert_breakpoint(cs, trace_handler_addr, 4, GDB_BREAKPOINT_SW);
|
||||
}
|
||||
|
||||
void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
|
||||
{
|
||||
int n;
|
||||
@@ -1593,70 +1673,194 @@ void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Revert any side-effects caused during single step */
|
||||
static void restore_singlestep_env(CPUState *cs)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint32_t insn;
|
||||
int reg;
|
||||
int spr;
|
||||
|
||||
insn = ppc_gdb_read_insn(cs, env->spr[SPR_SRR0] - 4);
|
||||
|
||||
env->spr[SPR_SRR0] = env->sstep_srr0;
|
||||
env->spr[SPR_SRR1] = env->sstep_srr1;
|
||||
|
||||
if (ppc_gdb_get_op(insn) != 31) {
|
||||
return;
|
||||
}
|
||||
|
||||
reg = ppc_gdb_get_rt(insn);
|
||||
|
||||
switch (ppc_gdb_get_xop(insn)) {
|
||||
case XOP_MTSPR:
|
||||
/*
|
||||
* mtspr: the guest altered the SRR, so do not use the
|
||||
* pre-step value.
|
||||
*/
|
||||
spr = ppc_gdb_get_spr(insn);
|
||||
if (spr == SPR_SRR0 || spr == SPR_SRR1) {
|
||||
env->spr[spr] = env->gpr[reg];
|
||||
}
|
||||
break;
|
||||
case XOP_MFMSR:
|
||||
/*
|
||||
* mfmsr: clear MSR_SE bit to avoid the guest knowing
|
||||
* that it is being single-stepped.
|
||||
*/
|
||||
env->gpr[reg] &= ~(1ULL << MSR_SE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_handle_singlestep(CPUState *cs, target_ulong address)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
target_ulong trace_handler_addr;
|
||||
|
||||
if (kvm_has_guestdbg_singlestep()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
trace_handler_addr = ppc_get_trace_int_handler_addr(cs);
|
||||
|
||||
if (address == trace_handler_addr) {
|
||||
kvm_remove_breakpoint(cs, trace_handler_addr, 4, GDB_BREAKPOINT_SW);
|
||||
|
||||
if (env->sstep_msr & (1ULL << MSR_SE)) {
|
||||
/*
|
||||
* The guest expects the last instruction to have caused a
|
||||
* single step, go back into the interrupt handler.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
env->nip = env->spr[SPR_SRR0];
|
||||
/* Bits 33-36, 43-47 are set by the interrupt */
|
||||
env->msr = env->spr[SPR_SRR1] & ~(1ULL << MSR_SE |
|
||||
PPC_BITMASK(33, 36) |
|
||||
PPC_BITMASK(43, 47));
|
||||
restore_singlestep_env(cs);
|
||||
|
||||
} else if (address == trace_handler_addr + 4) {
|
||||
/*
|
||||
* A step at trace_handler_addr would interfere with the
|
||||
* singlestep mechanism itself, so we have previously
|
||||
* displaced the breakpoint to the next instruction.
|
||||
*/
|
||||
kvm_remove_breakpoint(cs, trace_handler_addr + 4, 4, GDB_BREAKPOINT_SW);
|
||||
restore_singlestep_env(cs);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kvm_handle_hw_breakpoint(CPUState *cs,
|
||||
struct kvm_debug_exit_arch *arch_info)
|
||||
{
|
||||
int handle = 0;
|
||||
int n;
|
||||
int flag = 0;
|
||||
|
||||
if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
|
||||
if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
|
||||
n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
|
||||
if (n >= 0) {
|
||||
handle = 1;
|
||||
}
|
||||
} else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
|
||||
KVMPPC_DEBUG_WATCH_WRITE)) {
|
||||
n = find_hw_watchpoint(arch_info->address, &flag);
|
||||
if (n >= 0) {
|
||||
handle = 1;
|
||||
cs->watchpoint_hit = &hw_watchpoint;
|
||||
hw_watchpoint.vaddr = hw_debug_points[n].addr;
|
||||
hw_watchpoint.flags = flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static int kvm_handle_sw_breakpoint(CPUState *cs, target_ulong address)
|
||||
{
|
||||
target_ulong trace_handler_addr;
|
||||
|
||||
if (kvm_has_guestdbg_singlestep()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
trace_handler_addr = ppc_get_trace_int_handler_addr(cs);
|
||||
|
||||
if (address == trace_handler_addr) {
|
||||
CPU_FOREACH(cs) {
|
||||
if (cs->singlestep_enabled) {
|
||||
/*
|
||||
* We hit this breakpoint while another cpu is doing a
|
||||
* software single step. Go back into the guest to
|
||||
* give chance for the single step to finish.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
struct kvm_debug_exit_arch *arch_info = &run->debug.arch;
|
||||
int handle = 0;
|
||||
int n;
|
||||
int flag = 0;
|
||||
|
||||
if (cs->singlestep_enabled) {
|
||||
handle = 1;
|
||||
} else if (arch_info->status) {
|
||||
if (nb_hw_breakpoint + nb_hw_watchpoint > 0) {
|
||||
if (arch_info->status & KVMPPC_DEBUG_BREAKPOINT) {
|
||||
n = find_hw_breakpoint(arch_info->address, GDB_BREAKPOINT_HW);
|
||||
if (n >= 0) {
|
||||
handle = 1;
|
||||
}
|
||||
} else if (arch_info->status & (KVMPPC_DEBUG_WATCH_READ |
|
||||
KVMPPC_DEBUG_WATCH_WRITE)) {
|
||||
n = find_hw_watchpoint(arch_info->address, &flag);
|
||||
if (n >= 0) {
|
||||
handle = 1;
|
||||
cs->watchpoint_hit = &hw_watchpoint;
|
||||
hw_watchpoint.vaddr = hw_debug_points[n].addr;
|
||||
hw_watchpoint.flags = flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
|
||||
handle = 1;
|
||||
} else {
|
||||
/* QEMU is not able to handle debug exception, so inject
|
||||
* program exception to guest;
|
||||
* Yes program exception NOT debug exception !!
|
||||
* When QEMU is using debug resources then debug exception must
|
||||
* be always set. To achieve this we set MSR_DE and also set
|
||||
* MSRP_DEP so guest cannot change MSR_DE.
|
||||
* When emulating debug resource for guest we want guest
|
||||
* to control MSR_DE (enable/disable debug interrupt on need).
|
||||
* Supporting both configurations are NOT possible.
|
||||
* So the result is that we cannot share debug resources
|
||||
* between QEMU and Guest on BOOKE architecture.
|
||||
* In the current design QEMU gets the priority over guest,
|
||||
* this means that if QEMU is using debug resources then guest
|
||||
* cannot use them;
|
||||
* For software breakpoint QEMU uses a privileged instruction;
|
||||
* So there cannot be any reason that we are here for guest
|
||||
* set debug exception, only possibility is guest executed a
|
||||
* privileged / illegal instruction and that's why we are
|
||||
* injecting a program interrupt.
|
||||
*/
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
/* env->nip is PC, so increment this by 4 to use
|
||||
* ppc_cpu_do_interrupt(), which set srr0 = env->nip - 4.
|
||||
*/
|
||||
env->nip += 4;
|
||||
cs->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_INVAL;
|
||||
ppc_cpu_do_interrupt(cs);
|
||||
return kvm_handle_singlestep(cs, arch_info->address);
|
||||
}
|
||||
|
||||
return handle;
|
||||
if (arch_info->status) {
|
||||
return kvm_handle_hw_breakpoint(cs, arch_info);
|
||||
}
|
||||
|
||||
if (kvm_find_sw_breakpoint(cs, arch_info->address)) {
|
||||
return kvm_handle_sw_breakpoint(cs, arch_info->address);
|
||||
}
|
||||
|
||||
/*
|
||||
* QEMU is not able to handle debug exception, so inject
|
||||
* program exception to guest;
|
||||
* Yes program exception NOT debug exception !!
|
||||
* When QEMU is using debug resources then debug exception must
|
||||
* be always set. To achieve this we set MSR_DE and also set
|
||||
* MSRP_DEP so guest cannot change MSR_DE.
|
||||
* When emulating debug resource for guest we want guest
|
||||
* to control MSR_DE (enable/disable debug interrupt on need).
|
||||
* Supporting both configurations are NOT possible.
|
||||
* So the result is that we cannot share debug resources
|
||||
* between QEMU and Guest on BOOKE architecture.
|
||||
* In the current design QEMU gets the priority over guest,
|
||||
* this means that if QEMU is using debug resources then guest
|
||||
* cannot use them;
|
||||
* For software breakpoint QEMU uses a privileged instruction;
|
||||
* So there cannot be any reason that we are here for guest
|
||||
* set debug exception, only possibility is guest executed a
|
||||
* privileged / illegal instruction and that's why we are
|
||||
* injecting a program interrupt.
|
||||
*/
|
||||
cpu_synchronize_state(cs);
|
||||
/*
|
||||
* env->nip is PC, so increment this by 4 to use
|
||||
* ppc_cpu_do_interrupt(), which set srr0 = env->nip - 4.
|
||||
*/
|
||||
env->nip += 4;
|
||||
cs->exception_index = POWERPC_EXCP_PROGRAM;
|
||||
env->error_code = POWERPC_EXCP_INVAL;
|
||||
ppc_cpu_do_interrupt(cs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
|
||||
|
Reference in New Issue
Block a user