From: Jan Kiszka <jan.kiszka@web.de>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 3/5] Add read watchpoint support
Date: Sat, 31 May 2008 15:15:33 +0200 [thread overview]
Message-ID: <48414F75.5080202@web.de> (raw)
In-Reply-To: <48414AC8.7080206@web.de>
This patch adds read access detection to the watchpoint subsystem. It
adds a few additional instructions to the io_read path even when
watchpoints are disabled. Me feeling is that this does not cause a
relevant slowdown and can be justified by the enhanced feature set.
But I must say that the softmmu subsystem of QEMU is not yet my home. So
parts of this patch were not really designed, but engineered ;).
Nevertheless, things work smoothly for me, no regressions found so far.
Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
---
cpu-defs.h | 8 +++---
exec.c | 70 ++++++++++++++++++++++++++++-------------------------
softmmu_template.h | 15 +++++++----
3 files changed, 52 insertions(+), 41 deletions(-)
Index: b/exec.c
===================================================================
--- a/exec.c
+++ b/exec.c
@@ -808,9 +808,9 @@ void tb_invalidate_phys_page_range(targe
if (current_tb_not_found) {
current_tb_not_found = 0;
current_tb = NULL;
- if (env->mem_write_pc) {
+ if (env->iomem_access_pc) {
/* now we have a real cpu fault */
- current_tb = tb_find_pc(env->mem_write_pc);
+ current_tb = tb_find_pc(env->iomem_access_pc);
}
}
if (current_tb == tb &&
@@ -823,7 +823,7 @@ void tb_invalidate_phys_page_range(targe
current_tb_modified = 1;
cpu_restore_state(current_tb, env,
- env->mem_write_pc, NULL);
+ env->iomem_access_pc, NULL);
#if defined(TARGET_I386)
current_flags = env->hflags;
current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
@@ -855,7 +855,7 @@ void tb_invalidate_phys_page_range(targe
if (!p->first_tb) {
invalidate_page_bitmap(p);
if (is_cpu_write_access) {
- tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
+ tlb_unprotect_code_phys(env, start, env->iomem_access_vaddr);
}
}
#endif
@@ -881,7 +881,7 @@ static inline void tb_invalidate_phys_pa
if (1) {
if (loglevel) {
fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
- cpu_single_env->mem_write_vaddr, len,
+ cpu_single_env->iomem_access_vaddr, len,
cpu_single_env->eip,
cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
}
@@ -1769,7 +1769,7 @@ int tlb_set_page_exec(CPUState *env, tar
PhysPageDesc *p;
unsigned long pd;
unsigned int index;
- target_ulong address;
+ target_ulong address, address_read;
target_phys_addr_t addend;
int ret;
CPUTLBEntry *te;
@@ -1801,18 +1801,18 @@ int tlb_set_page_exec(CPUState *env, tar
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
}
+ address_read = address;
/* Make accesses to pages with watchpoints go via the
watchpoint trap routines. */
for (i = 0; i < env->nb_watchpoints; i++) {
if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
if (address & ~TARGET_PAGE_MASK) {
env->watchpoint[i].addend = 0;
- address = vaddr | io_mem_watch;
+ address_read = address = vaddr | io_mem_watch;
} else {
env->watchpoint[i].addend = pd - paddr +
(unsigned long) phys_ram_base;
- /* TODO: Figure out how to make read watchpoints coexist
- with code. */
+ address_read = vaddr | io_mem_watch;
pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
}
}
@@ -1823,7 +1823,7 @@ int tlb_set_page_exec(CPUState *env, tar
te = &env->tlb_table[mmu_idx][index];
te->addend = addend;
if (prot & PAGE_READ) {
- te->addr_read = address;
+ te->addr_read = address_read;
} else {
te->addr_read = -1;
}
@@ -2304,7 +2304,8 @@ static void notdirty_mem_writeb(void *op
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, addr,
+ cpu_single_env->iomem_access_vaddr);
}
static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2330,7 +2331,8 @@ static void notdirty_mem_writew(void *op
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, addr,
+ cpu_single_env->iomem_access_vaddr);
}
static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2356,7 +2358,8 @@ static void notdirty_mem_writel(void *op
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
+ tlb_set_dirty(cpu_single_env, addr,
+ cpu_single_env->iomem_access_vaddr);
}
static CPUReadMemoryFunc *error_mem_read[3] = {
@@ -2372,24 +2375,6 @@ static CPUWriteMemoryFunc *notdirty_mem_
};
#if defined(CONFIG_SOFTMMU)
-/* 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 uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- return ldub_phys(addr);
-}
-
-static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- return lduw_phys(addr);
-}
-
-static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- return ldl_phys(addr);
-}
-
/* Generate a debug exception if a watchpoint has been hit.
Returns the real physical address of the access. addr will be a host
address in case of a RAM location. */
@@ -2404,7 +2389,7 @@ static target_ulong check_watchpoint(tar
retaddr = addr;
for (i = 0; i < env->nb_watchpoints; i++) {
watch = env->watchpoint[i].vaddr;
- if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
+ if (((env->iomem_access_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
retaddr = addr - env->watchpoint[i].addend;
if (((addr ^ watch) & (~TARGET_PAGE_MASK - (len - 1))) == 0 &&
(env->watchpoint[i].type == type ||
@@ -2418,6 +2403,27 @@ static target_ulong check_watchpoint(tar
return retaddr;
}
+
+/* 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 uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+ addr = check_watchpoint(addr, 1, GDB_WATCHPOINT_READ);
+ return ldub_phys(addr);
+}
+
+static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+ addr = check_watchpoint(addr, 2, GDB_WATCHPOINT_READ);
+ return lduw_phys(addr);
+}
+
+static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ addr = check_watchpoint(addr, 4, GDB_WATCHPOINT_READ);
+ return ldl_phys(addr);
+}
static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
Index: b/cpu-defs.h
===================================================================
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -136,10 +136,10 @@ typedef struct CPUTLBEntry {
/* in order to avoid passing too many arguments to the memory \
write helpers, we store some rarely used information in the CPU \
context) */ \
- unsigned long mem_write_pc; /* host pc at which the memory was \
- written */ \
- target_ulong mem_write_vaddr; /* target virtual addr at which the \
- memory was written */ \
+ unsigned long iomem_access_pc; /* host pc at which the io-memory \
+ was accessed */ \
+ target_ulong iomem_access_vaddr; /* target virtual addr at which \
+ the io-memory was accessed */ \
int halted; /* TRUE if the CPU is in suspend state */ \
/* The meaning of the MMU modes is defined in the target code. */ \
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
Index: b/softmmu_template.h
===================================================================
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -51,12 +51,15 @@ static DATA_TYPE glue(glue(slow_ld, SUFF
int mmu_idx,
void *retaddr);
static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
- target_ulong tlb_addr)
+ target_ulong tlb_addr,
+ void *retaddr)
{
DATA_TYPE res;
int index;
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ env->iomem_access_vaddr = tlb_addr;
+ env->iomem_access_pc = (unsigned long)retaddr;
#if SHIFT <= 2
res = io_mem_read[index][SHIFT](io_mem_opaque[index], physaddr);
#else
@@ -95,7 +98,8 @@ DATA_TYPE REGPARM glue(glue(__ld, SUFFIX
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
- res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
+ retaddr = GETPC();
+ res = glue(io_read, SUFFIX)(physaddr, tlb_addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
/* slow unaligned access (it spans two pages or IO) */
do_unaligned_access:
@@ -147,7 +151,8 @@ static DATA_TYPE glue(glue(slow_ld, SUFF
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
goto do_unaligned_access;
- res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
+ retaddr = GETPC();
+ res = glue(io_read, SUFFIX)(physaddr, tlb_addr, retaddr);
} else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
do_unaligned_access:
/* slow unaligned access (it spans two pages) */
@@ -191,8 +196,8 @@ static inline void glue(io_write, SUFFIX
int index;
index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- env->mem_write_vaddr = tlb_addr;
- env->mem_write_pc = (unsigned long)retaddr;
+ env->iomem_access_vaddr = tlb_addr;
+ env->iomem_access_pc = (unsigned long)retaddr;
#if SHIFT <= 2
io_mem_write[index][SHIFT](io_mem_opaque[index], physaddr, val);
#else
next prev parent reply other threads:[~2008-05-31 13:50 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-31 12:55 [Qemu-devel] [PATCH 0/5] Debugger enhancements Jan Kiszka
2008-05-31 13:15 ` Jan Kiszka [this message]
2008-05-31 13:15 ` [Qemu-devel] [PATCH 2/5] Watchpoint length and type awareness Jan Kiszka
2008-05-31 13:26 ` [Qemu-devel] [PATCH 4/5] Report exact PC on watchpoint hit Jan Kiszka
2008-05-31 14:11 ` Paul Brook
2008-05-31 14:42 ` Jan Kiszka
2008-05-31 15:17 ` Paul Brook
2008-05-31 13:44 ` [Qemu-devel] [PATCH 5/5] Enhance SMP guest debugging Jan Kiszka
2008-05-31 13:49 ` [Qemu-devel] [PATCH 1/5] Refactor breakpoint API and gdbstub integration Jan Kiszka
2008-05-31 16:50 ` [Qemu-devel] [PATCH 0/5] Debugger enhancements Fabrice Bellard
2008-05-31 17:05 ` Paul Brook
2008-05-31 17:29 ` [Qemu-devel] " Jan Kiszka
2008-05-31 18:33 ` [Qemu-devel] " Fabrice Bellard
2008-06-01 13:54 ` [Qemu-devel] " Jan Kiszka
2008-06-01 12:38 ` [Qemu-devel] " Jamie Lokier
2008-06-01 13:56 ` [Qemu-devel] " Jan Kiszka
2008-05-31 17:20 ` Jan Kiszka
2008-05-31 18:42 ` Fabrice Bellard
2008-06-01 0:06 ` Paul Brook
2008-06-01 13:53 ` Jan Kiszka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48414F75.5080202@web.de \
--to=jan.kiszka@web.de \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.