cpu: Add callback to check architectural watchpoint match
When QEMU watchpoint matches, that is not definitely an architectural watchpoint match yet. If it is a stop-before-access watchpoint then that is hardly possible to ignore it after throwing a TCG exception. A special callback is introduced to check for architectural watchpoint match before raising a TCG exception. Signed-off-by: Sergey Fedorov <serge.fdrv@gmail.com> Message-id: 1454256948-10485-2-git-send-email-serge.fdrv@gmail.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
				
					committed by
					
						
						Peter Maydell
					
				
			
			
				
	
			
			
			
						parent
						
							7d197d2db5
						
					
				
				
					commit
					568496c0c0
				
			
							
								
								
									
										6
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								exec.c
									
									
									
									
									
								
							@@ -2070,6 +2070,7 @@ static const MemoryRegionOps notdirty_mem_ops = {
 | 
				
			|||||||
static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
 | 
					static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    CPUState *cpu = current_cpu;
 | 
					    CPUState *cpu = current_cpu;
 | 
				
			||||||
 | 
					    CPUClass *cc = CPU_GET_CLASS(cpu);
 | 
				
			||||||
    CPUArchState *env = cpu->env_ptr;
 | 
					    CPUArchState *env = cpu->env_ptr;
 | 
				
			||||||
    target_ulong pc, cs_base;
 | 
					    target_ulong pc, cs_base;
 | 
				
			||||||
    target_ulong vaddr;
 | 
					    target_ulong vaddr;
 | 
				
			||||||
@@ -2095,6 +2096,11 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
 | 
				
			|||||||
            wp->hitaddr = vaddr;
 | 
					            wp->hitaddr = vaddr;
 | 
				
			||||||
            wp->hitattrs = attrs;
 | 
					            wp->hitattrs = attrs;
 | 
				
			||||||
            if (!cpu->watchpoint_hit) {
 | 
					            if (!cpu->watchpoint_hit) {
 | 
				
			||||||
 | 
					                if (wp->flags & BP_CPU &&
 | 
				
			||||||
 | 
					                    !cc->debug_check_watchpoint(cpu, wp)) {
 | 
				
			||||||
 | 
					                    wp->flags &= ~BP_WATCHPOINT_HIT;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                cpu->watchpoint_hit = wp;
 | 
					                cpu->watchpoint_hit = wp;
 | 
				
			||||||
                tb_check_watchpoint(cpu);
 | 
					                tb_check_watchpoint(cpu);
 | 
				
			||||||
                if (wp->flags & BP_STOP_BEFORE_ACCESS) {
 | 
					                if (wp->flags & BP_STOP_BEFORE_ACCESS) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,6 +64,7 @@ typedef uint64_t vaddr;
 | 
				
			|||||||
#define CPU_GET_CLASS(obj) OBJECT_GET_CLASS(CPUClass, (obj), TYPE_CPU)
 | 
					#define CPU_GET_CLASS(obj) OBJECT_GET_CLASS(CPUClass, (obj), TYPE_CPU)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct CPUState CPUState;
 | 
					typedef struct CPUState CPUState;
 | 
				
			||||||
 | 
					typedef struct CPUWatchpoint CPUWatchpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
 | 
					typedef void (*CPUUnassignedAccess)(CPUState *cpu, hwaddr addr,
 | 
				
			||||||
                                    bool is_write, bool is_exec, int opaque,
 | 
					                                    bool is_write, bool is_exec, int opaque,
 | 
				
			||||||
@@ -106,6 +107,8 @@ struct TranslationBlock;
 | 
				
			|||||||
 *       a memory access with the specified memory transaction attributes.
 | 
					 *       a memory access with the specified memory transaction attributes.
 | 
				
			||||||
 * @gdb_read_register: Callback for letting GDB read a register.
 | 
					 * @gdb_read_register: Callback for letting GDB read a register.
 | 
				
			||||||
 * @gdb_write_register: Callback for letting GDB write a register.
 | 
					 * @gdb_write_register: Callback for letting GDB write a register.
 | 
				
			||||||
 | 
					 * @debug_check_watchpoint: Callback: return true if the architectural
 | 
				
			||||||
 | 
					 *       watchpoint whose address has matched should really fire.
 | 
				
			||||||
 * @debug_excp_handler: Callback for handling debug exceptions.
 | 
					 * @debug_excp_handler: Callback for handling debug exceptions.
 | 
				
			||||||
 * @write_elf64_note: Callback for writing a CPU-specific ELF note to a
 | 
					 * @write_elf64_note: Callback for writing a CPU-specific ELF note to a
 | 
				
			||||||
 * 64-bit VM coredump.
 | 
					 * 64-bit VM coredump.
 | 
				
			||||||
@@ -165,6 +168,7 @@ typedef struct CPUClass {
 | 
				
			|||||||
    int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
 | 
					    int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
 | 
				
			||||||
    int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
 | 
					    int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
 | 
				
			||||||
    int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
 | 
					    int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
 | 
				
			||||||
 | 
					    bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
 | 
				
			||||||
    void (*debug_excp_handler)(CPUState *cpu);
 | 
					    void (*debug_excp_handler)(CPUState *cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
 | 
					    int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
 | 
				
			||||||
@@ -207,14 +211,14 @@ typedef struct CPUBreakpoint {
 | 
				
			|||||||
    QTAILQ_ENTRY(CPUBreakpoint) entry;
 | 
					    QTAILQ_ENTRY(CPUBreakpoint) entry;
 | 
				
			||||||
} CPUBreakpoint;
 | 
					} CPUBreakpoint;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct CPUWatchpoint {
 | 
					struct CPUWatchpoint {
 | 
				
			||||||
    vaddr vaddr;
 | 
					    vaddr vaddr;
 | 
				
			||||||
    vaddr len;
 | 
					    vaddr len;
 | 
				
			||||||
    vaddr hitaddr;
 | 
					    vaddr hitaddr;
 | 
				
			||||||
    MemTxAttrs hitattrs;
 | 
					    MemTxAttrs hitattrs;
 | 
				
			||||||
    int flags; /* BP_* */
 | 
					    int flags; /* BP_* */
 | 
				
			||||||
    QTAILQ_ENTRY(CPUWatchpoint) entry;
 | 
					    QTAILQ_ENTRY(CPUWatchpoint) entry;
 | 
				
			||||||
} CPUWatchpoint;
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct KVMState;
 | 
					struct KVMState;
 | 
				
			||||||
struct kvm_run;
 | 
					struct kvm_run;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -189,6 +189,14 @@ static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* If no extra check is required, QEMU watchpoint match can be considered
 | 
				
			||||||
 | 
					     * as an architectural match.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool target_words_bigendian(void);
 | 
					bool target_words_bigendian(void);
 | 
				
			||||||
static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
 | 
					static bool cpu_common_virtio_is_big_endian(CPUState *cpu)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -353,6 +361,7 @@ static void cpu_class_init(ObjectClass *klass, void *data)
 | 
				
			|||||||
    k->gdb_write_register = cpu_common_gdb_write_register;
 | 
					    k->gdb_write_register = cpu_common_gdb_write_register;
 | 
				
			||||||
    k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
 | 
					    k->virtio_is_big_endian = cpu_common_virtio_is_big_endian;
 | 
				
			||||||
    k->debug_excp_handler = cpu_common_noop;
 | 
					    k->debug_excp_handler = cpu_common_noop;
 | 
				
			||||||
 | 
					    k->debug_check_watchpoint = cpu_common_debug_check_watchpoint;
 | 
				
			||||||
    k->cpu_exec_enter = cpu_common_noop;
 | 
					    k->cpu_exec_enter = cpu_common_noop;
 | 
				
			||||||
    k->cpu_exec_exit = cpu_common_noop;
 | 
					    k->cpu_exec_exit = cpu_common_noop;
 | 
				
			||||||
    k->cpu_exec_interrupt = cpu_common_exec_interrupt;
 | 
					    k->cpu_exec_interrupt = cpu_common_exec_interrupt;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user