#include "trace.h"
#endif
+#define WANT_EXEC_OBSOLETE
+#include "exec-obsolete.h"
+
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
//#define DEBUG_TLB
static MemoryRegion *system_memory;
static MemoryRegion *system_io;
+MemoryRegion io_mem_ram, io_mem_rom, io_mem_unassigned, io_mem_notdirty;
+static MemoryRegion io_mem_subpage_ram;
+
#endif
CPUState *first_cpu;
/* current CPU in the current thread. It is only valid inside
cpu_exec() */
-CPUState *cpu_single_env;
+DEFINE_TLS(CPUState *,cpu_single_env);
/* 0 = Do not count executed instructions.
1 = Precise instruction counting.
2 = Adaptive rate instruction counting. */
int use_icount = 0;
-/* Current instruction counter. While executing translated code this may
- include some instructions that have not yet been executed. */
-int64_t qemu_icount;
typedef struct PageDesc {
/* list of TBs intersecting this ram page */
#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_bits;
unsigned long qemu_host_page_size;
unsigned long qemu_host_page_mask;
static void memory_map_init(void);
/* io memory support */
-CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
-CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
-void *io_mem_opaque[IO_MEM_NB_ENTRIES];
+MemoryRegion *io_mem_region[IO_MEM_NB_ENTRIES];
static char io_mem_used[IO_MEM_NB_ENTRIES];
-static int io_mem_watch;
+static MemoryRegion io_mem_watch;
#endif
/* log support */
qemu_host_page_size = qemu_real_host_page_size;
if (qemu_host_page_size < TARGET_PAGE_SIZE)
qemu_host_page_size = TARGET_PAGE_SIZE;
- qemu_host_page_bits = 0;
- while ((1 << qemu_host_page_bits) < qemu_host_page_size)
- qemu_host_page_bits++;
qemu_host_page_mask = ~(qemu_host_page_size - 1);
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
pd = *lp;
if (pd == NULL) {
int i;
+ int first_index = index & ~(L2_SIZE - 1);
if (!alloc) {
return NULL;
*lp = pd = g_malloc(sizeof(PhysPageDesc) * L2_SIZE);
for (i = 0; i < L2_SIZE; i++) {
- pd[i].phys_offset = IO_MEM_UNASSIGNED;
- pd[i].region_offset = (index + i) << TARGET_PAGE_BITS;
+ pd[i].phys_offset = io_mem_unassigned.ram_addr;
+ pd[i].region_offset = (first_index + i) << TARGET_PAGE_BITS;
}
}
return pd + (index & (L2_SIZE - 1));
}
-static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
+static inline PhysPageDesc phys_page_find(target_phys_addr_t index)
{
- return phys_page_find_alloc(index, 0);
+ PhysPageDesc *p = phys_page_find_alloc(index, 0);
+
+ if (p) {
+ return *p;
+ } else {
+ return (PhysPageDesc) {
+ .phys_offset = io_mem_unassigned.ram_addr,
+ .region_offset = index << TARGET_PAGE_BITS,
+ };
+ }
}
static void tlb_protect_code(ram_addr_t ram_addr);
code_gen_buffer_size = tb_size;
if (code_gen_buffer_size == 0) {
#if defined(CONFIG_USER_ONLY)
- /* in user mode, phys_ram_size is not meaningful */
code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
#else
/* XXX: needs adjustments */
if (code_gen_buffer_size > (512 * 1024 * 1024))
code_gen_buffer_size = (512 * 1024 * 1024);
#elif defined(__arm__)
- /* Map the buffer below 32M, so we can use direct calls and branches */
- flags |= MAP_FIXED;
- start = (void *) 0x01000000UL;
+ /* Keep the buffer no bigger than 16MB to branch between blocks */
if (code_gen_buffer_size > 16 * 1024 * 1024)
code_gen_buffer_size = 16 * 1024 * 1024;
#elif defined(__s390x__)
target_phys_addr_t addr;
target_ulong pd;
ram_addr_t ram_addr;
- PhysPageDesc *p;
+ PhysPageDesc p;
addr = cpu_get_phys_page_debug(env, pc);
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
}
static char logfile_buf[4096];
setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
}
-#elif !defined(_WIN32)
- /* Win32 doesn't support line-buffering and requires size >= 2 */
+#elif defined(_WIN32)
+ /* Win32 doesn't support line-buffering, so use unbuffered output. */
+ setvbuf(logfile, NULL, _IONBF, 0);
+#else
setvbuf(logfile, NULL, _IOLBF, 0);
#endif
log_append = 1;
{ 0, NULL, NULL },
};
-#ifndef CONFIG_USER_ONLY
-static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
- = QLIST_HEAD_INITIALIZER(memory_client_list);
-
-static void cpu_notify_set_memory(target_phys_addr_t start_addr,
- ram_addr_t size,
- ram_addr_t phys_offset,
- bool log_dirty)
-{
- CPUPhysMemoryClient *client;
- QLIST_FOREACH(client, &memory_client_list, list) {
- client->set_memory(client, start_addr, size, phys_offset, log_dirty);
- }
-}
-
-static int cpu_notify_sync_dirty_bitmap(target_phys_addr_t start,
- target_phys_addr_t end)
-{
- CPUPhysMemoryClient *client;
- QLIST_FOREACH(client, &memory_client_list, list) {
- int r = client->sync_dirty_bitmap(client, start, end);
- if (r < 0)
- return r;
- }
- return 0;
-}
-
-static int cpu_notify_migration_log(int enable)
-{
- CPUPhysMemoryClient *client;
- QLIST_FOREACH(client, &memory_client_list, list) {
- int r = client->migration_log(client, enable);
- if (r < 0)
- return r;
- }
- return 0;
-}
-
-struct last_map {
- target_phys_addr_t start_addr;
- ram_addr_t size;
- ram_addr_t phys_offset;
-};
-
-/* The l1_phys_map provides the upper P_L1_BITs of the guest physical
- * address. Each intermediate table provides the next L2_BITs of guest
- * physical address space. The number of levels vary based on host and
- * guest configuration, making it efficient to build the final guest
- * physical address by seeding the L1 offset and shifting and adding in
- * each L2 offset as we recurse through them. */
-static void phys_page_for_each_1(CPUPhysMemoryClient *client, int level,
- void **lp, target_phys_addr_t addr,
- struct last_map *map)
-{
- int i;
-
- if (*lp == NULL) {
- return;
- }
- if (level == 0) {
- PhysPageDesc *pd = *lp;
- addr <<= L2_BITS + TARGET_PAGE_BITS;
- for (i = 0; i < L2_SIZE; ++i) {
- if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
- target_phys_addr_t start_addr = addr | i << TARGET_PAGE_BITS;
-
- if (map->size &&
- start_addr == map->start_addr + map->size &&
- pd[i].phys_offset == map->phys_offset + map->size) {
-
- map->size += TARGET_PAGE_SIZE;
- continue;
- } else if (map->size) {
- client->set_memory(client, map->start_addr,
- map->size, map->phys_offset, false);
- }
-
- map->start_addr = start_addr;
- map->size = TARGET_PAGE_SIZE;
- map->phys_offset = pd[i].phys_offset;
- }
- }
- } else {
- void **pp = *lp;
- for (i = 0; i < L2_SIZE; ++i) {
- phys_page_for_each_1(client, level - 1, pp + i,
- (addr << L2_BITS) | i, map);
- }
- }
-}
-
-static void phys_page_for_each(CPUPhysMemoryClient *client)
-{
- int i;
- struct last_map map = { };
-
- for (i = 0; i < P_L1_SIZE; ++i) {
- phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
- l1_phys_map + i, i, &map);
- }
- if (map.size) {
- client->set_memory(client, map.start_addr, map.size, map.phys_offset,
- false);
- }
-}
-
-void cpu_register_phys_memory_client(CPUPhysMemoryClient *client)
-{
- QLIST_INSERT_HEAD(&memory_client_list, client, list);
- phys_page_for_each(client);
-}
-
-void cpu_unregister_phys_memory_client(CPUPhysMemoryClient *client)
-{
- QLIST_REMOVE(client, list);
-}
-#endif
-
static int cmp1(const char *s1, int n, const char *s2)
{
if (strlen(s2) != n)
.addend = -1,
};
-/* NOTE: if flush_global is true, also flush global entries (not
- implemented yet) */
+/* NOTE:
+ * If flush_global is true (the usual case), flush all tlb entries.
+ * If flush_global is false, flush (at least) all tlb entries not
+ * marked global.
+ *
+ * Since QEMU doesn't currently implement a global/not-global flag
+ * for tlb entries, at the moment tlb_flush() will also flush all
+ * tlb entries in the flush_global == false case. This is OK because
+ * CPU architectures generally permit an implementation to drop
+ * entries from the TLB at any time, so flushing more entries than
+ * required is only an efficiency issue, not a correctness issue.
+ */
void tlb_flush(CPUState *env, int flush_global)
{
int i;
unsigned long start, unsigned long length)
{
unsigned long addr;
- if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+ if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
if ((addr - start) < length) {
tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | TLB_NOTDIRTY;
{
int ret = 0;
in_migration = enable;
- ret = cpu_notify_migration_log(!!enable);
return ret;
}
-int cpu_physical_memory_get_dirty_tracking(void)
-{
- return in_migration;
-}
-
-int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr,
- target_phys_addr_t end_addr)
-{
- int ret;
-
- ret = cpu_notify_sync_dirty_bitmap(start_addr, end_addr);
- return ret;
-}
-
-int cpu_physical_log_start(target_phys_addr_t start_addr,
- ram_addr_t size)
-{
- CPUPhysMemoryClient *client;
- QLIST_FOREACH(client, &memory_client_list, list) {
- if (client->log_start) {
- int r = client->log_start(client, start_addr, size);
- if (r < 0) {
- return r;
- }
- }
- }
- return 0;
-}
-
-int cpu_physical_log_stop(target_phys_addr_t start_addr,
- ram_addr_t size)
-{
- CPUPhysMemoryClient *client;
- QLIST_FOREACH(client, &memory_client_list, list) {
- if (client->log_stop) {
- int r = client->log_stop(client, start_addr, size);
- if (r < 0) {
- return r;
- }
- }
- }
- return 0;
-}
-
static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
{
ram_addr_t ram_addr;
void *p;
- if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+ if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
+ tlb_entry->addend);
ram_addr = qemu_ram_addr_from_host_nofail(p);
env->tlb_flush_mask = mask;
}
+static bool is_ram_rom(ram_addr_t pd)
+{
+ pd &= ~TARGET_PAGE_MASK;
+ return pd == io_mem_ram.ram_addr || pd == io_mem_rom.ram_addr;
+}
+
+static bool is_romd(ram_addr_t pd)
+{
+ MemoryRegion *mr;
+
+ pd &= ~TARGET_PAGE_MASK;
+ mr = io_mem_region[pd];
+ return mr->rom_device && mr->readable;
+}
+
+static bool is_ram_rom_romd(ram_addr_t pd)
+{
+ return is_ram_rom(pd) || is_romd(pd);
+}
+
/* Add a new TLB entry. At most one entry for a given virtual address
is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
supplied size is only used by tlb_flush_page. */
target_phys_addr_t paddr, int prot,
int mmu_idx, target_ulong size)
{
- PhysPageDesc *p;
+ PhysPageDesc p;
unsigned long pd;
unsigned int index;
target_ulong address;
tlb_add_large_page(env, vaddr, size);
}
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
#if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
" prot=%x idx=%d pd=0x%08lx\n",
#endif
address = vaddr;
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
+ if (!is_ram_rom_romd(pd)) {
/* IO memory case (romd handled later) */
address |= TLB_MMIO;
}
addend = (unsigned long)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK);
- if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
+ if (is_ram_rom(pd)) {
/* Normal RAM. */
iotlb = pd & TARGET_PAGE_MASK;
- if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
- iotlb |= IO_MEM_NOTDIRTY;
+ if ((pd & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr)
+ iotlb |= io_mem_notdirty.ram_addr;
else
- iotlb |= IO_MEM_ROM;
+ iotlb |= io_mem_rom.ram_addr;
} else {
/* IO handlers are currently passed a physical address.
It would be nice to pass an offset from the base address
We can't use the high bits of pd for this because
IO_MEM_ROMD uses these as a ram address. */
iotlb = (pd & ~TARGET_PAGE_MASK);
- if (p) {
- iotlb += p->region_offset;
- } else {
- iotlb += paddr;
- }
+ iotlb += p.region_offset;
}
code_address = address;
if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
/* Avoid trapping reads of pages with a write breakpoint. */
if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
- iotlb = io_mem_watch + paddr;
+ iotlb = io_mem_watch.ram_addr + paddr;
address |= TLB_MMIO;
break;
}
te->addr_code = -1;
}
if (prot & PAGE_WRITE) {
- if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
- (pd & IO_MEM_ROMD)) {
+ if ((pd & ~TARGET_PAGE_MASK) == io_mem_rom.ram_addr || is_romd(pd)) {
/* Write access calls the I/O callback. */
te->addr_write = address | TLB_MMIO;
- } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
+ } else if ((pd & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr &&
!cpu_physical_memory_is_dirty(pd)) {
te->addr_write = address | TLB_NOTDIRTY;
} else {
#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
typedef struct subpage_t {
+ MemoryRegion iomem;
target_phys_addr_t base;
ram_addr_t sub_io_index[TARGET_PAGE_SIZE];
ram_addr_t region_offset[TARGET_PAGE_SIZE];
start_addr and region_offset are rounded down to a page boundary
before calculating this offset. This should not be a problem unless
the low bits of start_addr and region_offset differ. */
-void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
- ram_addr_t size,
- ram_addr_t phys_offset,
- ram_addr_t region_offset,
- bool log_dirty)
+void cpu_register_physical_memory_log(MemoryRegionSection *section,
+ bool readable, bool readonly)
{
+ target_phys_addr_t start_addr = section->offset_within_address_space;
+ ram_addr_t size = section->size;
+ ram_addr_t phys_offset = section->mr->ram_addr;
+ ram_addr_t region_offset = section->offset_within_region;
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
CPUState *env;
ram_addr_t orig_size = size;
subpage_t *subpage;
+ if (memory_region_is_ram(section->mr)) {
+ phys_offset += region_offset;
+ region_offset = 0;
+ }
+
+ if (readonly) {
+ phys_offset |= io_mem_rom.ram_addr;
+ }
+
assert(size);
- cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
- if (phys_offset == IO_MEM_UNASSIGNED) {
+ if (phys_offset == io_mem_unassigned.ram_addr) {
region_offset = start_addr;
}
region_offset &= TARGET_PAGE_MASK;
addr = start_addr;
do {
- p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
+ p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 0);
+ if (p && p->phys_offset != io_mem_unassigned.ram_addr) {
ram_addr_t orig_memory = p->phys_offset;
target_phys_addr_t start_addr2, end_addr2;
int need_subpage = 0;
+ MemoryRegion *mr = io_mem_region[orig_memory & ~TARGET_PAGE_MASK];
CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
need_subpage);
if (need_subpage) {
- if (!(orig_memory & IO_MEM_SUBPAGE)) {
+ if (!(mr->subpage)) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
&p->phys_offset, orig_memory,
p->region_offset);
} else {
- subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
- >> IO_MEM_SHIFT];
+ subpage = container_of(mr, subpage_t, iomem);
}
subpage_register(subpage, start_addr2, end_addr2, phys_offset,
region_offset);
p->region_offset = 0;
} else {
p->phys_offset = phys_offset;
- if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
- (phys_offset & IO_MEM_ROMD))
+ p->region_offset = region_offset;
+ if (is_ram_rom_romd(phys_offset))
phys_offset += TARGET_PAGE_SIZE;
}
} else {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p->phys_offset = phys_offset;
p->region_offset = region_offset;
- if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
- (phys_offset & IO_MEM_ROMD)) {
+ if (is_ram_rom_romd(phys_offset)) {
phys_offset += TARGET_PAGE_SIZE;
} else {
target_phys_addr_t start_addr2, end_addr2;
if (need_subpage) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
- &p->phys_offset, IO_MEM_UNASSIGNED,
+ &p->phys_offset,
+ io_mem_unassigned.ram_addr,
addr & TARGET_PAGE_MASK);
subpage_register(subpage, start_addr2, end_addr2,
phys_offset, region_offset);
}
}
-/* XXX: temporary until new memory mapping API */
-ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
-{
- PhysPageDesc *p;
-
- p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p)
- return IO_MEM_UNASSIGNED;
- return p->phys_offset;
-}
-
void qemu_register_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size)
{
if (kvm_enabled())
static ram_addr_t find_ram_offset(ram_addr_t size)
{
RAMBlock *block, *next_block;
- ram_addr_t offset = 0, mingap = RAM_ADDR_MAX;
+ ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
if (QLIST_EMPTY(&ram_list.blocks))
return 0;
}
}
if (next - end >= size && next - end < mingap) {
- offset = end;
+ offset = end;
mingap = next - end;
}
}
+
+ if (offset == RAM_ADDR_MAX) {
+ fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
+ (uint64_t)size);
+ abort();
+ }
+
return offset;
}
return last;
}
-ram_addr_t qemu_ram_alloc_from_ptr(DeviceState *dev, const char *name,
- ram_addr_t size, void *host)
+void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
{
RAMBlock *new_block, *block;
- size = TARGET_PAGE_ALIGN(size);
- new_block = g_malloc0(sizeof(*new_block));
+ new_block = NULL;
+ QLIST_FOREACH(block, &ram_list.blocks, next) {
+ if (block->offset == addr) {
+ new_block = block;
+ break;
+ }
+ }
+ assert(new_block);
+ assert(!new_block->idstr[0]);
if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
char *id = dev->parent_bus->info->get_dev_path(dev);
pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
QLIST_FOREACH(block, &ram_list.blocks, next) {
- if (!strcmp(block->idstr, new_block->idstr)) {
+ if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
new_block->idstr);
abort();
}
}
+}
+
+ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
+ MemoryRegion *mr)
+{
+ RAMBlock *new_block;
+ size = TARGET_PAGE_ALIGN(size);
+ new_block = g_malloc0(sizeof(*new_block));
+
+ new_block->mr = mr;
new_block->offset = find_ram_offset(size);
if (host) {
new_block->host = host;
}
#else
if (xen_enabled()) {
- xen_ram_alloc(new_block->offset, size);
+ xen_ram_alloc(new_block->offset, size, mr);
} else {
new_block->host = qemu_vmalloc(size);
}
return new_block->offset;
}
-ram_addr_t qemu_ram_alloc(DeviceState *dev, const char *name, ram_addr_t size)
+ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr)
{
- return qemu_ram_alloc_from_ptr(dev, name, size, NULL);
+ return qemu_ram_alloc_from_ptr(size, NULL, mr);
}
void qemu_ram_free_from_ptr(ram_addr_t addr)
return ram_addr;
}
-static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t unassigned_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 1);
+ cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, size);
#endif
return 0;
}
-static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
+static void unassigned_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
-#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 2);
-#endif
- return 0;
-}
-
-static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
-{
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
+ printf("Unassigned mem write " TARGET_FMT_plx " = 0x%"PRIx64"\n", addr, val);
#endif
#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 0, 0, 0, 4);
+ cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, size);
#endif
- return 0;
}
-static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
-#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 1);
-#endif
-}
+static const MemoryRegionOps unassigned_mem_ops = {
+ .read = unassigned_mem_read,
+ .write = unassigned_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
-static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static uint64_t error_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
-#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 2);
-#endif
+ abort();
}
-static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void error_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
{
-#ifdef DEBUG_UNASSIGNED
- printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
-#endif
-#if defined(TARGET_ALPHA) || defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE)
- cpu_unassigned_access(cpu_single_env, addr, 1, 0, 0, 4);
-#endif
+ abort();
}
-static CPUReadMemoryFunc * const unassigned_mem_read[3] = {
- unassigned_mem_readb,
- unassigned_mem_readw,
- unassigned_mem_readl,
+static const MemoryRegionOps error_mem_ops = {
+ .read = error_mem_read,
+ .write = error_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static CPUWriteMemoryFunc * const unassigned_mem_write[3] = {
- unassigned_mem_writeb,
- unassigned_mem_writew,
- unassigned_mem_writel,
+static const MemoryRegionOps rom_mem_ops = {
+ .read = error_mem_read,
+ .write = unassigned_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static void notdirty_mem_writeb(void *opaque, target_phys_addr_t ram_addr,
- uint32_t val)
+static void notdirty_mem_write(void *opaque, target_phys_addr_t ram_addr,
+ uint64_t val, unsigned size)
{
int dirty_flags;
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
#if !defined(CONFIG_USER_ONLY)
- tb_invalidate_phys_page_fast(ram_addr, 1);
+ tb_invalidate_phys_page_fast(ram_addr, size);
dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
#endif
}
- stb_p(qemu_get_ram_ptr(ram_addr), val);
- dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
- cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
- /* we remove the notdirty callback only if the code has been
- flushed */
- if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
-}
-
-static void notdirty_mem_writew(void *opaque, target_phys_addr_t ram_addr,
- uint32_t val)
-{
- int dirty_flags;
- dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
- if (!(dirty_flags & CODE_DIRTY_FLAG)) {
-#if !defined(CONFIG_USER_ONLY)
- tb_invalidate_phys_page_fast(ram_addr, 2);
- dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
-#endif
- }
- stw_p(qemu_get_ram_ptr(ram_addr), val);
- dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
- cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
- /* we remove the notdirty callback only if the code has been
- flushed */
- if (dirty_flags == 0xff)
- tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
-}
-
-static void notdirty_mem_writel(void *opaque, target_phys_addr_t ram_addr,
- uint32_t val)
-{
- int dirty_flags;
- dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
- if (!(dirty_flags & CODE_DIRTY_FLAG)) {
-#if !defined(CONFIG_USER_ONLY)
- tb_invalidate_phys_page_fast(ram_addr, 4);
- dirty_flags = cpu_physical_memory_get_dirty_flags(ram_addr);
-#endif
+ switch (size) {
+ case 1:
+ stb_p(qemu_get_ram_ptr(ram_addr), val);
+ break;
+ case 2:
+ stw_p(qemu_get_ram_ptr(ram_addr), val);
+ break;
+ case 4:
+ stl_p(qemu_get_ram_ptr(ram_addr), val);
+ break;
+ default:
+ abort();
}
- stl_p(qemu_get_ram_ptr(ram_addr), val);
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
cpu_physical_memory_set_dirty_flags(ram_addr, dirty_flags);
/* we remove the notdirty callback only if the code has been
tlb_set_dirty(cpu_single_env, cpu_single_env->mem_io_vaddr);
}
-static CPUReadMemoryFunc * const error_mem_read[3] = {
- NULL, /* never used */
- NULL, /* never used */
- NULL, /* never used */
-};
-
-static CPUWriteMemoryFunc * const notdirty_mem_write[3] = {
- notdirty_mem_writeb,
- notdirty_mem_writew,
- notdirty_mem_writel,
+static const MemoryRegionOps notdirty_mem_ops = {
+ .read = error_mem_read,
+ .write = notdirty_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
/* Generate a debug exception if a watchpoint has been hit. */
/* 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)
-{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_READ);
- return ldub_phys(addr);
-}
-
-static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_READ);
- return lduw_phys(addr);
-}
-
-static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_READ);
- return ldl_phys(addr);
-}
-
-static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
+static uint64_t watch_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x0, BP_MEM_WRITE);
- stb_phys(addr, val);
-}
-
-static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x1, BP_MEM_WRITE);
- stw_phys(addr, val);
+ check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_READ);
+ switch (size) {
+ case 1: return ldub_phys(addr);
+ case 2: return lduw_phys(addr);
+ case 4: return ldl_phys(addr);
+ default: abort();
+ }
}
-static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
+static void watch_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
- check_watchpoint(addr & ~TARGET_PAGE_MASK, ~0x3, BP_MEM_WRITE);
- stl_phys(addr, val);
+ check_watchpoint(addr & ~TARGET_PAGE_MASK, ~(size - 1), BP_MEM_WRITE);
+ switch (size) {
+ case 1: stb_phys(addr, val);
+ case 2: stw_phys(addr, val);
+ case 4: stl_phys(addr, val);
+ default: abort();
+ }
}
-static CPUReadMemoryFunc * const watch_mem_read[3] = {
- watch_mem_readb,
- watch_mem_readw,
- watch_mem_readl,
+static const MemoryRegionOps watch_mem_ops = {
+ .read = watch_mem_read,
+ .write = watch_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
-static CPUWriteMemoryFunc * const watch_mem_write[3] = {
- watch_mem_writeb,
- watch_mem_writew,
- watch_mem_writel,
-};
-
-static inline uint32_t subpage_readlen (subpage_t *mmio,
- target_phys_addr_t addr,
- unsigned int len)
+static uint64_t subpage_read(void *opaque, target_phys_addr_t addr,
+ unsigned len)
{
+ subpage_t *mmio = opaque;
unsigned int idx = SUBPAGE_IDX(addr);
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
addr += mmio->region_offset[idx];
idx = mmio->sub_io_index[idx];
- return io_mem_read[idx][len](io_mem_opaque[idx], addr);
+ return io_mem_read(idx, addr, len);
}
-static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
- uint32_t value, unsigned int len)
+static void subpage_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned len)
{
+ subpage_t *mmio = opaque;
unsigned int idx = SUBPAGE_IDX(addr);
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n",
+ printf("%s: subpage %p len %d addr " TARGET_FMT_plx
+ " idx %d value %"PRIx64"\n",
__func__, mmio, len, addr, idx, value);
#endif
addr += mmio->region_offset[idx];
idx = mmio->sub_io_index[idx];
- io_mem_write[idx][len](io_mem_opaque[idx], addr, value);
+ io_mem_write(idx, addr, value, len);
}
-static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
-{
- return subpage_readlen(opaque, addr, 0);
-}
-
-static void subpage_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- subpage_writelen(opaque, addr, value, 0);
-}
-
-static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
-{
- return subpage_readlen(opaque, addr, 1);
-}
-
-static void subpage_writew (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- subpage_writelen(opaque, addr, value, 1);
-}
+static const MemoryRegionOps subpage_ops = {
+ .read = subpage_read,
+ .write = subpage_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
-static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
+static uint64_t subpage_ram_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
- return subpage_readlen(opaque, addr, 2);
+ ram_addr_t raddr = addr;
+ void *ptr = qemu_get_ram_ptr(raddr);
+ switch (size) {
+ case 1: return ldub_p(ptr);
+ case 2: return lduw_p(ptr);
+ case 4: return ldl_p(ptr);
+ default: abort();
+ }
}
-static void subpage_writel (void *opaque, target_phys_addr_t addr,
- uint32_t value)
+static void subpage_ram_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
{
- subpage_writelen(opaque, addr, value, 2);
+ ram_addr_t raddr = addr;
+ void *ptr = qemu_get_ram_ptr(raddr);
+ switch (size) {
+ case 1: return stb_p(ptr, value);
+ case 2: return stw_p(ptr, value);
+ case 4: return stl_p(ptr, value);
+ default: abort();
+ }
}
-static CPUReadMemoryFunc * const subpage_read[] = {
- &subpage_readb,
- &subpage_readw,
- &subpage_readl,
-};
-
-static CPUWriteMemoryFunc * const subpage_write[] = {
- &subpage_writeb,
- &subpage_writew,
- &subpage_writel,
+static const MemoryRegionOps subpage_ram_ops = {
+ .read = subpage_ram_read,
+ .write = subpage_ram_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
};
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %ld\n", __func__,
mmio, start, end, idx, eidx, memory);
#endif
- if ((memory & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
- memory = IO_MEM_UNASSIGNED;
- memory = (memory >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+ if ((memory & ~TARGET_PAGE_MASK) == io_mem_ram.ram_addr) {
+ memory = io_mem_subpage_ram.ram_addr;
+ }
+ memory &= IO_MEM_NB_ENTRIES - 1;
for (; idx <= eidx; idx++) {
mmio->sub_io_index[idx] = memory;
mmio->region_offset[idx] = region_offset;
mmio = g_malloc0(sizeof(subpage_t));
mmio->base = base;
- subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio,
- DEVICE_NATIVE_ENDIAN);
+ memory_region_init_io(&mmio->iomem, &subpage_ops, mmio,
+ "subpage", TARGET_PAGE_SIZE);
+ mmio->iomem.subpage = true;
+ subpage_memory = mmio->iomem.ram_addr;
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
mmio, base, TARGET_PAGE_SIZE, subpage_memory);
#endif
- *phys = subpage_memory | IO_MEM_SUBPAGE;
+ *phys = subpage_memory;
subpage_register(mmio, 0, TARGET_PAGE_SIZE-1, orig_memory, region_offset);
return mmio;
return -1;
}
-/*
- * Usually, devices operate in little endian mode. There are devices out
- * there that operate in big endian too. Each device gets byte swapped
- * mmio if plugged onto a CPU that does the other endianness.
- *
- * CPU Device swap?
- *
- * little little no
- * little big yes
- * big little yes
- * big big no
- */
-
-typedef struct SwapEndianContainer {
- CPUReadMemoryFunc *read[3];
- CPUWriteMemoryFunc *write[3];
- void *opaque;
-} SwapEndianContainer;
-
-static uint32_t swapendian_mem_readb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- SwapEndianContainer *c = opaque;
- val = c->read[0](c->opaque, addr);
- return val;
-}
-
-static uint32_t swapendian_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- SwapEndianContainer *c = opaque;
- val = bswap16(c->read[1](c->opaque, addr));
- return val;
-}
-
-static uint32_t swapendian_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- SwapEndianContainer *c = opaque;
- val = bswap32(c->read[2](c->opaque, addr));
- return val;
-}
-
-static CPUReadMemoryFunc * const swapendian_readfn[3]={
- swapendian_mem_readb,
- swapendian_mem_readw,
- swapendian_mem_readl
-};
-
-static void swapendian_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- SwapEndianContainer *c = opaque;
- c->write[0](c->opaque, addr, val);
-}
-
-static void swapendian_mem_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- SwapEndianContainer *c = opaque;
- c->write[1](c->opaque, addr, bswap16(val));
-}
-
-static void swapendian_mem_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- SwapEndianContainer *c = opaque;
- c->write[2](c->opaque, addr, bswap32(val));
-}
-
-static CPUWriteMemoryFunc * const swapendian_writefn[3]={
- swapendian_mem_writeb,
- swapendian_mem_writew,
- swapendian_mem_writel
-};
-
-static void swapendian_init(int io_index)
-{
- SwapEndianContainer *c = g_malloc(sizeof(SwapEndianContainer));
- int i;
-
- /* Swap mmio for big endian targets */
- c->opaque = io_mem_opaque[io_index];
- for (i = 0; i < 3; i++) {
- c->read[i] = io_mem_read[io_index][i];
- c->write[i] = io_mem_write[io_index][i];
-
- io_mem_read[io_index][i] = swapendian_readfn[i];
- io_mem_write[io_index][i] = swapendian_writefn[i];
- }
- io_mem_opaque[io_index] = c;
-}
-
-static void swapendian_del(int io_index)
-{
- if (io_mem_read[io_index][0] == swapendian_readfn[0]) {
- g_free(io_mem_opaque[io_index]);
- }
-}
-
/* mem_read and mem_write are arrays of functions containing the
function to access byte (index 0), word (index 1) and dword (index
2). Functions can be omitted with a NULL function pointer.
modified. If it is zero, a new io zone is allocated. The return
value can be used with cpu_register_physical_memory(). (-1) is
returned if error. */
-static int cpu_register_io_memory_fixed(int io_index,
- CPUReadMemoryFunc * const *mem_read,
- CPUWriteMemoryFunc * const *mem_write,
- void *opaque, enum device_endian endian)
+static int cpu_register_io_memory_fixed(int io_index, MemoryRegion *mr)
{
- int i;
-
if (io_index <= 0) {
io_index = get_free_io_mem_idx();
if (io_index == -1)
return io_index;
} else {
- io_index >>= IO_MEM_SHIFT;
if (io_index >= IO_MEM_NB_ENTRIES)
return -1;
}
- for (i = 0; i < 3; ++i) {
- io_mem_read[io_index][i]
- = (mem_read[i] ? mem_read[i] : unassigned_mem_read[i]);
- }
- for (i = 0; i < 3; ++i) {
- io_mem_write[io_index][i]
- = (mem_write[i] ? mem_write[i] : unassigned_mem_write[i]);
- }
- io_mem_opaque[io_index] = opaque;
+ io_mem_region[io_index] = mr;
- switch (endian) {
- case DEVICE_BIG_ENDIAN:
-#ifndef TARGET_WORDS_BIGENDIAN
- swapendian_init(io_index);
-#endif
- break;
- case DEVICE_LITTLE_ENDIAN:
-#ifdef TARGET_WORDS_BIGENDIAN
- swapendian_init(io_index);
-#endif
- break;
- case DEVICE_NATIVE_ENDIAN:
- default:
- break;
- }
-
- return (io_index << IO_MEM_SHIFT);
+ return io_index;
}
-int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
- CPUWriteMemoryFunc * const *mem_write,
- void *opaque, enum device_endian endian)
+int cpu_register_io_memory(MemoryRegion *mr)
{
- return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque, endian);
+ return cpu_register_io_memory_fixed(0, mr);
}
-void cpu_unregister_io_memory(int io_table_address)
+void cpu_unregister_io_memory(int io_index)
{
- int i;
- int io_index = io_table_address >> IO_MEM_SHIFT;
-
- swapendian_del(io_index);
-
- for (i=0;i < 3; i++) {
- io_mem_read[io_index][i] = unassigned_mem_read[i];
- io_mem_write[io_index][i] = unassigned_mem_write[i];
- }
- io_mem_opaque[io_index] = NULL;
+ io_mem_region[io_index] = NULL;
io_mem_used[io_index] = 0;
}
{
int i;
- cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read,
- unassigned_mem_write, NULL,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read,
- unassigned_mem_write, NULL,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
- notdirty_mem_write, NULL,
- DEVICE_NATIVE_ENDIAN);
+ /* Must be first: */
+ memory_region_init_io(&io_mem_ram, &error_mem_ops, NULL, "ram", UINT64_MAX);
+ assert(io_mem_ram.ram_addr == 0);
+ memory_region_init_io(&io_mem_rom, &rom_mem_ops, NULL, "rom", UINT64_MAX);
+ memory_region_init_io(&io_mem_unassigned, &unassigned_mem_ops, NULL,
+ "unassigned", UINT64_MAX);
+ memory_region_init_io(&io_mem_notdirty, ¬dirty_mem_ops, NULL,
+ "notdirty", UINT64_MAX);
+ memory_region_init_io(&io_mem_subpage_ram, &subpage_ram_ops, NULL,
+ "subpage-ram", UINT64_MAX);
for (i=0; i<5; i++)
io_mem_used[i] = 1;
- io_mem_watch = cpu_register_io_memory(watch_mem_read,
- watch_mem_write, NULL,
- DEVICE_NATIVE_ENDIAN);
+ memory_region_init_io(&io_mem_watch, &watch_mem_ops, NULL,
+ "watch", UINT64_MAX);
}
static void memory_map_init(void)
uint32_t val;
target_phys_addr_t page;
ram_addr_t pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
if (l > len)
l = len;
p = phys_page_find(page >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
if (is_write) {
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
- target_phys_addr_t addr1 = addr;
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
+ target_phys_addr_t addr1;
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr1 = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
/* XXX: could force cpu_single_env to NULL to avoid
potential bugs */
if (l >= 4 && ((addr1 & 3) == 0)) {
/* 32 bit write access */
val = ldl_p(buf);
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr1, val);
+ io_mem_write(io_index, addr1, val, 4);
l = 4;
} else if (l >= 2 && ((addr1 & 1) == 0)) {
/* 16 bit write access */
val = lduw_p(buf);
- io_mem_write[io_index][1](io_mem_opaque[io_index], addr1, val);
+ io_mem_write(io_index, addr1, val, 2);
l = 2;
} else {
/* 8 bit write access */
val = ldub_p(buf);
- io_mem_write[io_index][0](io_mem_opaque[io_index], addr1, val);
+ io_mem_write(io_index, addr1, val, 1);
l = 1;
}
} else {
qemu_put_ram_ptr(ptr);
}
} else {
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
- !(pd & IO_MEM_ROMD)) {
- target_phys_addr_t addr1 = addr;
+ if (!is_ram_rom_romd(pd)) {
+ target_phys_addr_t addr1;
/* I/O case */
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr1 = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr1 = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
if (l >= 4 && ((addr1 & 3) == 0)) {
/* 32 bit read access */
- val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr1);
+ val = io_mem_read(io_index, addr1, 4);
stl_p(buf, val);
l = 4;
} else if (l >= 2 && ((addr1 & 1) == 0)) {
/* 16 bit read access */
- val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr1);
+ val = io_mem_read(io_index, addr1, 2);
stw_p(buf, val);
l = 2;
} else {
/* 8 bit read access */
- val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr1);
+ val = io_mem_read(io_index, addr1, 1);
stb_p(buf, val);
l = 1;
}
uint8_t *ptr;
target_phys_addr_t page;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
if (l > len)
l = len;
p = phys_page_find(page >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
- (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
- !(pd & IO_MEM_ROMD)) {
+ if (!is_ram_rom_romd(pd)) {
/* do nothing */
} else {
unsigned long addr1;
int l;
target_phys_addr_t page;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
ram_addr_t raddr = RAM_ADDR_MAX;
ram_addr_t rlen;
void *ret;
if (l > len)
l = len;
p = phys_page_find(page >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
if (todo || bounce.buffer) {
break;
}
uint8_t *ptr;
uint32_t val;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
- !(pd & IO_MEM_ROMD)) {
+ if (!is_ram_rom_romd(pd)) {
/* I/O case */
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
- val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
+ val = io_mem_read(io_index, addr, 4);
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
val = bswap32(val);
uint8_t *ptr;
uint64_t val;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
- !(pd & IO_MEM_ROMD)) {
+ if (!is_ram_rom_romd(pd)) {
/* I/O case */
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
/* XXX This is broken when device endian != cpu endian.
Fix and add "endian" variable check */
#ifdef TARGET_WORDS_BIGENDIAN
- val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
- val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
+ val = io_mem_read(io_index, addr, 4) << 32;
+ val |= io_mem_read(io_index, addr + 4, 4);
#else
- val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
- val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
+ val = io_mem_read(io_index, addr, 4);
+ val |= io_mem_read(io_index, addr + 4, 4) << 32;
#endif
} else {
/* RAM case */
uint8_t *ptr;
uint64_t val;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
- !(pd & IO_MEM_ROMD)) {
+ if (!is_ram_rom_romd(pd)) {
/* I/O case */
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
- val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
+ val = io_mem_read(io_index, addr, 2);
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
val = bswap16(val);
int io_index;
uint8_t *ptr;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
+ io_mem_write(io_index, addr, val, 4);
} else {
unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
ptr = qemu_get_ram_ptr(addr1);
int io_index;
uint8_t *ptr;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
#ifdef TARGET_WORDS_BIGENDIAN
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
+ io_mem_write(io_index, addr, val >> 32, 4);
+ io_mem_write(io_index, addr + 4, (uint32_t)val, 4);
#else
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
+ io_mem_write(io_index, addr, (uint32_t)val, 4);
+ io_mem_write(io_index, addr + 4, val >> 32, 4);
#endif
} else {
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
int io_index;
uint8_t *ptr;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
val = bswap32(val);
val = bswap32(val);
}
#endif
- io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+ io_mem_write(io_index, addr, val, 4);
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
int io_index;
uint8_t *ptr;
unsigned long pd;
- PhysPageDesc *p;
+ PhysPageDesc p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!p) {
- pd = IO_MEM_UNASSIGNED;
- } else {
- pd = p->phys_offset;
- }
+ pd = p.phys_offset;
- if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
- io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
- if (p)
- addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
+ if ((pd & ~TARGET_PAGE_MASK) != io_mem_ram.ram_addr) {
+ io_index = pd & (IO_MEM_NB_ENTRIES - 1);
+ addr = (addr & ~TARGET_PAGE_MASK) + p.region_offset;
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
val = bswap16(val);
val = bswap16(val);
}
#endif
- io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
+ io_mem_write(io_index, addr, val, 2);
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
tcg_dump_info(f, cpu_fprintf);
}
+/* NOTE: this function can trigger an exception */
+/* NOTE2: the returned address is not exactly the physical address: it
+ is the offset relative to phys_ram_base */
+tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
+{
+ int mmu_idx, page_index, pd;
+ void *p;
+
+ page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ mmu_idx = cpu_mmu_index(env1);
+ if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
+ (addr & TARGET_PAGE_MASK))) {
+ ldub_code(addr);
+ }
+ pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK;
+ if (pd != io_mem_ram.ram_addr && pd != io_mem_rom.ram_addr
+ && !is_romd(pd)) {
+#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
+ cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
+#else
+ cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
+#endif
+ }
+ p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
+ return qemu_ram_addr_from_host_nofail(p);
+}
+
+/*
+ * A helper function for the _utterly broken_ virtio device model to find out if
+ * it's running on a big endian machine. Don't do this at home kids!
+ */
+bool virtio_is_big_endian(void);
+bool virtio_is_big_endian(void)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
#define MMUSUFFIX _cmmu
+#undef GETPC
#define GETPC() NULL
#define env cpu_single_env
#define SOFTMMU_CODE_ACCESS