mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 16:53:55 -06:00
Allow page table bit to swap endianness.
Reorganize watchpoints out of i/o path. Return host address from probe_write / probe_access. -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl1uiyYdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV8AuwgAnYLQQbL8kjSqzp7q gRlj0M2SX41ZW3fMkI794RwsljD9Z0QS7YGnpzHolig9XUYrGnip7STrMvlCr/1L CIMWNHlgitgBMszLqg42/TB+6RxXn+DMX/ShUzTagC6xQhinCIpdEjoLaTKSgeP+ foIyJ2uoJLKOBP8cPTQp8evongtoQIljpsZZ0K8a4sreO1d6ytH+olkuoGiROft+ VoJkA+kNHd9cE+LPCva8UFGu1QE6uCySvhepzOpnvOtK+SXKUm2yLOFGu7RWP1pT RkE0oRyRnImtg+cViHfUUFogIffFROdL5tuYMQVuqbINeROPUgJPav+R1Nz1P60a xM2HEw== =bLLU -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20190903' into staging Allow page table bit to swap endianness. Reorganize watchpoints out of i/o path. Return host address from probe_write / probe_access. # gpg: Signature made Tue 03 Sep 2019 16:47:50 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-tcg-20190903: (36 commits) tcg: Factor out probe_write() logic into probe_access() tcg: Make probe_write() return a pointer to the host page s390x/tcg: Pass a size to probe_write() in do_csst() hppa/tcg: Call probe_write() also for CONFIG_USER_ONLY mips/tcg: Call probe_write() for CONFIG_USER_ONLY as well tcg: Enforce single page access in probe_write() tcg: Factor out CONFIG_USER_ONLY probe_write() from s390x code s390x/tcg: Fix length calculation in probe_write_access() s390x/tcg: Use guest_addr_valid() instead of h2g_valid() in probe_write_access() tcg: Check for watchpoints in probe_write() cputlb: Handle watchpoints via TLB_WATCHPOINT cputlb: Remove double-alignment in store_helper cputlb: Fix size operand for tlb_fill on unaligned store exec: Factor out cpu_watchpoint_address_matches cputlb: Fold TLB_RECHECK into TLB_INVALID_MASK exec: Factor out core logic of check_watchpoint() exec: Move user-only watchpoint stubs inline target/sparc: sun4u Invert Endian TTE bit target/sparc: Add TLB entry with attributes cputlb: Byte swap memory transaction attribute ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9de65783e1
57 changed files with 918 additions and 865 deletions
177
exec.c
177
exec.c
|
@ -193,15 +193,12 @@ typedef struct subpage_t {
|
|||
#define PHYS_SECTION_UNASSIGNED 0
|
||||
#define PHYS_SECTION_NOTDIRTY 1
|
||||
#define PHYS_SECTION_ROM 2
|
||||
#define PHYS_SECTION_WATCH 3
|
||||
|
||||
static void io_mem_init(void);
|
||||
static void memory_map_init(void);
|
||||
static void tcg_log_global_after_sync(MemoryListener *listener);
|
||||
static void tcg_commit(MemoryListener *listener);
|
||||
|
||||
static MemoryRegion io_mem_watch;
|
||||
|
||||
/**
|
||||
* CPUAddressSpace: all the information a CPU needs about an AddressSpace
|
||||
* @cpu: the CPU whose AddressSpace this is
|
||||
|
@ -1062,28 +1059,7 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, vaddr len,
|
||||
int flags)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint)
|
||||
{
|
||||
}
|
||||
|
||||
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
||||
int flags, CPUWatchpoint **watchpoint)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#else
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Add a watchpoint. */
|
||||
int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len,
|
||||
int flags, CPUWatchpoint **watchpoint)
|
||||
|
@ -1159,9 +1135,8 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask)
|
|||
* partially or completely with the address range covered by the
|
||||
* access).
|
||||
*/
|
||||
static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
|
||||
vaddr addr,
|
||||
vaddr len)
|
||||
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
|
||||
|
@ -1174,7 +1149,20 @@ static inline bool cpu_watchpoint_address_matches(CPUWatchpoint *wp,
|
|||
return !(addr > wpend || wp->vaddr > addrend);
|
||||
}
|
||||
|
||||
#endif
|
||||
/* 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, TARGET_PAGE_SIZE)) {
|
||||
ret |= wp->flags;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/* Add a breakpoint. */
|
||||
int cpu_breakpoint_insert(CPUState *cpu, vaddr pc, int flags,
|
||||
|
@ -1481,7 +1469,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
|||
target_ulong *address)
|
||||
{
|
||||
hwaddr iotlb;
|
||||
CPUWatchpoint *wp;
|
||||
|
||||
if (memory_region_is_ram(section->mr)) {
|
||||
/* Normal RAM. */
|
||||
|
@ -1499,19 +1486,6 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
|||
iotlb += xlat;
|
||||
}
|
||||
|
||||
/* Make accesses to pages with watchpoints go via the
|
||||
watchpoint trap routines. */
|
||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||
if (cpu_watchpoint_address_matches(wp, vaddr, TARGET_PAGE_SIZE)) {
|
||||
/* Avoid trapping reads of pages with a write breakpoint. */
|
||||
if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
|
||||
iotlb = PHYS_SECTION_WATCH + paddr;
|
||||
*address |= TLB_MMIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iotlb;
|
||||
}
|
||||
#endif /* defined(CONFIG_USER_ONLY) */
|
||||
|
@ -2814,32 +2788,35 @@ static const MemoryRegionOps notdirty_mem_ops = {
|
|||
};
|
||||
|
||||
/* Generate a debug exception if a watchpoint has been hit. */
|
||||
static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
||||
void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
|
||||
MemTxAttrs attrs, int flags, uintptr_t ra)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
target_ulong vaddr;
|
||||
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 is will trigger after the
|
||||
* current instruction. */
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
||||
vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
|
||||
|
||||
addr = cc->adjust_watchpoint_address(cpu, addr, len);
|
||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||
if (cpu_watchpoint_address_matches(wp, vaddr, len)
|
||||
if (watchpoint_address_matches(wp, addr, len)
|
||||
&& (wp->flags & flags)) {
|
||||
if (flags == BP_MEM_READ) {
|
||||
wp->flags |= BP_WATCHPOINT_HIT_READ;
|
||||
} else {
|
||||
wp->flags |= BP_WATCHPOINT_HIT_WRITE;
|
||||
}
|
||||
wp->hitaddr = vaddr;
|
||||
wp->hitaddr = MAX(addr, wp->vaddr);
|
||||
wp->hitattrs = attrs;
|
||||
if (!cpu->watchpoint_hit) {
|
||||
if (wp->flags & BP_CPU &&
|
||||
|
@ -2854,11 +2831,14 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
|||
if (wp->flags & BP_STOP_BEFORE_ACCESS) {
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
mmap_unlock();
|
||||
cpu_loop_exit(cpu);
|
||||
cpu_loop_exit_restore(cpu, ra);
|
||||
} else {
|
||||
/* Force execution of one insn next time. */
|
||||
cpu->cflags_next_tb = 1 | curr_cflags();
|
||||
mmap_unlock();
|
||||
if (ra) {
|
||||
cpu_restore_state(cpu, ra, true);
|
||||
}
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
}
|
||||
|
@ -2868,80 +2848,6 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
|
||||
unsigned size, MemTxAttrs attrs)
|
||||
{
|
||||
MemTxResult res;
|
||||
uint64_t data;
|
||||
int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
|
||||
AddressSpace *as = current_cpu->cpu_ases[asidx].as;
|
||||
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ);
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = address_space_ldub(as, addr, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
data = address_space_lduw(as, addr, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
data = address_space_ldl(as, addr, attrs, &res);
|
||||
break;
|
||||
case 8:
|
||||
data = address_space_ldq(as, addr, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
*pdata = data;
|
||||
return res;
|
||||
}
|
||||
|
||||
static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
MemTxResult res;
|
||||
int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
|
||||
AddressSpace *as = current_cpu->cpu_ases[asidx].as;
|
||||
|
||||
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE);
|
||||
switch (size) {
|
||||
case 1:
|
||||
address_space_stb(as, addr, val, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
address_space_stw(as, addr, val, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
address_space_stl(as, addr, val, attrs, &res);
|
||||
break;
|
||||
case 8:
|
||||
address_space_stq(as, addr, val, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps watch_mem_ops = {
|
||||
.read_with_attrs = watch_mem_read,
|
||||
.write_with_attrs = watch_mem_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 8,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, hwaddr len);
|
||||
static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
|
||||
|
@ -3117,9 +3023,6 @@ static void io_mem_init(void)
|
|||
memory_region_init_io(&io_mem_notdirty, NULL, ¬dirty_mem_ops, NULL,
|
||||
NULL, UINT64_MAX);
|
||||
memory_region_clear_global_locking(&io_mem_notdirty);
|
||||
|
||||
memory_region_init_io(&io_mem_watch, NULL, &watch_mem_ops, NULL,
|
||||
NULL, UINT64_MAX);
|
||||
}
|
||||
|
||||
AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
|
||||
|
@ -3133,8 +3036,6 @@ AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
|
|||
assert(n == PHYS_SECTION_NOTDIRTY);
|
||||
n = dummy_section(&d->map, fv, &io_mem_rom);
|
||||
assert(n == PHYS_SECTION_ROM);
|
||||
n = dummy_section(&d->map, fv, &io_mem_watch);
|
||||
assert(n == PHYS_SECTION_WATCH);
|
||||
|
||||
d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
|
||||
|
||||
|
@ -3366,8 +3267,9 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
|
|||
l = memory_access_size(mr, l, addr1);
|
||||
/* XXX: could force current_cpu to NULL to avoid
|
||||
potential bugs */
|
||||
val = ldn_p(buf, l);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, l, attrs);
|
||||
val = ldn_he_p(buf, l);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val,
|
||||
size_memop(l), attrs);
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
|
||||
|
@ -3428,8 +3330,9 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
|
|||
/* I/O case */
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
l = memory_access_size(mr, l, addr1);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, l, attrs);
|
||||
stn_p(buf, l, val);
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val,
|
||||
size_memop(l), attrs);
|
||||
stn_he_p(buf, l, val);
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue