* GNU GPL, version 2 or (at your option) any later version.
*/
-#include "memory.h"
-#include "exec-memory.h"
-#include "ioport.h"
-#include "bitops.h"
-#include "kvm.h"
+#include "exec/memory.h"
+#include "exec/address-spaces.h"
+#include "exec/ioport.h"
+#include "qemu/bitops.h"
+#include "sysemu/kvm.h"
#include <assert.h>
-#include "memory-internal.h"
+#include "exec/memory-internal.h"
-unsigned memory_region_transaction_depth = 0;
+static unsigned memory_region_transaction_depth;
+static bool memory_region_update_pending;
static bool global_dirty_log = false;
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
/* Range of memory in the global map. Addresses are absolute. */
struct FlatRange {
MemoryRegion *mr;
- target_phys_addr_t offset_in_region;
+ hwaddr offset_in_region;
AddrRange addr;
uint8_t dirty_log_mask;
bool readable;
}
static void memory_region_read_accessor(void *opaque,
- target_phys_addr_t addr,
+ hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
}
static void memory_region_write_accessor(void *opaque,
- target_phys_addr_t addr,
+ hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
mr->ops->write(mr->opaque, addr, tmp, size);
}
-static void access_with_adjusted_size(target_phys_addr_t addr,
+static void access_with_adjusted_size(hwaddr addr,
uint64_t *value,
unsigned size,
unsigned access_size_min,
unsigned access_size_max,
void (*access)(void *opaque,
- target_phys_addr_t addr,
+ hwaddr addr,
uint64_t *value,
unsigned size,
unsigned shift,
{
MemoryRegion *subregion;
unsigned i;
- target_phys_addr_t offset_in_region;
+ hwaddr offset_in_region;
Int128 remain;
Int128 now;
FlatRange fr;
offset_in_region += int128_get64(now);
int128_subfrom(&remain, now);
}
- if (int128_eq(base, view->ranges[i].addr.start)) {
- now = int128_min(remain, view->ranges[i].addr.size);
- int128_addto(&base, now);
- offset_in_region += int128_get64(now);
- int128_subfrom(&remain, now);
- }
+ now = int128_sub(int128_min(int128_add(base, remain),
+ addrrange_end(view->ranges[i].addr)),
+ base);
+ int128_addto(&base, now);
+ offset_in_region += int128_get64(now);
+ int128_subfrom(&remain, now);
}
if (int128_nz(remain)) {
fr.mr = mr;
flatview_init(&view);
- render_memory_region(&view, mr, int128_zero(),
- addrrange_make(int128_zero(), int128_2_64()), false);
+ if (mr) {
+ render_memory_region(&view, mr, int128_zero(),
+ addrrange_make(int128_zero(), int128_2_64()), false);
+ }
flatview_simplify(&view);
return view;
assert(memory_region_transaction_depth);
--memory_region_transaction_depth;
- if (!memory_region_transaction_depth) {
+ if (!memory_region_transaction_depth && memory_region_update_pending) {
+ memory_region_update_pending = false;
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
}
static bool memory_region_access_valid(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
unsigned size,
bool is_write)
{
}
static uint64_t memory_region_dispatch_read1(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
unsigned size)
{
uint64_t data = 0;
}
if (!mr->ops->read) {
- return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr);
+ return mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr);
}
/* FIXME: support unaligned access */
}
static uint64_t memory_region_dispatch_read(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
unsigned size)
{
uint64_t ret;
}
static void memory_region_dispatch_write(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
uint64_t data,
unsigned size)
{
adjust_endianness(mr, &data, size);
if (!mr->ops->write) {
- mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data);
+ mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, data);
return;
}
void memory_region_init_alias(MemoryRegion *mr,
const char *name,
MemoryRegion *orig,
- target_phys_addr_t offset,
+ hwaddr offset,
uint64_t size)
{
memory_region_init(mr, name, size);
mr->ram_addr = qemu_ram_alloc(size, mr);
}
-static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+static uint64_t invalid_read(void *opaque, hwaddr addr,
unsigned size)
{
MemoryRegion *mr = opaque;
return -1U;
}
-static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+static void invalid_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
MemoryRegion *mr = opaque;
void memory_region_destroy(MemoryRegion *mr)
{
assert(QTAILQ_EMPTY(&mr->subregions));
+ assert(memory_region_transaction_depth == 0);
mr->destructor(mr);
memory_region_clear_coalescing(mr);
g_free((char *)mr->name);
memory_region_transaction_begin();
mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
-bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- target_phys_addr_t size, unsigned client)
+bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr,
+ hwaddr size, unsigned client)
{
assert(mr->terminates);
return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
1 << client);
}
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- target_phys_addr_t size)
+void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
+ hwaddr size)
{
assert(mr->terminates);
return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1);
}
+bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
+ hwaddr size, unsigned client)
+{
+ bool ret;
+ assert(mr->terminates);
+ ret = cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
+ 1 << client);
+ if (ret) {
+ cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
+ mr->ram_addr + addr + size,
+ 1 << client);
+ }
+ return ret;
+}
+
+
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
{
AddressSpace *as;
if (mr->readonly != readonly) {
memory_region_transaction_begin();
mr->readonly = readonly;
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
}
if (mr->readable != readable) {
memory_region_transaction_begin();
mr->readable = readable;
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
}
-void memory_region_reset_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- target_phys_addr_t size, unsigned client)
+void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr,
+ hwaddr size, unsigned client)
{
assert(mr->terminates);
cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
}
void memory_region_add_coalescing(MemoryRegion *mr,
- target_phys_addr_t offset,
+ hwaddr offset,
uint64_t size)
{
CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr));
}
void memory_region_add_eventfd(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
unsigned size,
bool match_data,
uint64_t data,
};
unsigned i;
+ adjust_endianness(mr, &mrfd.data, size);
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
mr->ioeventfds[i] = mrfd;
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
void memory_region_del_eventfd(MemoryRegion *mr,
- target_phys_addr_t addr,
+ hwaddr addr,
unsigned size,
bool match_data,
uint64_t data,
};
unsigned i;
+ adjust_endianness(mr, &mrfd.data, size);
memory_region_transaction_begin();
for (i = 0; i < mr->ioeventfd_nb; ++i) {
if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
--mr->ioeventfd_nb;
mr->ioeventfds = g_realloc(mr->ioeventfds,
sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
static void memory_region_add_subregion_common(MemoryRegion *mr,
- target_phys_addr_t offset,
+ hwaddr offset,
MemoryRegion *subregion)
{
MemoryRegion *other;
if (subregion->may_overlap || other->may_overlap) {
continue;
}
- if (int128_gt(int128_make64(offset),
+ if (int128_ge(int128_make64(offset),
int128_add(int128_make64(other->addr), other->size))
|| int128_le(int128_add(int128_make64(offset), subregion->size),
int128_make64(other->addr))) {
}
QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
done:
+ memory_region_update_pending |= mr->enabled && subregion->enabled;
memory_region_transaction_commit();
}
void memory_region_add_subregion(MemoryRegion *mr,
- target_phys_addr_t offset,
+ hwaddr offset,
MemoryRegion *subregion)
{
subregion->may_overlap = false;
}
void memory_region_add_subregion_overlap(MemoryRegion *mr,
- target_phys_addr_t offset,
+ hwaddr offset,
MemoryRegion *subregion,
unsigned priority)
{
assert(subregion->parent == mr);
subregion->parent = NULL;
QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
+ memory_region_update_pending |= mr->enabled && subregion->enabled;
memory_region_transaction_commit();
}
}
memory_region_transaction_begin();
mr->enabled = enabled;
+ memory_region_update_pending = true;
memory_region_transaction_commit();
}
-void memory_region_set_address(MemoryRegion *mr, target_phys_addr_t addr)
+void memory_region_set_address(MemoryRegion *mr, hwaddr addr)
{
MemoryRegion *parent = mr->parent;
unsigned priority = mr->priority;
memory_region_transaction_commit();
}
-void memory_region_set_alias_offset(MemoryRegion *mr, target_phys_addr_t offset)
+void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset)
{
assert(mr->alias);
memory_region_transaction_begin();
mr->alias_offset = offset;
+ memory_region_update_pending |= mr->enabled;
memory_region_transaction_commit();
}
}
MemoryRegionSection memory_region_find(MemoryRegion *address_space,
- target_phys_addr_t addr, uint64_t size)
+ hwaddr addr, uint64_t size)
{
AddressSpace *as = memory_region_to_address_space(address_space);
AddrRange range = addrrange_make(int128_make64(addr),
QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link);
as->name = NULL;
memory_region_transaction_commit();
+ address_space_init_dispatch(as);
+}
+
+void address_space_destroy(AddressSpace *as)
+{
+ /* Flush out anything from MemoryListeners listening in on this */
+ memory_region_transaction_begin();
+ as->root = NULL;
+ memory_region_transaction_commit();
+ QTAILQ_REMOVE(&address_spaces, as, address_spaces_link);
+ address_space_destroy_dispatch(as);
+ flatview_destroy(as->current_map);
+ g_free(as->current_map);
}
-uint64_t io_mem_read(MemoryRegion *mr, target_phys_addr_t addr, unsigned size)
+uint64_t io_mem_read(MemoryRegion *mr, hwaddr addr, unsigned size)
{
return memory_region_dispatch_read(mr, addr, size);
}
-void io_mem_write(MemoryRegion *mr, target_phys_addr_t addr,
+void io_mem_write(MemoryRegion *mr, hwaddr addr,
uint64_t val, unsigned size)
{
memory_region_dispatch_write(mr, addr, val, size);
static void mtree_print_mr(fprintf_function mon_printf, void *f,
const MemoryRegion *mr, unsigned int level,
- target_phys_addr_t base,
+ hwaddr base,
MemoryRegionListHead *alias_print_queue)
{
MemoryRegionList *new_ml, *ml, *next_ml;
const MemoryRegion *submr;
unsigned int i;
- if (!mr) {
+ if (!mr || !mr->enabled) {
return;
}
"-" TARGET_FMT_plx "\n",
base + mr->addr,
base + mr->addr
- + (target_phys_addr_t)int128_get64(mr->size) - 1,
+ + (hwaddr)int128_get64(mr->size) - 1,
mr->priority,
mr->readable ? 'R' : '-',
!mr->readonly && !(mr->rom_device && mr->readable) ? 'W'
mr->alias->name,
mr->alias_offset,
mr->alias_offset
- + (target_phys_addr_t)int128_get64(mr->size) - 1);
+ + (hwaddr)int128_get64(mr->size) - 1);
} else {
mon_printf(f,
TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s\n",
base + mr->addr,
base + mr->addr
- + (target_phys_addr_t)int128_get64(mr->size) - 1,
+ + (hwaddr)int128_get64(mr->size) - 1,
mr->priority,
mr->readable ? 'R' : '-',
!mr->readonly && !(mr->rom_device && mr->readable) ? 'W'