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