From bbcfd2913cdb8623d1c57fa26bf481f34bf7989a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 11 Apr 2013 15:33:16 +0200 Subject: [PATCH 01/15] exec: remove obsolete comment See how we call memory_region_section_addr two lines below to convert a physical address to a base address in the region. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/exec.c b/exec.c index aec65c5063..197625c916 100644 --- a/exec.c +++ b/exec.c @@ -639,12 +639,6 @@ hwaddr memory_region_section_get_iotlb(CPUArchState *env, iotlb |= phys_section_rom; } } else { - /* IO handlers are currently passed a physical address. - It would be nice to pass an offset from the base address - of that region. This would avoid having to special case RAM, - and avoid full address decoding in every device. - We can't use the high bits of pd for this because - IO_MEM_ROMD uses these as a ram address. */ iotlb = section - phys_sections; iotlb += memory_region_section_addr(section, paddr); } From 4f39178b3ab54538759df92a38655063f5d59301 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 14 May 2013 11:44:02 +0200 Subject: [PATCH 02/15] exec: eliminate qemu_put_ram_ptr Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 8 -------- hw/pci/pci.c | 2 -- hw/scsi/megasas.c | 1 - include/exec/cpu-common.h | 1 - trace-events | 3 --- 5 files changed, 15 deletions(-) diff --git a/exec.c b/exec.c index 197625c916..fa5f9c3171 100644 --- a/exec.c +++ b/exec.c @@ -1334,11 +1334,6 @@ static void *qemu_ram_ptr_length(ram_addr_t addr, ram_addr_t *size) } } -void qemu_put_ram_ptr(void *addr) -{ - trace_qemu_put_ram_ptr(addr); -} - int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr) { RAMBlock *block; @@ -1928,7 +1923,6 @@ void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, ptr = qemu_get_ram_ptr(addr1); memcpy(ptr, buf, l); invalidate_and_set_dirty(addr1, l); - qemu_put_ram_ptr(ptr); } } else { if (!(memory_region_is_ram(section->mr) || @@ -1958,7 +1952,6 @@ void address_space_rw(AddressSpace *as, hwaddr addr, uint8_t *buf, + memory_region_section_addr(section, addr)); memcpy(buf, ptr, l); - qemu_put_ram_ptr(ptr); } } len -= l; @@ -2020,7 +2013,6 @@ void cpu_physical_memory_write_rom(hwaddr addr, ptr = qemu_get_ram_ptr(addr1); memcpy(ptr, buf, l); invalidate_and_set_dirty(addr1, l); - qemu_put_ram_ptr(ptr); } len -= l; buf += l; diff --git a/hw/pci/pci.c b/hw/pci/pci.c index d5257ed4c5..bb3879bd88 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1959,8 +1959,6 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom) pci_patch_ids(pdev, ptr, size); } - qemu_put_ram_ptr(ptr); - pci_register_bar(pdev, PCI_ROM_SLOT, 0, &pdev->rom); return 0; diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 4934a815ce..fe6550ca54 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -711,7 +711,6 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) ptr = memory_region_get_ram_ptr(&s->dev.rom); memcpy(biosver, ptr + 0x41, 31); - qemu_put_ram_ptr(ptr); memcpy(info.image_component[1].name, "BIOS", 4); memcpy(info.image_component[1].version, biosver, strlen((const char *)biosver)); diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 2e5f11f47f..cafc3c21b1 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -51,7 +51,6 @@ typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); /* This should only be used for ram local to a device. */ void *qemu_get_ram_ptr(ram_addr_t addr); -void qemu_put_ram_ptr(void *addr); /* This should not be used by devices. */ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr); ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr); diff --git a/trace-events b/trace-events index 9c73931f37..b123b0f38d 100644 --- a/trace-events +++ b/trace-events @@ -813,9 +813,6 @@ xen_map_cache_return(void* ptr) "%p" xen_map_block(uint64_t phys_addr, uint64_t size) "%#"PRIx64", size %#"PRIx64 xen_unmap_block(void* addr, unsigned long size) "%p, size %#lx" -# exec.c -qemu_put_ram_ptr(void* addr) "%p" - # hw/xen_platform.c xen_platform_log(char *s) "xen platform: %s" From ee983cb3cc8f856b408a272269f434cc9a82ceff Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 14 May 2013 11:47:56 +0200 Subject: [PATCH 03/15] exec: make qemu_get_ram_ptr private It is a private interface between exec.c and memory.c. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- include/exec/cpu-common.h | 2 -- include/exec/memory-internal.h | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index cafc3c21b1..af851aa633 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -49,8 +49,6 @@ typedef void CPUWriteMemoryFunc(void *opaque, hwaddr addr, uint32_t value); typedef uint32_t CPUReadMemoryFunc(void *opaque, hwaddr addr); void qemu_ram_remap(ram_addr_t addr, ram_addr_t length); -/* This should only be used for ram local to a device. */ -void *qemu_get_ram_ptr(ram_addr_t addr); /* This should not be used by devices. */ int qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr); ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr); diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index 1b156fd58f..8d15f90417 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -46,6 +46,7 @@ void address_space_destroy_dispatch(AddressSpace *as); ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host, MemoryRegion *mr); ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr); +void *qemu_get_ram_ptr(ram_addr_t addr); void qemu_ram_free(ram_addr_t addr); void qemu_ram_free_from_ptr(ram_addr_t addr); From 8b0d6711a276bdb9edcd9299b194c7c0d6b56a88 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 May 2013 12:40:58 +0200 Subject: [PATCH 04/15] exec: eliminate stq_phys_notdirty It is not used anywhere. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 27 --------------------------- include/exec/cpu-common.h | 1 - include/exec/poison.h | 1 - 3 files changed, 29 deletions(-) diff --git a/exec.c b/exec.c index fa5f9c3171..1355661963 100644 --- a/exec.c +++ b/exec.c @@ -2390,33 +2390,6 @@ void stl_phys_notdirty(hwaddr addr, uint32_t val) } } -void stq_phys_notdirty(hwaddr addr, uint64_t val) -{ - uint8_t *ptr; - MemoryRegionSection *section; - - section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); - - if (!memory_region_is_ram(section->mr) || section->readonly) { - addr = memory_region_section_addr(section, addr); - if (memory_region_is_ram(section->mr)) { - section = &phys_sections[phys_section_rom]; - } -#ifdef TARGET_WORDS_BIGENDIAN - io_mem_write(section->mr, addr, val >> 32, 4); - io_mem_write(section->mr, addr + 4, (uint32_t)val, 4); -#else - io_mem_write(section->mr, addr, (uint32_t)val, 4); - io_mem_write(section->mr, addr + 4, val >> 32, 4); -#endif - } else { - ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr) - & TARGET_PAGE_MASK) - + memory_region_section_addr(section, addr)); - stq_p(ptr, val); - } -} - /* warning: addr must be aligned */ static inline void stl_phys_internal(hwaddr addr, uint32_t val, enum device_endian endian) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index af851aa633..af5258d414 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -102,7 +102,6 @@ uint32_t lduw_phys(hwaddr addr); uint32_t ldl_phys(hwaddr addr); uint64_t ldq_phys(hwaddr addr); void stl_phys_notdirty(hwaddr addr, uint32_t val); -void stq_phys_notdirty(hwaddr addr, uint64_t val); void stw_phys(hwaddr addr, uint32_t val); void stl_phys(hwaddr addr, uint32_t val); void stq_phys(hwaddr addr, uint64_t val); diff --git a/include/exec/poison.h b/include/exec/poison.h index 7d7b23b1fc..2341a75041 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -42,7 +42,6 @@ #pragma GCC poison ldl_phys #pragma GCC poison ldq_phys #pragma GCC poison stl_phys_notdirty -#pragma GCC poison stq_phys_notdirty #pragma GCC poison stw_phys #pragma GCC poison stl_phys #pragma GCC poison stq_phys From 68f3f65b09a1ce8c82fac17911ffc3bb6031ebe4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 7 May 2013 11:30:23 +0200 Subject: [PATCH 05/15] memory: assert that PhysPageEntry's ptr does not overflow While sized to 15 bits in PhysPageEntry, the ptr field is ORed into the iotlb entries together with a page-aligned pointer. The ptr field must not overflow into this page-aligned value, assert that it is smaller than the page size. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/exec.c b/exec.c index 1355661963..8562fcac9c 100644 --- a/exec.c +++ b/exec.c @@ -713,6 +713,12 @@ static void destroy_all_mappings(AddressSpaceDispatch *d) static uint16_t phys_section_add(MemoryRegionSection *section) { + /* The physical section number is ORed with a page-aligned + * pointer to produce the iotlb entries. Thus it should + * never overflow into the page-aligned value. + */ + assert(phys_sections_nb < TARGET_PAGE_SIZE); + if (phys_sections_nb == phys_sections_nb_alloc) { phys_sections_nb_alloc = MAX(phys_sections_nb_alloc * 2, 16); phys_sections = g_renew(MemoryRegionSection, phys_sections, From 73034e9e087aa51b85cf86b6c81ef92f7e1e9d09 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 7 May 2013 15:48:28 +0200 Subject: [PATCH 06/15] memory: allow memory_region_find() to run on non-root memory regions memory_region_find() is similar to registering a MemoryListener and checking for the MemoryRegionSections that come from a particular region. There is no reason for this to be limited to a root memory region. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- include/exec/memory.h | 28 +++++++++++++++++++--------- memory.c | 20 +++++++++++++++----- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 9e88320113..329ffb191d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -718,24 +718,34 @@ void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset); /** - * memory_region_find: locate a MemoryRegion in an address space + * memory_region_find: translate an address/size relative to a + * MemoryRegion into a #MemoryRegionSection. * - * Locates the first #MemoryRegion within an address space given by - * @address_space that overlaps the range given by @addr and @size. + * Locates the first #MemoryRegion within @mr that overlaps the range + * given by @addr and @size. * * Returns a #MemoryRegionSection that describes a contiguous overlap. * It will have the following characteristics: - * .@offset_within_address_space >= @addr - * .@offset_within_address_space + .@size <= @addr + @size * .@size = 0 iff no overlap was found * .@mr is non-%NULL iff an overlap was found * - * @address_space: a top-level (i.e. parentless) region that contains - * the region to be found - * @addr: start of the area within @address_space to be searched + * Remember that in the return value the @offset_within_region is + * relative to the returned region (in the .@mr field), not to the + * @mr argument. + * + * Similarly, the .@offset_within_address_space is relative to the + * address space that contains both regions, the passed and the + * returned one. However, in the special case where the @mr argument + * has no parent (and thus is the root of the address space), the + * following will hold: + * .@offset_within_address_space >= @addr + * .@offset_within_address_space + .@size <= @addr + @size + * + * @mr: a MemoryRegion within which @addr is a relative address + * @addr: start of the area within @as to be searched * @size: size of the area to be searched */ -MemoryRegionSection memory_region_find(MemoryRegion *address_space, +MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size); /** diff --git a/memory.c b/memory.c index 75ca281e97..34bfb13894 100644 --- a/memory.c +++ b/memory.c @@ -1451,15 +1451,24 @@ static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) sizeof(FlatRange), cmp_flatrange_addr); } -MemoryRegionSection memory_region_find(MemoryRegion *address_space, +MemoryRegionSection memory_region_find(MemoryRegion *mr, hwaddr addr, uint64_t size) { - AddressSpace *as = memory_region_to_address_space(address_space); - AddrRange range = addrrange_make(int128_make64(addr), - int128_make64(size)); - FlatRange *fr = address_space_lookup(as, range); MemoryRegionSection ret = { .mr = NULL, .size = 0 }; + MemoryRegion *root; + AddressSpace *as; + AddrRange range; + FlatRange *fr; + addr += mr->addr; + for (root = mr; root->parent; ) { + root = root->parent; + addr += root->addr; + } + + as = memory_region_to_address_space(root); + range = addrrange_make(int128_make64(addr), int128_make64(size)); + fr = address_space_lookup(as, range); if (!fr) { return ret; } @@ -1470,6 +1479,7 @@ MemoryRegionSection memory_region_find(MemoryRegion *address_space, } ret.mr = fr->mr; + ret.address_space = as; range = addrrange_intersection(range, fr->addr); ret.offset_within_region = fr->offset_in_region; ret.offset_within_region += int128_get64(int128_sub(range.start, From 4b81126e3399bfbcc47a4d696902c93401169f72 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 6 May 2013 18:07:05 +0200 Subject: [PATCH 07/15] memory: Replace open-coded memory_region_is_romd Improves readability. Reviewed-by: Peter Maydell Signed-off-by: Jan Kiszka --- translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translate-all.c b/translate-all.c index da93608f03..0d84b0d0c6 100644 --- a/translate-all.c +++ b/translate-all.c @@ -1359,7 +1359,7 @@ void tb_invalidate_phys_addr(hwaddr addr) section = phys_page_find(address_space_memory.dispatch, addr >> TARGET_PAGE_BITS); if (!(memory_region_is_ram(section->mr) - || (section->mr->rom_device && section->mr->readable))) { + || memory_region_is_romd(section->mr))) { return; } ram_addr = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK) From 5f9a5ea1c0a8391033e7d33abd335dd804a1001a Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 7 May 2013 19:04:25 +0200 Subject: [PATCH 08/15] memory: Rename readable flag to romd_mode "Readable" is a very unfortunate name for this flag because even a rom_device region will always be readable from the guest POV. What differs is the mapping, just like the comments had to explain already. Also, readable could currently be understood as being a generic region flag, but it only applies to rom_device regions. So rename the flag and the function to modify it after the original term "ROMD" which could also be interpreted as "ROM direct", i.e. ROM mode with direct access. In any case, the scope of the flag is clearer now. Signed-off-by: Jan Kiszka Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- hw/block/pflash_cfi01.c | 6 +++--- hw/block/pflash_cfi02.c | 2 +- include/exec/memory.h | 22 +++++++++++----------- memory.c | 30 +++++++++++++++--------------- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 3ff20e0c6f..63d7c9951f 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -105,7 +105,7 @@ static void pflash_timer (void *opaque) DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); /* Reset flash */ pfl->status ^= 0x80; - memory_region_rom_device_set_readable(&pfl->mem, true); + memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; pfl->cmd = 0; } @@ -281,7 +281,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, if (!pfl->wcycle) { /* Set the device in I/O access mode */ - memory_region_rom_device_set_readable(&pfl->mem, false); + memory_region_rom_device_set_romd(&pfl->mem, false); } switch (pfl->wcycle) { @@ -458,7 +458,7 @@ static void pflash_write(pflash_t *pfl, hwaddr offset, "\n", __func__, offset, pfl->wcycle, pfl->cmd, value); reset_flash: - memory_region_rom_device_set_readable(&pfl->mem, true); + memory_region_rom_device_set_romd(&pfl->mem, true); pfl->wcycle = 0; pfl->cmd = 0; diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 9a7fa707ca..5f25246926 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -111,7 +111,7 @@ static void pflash_setup_mappings(pflash_t *pfl) static void pflash_register_memory(pflash_t *pfl, int rom_mode) { - memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode); + memory_region_rom_device_set_romd(&pfl->orig_mem, rom_mode); pfl->rom_mode = rom_mode; } diff --git a/include/exec/memory.h b/include/exec/memory.h index 329ffb191d..e1208e476f 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -126,7 +126,7 @@ struct MemoryRegion { ram_addr_t ram_addr; bool subpage; bool terminates; - bool readable; + bool romd_mode; bool ram; bool readonly; /* For RAM regions */ bool enabled; @@ -355,16 +355,16 @@ uint64_t memory_region_size(MemoryRegion *mr); bool memory_region_is_ram(MemoryRegion *mr); /** - * memory_region_is_romd: check whether a memory region is ROMD + * memory_region_is_romd: check whether a memory region is in ROMD mode * - * Returns %true is a memory region is ROMD and currently set to allow + * Returns %true if a memory region is a ROM device and currently set to allow * direct reads. * * @mr: the memory region being queried */ static inline bool memory_region_is_romd(MemoryRegion *mr) { - return mr->rom_device && mr->readable; + return mr->rom_device && mr->romd_mode; } /** @@ -502,18 +502,18 @@ void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, void memory_region_set_readonly(MemoryRegion *mr, bool readonly); /** - * memory_region_rom_device_set_readable: enable/disable ROM readability + * memory_region_rom_device_set_romd: enable/disable ROMD mode * * Allows a ROM device (initialized with memory_region_init_rom_device() to - * to be marked as readable (default) or not readable. When it is readable, - * the device is mapped to guest memory. When not readable, reads are - * forwarded to the #MemoryRegion.read function. + * set to ROMD mode (default) or MMIO mode. When it is in ROMD mode, the + * device is mapped to guest memory and satisfies read access directly. + * When in MMIO mode, reads are forwarded to the #MemoryRegion.read function. + * Writes are always handled by the #MemoryRegion.write function. * * @mr: the memory region to be updated - * @readable: whether reads are satisified directly (%true) or via callbacks - * (%false) + * @romd_mode: %true to put the region into ROMD mode */ -void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable); +void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode); /** * memory_region_set_coalescing: Enable memory coalescing for the region. diff --git a/memory.c b/memory.c index 34bfb13894..013464b107 100644 --- a/memory.c +++ b/memory.c @@ -213,7 +213,7 @@ struct FlatRange { hwaddr offset_in_region; AddrRange addr; uint8_t dirty_log_mask; - bool readable; + bool romd_mode; bool readonly; }; @@ -236,7 +236,7 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b) return a->mr == b->mr && addrrange_equal(a->addr, b->addr) && a->offset_in_region == b->offset_in_region - && a->readable == b->readable + && a->romd_mode == b->romd_mode && a->readonly == b->readonly; } @@ -276,7 +276,7 @@ static bool can_merge(FlatRange *r1, FlatRange *r2) r1->addr.size), int128_make64(r2->offset_in_region)) && r1->dirty_log_mask == r2->dirty_log_mask - && r1->readable == r2->readable + && r1->romd_mode == r2->romd_mode && r1->readonly == r2->readonly; } @@ -532,7 +532,7 @@ static void render_memory_region(FlatView *view, fr.offset_in_region = offset_in_region; fr.addr = addrrange_make(base, now); fr.dirty_log_mask = mr->dirty_log_mask; - fr.readable = mr->readable; + fr.romd_mode = mr->romd_mode; fr.readonly = readonly; flatview_insert(view, i, &fr); ++i; @@ -552,7 +552,7 @@ static void render_memory_region(FlatView *view, fr.offset_in_region = offset_in_region; fr.addr = addrrange_make(base, remain); fr.dirty_log_mask = mr->dirty_log_mask; - fr.readable = mr->readable; + fr.romd_mode = mr->romd_mode; fr.readonly = readonly; flatview_insert(view, i, &fr); } @@ -801,7 +801,7 @@ void memory_region_init(MemoryRegion *mr, mr->enabled = true; mr->terminates = false; mr->ram = false; - mr->readable = true; + mr->romd_mode = true; mr->readonly = false; mr->rom_device = false; mr->destructor = memory_region_destructor_none; @@ -1121,11 +1121,11 @@ void memory_region_set_readonly(MemoryRegion *mr, bool readonly) } } -void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable) +void memory_region_rom_device_set_romd(MemoryRegion *mr, bool romd_mode) { - if (mr->readable != readable) { + if (mr->romd_mode != romd_mode) { memory_region_transaction_begin(); - mr->readable = readable; + mr->romd_mode = romd_mode; memory_region_update_pending |= mr->enabled; memory_region_transaction_commit(); } @@ -1659,9 +1659,9 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, base + mr->addr + (hwaddr)int128_get64(mr->size) - 1, mr->priority, - mr->readable ? 'R' : '-', - !mr->readonly && !(mr->rom_device && mr->readable) ? 'W' - : '-', + mr->romd_mode ? 'R' : '-', + !mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W' + : '-', mr->name, mr->alias->name, mr->alias_offset, @@ -1674,9 +1674,9 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f, base + mr->addr + (hwaddr)int128_get64(mr->size) - 1, mr->priority, - mr->readable ? 'R' : '-', - !mr->readonly && !(mr->rom_device && mr->readable) ? 'W' - : '-', + mr->romd_mode ? 'R' : '-', + !mr->readonly && !(mr->rom_device && mr->romd_mode) ? 'W' + : '-', mr->name); } From 5553e3a5c95f4a842489384a2fafb27d7555a4ef Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 3 May 2013 17:18:36 +0200 Subject: [PATCH 09/15] memory: do not duplicate memory_region_destructor_none Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- memory.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/memory.c b/memory.c index 013464b107..54314636e3 100644 --- a/memory.c +++ b/memory.c @@ -768,10 +768,6 @@ static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr) qemu_ram_free_from_ptr(mr->ram_addr); } -static void memory_region_destructor_iomem(MemoryRegion *mr) -{ -} - static void memory_region_destructor_rom_device(MemoryRegion *mr) { qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK); @@ -929,7 +925,6 @@ void memory_region_init_io(MemoryRegion *mr, mr->ops = ops; mr->opaque = opaque; mr->terminates = true; - mr->destructor = memory_region_destructor_iomem; mr->ram_addr = ~(ram_addr_t)0; } From 1d671369c3f8eb2b5dfd0e1709688faba9b85f95 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 24 Apr 2013 10:46:55 +0200 Subject: [PATCH 10/15] memory: make memory_global_sync_dirty_bitmap take an AddressSpace Since this is a MemoryListener operation, it only makes sense on an AddressSpace granularity. Suggested-by: Peter Maydell Signed-off-by: Paolo Bonzini --- arch_init.c | 2 +- include/exec/memory.h | 7 +++---- memory.c | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/arch_init.c b/arch_init.c index 49c5dc27e6..5d32ecf23a 100644 --- a/arch_init.c +++ b/arch_init.c @@ -386,7 +386,7 @@ static void migration_bitmap_sync(void) } trace_migration_bitmap_sync_start(); - memory_global_sync_dirty_bitmap(get_system_memory()); + address_space_sync_dirty_bitmap(&address_space_memory); QTAILQ_FOREACH(block, &ram_list.blocks, next) { for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) { diff --git a/include/exec/memory.h b/include/exec/memory.h index e1208e476f..91be2a3c7a 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -766,13 +766,12 @@ memory_region_section_addr(MemoryRegionSection *section, } /** - * memory_global_sync_dirty_bitmap: synchronize the dirty log for all memory + * address_space_sync_dirty_bitmap: synchronize the dirty log for all memory * * Synchronizes the dirty page log for an entire address space. - * @address_space: a top-level (i.e. parentless) region that contains the - * memory being synchronized + * @as: the address space that contains the memory being synchronized */ -void memory_global_sync_dirty_bitmap(MemoryRegion *address_space); +void address_space_sync_dirty_bitmap(AddressSpace *as); /** * memory_region_transaction_begin: Start a transaction. diff --git a/memory.c b/memory.c index 54314636e3..11bbeb7445 100644 --- a/memory.c +++ b/memory.c @@ -1485,9 +1485,8 @@ MemoryRegionSection memory_region_find(MemoryRegion *mr, return ret; } -void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) +void address_space_sync_dirty_bitmap(AddressSpace *as) { - AddressSpace *as = memory_region_to_address_space(address_space); FlatRange *fr; FOR_EACH_FLAT_RANGE(fr, as->current_map) { From 4c19eb721a5929f2277d33a98bb59963c58c2e3b Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 30 Oct 2012 13:47:44 +0200 Subject: [PATCH 11/15] memory: fix address space initialization/destruction A couple of fields were left uninitialized. This was not observed earlier because all address spaces were statically allocated. Also free allocation for those fields. Reviewed-by: Peter Maydell Signed-off-by: Avi Kivity Signed-off-by: Paolo Bonzini --- memory.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/memory.c b/memory.c index 11bbeb7445..9478f98fdc 100644 --- a/memory.c +++ b/memory.c @@ -1572,6 +1572,8 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) as->root = root; as->current_map = g_new(FlatView, 1); flatview_init(as->current_map); + as->ioeventfd_nb = 0; + as->ioeventfds = NULL; QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); as->name = NULL; memory_region_transaction_commit(); @@ -1588,6 +1590,7 @@ void address_space_destroy(AddressSpace *as) address_space_destroy_dispatch(as); flatview_destroy(as->current_map); g_free(as->current_map); + g_free(as->ioeventfds); } uint64_t io_mem_read(MemoryRegion *mr, hwaddr addr, unsigned size) From 311f83ca08c011b048c063c2fd3038a8957970bc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 13 May 2013 15:54:44 +0200 Subject: [PATCH 12/15] s390x: reduce TARGET_PHYS_ADDR_SPACE_BITS to 62 With the next patch, the memory API will complain if the TARGET_PHYS_ADDR_SPACE_BITS gets dangerously close to an overflow. s390x can handle up to 64 bit of physical address space from its page tables, but we never use that much. Just decrease the value. Cc: Alexander Graf Signed-off-by: Paolo Bonzini --- target-s390x/cpu.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 0ce82cf830..6304c4d90b 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -34,7 +34,10 @@ #include "exec/cpu-defs.h" #define TARGET_PAGE_BITS 12 -#define TARGET_PHYS_ADDR_SPACE_BITS 64 +/* Actually 64-bits, limited by the memory API to 62 bits. We + * never use that much. + */ +#define TARGET_PHYS_ADDR_SPACE_BITS 62 #define TARGET_VIRT_ADDR_SPACE_BITS 64 #include "exec/cpu-all.h" From 86a8623692b1b559a419a92eb8b6897c221bca74 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 30 Oct 2012 13:47:45 +0200 Subject: [PATCH 13/15] memory: limit sections in the radix tree to the actual address space size The radix tree is statically sized to fit TARGET_PHYS_ADDR_SPACE_BITS. If a larger memory region is registered, it will overflow. Fix by limiting any section in the radix tree to the supported size. This problem was not observed earlier since artificial regions (containers and aliases) are eliminated by the memory core, leaving only device regions which have reasonable sizes. An IOMMU however cannot be eliminated by the memory core, and may have an artificial size. Reviewed-by: Peter Maydell Signed-off-by: Avi Kivity [ Fail the build if TARGET_PHYS_ADDR_SPACE_BITS is too large - Paolo ] Signed-off-by: Paolo Bonzini --- exec.c | 13 ++++++++++++- include/exec/memory.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 8562fcac9c..3fdca46a6a 100644 --- a/exec.c +++ b/exec.c @@ -775,10 +775,21 @@ static void register_multipage(AddressSpaceDispatch *d, MemoryRegionSection *sec section_index); } +QEMU_BUILD_BUG_ON(TARGET_PHYS_ADDR_SPACE_BITS > MAX_PHYS_ADDR_SPACE_BITS) + +static MemoryRegionSection limit(MemoryRegionSection section) +{ + section.size = MIN(section.offset_within_address_space + section.size, + MAX_PHYS_ADDR + 1) + - section.offset_within_address_space; + + return section; +} + static void mem_add(MemoryListener *listener, MemoryRegionSection *section) { AddressSpaceDispatch *d = container_of(listener, AddressSpaceDispatch, listener); - MemoryRegionSection now = *section, remain = *section; + MemoryRegionSection now = limit(*section), remain = limit(*section); if ((now.offset_within_address_space & ~TARGET_PAGE_MASK) || (now.size < TARGET_PAGE_SIZE)) { diff --git a/include/exec/memory.h b/include/exec/memory.h index 91be2a3c7a..fdf55feea1 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -26,6 +26,9 @@ #include "exec/ioport.h" #include "qemu/int128.h" +#define MAX_PHYS_ADDR_SPACE_BITS 62 +#define MAX_PHYS_ADDR (((hwaddr)1 << MAX_PHYS_ADDR_SPACE_BITS) - 1) + typedef struct MemoryRegionOps MemoryRegionOps; typedef struct MemoryRegionPortio MemoryRegionPortio; typedef struct MemoryRegionMmio MemoryRegionMmio; From f43793c7caab49c68b41c3b8524fc35b4c206856 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 16 Apr 2013 15:39:51 +0200 Subject: [PATCH 14/15] memory: populate FlatView for new address spaces Even a new address space might have a non-empty FlatView. In order to initialize it properly, address_space_init should (a) call memory_region_transaction_commit after the address space is inserted into the list; (b) force memory_region_transaction_commit to do something. This bug was latent so far because all address spaces started empty, including the PCI address space where the bus master region is initially disabled. However, the target address space of an IOMMU is usually rooted at get_system_memory(), which might not be empty at the time the IOMMU is created. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- memory.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/memory.c b/memory.c index 9478f98fdc..99f046d8bb 100644 --- a/memory.c +++ b/memory.c @@ -1576,8 +1576,9 @@ void address_space_init(AddressSpace *as, MemoryRegion *root) as->ioeventfds = NULL; QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); as->name = NULL; - memory_region_transaction_commit(); address_space_init_dispatch(as); + memory_region_update_pending |= root->enabled; + memory_region_transaction_commit(); } void address_space_destroy(AddressSpace *as) From fd2989341e758813351c2fc1446cc8fbcae06ad9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 20 May 2013 12:21:07 +0200 Subject: [PATCH 15/15] memory: clean up phys_page_find Remove the goto. Reviewed-by: Peter Maydell Signed-off-by: Paolo Bonzini --- exec.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/exec.c b/exec.c index 3fdca46a6a..3a9ddcb41f 100644 --- a/exec.c +++ b/exec.c @@ -187,19 +187,15 @@ MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr index) PhysPageEntry lp = d->phys_map; PhysPageEntry *p; int i; - uint16_t s_index = phys_section_unassigned; for (i = P_L2_LEVELS - 1; i >= 0 && !lp.is_leaf; i--) { if (lp.ptr == PHYS_MAP_NODE_NIL) { - goto not_found; + return &phys_sections[phys_section_unassigned]; } p = phys_map_nodes[lp.ptr]; lp = p[(index >> (i * L2_BITS)) & (L2_SIZE - 1)]; } - - s_index = lp.ptr; -not_found: - return &phys_sections[s_index]; + return &phys_sections[lp.ptr]; } bool memory_region_is_unassigned(MemoryRegion *mr)