*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
+#include "exec/page-vary.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/cacheflush.h"
+#include "qemu/hbitmap.h"
+#include "qemu/madvise.h"
#ifdef CONFIG_TCG
#include "hw/core/tcg-cpu-ops.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"
#include "qemu/qemu-print.h"
+#include "qemu/log.h"
+#include "qemu/memalign.h"
#include "exec/memory.h"
#include "exec/ioport.h"
#include "sysemu/dma.h"
#include "exec/memory-internal.h"
#include "exec/ram_addr.h"
-#include "exec/log.h"
#include "qemu/pmem.h"
/* Called from RCU critical section */
MemoryRegionSection *
-address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
+address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr,
hwaddr *xlat, hwaddr *plen,
MemTxAttrs attrs, int *prot)
{
IOMMUMemoryRegionClass *imrc;
IOMMUTLBEntry iotlb;
int iommu_idx;
+ hwaddr addr = orig_addr;
AddressSpaceDispatch *d =
qatomic_rcu_read(&cpu->cpu_ases[asidx].memory_dispatch);
return section;
translate_fail:
+ /*
+ * We should be given a page-aligned address -- certainly
+ * tlb_set_page_with_attrs() does so. The page offset of xlat
+ * is used to index sections[], and PHYS_SECTION_UNASSIGNED = 0.
+ * The page portion of xlat will be logged by memory_region_access_valid()
+ * when this memory access is rejected, so use the original untranslated
+ * physical address.
+ */
+ assert((orig_addr & ~TARGET_PAGE_MASK) == 0);
+ *xlat = orig_addr;
return &d->map.sections[PHYS_SECTION_UNASSIGNED];
}
if (tcg_enabled()) {
newas->tcg_as_listener.log_global_after_sync = tcg_log_global_after_sync;
newas->tcg_as_listener.commit = tcg_commit;
+ newas->tcg_as_listener.name = "tcg";
memory_listener_register(&newas->tcg_as_listener, as);
}
}
return cpu->cpu_ases[asidx].as;
}
-/* Add a watchpoint. */
-int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
- int flags, CPUWatchpoint **watchpoint)
-{
- CPUWatchpoint *wp;
- vaddr in_page;
-
- /* forbid ranges which are empty or run off the end of the address space */
- if (len == 0 || (addr + len - 1) < addr) {
- error_report("tried to set invalid watchpoint at %"
- VADDR_PRIx ", len=%" VADDR_PRIu, addr, len);
- return -EINVAL;
- }
- wp = g_malloc(sizeof(*wp));
-
- wp->vaddr = addr;
- wp->len = len;
- wp->flags = flags;
-
- /* keep all GDB-injected watchpoints in front */
- if (flags & BP_GDB) {
- QTAILQ_INSERT_HEAD(&cpu->watchpoints, wp, entry);
- } else {
- QTAILQ_INSERT_TAIL(&cpu->watchpoints, wp, entry);
- }
-
- in_page = -(addr | TARGET_PAGE_MASK);
- if (len <= in_page) {
- tlb_flush_page(cpu, addr);
- } else {
- tlb_flush(cpu);
- }
-
- if (watchpoint)
- *watchpoint = wp;
- return 0;
-}
-
-/* Remove a specific watchpoint. */
-int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
- int flags)
-{
- CPUWatchpoint *wp;
-
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (addr == wp->vaddr && len == wp->len
- && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
- cpu_watchpoint_remove_by_ref(cpu, wp);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/* Remove a specific watchpoint by reference. */
-void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
-{
- QTAILQ_REMOVE(&cpu->watchpoints, watchpoint, entry);
-
- tlb_flush_page(cpu, watchpoint->vaddr);
-
- g_free(watchpoint);
-}
-
-/* Remove all matching watchpoints. */
-void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
-{
- CPUWatchpoint *wp, *next;
-
- QTAILQ_FOREACH_SAFE(wp, &cpu->watchpoints, entry, next) {
- if (wp->flags & mask) {
- cpu_watchpoint_remove_by_ref(cpu, wp);
- }
- }
-}
-
-#ifdef CONFIG_TCG
-/* Return true if this watchpoint address matches the specified
- * access (ie the address range covered by the watchpoint overlaps
- * partially or completely with the address range covered by the
- * access).
- */
-static inline bool watchpoint_address_matches(CPUWatchpoint *wp,
- vaddr addr, vaddr len)
-{
- /* We know the lengths are non-zero, but a little caution is
- * required to avoid errors in the case where the range ends
- * exactly at the top of the address space and so addr + len
- * wraps round to zero.
- */
- vaddr wpend = wp->vaddr + wp->len - 1;
- vaddr addrend = addr + len - 1;
-
- return !(addr > wpend || wp->vaddr > addrend);
-}
-
-/* Return flags for watchpoints that match addr + prot. */
-int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len)
-{
- CPUWatchpoint *wp;
- int ret = 0;
-
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (watchpoint_address_matches(wp, addr, len)) {
- ret |= wp->flags;
- }
- }
- return ret;
-}
-
-/* Generate a debug exception if a watchpoint has been hit. */
-void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
- MemTxAttrs attrs, int flags, uintptr_t ra)
-{
- CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUWatchpoint *wp;
-
- assert(tcg_enabled());
- if (cpu->watchpoint_hit) {
- /*
- * We re-entered the check after replacing the TB.
- * Now raise the debug interrupt so that it will
- * trigger after the current instruction.
- */
- qemu_mutex_lock_iothread();
- cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG);
- qemu_mutex_unlock_iothread();
- return;
- }
-
- if (cc->tcg_ops->adjust_watchpoint_address) {
- /* this is currently used only by ARM BE32 */
- addr = cc->tcg_ops->adjust_watchpoint_address(cpu, addr, len);
- }
- QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
- if (watchpoint_address_matches(wp, addr, len)
- && (wp->flags & flags)) {
- if (replay_running_debug()) {
- /*
- * replay_breakpoint reads icount.
- * Force recompile to succeed, because icount may
- * be read only at the end of the block.
- */
- if (!cpu->can_do_io) {
- /* Force execution of one insn next time. */
- cpu->cflags_next_tb = 1 | CF_LAST_IO | curr_cflags(cpu);
- cpu_loop_exit_restore(cpu, ra);
- }
- /*
- * Don't process the watchpoints when we are
- * in a reverse debugging operation.
- */
- replay_breakpoint();
- return;
- }
- if (flags == BP_MEM_READ) {
- wp->flags |= BP_WATCHPOINT_HIT_READ;
- } else {
- wp->flags |= BP_WATCHPOINT_HIT_WRITE;
- }
- wp->hitaddr = MAX(addr, wp->vaddr);
- wp->hitattrs = attrs;
- if (!cpu->watchpoint_hit) {
- if (wp->flags & BP_CPU && cc->tcg_ops->debug_check_watchpoint &&
- !cc->tcg_ops->debug_check_watchpoint(cpu, wp)) {
- wp->flags &= ~BP_WATCHPOINT_HIT;
- continue;
- }
- cpu->watchpoint_hit = wp;
-
- mmap_lock();
- tb_check_watchpoint(cpu, ra);
- if (wp->flags & BP_STOP_BEFORE_ACCESS) {
- cpu->exception_index = EXCP_DEBUG;
- mmap_unlock();
- cpu_loop_exit_restore(cpu, ra);
- } else {
- /* Force execution of one insn next time. */
- cpu->cflags_next_tb = 1 | curr_cflags(cpu);
- mmap_unlock();
- if (ra) {
- cpu_restore_state(cpu, ra, true);
- }
- cpu_loop_exit_noexc(cpu);
- }
- }
- } else {
- wp->flags &= ~BP_WATCHPOINT_HIT;
- }
- }
-}
-
-#endif /* CONFIG_TCG */
-
/* Called from RCU critical section */
static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
{
qemu_mutex_unlock(&ram_list.mutex);
}
-void ram_block_dump(Monitor *mon)
+GString *ram_block_format(void)
{
RAMBlock *block;
char *psize;
+ GString *buf = g_string_new("");
RCU_READ_LOCK_GUARD();
- monitor_printf(mon, "%24s %8s %18s %18s %18s\n",
- "Block Name", "PSize", "Offset", "Used", "Total");
+ g_string_append_printf(buf, "%24s %8s %18s %18s %18s\n",
+ "Block Name", "PSize", "Offset", "Used", "Total");
RAMBLOCK_FOREACH(block) {
psize = size_to_str(block->page_size);
- monitor_printf(mon, "%24s %8s 0x%016" PRIx64 " 0x%016" PRIx64
- " 0x%016" PRIx64 "\n", block->idstr, psize,
- (uint64_t)block->offset,
- (uint64_t)block->used_length,
- (uint64_t)block->max_length);
+ g_string_append_printf(buf, "%24s %8s 0x%016" PRIx64 " 0x%016" PRIx64
+ " 0x%016" PRIx64 "\n", block->idstr, psize,
+ (uint64_t)block->offset,
+ (uint64_t)block->used_length,
+ (uint64_t)block->max_length);
g_free(psize);
}
+
+ return buf;
}
-#ifdef __linux__
-/*
- * FIXME TOCTTOU: this iterates over memory backends' mem-path, which
- * may or may not name the same files / on the same filesystem now as
- * when we actually open and map them. Iterate over the file
- * descriptors instead, and use qemu_fd_getpagesize().
- */
static int find_min_backend_pagesize(Object *obj, void *opaque)
{
long *hpsize_min = opaque;
object_child_foreach(memdev_root, find_max_backend_pagesize, &pagesize);
return pagesize;
}
-#else
-long qemu_minrampagesize(void)
-{
- return qemu_real_host_page_size;
-}
-long qemu_maxrampagesize(void)
-{
- return qemu_real_host_page_size;
-}
-#endif
#ifdef CONFIG_POSIX
static int64_t get_file_size(int fd)
path = g_strdup_printf("/sys/dev/char/%d:%d",
major(st.st_rdev), minor(st.st_rdev));
rpath = realpath(path, NULL);
+ if (!rpath) {
+ return -errno;
+ }
rc = daxctl_new(&ctx);
if (rc) {
rb->flags &= ~RAM_MIGRATABLE;
}
+int qemu_ram_get_fd(RAMBlock *rb)
+{
+ return rb->fd;
+}
+
/* Called with iothread lock held. */
void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev)
{
int64_t file_size, file_align;
/* Just support these ram flags by now. */
- assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE)) == 0);
+ assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
+ RAM_PROTECTED)) == 0);
if (xen_enabled()) {
error_setg(errp, "-mem-path not supported with Xen");
}
file_align = get_file_align(fd);
- if (file_align > 0 && mr && file_align > mr->align) {
+ if (file_align > 0 && file_align > mr->align) {
error_setg(errp, "backing store align 0x%" PRIx64
" is larger than 'align' option 0x%" PRIx64,
file_align, mr->align);
new_block->max_length = max_size;
assert(max_size >= size);
new_block->fd = -1;
- new_block->page_size = qemu_real_host_page_size;
+ new_block->page_size = qemu_real_host_page_size();
new_block->host = host;
new_block->flags = ram_flags;
ram_block_add(new_block, &local_err);
return block->offset + offset;
}
+ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
+{
+ ram_addr_t ram_addr;
+
+ ram_addr = qemu_ram_addr_from_host(ptr);
+ if (ram_addr == RAM_ADDR_INVALID) {
+ error_report("Bad ram pointer %p", ptr);
+ abort();
+ }
+ return ram_addr;
+}
+
static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
MemTxAttrs attrs, void *buf, hwaddr len);
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
MemTxResult res;
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p len %u addr " TARGET_FMT_plx "\n", __func__,
+ printf("%s: subpage %p len %u addr " HWADDR_FMT_plx "\n", __func__,
subpage, len, addr);
#endif
res = flatview_read(subpage->fv, addr + subpage->base, attrs, buf, len);
uint8_t buf[8];
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p len %u addr " TARGET_FMT_plx
+ printf("%s: subpage %p len %u addr " HWADDR_FMT_plx
" value %"PRIx64"\n",
__func__, subpage, len, addr, value);
#endif
{
subpage_t *subpage = opaque;
#if defined(DEBUG_SUBPAGE)
- printf("%s: subpage %p %c len %u addr " TARGET_FMT_plx "\n",
+ printf("%s: subpage %p %c len %u addr " HWADDR_FMT_plx "\n",
__func__, subpage, is_write ? 'w' : 'r', len, addr);
#endif
NULL, TARGET_PAGE_SIZE);
mmio->iomem.subpage = true;
#if defined(DEBUG_SUBPAGE)
- printf("%s: %p base " TARGET_FMT_plx " len %08x\n", __func__,
+ printf("%s: %p base " HWADDR_FMT_plx " len %08x\n", __func__,
mmio, base, TARGET_PAGE_SIZE);
#endif
* In record/replay mode this causes a deadlock, because
* run_on_cpu waits for rr mutex. Therefore no races are possible
* in this case and no need for making run_on_cpu when
- * record/replay is not enabled.
+ * record/replay is enabled.
*/
cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener);
run_on_cpu(cpuas->cpu, do_nothing, RUN_ON_CPU_NULL);
invalidate_and_set_dirty(mr, addr, size);
}
-static int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
+int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
{
unsigned access_size_max = mr->ops->valid.max_access_size;
return l;
}
-static bool prepare_mmio_access(MemoryRegion *mr)
+bool prepare_mmio_access(MemoryRegion *mr)
{
bool release_lock = false;
return release_lock;
}
+/**
+ * flatview_access_allowed
+ * @mr: #MemoryRegion to be accessed
+ * @attrs: memory transaction attributes
+ * @addr: address within that memory region
+ * @len: the number of bytes to access
+ *
+ * Check if a memory transaction is allowed.
+ *
+ * Returns: true if transaction is allowed, false if denied.
+ */
+static bool flatview_access_allowed(MemoryRegion *mr, MemTxAttrs attrs,
+ hwaddr addr, hwaddr len)
+{
+ if (likely(!attrs.memory)) {
+ return true;
+ }
+ if (memory_region_is_ram(mr)) {
+ return true;
+ }
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "Invalid access to non-RAM device at "
+ "addr 0x%" HWADDR_PRIX ", size %" HWADDR_PRIu ", "
+ "region '%s'\n", addr, len, memory_region_name(mr));
+ return false;
+}
+
/* Called within RCU critical section. */
static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
MemTxAttrs attrs,
const uint8_t *buf = ptr;
for (;;) {
- if (!memory_access_is_direct(mr, true)) {
+ if (!flatview_access_allowed(mr, attrs, addr1, l)) {
+ result |= MEMTX_ACCESS_ERROR;
+ /* Keep going. */
+ } else if (!memory_access_is_direct(mr, true)) {
release_lock |= prepare_mmio_access(mr);
l = memory_access_size(mr, l, addr1);
/* XXX: could force current_cpu to NULL to avoid
hwaddr l;
hwaddr addr1;
MemoryRegion *mr;
- MemTxResult result = MEMTX_OK;
l = len;
mr = flatview_translate(fv, addr, &addr1, &l, true, attrs);
- result = flatview_write_continue(fv, addr, attrs, buf, len,
- addr1, l, mr);
-
- return result;
+ if (!flatview_access_allowed(mr, attrs, addr, len)) {
+ return MEMTX_ACCESS_ERROR;
+ }
+ return flatview_write_continue(fv, addr, attrs, buf, len,
+ addr1, l, mr);
}
/* Called within RCU critical section. */
fuzz_dma_read_cb(addr, len, mr);
for (;;) {
- if (!memory_access_is_direct(mr, false)) {
+ if (!flatview_access_allowed(mr, attrs, addr1, l)) {
+ result |= MEMTX_ACCESS_ERROR;
+ /* Keep going. */
+ } else if (!memory_access_is_direct(mr, false)) {
/* I/O case */
release_lock |= prepare_mmio_access(mr);
l = memory_access_size(mr, l, addr1);
l = len;
mr = flatview_translate(fv, addr, &addr1, &l, false, attrs);
+ if (!flatview_access_allowed(mr, attrs, addr, len)) {
+ return MEMTX_ACCESS_ERROR;
+ }
return flatview_read_continue(fv, addr, attrs, buf, len,
addr1, l, mr);
}
}
}
+MemTxResult address_space_set(AddressSpace *as, hwaddr addr,
+ uint8_t c, hwaddr len, MemTxAttrs attrs)
+{
+#define FILLBUF_SIZE 512
+ uint8_t fillbuf[FILLBUF_SIZE];
+ int l;
+ MemTxResult error = MEMTX_OK;
+
+ memset(fillbuf, c, FILLBUF_SIZE);
+ while (len > 0) {
+ l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE;
+ error |= address_space_write(as, addr, attrs, fillbuf, l);
+ len -= l;
+ addr += l;
+ }
+
+ return error;
+}
+
void cpu_physical_memory_rw(hwaddr addr, void *buf,
hwaddr len, bool is_write)
{
MemTxAttrs attrs)
{
FlatView *fv;
- bool result;
RCU_READ_LOCK_GUARD();
fv = address_space_to_flatview(as);
- result = flatview_access_valid(fv, addr, len, is_write, attrs);
- return result;
+ return flatview_access_valid(fv, addr, len, is_write, attrs);
}
static hwaddr
hwaddr len = *plen;
hwaddr l, xlat;
MemoryRegion *mr;
- void *ptr;
FlatView *fv;
if (len == 0) {
*plen = flatview_extend_translation(fv, addr, len, mr, xlat,
l, is_write, attrs);
fuzz_dma_read_cb(addr, *plen, mr);
- ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
-
- return ptr;
+ return qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
}
/* Unmaps a memory region previously mapped by address_space_map().
#include "memory_ldst.c.inc"
/* virtual memory access for debug (includes writing to ROM) */
-int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
- void *ptr, target_ulong len, bool is_write)
+int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
+ void *ptr, size_t len, bool is_write)
{
hwaddr phys_addr;
- target_ulong l, page;
+ vaddr l, page;
uint8_t *buf = ptr;
cpu_synchronize_state(cpu);
{
MemoryRegion*mr;
hwaddr l = 1;
- bool res;
RCU_READ_LOCK_GUARD();
mr = address_space_translate(&address_space_memory,
phys_addr, &phys_addr, &l, false,
MEMTXATTRS_UNSPECIFIED);
- res = !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
- return res;
+ return !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
}
int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
const char *names[] = { " [unassigned]", " [not dirty]",
" [ROM]", " [watch]" };
- qemu_printf(" #%d @" TARGET_FMT_plx ".." TARGET_FMT_plx
+ qemu_printf(" #%d @" HWADDR_FMT_plx ".." HWADDR_FMT_plx
" %s%s%s%s%s",
i,
s->offset_within_address_space,
- s->offset_within_address_space + MR_SIZE(s->mr->size),
+ s->offset_within_address_space + MR_SIZE(s->size),
s->mr->name ? s->mr->name : "(noname)",
i < ARRAY_SIZE(names) ? names[i] : "",
s->mr == root ? " [ROOT]" : "",