aboutsummaryrefslogtreecommitdiff
path: root/exec.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2019-08-24 09:51:09 -0700
committerRichard Henderson <richard.henderson@linaro.org>2019-09-03 08:30:39 -0700
commit50b107c5d617eaf93301cef20221312e7a986701 (patch)
tree8ff2f1b256e9847308d30c90fc431d91023e45d1 /exec.c
parent5787585d0406cfd54dda0c71ea1a603347ce6e71 (diff)
downloadqemu-50b107c5d617eaf93301cef20221312e7a986701.zip
qemu-50b107c5d617eaf93301cef20221312e7a986701.tar.gz
qemu-50b107c5d617eaf93301cef20221312e7a986701.tar.bz2
cputlb: Handle watchpoints via TLB_WATCHPOINT
The raising of exceptions from check_watchpoint, buried inside of the I/O subsystem, is fundamentally broken. We do not have the helper return address with which we can unwind guest state. Replace PHYS_SECTION_WATCH and io_mem_watch with TLB_WATCHPOINT. Move the call to cpu_check_watchpoint into the cputlb helpers where we do have the helper return address. This allows watchpoints on RAM to bypass the full i/o access path. Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: David Hildenbrand <david@redhat.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'exec.c')
-rw-r--r--exec.c114
1 files changed, 7 insertions, 107 deletions
diff --git a/exec.c b/exec.c
index 8575ce5..ad0f4a5 100644
--- a/exec.c
+++ b/exec.c
@@ -193,15 +193,12 @@ typedef struct subpage_t {
#define PHYS_SECTION_UNASSIGNED 0
#define PHYS_SECTION_NOTDIRTY 1
#define PHYS_SECTION_ROM 2
-#define PHYS_SECTION_WATCH 3
static void io_mem_init(void);
static void memory_map_init(void);
static void tcg_log_global_after_sync(MemoryListener *listener);
static void tcg_commit(MemoryListener *listener);
-static MemoryRegion io_mem_watch;
-
/**
* CPUAddressSpace: all the information a CPU needs about an AddressSpace
* @cpu: the CPU whose AddressSpace this is
@@ -1472,7 +1469,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
target_ulong *address)
{
hwaddr iotlb;
- int flags, match;
if (memory_region_is_ram(section->mr)) {
/* Normal RAM. */
@@ -1490,19 +1486,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
iotlb += xlat;
}
- /* Avoid trapping reads of pages with a write breakpoint. */
- match = (prot & PAGE_READ ? BP_MEM_READ : 0)
- | (prot & PAGE_WRITE ? BP_MEM_WRITE : 0);
- flags = cpu_watchpoint_address_matches(cpu, vaddr, TARGET_PAGE_SIZE);
- if (flags & match) {
- /*
- * Make accesses to pages with watchpoints go via the
- * watchpoint trap routines.
- */
- iotlb = PHYS_SECTION_WATCH + paddr;
- *address |= TLB_MMIO;
- }
-
return iotlb;
}
#endif /* defined(CONFIG_USER_ONLY) */
@@ -2810,10 +2793,14 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
assert(tcg_enabled());
if (cpu->watchpoint_hit) {
- /* We re-entered the check after replacing the TB. Now raise
- * the debug interrupt so that is will trigger after the
- * current instruction. */
+ /*
+ * We re-entered the check after replacing the TB.
+ * Now raise the debug interrupt so that it will
+ * trigger after the current instruction.
+ */
+ qemu_mutex_lock_iothread();
cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
+ qemu_mutex_unlock_iothread();
return;
}
@@ -2858,88 +2845,6 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
}
}
-static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
-{
- CPUState *cpu = current_cpu;
- vaddr addr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
-
- cpu_check_watchpoint(cpu, addr, len, attrs, flags, 0);
-}
-
-/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
- so these check for a hit then pass through to the normal out-of-line
- phys routines. */
-static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
- unsigned size, MemTxAttrs attrs)
-{
- MemTxResult res;
- uint64_t data;
- int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
- AddressSpace *as = current_cpu->cpu_ases[asidx].as;
-
- check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ);
- switch (size) {
- case 1:
- data = address_space_ldub(as, addr, attrs, &res);
- break;
- case 2:
- data = address_space_lduw(as, addr, attrs, &res);
- break;
- case 4:
- data = address_space_ldl(as, addr, attrs, &res);
- break;
- case 8:
- data = address_space_ldq(as, addr, attrs, &res);
- break;
- default: abort();
- }
- *pdata = data;
- return res;
-}
-
-static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size,
- MemTxAttrs attrs)
-{
- MemTxResult res;
- int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
- AddressSpace *as = current_cpu->cpu_ases[asidx].as;
-
- check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE);
- switch (size) {
- case 1:
- address_space_stb(as, addr, val, attrs, &res);
- break;
- case 2:
- address_space_stw(as, addr, val, attrs, &res);
- break;
- case 4:
- address_space_stl(as, addr, val, attrs, &res);
- break;
- case 8:
- address_space_stq(as, addr, val, attrs, &res);
- break;
- default: abort();
- }
- return res;
-}
-
-static const MemoryRegionOps watch_mem_ops = {
- .read_with_attrs = watch_mem_read,
- .write_with_attrs = watch_mem_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = false,
- },
- .impl = {
- .min_access_size = 1,
- .max_access_size = 8,
- .unaligned = false,
- },
-};
-
static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, uint8_t *buf, hwaddr len);
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
@@ -3115,9 +3020,6 @@ static void io_mem_init(void)
memory_region_init_io(&io_mem_notdirty, NULL, &notdirty_mem_ops, NULL,
NULL, UINT64_MAX);
memory_region_clear_global_locking(&io_mem_notdirty);
-
- memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL,
- NULL, UINT64_MAX);
}
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
@@ -3131,8 +3033,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
assert(n == PHYS_SECTION_NOTDIRTY);
n = dummy_section(&d->map, fv, &io_mem_rom);
assert(n == PHYS_SECTION_ROM);
- n = dummy_section(&d->map, fv, &io_mem_watch);
- assert(n == PHYS_SECTION_WATCH);
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };