Merge tag 'pull-tcg-20240130' of https://gitlab.com/rth7680/qemu into staging

linux-user: Allow gdbstub to ignore page protection
cpu-exec: simplify jump cache management
include/exec: Cleanups toward building accel/tcg once

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmW4LXcdHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+CgAf8CdqkvKsUK9/5bu99
# 9E4kRBkR8KqWYvBfRs4IFmjoEdEa4sCujWrHliOcW7Kh+XlVyAPI9rZG32QkxCEQ
# hi9WXieXjfPLTTmrbeiq7cwxztSj8Z55wwvbxkrtFyGDQ0AMccp49tAvfejEb6VD
# Ssx96nWQDgryLrn+My+wMQjl9aVKUWp5vB8k12aAcpRXPH2yoGE2JHAZ1C743nA6
# rShiJAT78HwERcMXDeYmmriYg0s4Z4+A6ErTiXDnFgj87YanHZc0I/55G5Sh+pW8
# REicD3jwS0GHOOHL0K781FopE1wTM442GLVxobXoxUXsHEiO+3TK5JdEIqvSstYA
# fRB8Pg==
# =xZOe
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 29 Jan 2024 22:57:59 GMT
# 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

* tag 'pull-tcg-20240130' of https://gitlab.com/rth7680/qemu: (31 commits)
  target/i386: Extract x86_cpu_exec_halt() from accel/tcg/
  accel/tcg: Introduce TCGCPUOps::cpu_exec_halt() handler
  accel/tcg: Inline need_replay_interrupt
  target/i386: Extract x86_need_replay_interrupt() from accel/tcg/
  accel/tcg: Introduce TCGCPUOps::need_replay_interrupt() handler
  accel/tcg: Use CPUState.cc instead of CPU_GET_CLASS in cpu-exec.c
  target/loongarch: Constify loongarch_tcg_ops
  include/qemu: Add TCGCPUOps typedef to typedefs.h
  accel/tcg: Un-inline icount_exit_request() for clarity
  accel/tcg: Rename tcg_cpus_exec() -> tcg_cpu_exec()
  accel/tcg: Rename tcg_cpus_destroy() -> tcg_cpu_destroy()
  accel/tcg: Rename tcg_ss[] -> tcg_specific_ss[] in meson
  accel/tcg: Move perf and debuginfo support to tcg/
  accel/tcg: Remove #ifdef TARGET_I386 from perf.c
  tcg: Make tb_cflags() usable from target-agnostic code
  accel/tcg: Make use of qemu_target_page_mask() in perf.c
  target: Make qemu_target_page_mask() available for *-user
  accel/tcg/cpu-exec: Use RCU_READ_LOCK_GUARD
  tests/tcg: Add the PROT_NONE gdbstub test
  tests/tcg: Factor out gdbstub test functions
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2024-01-30 15:53:37 +00:00
97 changed files with 580 additions and 730 deletions
+95 -128
View File
@@ -30,9 +30,6 @@
#include "qemu/rcu.h"
#include "exec/log.h"
#include "qemu/main-loop.h"
#if defined(TARGET_I386) && !defined(CONFIG_USER_ONLY)
#include "hw/i386/apic.h"
#endif
#include "sysemu/cpus.h"
#include "exec/cpu-all.h"
#include "sysemu/cpu-timers.h"
@@ -253,43 +250,29 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, vaddr pc,
hash = tb_jmp_cache_hash_func(pc);
jc = cpu->tb_jmp_cache;
if (cflags & CF_PCREL) {
/* Use acquire to ensure current load of pc from jc. */
tb = qatomic_load_acquire(&jc->array[hash].tb);
if (likely(tb &&
jc->array[hash].pc == pc &&
tb->cs_base == cs_base &&
tb->flags == flags &&
tb_cflags(tb) == cflags)) {
return tb;
}
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
if (tb == NULL) {
return NULL;
}
jc->array[hash].pc = pc;
/* Ensure pc is written first. */
qatomic_store_release(&jc->array[hash].tb, tb);
} else {
/* Use rcu_read to ensure current load of pc from *tb. */
tb = qatomic_rcu_read(&jc->array[hash].tb);
if (likely(tb &&
tb->pc == pc &&
tb->cs_base == cs_base &&
tb->flags == flags &&
tb_cflags(tb) == cflags)) {
return tb;
}
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
if (tb == NULL) {
return NULL;
}
/* Use the pc value already stored in tb->pc. */
qatomic_set(&jc->array[hash].tb, tb);
tb = qatomic_read(&jc->array[hash].tb);
if (likely(tb &&
jc->array[hash].pc == pc &&
tb->cs_base == cs_base &&
tb->flags == flags &&
tb_cflags(tb) == cflags)) {
goto hit;
}
tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags);
if (tb == NULL) {
return NULL;
}
jc->array[hash].pc = pc;
qatomic_set(&jc->array[hash].tb, tb);
hit:
/*
* As long as tb is not NULL, the contents are consistent. Therefore,
* the virtual PC has to match for non-CF_PCREL translations.
*/
assert((tb_cflags(tb) & CF_PCREL) || tb->pc == pc);
return tb;
}
@@ -357,9 +340,9 @@ static bool check_for_breakpoints_slow(CPUState *cpu, vaddr pc,
#ifdef CONFIG_USER_ONLY
g_assert_not_reached();
#else
CPUClass *cc = CPU_GET_CLASS(cpu);
assert(cc->tcg_ops->debug_check_breakpoint);
match_bp = cc->tcg_ops->debug_check_breakpoint(cpu);
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
assert(tcg_ops->debug_check_breakpoint);
match_bp = tcg_ops->debug_check_breakpoint(cpu);
#endif
}
@@ -476,10 +459,11 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
* counter hit zero); we must restore the guest PC to the address
* of the start of the TB.
*/
CPUClass *cc = CPU_GET_CLASS(cpu);
CPUClass *cc = cpu->cc;
const TCGCPUOps *tcg_ops = cc->tcg_ops;
if (cc->tcg_ops->synchronize_from_tb) {
cc->tcg_ops->synchronize_from_tb(cpu, last_tb);
if (tcg_ops->synchronize_from_tb) {
tcg_ops->synchronize_from_tb(cpu, last_tb);
} else {
tcg_debug_assert(!(tb_cflags(last_tb) & CF_PCREL));
assert(cc->set_pc);
@@ -511,19 +495,19 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
static void cpu_exec_enter(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
if (cc->tcg_ops->cpu_exec_enter) {
cc->tcg_ops->cpu_exec_enter(cpu);
if (tcg_ops->cpu_exec_enter) {
tcg_ops->cpu_exec_enter(cpu);
}
}
static void cpu_exec_exit(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
if (cc->tcg_ops->cpu_exec_exit) {
cc->tcg_ops->cpu_exec_exit(cpu);
if (tcg_ops->cpu_exec_exit) {
tcg_ops->cpu_exec_exit(cpu);
}
}
@@ -677,15 +661,11 @@ static inline bool cpu_handle_halt(CPUState *cpu)
{
#ifndef CONFIG_USER_ONLY
if (cpu->halted) {
#if defined(TARGET_I386)
if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
X86CPU *x86_cpu = X86_CPU(cpu);
bql_lock();
apic_poll_irq(x86_cpu->apic_state);
cpu_reset_interrupt(cpu, CPU_INTERRUPT_POLL);
bql_unlock();
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
if (tcg_ops->cpu_exec_halt) {
tcg_ops->cpu_exec_halt(cpu);
}
#endif /* TARGET_I386 */
if (!cpu_has_work(cpu)) {
return true;
}
@@ -699,7 +679,7 @@ static inline bool cpu_handle_halt(CPUState *cpu)
static inline void cpu_handle_debug_exception(CPUState *cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
CPUWatchpoint *wp;
if (!cpu->watchpoint_hit) {
@@ -708,8 +688,8 @@ static inline void cpu_handle_debug_exception(CPUState *cpu)
}
}
if (cc->tcg_ops->debug_excp_handler) {
cc->tcg_ops->debug_excp_handler(cpu);
if (tcg_ops->debug_excp_handler) {
tcg_ops->debug_excp_handler(cpu);
}
}
@@ -726,6 +706,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
#endif
return false;
}
if (cpu->exception_index >= EXCP_INTERRUPT) {
/* exit request from the cpu execution loop */
*ret = cpu->exception_index;
@@ -734,62 +715,59 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
}
cpu->exception_index = -1;
return true;
} else {
#if defined(CONFIG_USER_ONLY)
/* if user mode only, we simulate a fake exception
which will be handled outside the cpu execution
loop */
#if defined(TARGET_I386)
CPUClass *cc = CPU_GET_CLASS(cpu);
cc->tcg_ops->fake_user_interrupt(cpu);
#endif /* TARGET_I386 */
*ret = cpu->exception_index;
cpu->exception_index = -1;
return true;
#else
if (replay_exception()) {
CPUClass *cc = CPU_GET_CLASS(cpu);
bql_lock();
cc->tcg_ops->do_interrupt(cpu);
bql_unlock();
cpu->exception_index = -1;
}
if (unlikely(cpu->singlestep_enabled)) {
/*
* After processing the exception, ensure an EXCP_DEBUG is
* raised when single-stepping so that GDB doesn't miss the
* next instruction.
*/
*ret = EXCP_DEBUG;
cpu_handle_debug_exception(cpu);
return true;
}
} else if (!replay_has_interrupt()) {
/* give a chance to iothread in replay mode */
*ret = EXCP_INTERRUPT;
#if defined(CONFIG_USER_ONLY)
/*
* If user mode only, we simulate a fake exception which will be
* handled outside the cpu execution loop.
*/
#if defined(TARGET_I386)
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
tcg_ops->fake_user_interrupt(cpu);
#endif /* TARGET_I386 */
*ret = cpu->exception_index;
cpu->exception_index = -1;
return true;
#else
if (replay_exception()) {
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
bql_lock();
tcg_ops->do_interrupt(cpu);
bql_unlock();
cpu->exception_index = -1;
if (unlikely(cpu->singlestep_enabled)) {
/*
* After processing the exception, ensure an EXCP_DEBUG is
* raised when single-stepping so that GDB doesn't miss the
* next instruction.
*/
*ret = EXCP_DEBUG;
cpu_handle_debug_exception(cpu);
return true;
}
#endif
} else if (!replay_has_interrupt()) {
/* give a chance to iothread in replay mode */
*ret = EXCP_INTERRUPT;
return true;
}
#endif
return false;
}
#ifndef CONFIG_USER_ONLY
/*
* CPU_INTERRUPT_POLL is a virtual event which gets converted into a
* "real" interrupt event later. It does not need to be recorded for
* replay purposes.
*/
static inline bool need_replay_interrupt(int interrupt_request)
static inline bool icount_exit_request(CPUState *cpu)
{
#if defined(TARGET_I386)
return !(interrupt_request & CPU_INTERRUPT_POLL);
#else
return true;
#endif
if (!icount_enabled()) {
return false;
}
if (cpu->cflags_next_tb != -1 && !(cpu->cflags_next_tb & CF_USE_ICOUNT)) {
return false;
}
return cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0;
}
#endif /* !CONFIG_USER_ONLY */
static inline bool cpu_handle_interrupt(CPUState *cpu,
TranslationBlock **last_tb)
@@ -859,11 +837,12 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
True when it is, and we should restart on a new TB,
and via longjmp via cpu_loop_exit. */
else {
CPUClass *cc = CPU_GET_CLASS(cpu);
const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops;
if (cc->tcg_ops->cpu_exec_interrupt &&
cc->tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
if (need_replay_interrupt(interrupt_request)) {
if (tcg_ops->cpu_exec_interrupt &&
tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) {
if (!tcg_ops->need_replay_interrupt ||
tcg_ops->need_replay_interrupt(interrupt_request)) {
replay_interrupt();
}
/*
@@ -896,10 +875,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu,
}
/* Finally, check if we need to exit to the main loop. */
if (unlikely(qatomic_read(&cpu->exit_request))
|| (icount_enabled()
&& (cpu->cflags_next_tb == -1 || cpu->cflags_next_tb & CF_USE_ICOUNT)
&& cpu->neg.icount_decr.u16.low + cpu->icount_extra == 0)) {
if (unlikely(qatomic_read(&cpu->exit_request)) || icount_exit_request(cpu)) {
qatomic_set(&cpu->exit_request, 0);
if (cpu->exception_index == -1) {
cpu->exception_index = EXCP_INTERRUPT;
@@ -1012,14 +988,8 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc)
*/
h = tb_jmp_cache_hash_func(pc);
jc = cpu->tb_jmp_cache;
if (cflags & CF_PCREL) {
jc->array[h].pc = pc;
/* Ensure pc is written first. */
qatomic_store_release(&jc->array[h].tb, tb);
} else {
/* Use the pc value already stored in tb->pc. */
qatomic_set(&jc->array[h].tb, tb);
}
jc->array[h].pc = pc;
qatomic_set(&jc->array[h].tb, tb);
}
#ifndef CONFIG_USER_ONLY
@@ -1070,7 +1040,7 @@ int cpu_exec(CPUState *cpu)
return EXCP_HALTED;
}
rcu_read_lock();
RCU_READ_LOCK_GUARD();
cpu_exec_enter(cpu);
/*
@@ -1084,18 +1054,15 @@ int cpu_exec(CPUState *cpu)
ret = cpu_exec_setjmp(cpu, &sc);
cpu_exec_exit(cpu);
rcu_read_unlock();
return ret;
}
bool tcg_exec_realizefn(CPUState *cpu, Error **errp)
{
static bool tcg_target_initialized;
CPUClass *cc = CPU_GET_CLASS(cpu);
if (!tcg_target_initialized) {
cc->tcg_ops->initialize();
cpu->cc->tcg_ops->initialize();
tcg_target_initialized = true;
}
+6 -10
View File
@@ -1,8 +1,8 @@
tcg_ss = ss.source_set()
common_ss.add(when: 'CONFIG_TCG', if_true: files(
'cpu-exec-common.c',
))
tcg_ss.add(files(
tcg_specific_ss = ss.source_set()
tcg_specific_ss.add(files(
'tcg-all.c',
'cpu-exec.c',
'tb-maint.c',
@@ -11,16 +11,12 @@ tcg_ss.add(files(
'translate-all.c',
'translator.c',
))
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
tcg_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c'))
tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
tcg_specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c'))
if get_option('plugins')
tcg_ss.add(files('plugin-gen.c'))
tcg_specific_ss.add(files('plugin-gen.c'))
endif
tcg_ss.add(when: libdw, if_true: files('debuginfo.c'))
if host_os == 'linux'
tcg_ss.add(files('perf.c'))
endif
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss)
specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files(
'cputlb.c',
+5 -3
View File
@@ -13,9 +13,11 @@
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
/*
* Accessed in parallel; all accesses to 'tb' must be atomic.
* For CF_PCREL, accesses to 'pc' must be protected by a
* load_acquire/store_release to 'tb'.
* Invalidated in parallel; all accesses to 'tb' must be atomic.
* A valid entry is read/written by a single CPU, therefore there is
* no need for qatomic_rcu_read() and pc is always consistent with a
* non-NULL value of 'tb'. Strictly speaking pc is only needed for
* CF_PCREL, but it's used always for simplicity.
*/
struct CPUJumpCache {
struct rcu_head rcu;
+2 -2
View File
@@ -92,7 +92,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
if (cpu_can_run(cpu)) {
int r;
bql_unlock();
r = tcg_cpus_exec(cpu);
r = tcg_cpu_exec(cpu);
bql_lock();
switch (r) {
case EXCP_DEBUG:
@@ -118,7 +118,7 @@ static void *mttcg_cpu_thread_fn(void *arg)
qemu_wait_io_event(cpu);
} while (!cpu->unplug || cpu_can_run(cpu));
tcg_cpus_destroy(cpu);
tcg_cpu_destroy(cpu);
bql_unlock();
rcu_remove_force_rcu_notifier(&force_rcu.notifier);
rcu_unregister_thread();
+2 -2
View File
@@ -131,7 +131,7 @@ static void rr_deal_with_unplugged_cpus(void)
CPU_FOREACH(cpu) {
if (cpu->unplug && !cpu_can_run(cpu)) {
tcg_cpus_destroy(cpu);
tcg_cpu_destroy(cpu);
break;
}
}
@@ -258,7 +258,7 @@ static void *rr_cpu_thread_fn(void *arg)
if (icount_enabled()) {
icount_prepare_for_run(cpu, cpu_budget);
}
r = tcg_cpus_exec(cpu);
r = tcg_cpu_exec(cpu);
if (icount_enabled()) {
icount_process_data(cpu);
}
+2 -2
View File
@@ -63,12 +63,12 @@ void tcg_cpu_init_cflags(CPUState *cpu, bool parallel)
cpu->tcg_cflags |= cflags;
}
void tcg_cpus_destroy(CPUState *cpu)
void tcg_cpu_destroy(CPUState *cpu)
{
cpu_thread_signal_destroyed(cpu);
}
int tcg_cpus_exec(CPUState *cpu)
int tcg_cpu_exec(CPUState *cpu)
{
int ret;
assert(tcg_enabled());
+2 -2
View File
@@ -14,8 +14,8 @@
#include "sysemu/cpus.h"
void tcg_cpus_destroy(CPUState *cpu);
int tcg_cpus_exec(CPUState *cpu);
void tcg_cpu_destroy(CPUState *cpu);
int tcg_cpu_exec(CPUState *cpu);
void tcg_handle_interrupt(CPUState *cpu, int mask);
void tcg_cpu_init_cflags(CPUState *cpu, bool parallel);
+1 -1
View File
@@ -63,7 +63,7 @@
#include "tb-context.h"
#include "internal-common.h"
#include "internal-target.h"
#include "perf.h"
#include "tcg/perf.h"
#include "tcg/insn-start-words.h"
TBContext tb_ctx;
+2 -2
View File
@@ -1022,7 +1022,7 @@ void process_pending_signals(CPUArchState *env)
void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
MMUAccessType access_type, bool maperr, uintptr_t ra)
{
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
if (tcg_ops->record_sigsegv) {
tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
@@ -1038,7 +1038,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
MMUAccessType access_type, uintptr_t ra)
{
const struct TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
const TCGCPUOps *tcg_ops = CPU_GET_CLASS(cpu)->tcg_ops;
if (tcg_ops->record_sigbus) {
tcg_ops->record_sigbus(cpu, addr, access_type, ra);
+63 -15
View File
@@ -382,6 +382,9 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
vaddr l, page;
void * p;
uint8_t *buf = ptr;
ssize_t written;
int ret = -1;
int fd = -1;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
@@ -389,30 +392,75 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
if (l > len)
l = len;
flags = page_get_flags(page);
if (!(flags & PAGE_VALID))
return -1;
if (!(flags & PAGE_VALID)) {
goto out_close;
}
if (is_write) {
if (!(flags & PAGE_WRITE))
return -1;
if (flags & PAGE_WRITE) {
/* XXX: this code should not depend on lock_user */
p = lock_user(VERIFY_WRITE, addr, l, 0);
if (!p) {
goto out_close;
}
memcpy(p, buf, l);
unlock_user(p, addr, l);
} else {
/* Bypass the host page protection using ptrace. */
if (fd == -1) {
fd = open("/proc/self/mem", O_WRONLY);
if (fd == -1) {
goto out;
}
}
/*
* If there is a TranslationBlock and we weren't bypassing the
* host page protection, the memcpy() above would SEGV,
* ultimately leading to page_unprotect(). So invalidate the
* translations manually. Both invalidation and pwrite() must
* be under mmap_lock() in order to prevent the creation of
* another TranslationBlock in between.
*/
mmap_lock();
tb_invalidate_phys_range(addr, addr + l - 1);
written = pwrite(fd, buf, l,
(off_t)(uintptr_t)g2h_untagged(addr));
mmap_unlock();
if (written != l) {
goto out_close;
}
}
} else if (flags & PAGE_READ) {
/* XXX: this code should not depend on lock_user */
if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
return -1;
memcpy(p, buf, l);
unlock_user(p, addr, l);
} else {
if (!(flags & PAGE_READ))
return -1;
/* XXX: this code should not depend on lock_user */
if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
return -1;
p = lock_user(VERIFY_READ, addr, l, 1);
if (!p) {
goto out_close;
}
memcpy(buf, p, l);
unlock_user(p, addr, 0);
} else {
/* Bypass the host page protection using ptrace. */
if (fd == -1) {
fd = open("/proc/self/mem", O_RDONLY);
if (fd == -1) {
goto out;
}
}
if (pread(fd, buf, l,
(off_t)(uintptr_t)g2h_untagged(addr)) != l) {
goto out_close;
}
}
len -= l;
buf += l;
addr += l;
}
return 0;
ret = 0;
out_close:
if (fd != -1) {
close(fd);
}
out:
return ret;
}
#endif
+1 -1
View File
@@ -62,7 +62,7 @@
#include "hw/boards.h"
#include "qemu/cutils.h"
#include "sysemu/runstate.h"
#include "accel/tcg/debuginfo.h"
#include "tcg/debuginfo.h"
#include <zlib.h>
-49
View File
@@ -171,34 +171,10 @@ extern const TargetPageBits target_page;
#define TARGET_PAGE_ALIGN(addr) ROUND_UP((addr), TARGET_PAGE_SIZE)
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/*
* Original state of the write flag (used when tracking self-modifying code)
*/
#define PAGE_WRITE_ORG 0x0010
/*
* Invalidate the TLB entry immediately, helpful for s390x
* Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
*/
#define PAGE_WRITE_INV 0x0020
/* For use with page_set_flags: page is being replaced; target_data cleared. */
#define PAGE_RESET 0x0040
/* For linux-user, indicates that the page is MAP_ANON. */
#define PAGE_ANON 0x0080
#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY)
/* FIXME: Code that sets/uses this is broken and needs to go away. */
#define PAGE_RESERVED 0x0100
#endif
/* Target-specific bits that will be used via page_get_flags(). */
#define PAGE_TARGET_1 0x0200
#define PAGE_TARGET_2 0x0400
/*
* For linux-user, indicates that the page is mapped with the same semantics
* in both guest and host.
@@ -408,33 +384,8 @@ static inline bool tlb_hit(uint64_t tlb_addr, vaddr addr)
#endif /* !CONFIG_USER_ONLY */
/* accel/tcg/cpu-exec.c */
int cpu_exec(CPUState *cpu);
/* Validate correct placement of CPUArchState. */
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0);
QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState));
/**
* env_archcpu(env)
* @env: The architecture environment
*
* Return the ArchCPU associated with the environment.
*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
#endif /* CPU_ALL_H */
+57 -12
View File
@@ -3,9 +3,11 @@
/* CPU interfaces that are target independent. */
#include "exec/vaddr.h"
#ifndef CONFIG_USER_ONLY
#include "exec/hwaddr.h"
#endif
#include "hw/core/cpu.h"
#define EXCP_INTERRUPT 0x10000 /* async interruption */
#define EXCP_HLT 0x10001 /* hlt instruction reached */
@@ -14,18 +16,6 @@
#define EXCP_YIELD 0x10004 /* cpu wants to yield timeslice to another */
#define EXCP_ATOMIC 0x10005 /* stop-the-world and emulate atomic */
/**
* vaddr:
* Type wide enough to contain any #target_ulong virtual address.
*/
typedef uint64_t vaddr;
#define VADDR_PRId PRId64
#define VADDR_PRIu PRIu64
#define VADDR_PRIo PRIo64
#define VADDR_PRIx PRIx64
#define VADDR_PRIX PRIX64
#define VADDR_MAX UINT64_MAX
void cpu_exec_init_all(void);
void cpu_exec_step_atomic(CPUState *cpu);
@@ -217,4 +207,59 @@ G_NORETURN void cpu_loop_exit_atomic(CPUState *cpu, uintptr_t pc);
G_NORETURN void cpu_loop_exit(CPUState *cpu);
G_NORETURN void cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
#define PAGE_VALID 0x0008
/*
* Original state of the write flag (used when tracking self-modifying code)
*/
#define PAGE_WRITE_ORG 0x0010
/*
* Invalidate the TLB entry immediately, helpful for s390x
* Low-Address-Protection. Used with PAGE_WRITE in tlb_set_page_with_attrs()
*/
#define PAGE_WRITE_INV 0x0020
/* For use with page_set_flags: page is being replaced; target_data cleared. */
#define PAGE_RESET 0x0040
/* For linux-user, indicates that the page is MAP_ANON. */
#define PAGE_ANON 0x0080
/* Target-specific bits that will be used via page_get_flags(). */
#define PAGE_TARGET_1 0x0200
#define PAGE_TARGET_2 0x0400
/*
* For linux-user, indicates that the page is mapped with the same semantics
* in both guest and host.
*/
#define PAGE_PASSTHROUGH 0x0800
/* accel/tcg/cpu-exec.c */
int cpu_exec(CPUState *cpu);
/**
* env_archcpu(env)
* @env: The architecture environment
*
* Return the ArchCPU associated with the environment.
*/
static inline ArchCPU *env_archcpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
/**
* env_cpu(env)
* @env: The architecture environment
*
* Return the CPUState associated with the environment.
*/
static inline CPUState *env_cpu(CPUArchState *env)
{
return (void *)env - sizeof(CPUState);
}
#endif /* CPU_COMMON_H */
+2 -2
View File
@@ -121,8 +121,8 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len)
h2g_nocheck(x); \
})
#else
typedef target_ulong abi_ptr;
#define TARGET_ABI_FMT_ptr TARGET_FMT_lx
typedef vaddr abi_ptr;
#define TARGET_ABI_FMT_ptr VADDR_PRIx
#endif
uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr);
-6
View File
@@ -459,12 +459,6 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
#endif
/* Hide the qatomic_read to make code a little easier on the eyes */
static inline uint32_t tb_cflags(const TranslationBlock *tb)
{
return qatomic_read(&tb->cflags);
}
static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb)
{
#ifdef CONFIG_USER_ONLY
+6
View File
@@ -145,4 +145,10 @@ struct TranslationBlock {
/* The alignment given to TranslationBlock during allocation. */
#define CODE_GEN_ALIGN 16
/* Hide the qatomic_read to make code a little easier on the eyes */
static inline uint32_t tb_cflags(const TranslationBlock *tb)
{
return qatomic_read(&tb->cflags);
}
#endif /* EXEC_TRANSLATION_BLOCK_H */
+4 -4
View File
@@ -33,7 +33,7 @@
* the target-specific DisasContext, and then invoke translator_loop.
*/
void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb, int *max_insns,
target_ulong pc, void *host_pc);
vaddr pc, void *host_pc);
/**
* DisasJumpType:
@@ -79,8 +79,8 @@ typedef enum DisasJumpType {
*/
typedef struct DisasContextBase {
TranslationBlock *tb;
target_ulong pc_first;
target_ulong pc_next;
vaddr pc_first;
vaddr pc_next;
DisasJumpType is_jmp;
int num_insns;
int max_insns;
@@ -235,7 +235,7 @@ void translator_fake_ldb(uint8_t insn8, abi_ptr pc);
* Translators can use this to enforce the rule that only single-insn
* translation blocks are allowed to cross page boundaries.
*/
static inline bool is_same_page(const DisasContextBase *db, target_ulong addr)
static inline bool is_same_page(const DisasContextBase *db, vaddr addr)
{
return ((addr ^ db->pc_first) & TARGET_PAGE_MASK) == 0;
}
+18
View File
@@ -0,0 +1,18 @@
/* Define vaddr. */
#ifndef VADDR_H
#define VADDR_H
/**
* vaddr:
* Type wide enough to contain any #target_ulong virtual address.
*/
typedef uint64_t vaddr;
#define VADDR_PRId PRId64
#define VADDR_PRIu PRIu64
#define VADDR_PRIo PRIo64
#define VADDR_PRIx PRIx64
#define VADDR_PRIX PRIX64
#define VADDR_MAX UINT64_MAX
#endif
+2 -5
View File
@@ -22,8 +22,8 @@
#include "hw/qdev-core.h"
#include "disas/dis-asm.h"
#include "exec/cpu-common.h"
#include "exec/hwaddr.h"
#include "exec/vaddr.h"
#include "exec/memattrs.h"
#include "exec/tlb-common.h"
#include "qapi/qapi-types-run-state.h"
@@ -90,9 +90,6 @@ typedef enum MMUAccessType {
typedef struct CPUWatchpoint CPUWatchpoint;
/* see tcg-cpu-ops.h */
struct TCGCPUOps;
/* see accel-cpu.h */
struct AccelCPUClass;
@@ -177,7 +174,7 @@ struct CPUClass {
const struct SysemuCPUOps *sysemu_ops;
/* when TCG is not available, this pointer is NULL */
const struct TCGCPUOps *tcg_ops;
const TCGCPUOps *tcg_ops;
/*
* if not NULL, this is called in order for the CPUClass to initialize
+11 -8
View File
@@ -50,7 +50,7 @@ struct TCGCPUOps {
void (*debug_excp_handler)(CPUState *cpu);
#ifdef NEED_CPU_H
#if defined(CONFIG_USER_ONLY) && defined(TARGET_I386)
#ifdef CONFIG_USER_ONLY
/**
* @fake_user_interrupt: Callback for 'fake exception' handling.
*
@@ -58,13 +58,7 @@ struct TCGCPUOps {
* cpu execution loop (hack for x86 user mode).
*/
void (*fake_user_interrupt)(CPUState *cpu);
#else
/**
* @do_interrupt: Callback for interrupt handling.
*/
void (*do_interrupt)(CPUState *cpu);
#endif /* !CONFIG_USER_ONLY || !TARGET_I386 */
#ifdef CONFIG_USER_ONLY
/**
* record_sigsegv:
* @cpu: cpu context
@@ -114,8 +108,12 @@ struct TCGCPUOps {
void (*record_sigbus)(CPUState *cpu, vaddr addr,
MMUAccessType access_type, uintptr_t ra);
#else
/** @do_interrupt: Callback for interrupt handling. */
void (*do_interrupt)(CPUState *cpu);
/** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
/** @cpu_exec_halt: Callback for handling halt in cpu_exec */
void (*cpu_exec_halt)(CPUState *cpu);
/**
* @tlb_fill: Handle a softmmu tlb miss
*
@@ -170,6 +168,11 @@ struct TCGCPUOps {
*/
bool (*io_recompile_replay_branch)(CPUState *cpu,
const TranslationBlock *tb);
/**
* @need_replay_interrupt: Return %true if @interrupt_request
* needs to be recorded for replay purposes.
*/
bool (*need_replay_interrupt)(int interrupt_request);
#endif /* !CONFIG_USER_ONLY */
#endif /* NEED_CPU_H */

Some files were not shown because too many files have changed in this diff Show More