diff options
-rw-r--r-- | cpu-all.h | 10 | ||||
-rw-r--r-- | exec.c | 138 | ||||
-rw-r--r-- | gdbstub.c | 53 |
3 files changed, 152 insertions, 49 deletions
@@ -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); @@ -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 @@ -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"); |