Compare commits
	
		
			5 Commits
		
	
	
		
			v6.0.0-rc2
			...
			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