aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpu-all.h10
-rw-r--r--exec.c138
-rw-r--r--gdbstub.c53
3 files changed, 152 insertions, 49 deletions
diff --git a/cpu-all.h b/cpu-all.h
index 499e1483d9..1cf35ea235 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -473,6 +473,11 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
void cpu_single_step(CPUState *env, int enabled);
+/* Return the physical page corresponding to a virtual one. Use it
+ only for debugging because no protection checks are done. Return -1
+ if no page found. */
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
+
#define CPU_LOG_ALL 1
void cpu_set_log(int log_flags);
void cpu_set_log_filename(const char *filename);
@@ -515,6 +520,11 @@ int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write);
+void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr,
+ int len, int is_write);
+int cpu_memory_rw_debug(CPUState *env,
+ uint8_t *buf, target_ulong addr, int len, int is_write);
+
/* gdb stub API */
extern int gdbstub_fd;
CPUState *cpu_gdbstub_get_env(void *opaque);
diff --git a/exec.c b/exec.c
index 3ae2f31a9c..9104efbb1d 100644
--- a/exec.c
+++ b/exec.c
@@ -1561,6 +1561,144 @@ int cpu_register_io_memory(int io_index,
return io_index << IO_MEM_SHIFT;
}
+/* physical memory access (slow version, mainly for debug) */
+#if defined(CONFIG_USER_ONLY)
+void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr,
+ int len, int is_write)
+{
+ int l, flags;
+ target_ulong page;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ flags = page_get_flags(page);
+ if (!(flags & PAGE_VALID))
+ return;
+ if (is_write) {
+ if (!(flags & PAGE_WRITE))
+ return;
+ memcpy((uint8_t *)addr, buf, len);
+ } else {
+ if (!(flags & PAGE_READ))
+ return;
+ memcpy(buf, (uint8_t *)addr, len);
+ }
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+}
+#else
+void cpu_physical_memory_rw(CPUState *env, uint8_t *buf, target_ulong addr,
+ int len, int is_write)
+{
+ int l, io_index;
+ uint8_t *ptr;
+ uint32_t val;
+ target_ulong page, pd;
+ PageDesc *p;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ p = page_find(page >> TARGET_PAGE_BITS);
+ if (!p) {
+ pd = IO_MEM_UNASSIGNED;
+ } else {
+ pd = p->phys_offset;
+ }
+
+ if (is_write) {
+ if ((pd & ~TARGET_PAGE_MASK) != 0) {
+ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = ldl_raw(buf);
+ io_mem_write[io_index][2](addr, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = lduw_raw(buf);
+ io_mem_write[io_index][1](addr, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = ldub_raw(buf);
+ io_mem_write[io_index][0](addr, val);
+ l = 1;
+ }
+ } else {
+ /* RAM case */
+ ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ (addr & ~TARGET_PAGE_MASK);
+ memcpy(ptr, buf, l);
+ }
+ } else {
+ if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
+ (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) {
+ /* I/O case */
+ io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ if (l >= 4 && ((addr & 3) == 0)) {
+ /* 32 bit read access */
+ val = io_mem_read[io_index][2](addr);
+ stl_raw(buf, val);
+ l = 4;
+ } else if (l >= 2 && ((addr & 1) == 0)) {
+ /* 16 bit read access */
+ val = io_mem_read[io_index][1](addr);
+ stw_raw(buf, val);
+ l = 2;
+ } else {
+ /* 8 bit access */
+ val = io_mem_read[io_index][0](addr);
+ stb_raw(buf, val);
+ l = 1;
+ }
+ } else {
+ /* RAM case */
+ ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+ (addr & ~TARGET_PAGE_MASK);
+ memcpy(buf, ptr, l);
+ }
+ }
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+}
+#endif
+
+/* virtual memory access for debug */
+int cpu_memory_rw_debug(CPUState *env,
+ uint8_t *buf, target_ulong addr, int len, int is_write)
+{
+ int l;
+ target_ulong page, phys_addr;
+
+ while (len > 0) {
+ page = addr & TARGET_PAGE_MASK;
+ phys_addr = cpu_get_phys_page_debug(env, page);
+ /* if no physical page mapped, return an error */
+ if (phys_addr == -1)
+ return -1;
+ l = (page + TARGET_PAGE_SIZE) - addr;
+ if (l > len)
+ l = len;
+ cpu_physical_memory_rw(env, buf,
+ phys_addr + (addr & ~TARGET_PAGE_MASK), l,
+ is_write);
+ len -= l;
+ buf += l;
+ addr += l;
+ }
+ return 0;
+}
+
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _cmmu
diff --git a/gdbstub.c b/gdbstub.c
index 469a15962f..4fa4af79a3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -248,53 +248,6 @@ static int put_packet(char *buf)
return 0;
}
-/* better than nothing for SOFTMMU : we use physical addresses */
-#if !defined(CONFIG_USER_ONLY)
-static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
-{
- uint8_t *ptr;
-
- if (addr >= phys_ram_size ||
- ((int64_t)addr + len > phys_ram_size))
- return -1;
- ptr = phys_ram_base + addr;
- if (is_write)
- memcpy(ptr, buf, len);
- else
- memcpy(buf, ptr, len);
- return 0;
-}
-#else
-static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
-{
- int l, flags;
- uint32_t page;
-
- while (len > 0) {
- page = addr & TARGET_PAGE_MASK;
- l = (page + TARGET_PAGE_SIZE) - addr;
- if (l > len)
- l = len;
- flags = page_get_flags(page);
- if (!(flags & PAGE_VALID))
- return -1;
- if (is_write) {
- if (!(flags & PAGE_WRITE))
- return -1;
- memcpy((uint8_t *)addr, buf, l);
- } else {
- if (!(flags & PAGE_READ))
- return -1;
- memcpy(buf, (uint8_t *)addr, l);
- }
- len -= l;
- buf += l;
- addr += l;
- }
- return 0;
-}
-#endif
-
#if defined(TARGET_I386)
static void to_le32(uint8_t *p, int v)
@@ -514,16 +467,18 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
put_packet("OK");
break;
case 'm':
+ env = cpu_gdbstub_get_env(opaque);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
len = strtoul(p, NULL, 16);
- if (memory_rw(mem_buf, addr, len, 0) != 0)
+ if (cpu_memory_rw_debug(env, mem_buf, addr, len, 0) != 0)
memset(mem_buf, 0, len);
memtohex(buf, mem_buf, len);
put_packet(buf);
break;
case 'M':
+ env = cpu_gdbstub_get_env(opaque);
addr = strtoul(p, (char **)&p, 16);
if (*p == ',')
p++;
@@ -531,7 +486,7 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
if (*p == ',')
p++;
hextomem(mem_buf, p, len);
- if (memory_rw(mem_buf, addr, len, 1) != 0)
+ if (cpu_memory_rw_debug(env, mem_buf, addr, len, 1) != 0)
put_packet("ENN");
else
put_packet("OK");