Commit 6658ffb81ee56a510d7d77025872a508a9adce3a
1 parent
b35d7448
Watchpoint support (previous commit got eaten by Savannah server crash).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2479 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
186 additions
and
0 deletions
cpu-all.h
| @@ -775,10 +775,13 @@ extern int code_copy_enabled; | @@ -775,10 +775,13 @@ extern int code_copy_enabled; | ||
| 775 | #define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ | 775 | #define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ |
| 776 | #define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ | 776 | #define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ |
| 777 | #define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ | 777 | #define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ |
| 778 | +#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ | ||
| 778 | 779 | ||
| 779 | void cpu_interrupt(CPUState *s, int mask); | 780 | void cpu_interrupt(CPUState *s, int mask); |
| 780 | void cpu_reset_interrupt(CPUState *env, int mask); | 781 | void cpu_reset_interrupt(CPUState *env, int mask); |
| 781 | 782 | ||
| 783 | +int cpu_watchpoint_insert(CPUState *env, target_ulong addr); | ||
| 784 | +int cpu_watchpoint_remove(CPUState *env, target_ulong addr); | ||
| 782 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc); | 785 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc); |
| 783 | int cpu_breakpoint_remove(CPUState *env, target_ulong pc); | 786 | int cpu_breakpoint_remove(CPUState *env, target_ulong pc); |
| 784 | void cpu_single_step(CPUState *env, int enabled); | 787 | void cpu_single_step(CPUState *env, int enabled); |
cpu-defs.h
| @@ -76,6 +76,7 @@ typedef unsigned long ram_addr_t; | @@ -76,6 +76,7 @@ typedef unsigned long ram_addr_t; | ||
| 76 | #define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ | 76 | #define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ |
| 77 | #define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ | 77 | #define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ |
| 78 | #define MAX_BREAKPOINTS 32 | 78 | #define MAX_BREAKPOINTS 32 |
| 79 | +#define MAX_WATCHPOINTS 32 | ||
| 79 | 80 | ||
| 80 | #define TB_JMP_CACHE_BITS 12 | 81 | #define TB_JMP_CACHE_BITS 12 |
| 81 | #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) | 82 | #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) |
| @@ -125,6 +126,13 @@ typedef struct CPUTLBEntry { | @@ -125,6 +126,13 @@ typedef struct CPUTLBEntry { | ||
| 125 | int nb_breakpoints; \ | 126 | int nb_breakpoints; \ |
| 126 | int singlestep_enabled; \ | 127 | int singlestep_enabled; \ |
| 127 | \ | 128 | \ |
| 129 | + struct { \ | ||
| 130 | + target_ulong vaddr; \ | ||
| 131 | + int is_ram; \ | ||
| 132 | + } watchpoint[MAX_WATCHPOINTS]; \ | ||
| 133 | + int nb_watchpoints; \ | ||
| 134 | + int watchpoint_hit; \ | ||
| 135 | + \ | ||
| 128 | void *next_cpu; /* next CPU sharing TB cache */ \ | 136 | void *next_cpu; /* next CPU sharing TB cache */ \ |
| 129 | int cpu_index; /* CPU index (informative) */ \ | 137 | int cpu_index; /* CPU index (informative) */ \ |
| 130 | /* user data */ \ | 138 | /* user data */ \ |
cpu-exec.c
| @@ -409,6 +409,11 @@ int cpu_exec(CPUState *env1) | @@ -409,6 +409,11 @@ int cpu_exec(CPUState *env1) | ||
| 409 | #endif | 409 | #endif |
| 410 | interrupt_request = env->interrupt_request; | 410 | interrupt_request = env->interrupt_request; |
| 411 | if (__builtin_expect(interrupt_request, 0)) { | 411 | if (__builtin_expect(interrupt_request, 0)) { |
| 412 | + if (interrupt_request & CPU_INTERRUPT_DEBUG) { | ||
| 413 | + env->interrupt_request &= ~CPU_INTERRUPT_DEBUG; | ||
| 414 | + env->exception_index = EXCP_DEBUG; | ||
| 415 | + cpu_loop_exit(); | ||
| 416 | + } | ||
| 412 | #if defined(TARGET_I386) | 417 | #if defined(TARGET_I386) |
| 413 | if ((interrupt_request & CPU_INTERRUPT_SMI) && | 418 | if ((interrupt_request & CPU_INTERRUPT_SMI) && |
| 414 | !(env->hflags & HF_SMM_MASK)) { | 419 | !(env->hflags & HF_SMM_MASK)) { |
exec.c
| @@ -128,6 +128,9 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | @@ -128,6 +128,9 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; | ||
| 128 | CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; | 128 | CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; |
| 129 | void *io_mem_opaque[IO_MEM_NB_ENTRIES]; | 129 | void *io_mem_opaque[IO_MEM_NB_ENTRIES]; |
| 130 | static int io_mem_nb; | 130 | static int io_mem_nb; |
| 131 | +#if defined(CONFIG_SOFTMMU) | ||
| 132 | +static int io_mem_watch; | ||
| 133 | +#endif | ||
| 131 | 134 | ||
| 132 | /* log support */ | 135 | /* log support */ |
| 133 | char *logfilename = "/tmp/qemu.log"; | 136 | char *logfilename = "/tmp/qemu.log"; |
| @@ -274,6 +277,7 @@ void cpu_exec_init(CPUState *env) | @@ -274,6 +277,7 @@ void cpu_exec_init(CPUState *env) | ||
| 274 | cpu_index++; | 277 | cpu_index++; |
| 275 | } | 278 | } |
| 276 | env->cpu_index = cpu_index; | 279 | env->cpu_index = cpu_index; |
| 280 | + env->nb_watchpoints = 0; | ||
| 277 | *penv = env; | 281 | *penv = env; |
| 278 | } | 282 | } |
| 279 | 283 | ||
| @@ -1029,6 +1033,44 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) | @@ -1029,6 +1033,44 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc) | ||
| 1029 | } | 1033 | } |
| 1030 | #endif | 1034 | #endif |
| 1031 | 1035 | ||
| 1036 | +/* Add a watchpoint. */ | ||
| 1037 | +int cpu_watchpoint_insert(CPUState *env, target_ulong addr) | ||
| 1038 | +{ | ||
| 1039 | + int i; | ||
| 1040 | + | ||
| 1041 | + for (i = 0; i < env->nb_watchpoints; i++) { | ||
| 1042 | + if (addr == env->watchpoint[i].vaddr) | ||
| 1043 | + return 0; | ||
| 1044 | + } | ||
| 1045 | + if (env->nb_watchpoints >= MAX_WATCHPOINTS) | ||
| 1046 | + return -1; | ||
| 1047 | + | ||
| 1048 | + i = env->nb_watchpoints++; | ||
| 1049 | + env->watchpoint[i].vaddr = addr; | ||
| 1050 | + tlb_flush_page(env, addr); | ||
| 1051 | + /* FIXME: This flush is needed because of the hack to make memory ops | ||
| 1052 | + terminate the TB. It can be removed once the proper IO trap and | ||
| 1053 | + re-execute bits are in. */ | ||
| 1054 | + tb_flush(env); | ||
| 1055 | + return i; | ||
| 1056 | +} | ||
| 1057 | + | ||
| 1058 | +/* Remove a watchpoint. */ | ||
| 1059 | +int cpu_watchpoint_remove(CPUState *env, target_ulong addr) | ||
| 1060 | +{ | ||
| 1061 | + int i; | ||
| 1062 | + | ||
| 1063 | + for (i = 0; i < env->nb_watchpoints; i++) { | ||
| 1064 | + if (addr == env->watchpoint[i].vaddr) { | ||
| 1065 | + env->nb_watchpoints--; | ||
| 1066 | + env->watchpoint[i] = env->watchpoint[env->nb_watchpoints]; | ||
| 1067 | + tlb_flush_page(env, addr); | ||
| 1068 | + return 0; | ||
| 1069 | + } | ||
| 1070 | + } | ||
| 1071 | + return -1; | ||
| 1072 | +} | ||
| 1073 | + | ||
| 1032 | /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a | 1074 | /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a |
| 1033 | breakpoint is reached */ | 1075 | breakpoint is reached */ |
| 1034 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc) | 1076 | int cpu_breakpoint_insert(CPUState *env, target_ulong pc) |
| @@ -1484,6 +1526,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | @@ -1484,6 +1526,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | ||
| 1484 | target_phys_addr_t addend; | 1526 | target_phys_addr_t addend; |
| 1485 | int ret; | 1527 | int ret; |
| 1486 | CPUTLBEntry *te; | 1528 | CPUTLBEntry *te; |
| 1529 | + int i; | ||
| 1487 | 1530 | ||
| 1488 | p = phys_page_find(paddr >> TARGET_PAGE_BITS); | 1531 | p = phys_page_find(paddr >> TARGET_PAGE_BITS); |
| 1489 | if (!p) { | 1532 | if (!p) { |
| @@ -1510,6 +1553,22 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | @@ -1510,6 +1553,22 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr, | ||
| 1510 | address = vaddr; | 1553 | address = vaddr; |
| 1511 | addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); | 1554 | addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); |
| 1512 | } | 1555 | } |
| 1556 | + | ||
| 1557 | + /* Make accesses to pages with watchpoints go via the | ||
| 1558 | + watchpoint trap routines. */ | ||
| 1559 | + for (i = 0; i < env->nb_watchpoints; i++) { | ||
| 1560 | + if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { | ||
| 1561 | + if (address & ~TARGET_PAGE_MASK) { | ||
| 1562 | + env->watchpoint[i].is_ram = 0; | ||
| 1563 | + address = vaddr | io_mem_watch; | ||
| 1564 | + } else { | ||
| 1565 | + env->watchpoint[i].is_ram = 1; | ||
| 1566 | + /* TODO: Figure out how to make read watchpoints coexist | ||
| 1567 | + with code. */ | ||
| 1568 | + pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD; | ||
| 1569 | + } | ||
| 1570 | + } | ||
| 1571 | + } | ||
| 1513 | 1572 | ||
| 1514 | index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); | 1573 | index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 1515 | addend -= vaddr; | 1574 | addend -= vaddr; |
| @@ -1960,6 +2019,85 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = { | @@ -1960,6 +2019,85 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = { | ||
| 1960 | notdirty_mem_writel, | 2019 | notdirty_mem_writel, |
| 1961 | }; | 2020 | }; |
| 1962 | 2021 | ||
| 2022 | +#if defined(CONFIG_SOFTMMU) | ||
| 2023 | +/* Watchpoint access routines. Watchpoints are inserted using TLB tricks, | ||
| 2024 | + so these check for a hit then pass through to the normal out-of-line | ||
| 2025 | + phys routines. */ | ||
| 2026 | +static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) | ||
| 2027 | +{ | ||
| 2028 | + return ldub_phys(addr); | ||
| 2029 | +} | ||
| 2030 | + | ||
| 2031 | +static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) | ||
| 2032 | +{ | ||
| 2033 | + return lduw_phys(addr); | ||
| 2034 | +} | ||
| 2035 | + | ||
| 2036 | +static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) | ||
| 2037 | +{ | ||
| 2038 | + return ldl_phys(addr); | ||
| 2039 | +} | ||
| 2040 | + | ||
| 2041 | +/* Generate a debug exception if a watchpoint has been hit. | ||
| 2042 | + Returns the real physical address of the access. addr will be a host | ||
| 2043 | + address in the is_ram case. */ | ||
| 2044 | +static target_ulong check_watchpoint(target_phys_addr_t addr) | ||
| 2045 | +{ | ||
| 2046 | + CPUState *env = cpu_single_env; | ||
| 2047 | + target_ulong watch; | ||
| 2048 | + target_ulong retaddr; | ||
| 2049 | + int i; | ||
| 2050 | + | ||
| 2051 | + retaddr = addr; | ||
| 2052 | + for (i = 0; i < env->nb_watchpoints; i++) { | ||
| 2053 | + watch = env->watchpoint[i].vaddr; | ||
| 2054 | + if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) { | ||
| 2055 | + if (env->watchpoint[i].is_ram) | ||
| 2056 | + retaddr = addr - (unsigned long)phys_ram_base; | ||
| 2057 | + if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) { | ||
| 2058 | + cpu_single_env->watchpoint_hit = i + 1; | ||
| 2059 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG); | ||
| 2060 | + break; | ||
| 2061 | + } | ||
| 2062 | + } | ||
| 2063 | + } | ||
| 2064 | + return retaddr; | ||
| 2065 | +} | ||
| 2066 | + | ||
| 2067 | +static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, | ||
| 2068 | + uint32_t val) | ||
| 2069 | +{ | ||
| 2070 | + addr = check_watchpoint(addr); | ||
| 2071 | + stb_phys(addr, val); | ||
| 2072 | +} | ||
| 2073 | + | ||
| 2074 | +static void watch_mem_writew(void *opaque, target_phys_addr_t addr, | ||
| 2075 | + uint32_t val) | ||
| 2076 | +{ | ||
| 2077 | + addr = check_watchpoint(addr); | ||
| 2078 | + stw_phys(addr, val); | ||
| 2079 | +} | ||
| 2080 | + | ||
| 2081 | +static void watch_mem_writel(void *opaque, target_phys_addr_t addr, | ||
| 2082 | + uint32_t val) | ||
| 2083 | +{ | ||
| 2084 | + addr = check_watchpoint(addr); | ||
| 2085 | + stl_phys(addr, val); | ||
| 2086 | +} | ||
| 2087 | + | ||
| 2088 | +static CPUReadMemoryFunc *watch_mem_read[3] = { | ||
| 2089 | + watch_mem_readb, | ||
| 2090 | + watch_mem_readw, | ||
| 2091 | + watch_mem_readl, | ||
| 2092 | +}; | ||
| 2093 | + | ||
| 2094 | +static CPUWriteMemoryFunc *watch_mem_write[3] = { | ||
| 2095 | + watch_mem_writeb, | ||
| 2096 | + watch_mem_writew, | ||
| 2097 | + watch_mem_writel, | ||
| 2098 | +}; | ||
| 2099 | +#endif | ||
| 2100 | + | ||
| 1963 | static void io_mem_init(void) | 2101 | static void io_mem_init(void) |
| 1964 | { | 2102 | { |
| 1965 | cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); | 2103 | cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL); |
| @@ -1967,6 +2105,10 @@ static void io_mem_init(void) | @@ -1967,6 +2105,10 @@ static void io_mem_init(void) | ||
| 1967 | cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); | 2105 | cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL); |
| 1968 | io_mem_nb = 5; | 2106 | io_mem_nb = 5; |
| 1969 | 2107 | ||
| 2108 | +#if defined(CONFIG_SOFTMMU) | ||
| 2109 | + io_mem_watch = cpu_register_io_memory(-1, watch_mem_read, | ||
| 2110 | + watch_mem_write, NULL); | ||
| 2111 | +#endif | ||
| 1970 | /* alloc dirty bits array */ | 2112 | /* alloc dirty bits array */ |
| 1971 | phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); | 2113 | phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); |
| 1972 | memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); | 2114 | memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS); |
gdbstub.c
| @@ -856,6 +856,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) | @@ -856,6 +856,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) | ||
| 856 | if (cpu_breakpoint_insert(env, addr) < 0) | 856 | if (cpu_breakpoint_insert(env, addr) < 0) |
| 857 | goto breakpoint_error; | 857 | goto breakpoint_error; |
| 858 | put_packet(s, "OK"); | 858 | put_packet(s, "OK"); |
| 859 | +#ifndef CONFIG_USER_ONLY | ||
| 860 | + } else if (type == 2) { | ||
| 861 | + if (cpu_watchpoint_insert(env, addr) < 0) | ||
| 862 | + goto breakpoint_error; | ||
| 863 | + put_packet(s, "OK"); | ||
| 864 | +#endif | ||
| 859 | } else { | 865 | } else { |
| 860 | breakpoint_error: | 866 | breakpoint_error: |
| 861 | put_packet(s, "E22"); | 867 | put_packet(s, "E22"); |
| @@ -872,6 +878,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) | @@ -872,6 +878,11 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) | ||
| 872 | if (type == 0 || type == 1) { | 878 | if (type == 0 || type == 1) { |
| 873 | cpu_breakpoint_remove(env, addr); | 879 | cpu_breakpoint_remove(env, addr); |
| 874 | put_packet(s, "OK"); | 880 | put_packet(s, "OK"); |
| 881 | +#ifndef CONFIG_USER_ONLY | ||
| 882 | + } else if (type == 2) { | ||
| 883 | + cpu_watchpoint_remove(env, addr); | ||
| 884 | + put_packet(s, "OK"); | ||
| 885 | +#endif | ||
| 875 | } else { | 886 | } else { |
| 876 | goto breakpoint_error; | 887 | goto breakpoint_error; |
| 877 | } | 888 | } |
| @@ -914,6 +925,13 @@ static void gdb_vm_stopped(void *opaque, int reason) | @@ -914,6 +925,13 @@ static void gdb_vm_stopped(void *opaque, int reason) | ||
| 914 | cpu_single_step(s->env, 0); | 925 | cpu_single_step(s->env, 0); |
| 915 | 926 | ||
| 916 | if (reason == EXCP_DEBUG) { | 927 | if (reason == EXCP_DEBUG) { |
| 928 | + if (s->env->watchpoint_hit) { | ||
| 929 | + snprintf(buf, sizeof(buf), "T%02xwatch:%x;", SIGTRAP, | ||
| 930 | + s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr); | ||
| 931 | + put_packet(s, buf); | ||
| 932 | + s->env->watchpoint_hit = 0; | ||
| 933 | + return; | ||
| 934 | + } | ||
| 917 | tb_flush(s->env); | 935 | tb_flush(s->env); |
| 918 | ret = SIGTRAP; | 936 | ret = SIGTRAP; |
| 919 | } else if (reason == EXCP_INTERRUPT) { | 937 | } else if (reason == EXCP_INTERRUPT) { |
target-arm/translate.c
| @@ -45,6 +45,7 @@ typedef struct DisasContext { | @@ -45,6 +45,7 @@ typedef struct DisasContext { | ||
| 45 | struct TranslationBlock *tb; | 45 | struct TranslationBlock *tb; |
| 46 | int singlestep_enabled; | 46 | int singlestep_enabled; |
| 47 | int thumb; | 47 | int thumb; |
| 48 | + int is_mem; | ||
| 48 | #if !defined(CONFIG_USER_ONLY) | 49 | #if !defined(CONFIG_USER_ONLY) |
| 49 | int user; | 50 | int user; |
| 50 | #endif | 51 | #endif |
| @@ -290,6 +291,7 @@ static inline void gen_bx(DisasContext *s) | @@ -290,6 +291,7 @@ static inline void gen_bx(DisasContext *s) | ||
| 290 | #define gen_ldst(name, s) gen_op_##name##_raw() | 291 | #define gen_ldst(name, s) gen_op_##name##_raw() |
| 291 | #else | 292 | #else |
| 292 | #define gen_ldst(name, s) do { \ | 293 | #define gen_ldst(name, s) do { \ |
| 294 | + s->is_mem = 1; \ | ||
| 293 | if (IS_USER(s)) \ | 295 | if (IS_USER(s)) \ |
| 294 | gen_op_##name##_user(); \ | 296 | gen_op_##name##_user(); \ |
| 295 | else \ | 297 | else \ |
| @@ -1612,6 +1614,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | @@ -1612,6 +1614,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) | ||
| 1612 | gen_add_data_offset(s, insn); | 1614 | gen_add_data_offset(s, insn); |
| 1613 | if (insn & (1 << 20)) { | 1615 | if (insn & (1 << 20)) { |
| 1614 | /* load */ | 1616 | /* load */ |
| 1617 | + s->is_mem = 1; | ||
| 1615 | #if defined(CONFIG_USER_ONLY) | 1618 | #if defined(CONFIG_USER_ONLY) |
| 1616 | if (insn & (1 << 22)) | 1619 | if (insn & (1 << 22)) |
| 1617 | gen_op_ldub_raw(); | 1620 | gen_op_ldub_raw(); |
| @@ -2409,6 +2412,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2409,6 +2412,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2409 | dc->singlestep_enabled = env->singlestep_enabled; | 2412 | dc->singlestep_enabled = env->singlestep_enabled; |
| 2410 | dc->condjmp = 0; | 2413 | dc->condjmp = 0; |
| 2411 | dc->thumb = env->thumb; | 2414 | dc->thumb = env->thumb; |
| 2415 | + dc->is_mem = 0; | ||
| 2412 | #if !defined(CONFIG_USER_ONLY) | 2416 | #if !defined(CONFIG_USER_ONLY) |
| 2413 | dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; | 2417 | dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; |
| 2414 | #endif | 2418 | #endif |
| @@ -2447,6 +2451,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | @@ -2447,6 +2451,12 @@ static inline int gen_intermediate_code_internal(CPUState *env, | ||
| 2447 | gen_set_label(dc->condlabel); | 2451 | gen_set_label(dc->condlabel); |
| 2448 | dc->condjmp = 0; | 2452 | dc->condjmp = 0; |
| 2449 | } | 2453 | } |
| 2454 | + /* Terminate the TB on memory ops if watchpoints are present. */ | ||
| 2455 | + /* FIXME: This should be replacd by the deterministic execution | ||
| 2456 | + * IRQ raising bits. */ | ||
| 2457 | + if (dc->is_mem && env->nb_watchpoints) | ||
| 2458 | + break; | ||
| 2459 | + | ||
| 2450 | /* Translation stops when a conditional branch is enoutered. | 2460 | /* Translation stops when a conditional branch is enoutered. |
| 2451 | * Otherwise the subsequent code could get translated several times. | 2461 | * Otherwise the subsequent code could get translated several times. |
| 2452 | * Also stop translation when a page boundary is reached. This | 2462 | * Also stop translation when a page boundary is reached. This |