- Split out host signal handing from accel/tcg/user-exec.c
to linux-user/host/arch/host-signal.h - Replace TCGCPUOps.tlb_fill with TCGCPUOps.record_sigsegv for user-only - Add TCGCPUOps.record_sigbus for user-only - Remove a lot of target-specific cpu_loop handling for signals, now accomplished with generic code. -----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmGBG6YdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV+6Lwf6A03bNhdXQjSjwUOD tW0qGiZ5jtomitHdR04xawkGYWyAoojg7QMm8ZsOgGaGHVRaycmIXaOhIbX7S9/I aV0nSn4GHhCWtvFUFvsYdptN/sf1AtuG6L1T4uzJ3qog1G6aKbdbRl85aWWR4w6P +YTsQIQaU16k7vG7WwItMyga2fcAgT1qkofCHokw5CCJfni6mfNF1Ku8cWSVHSwF 5KXs7G5nGLHLKEAtrE+R7xzJPPwwmWR3BNHeTWSd0YDEMWEMxSzLZEHnnTeos4EF Hl1WNNO7d8W6KWud4nsMBuPumIMtJwDtqUqSyW4DfvO+Dw+dgvAqoxt8bV/jtJp+ QCLE0g== =Vv/u -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20211102' into staging - Split out host signal handing from accel/tcg/user-exec.c to linux-user/host/arch/host-signal.h - Replace TCGCPUOps.tlb_fill with TCGCPUOps.record_sigsegv for user-only - Add TCGCPUOps.record_sigbus for user-only - Remove a lot of target-specific cpu_loop handling for signals, now accomplished with generic code. # gpg: Signature made Tue 02 Nov 2021 07:06:14 AM EDT # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * remotes/rth/tags/pull-tcg-20211102: (60 commits) linux-user: Handle BUS_ADRALN in host_signal_handler tcg: Add helper_unaligned_{ld,st} for user-only sigbus accel/tcg: Report unaligned load/store for user-only accel/tcg: Report unaligned atomics for user-only target/sparc: Set fault address in sparc_cpu_do_unaligned_access target/sparc: Split out build_sfsr target/sparc: Remove DEBUG_UNALIGNED target/sh4: Set fault address in superh_cpu_do_unaligned_access target/s390x: Implement s390x_cpu_record_sigbus linux-user/ppc: Remove POWERPC_EXCP_ALIGN handling target/ppc: Restrict ppc_cpu_do_unaligned_access to sysemu target/ppc: Set fault address in ppc_cpu_do_unaligned_access target/ppc: Move SPR_DSISR setting to powerpc_excp target/microblaze: Do not set MO_ALIGN for user-only linux-user/hppa: Remove EXCP_UNALIGN handling target/arm: Implement arm_cpu_record_sigbus target/alpha: Implement alpha_cpu_record_sigbus linux-user: Add cpu_loop_exit_sigbus hw/core: Add TCGCPUOps.record_sigbus accel/tcg: Restrict TCGCPUOps::tlb_fill() to sysemu ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
102f39b32d
@ -462,6 +462,7 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
* memory.
|
||||
*/
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
@ -471,7 +472,6 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
qemu_plugin_disable_mem_helpers(cpu);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As we start the exclusive region before codegen we must still
|
||||
* be in the region if we longjump out of either the codegen or
|
||||
@ -916,6 +916,7 @@ int cpu_exec(CPUState *cpu)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
clear_helper_retaddr();
|
||||
tcg_debug_assert(!have_mmap_lock());
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
|
@ -27,48 +27,18 @@
|
||||
#include "exec/helper-proto.h"
|
||||
#include "qemu/atomic128.h"
|
||||
#include "trace/trace-root.h"
|
||||
#include "tcg/tcg-ldst.h"
|
||||
#include "internal.h"
|
||||
|
||||
#undef EAX
|
||||
#undef ECX
|
||||
#undef EDX
|
||||
#undef EBX
|
||||
#undef ESP
|
||||
#undef EBP
|
||||
#undef ESI
|
||||
#undef EDI
|
||||
#undef EIP
|
||||
#ifdef __linux__
|
||||
#include <sys/ucontext.h>
|
||||
#endif
|
||||
|
||||
__thread uintptr_t helper_retaddr;
|
||||
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
/*
|
||||
* Adjust the pc to pass to cpu_restore_state; return the memop type.
|
||||
*/
|
||||
static void QEMU_NORETURN cpu_exit_tb_from_sighandler(CPUState *cpu,
|
||||
sigset_t *old_set)
|
||||
MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write)
|
||||
{
|
||||
/* XXX: use siglongjmp ? */
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
}
|
||||
|
||||
/* 'pc' is the host PC at which the exception was raised. 'address' is
|
||||
the effective address of the memory exception. 'is_write' is 1 if a
|
||||
write caused the exception and otherwise 0'. 'old_set' is the
|
||||
signal set which should be restored */
|
||||
static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
int is_write, sigset_t *old_set)
|
||||
{
|
||||
CPUState *cpu = current_cpu;
|
||||
CPUClass *cc;
|
||||
unsigned long address = (unsigned long)info->si_addr;
|
||||
MMUAccessType access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
|
||||
switch (helper_retaddr) {
|
||||
default:
|
||||
/*
|
||||
@ -77,7 +47,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
* pointer into the generated code that will unwind to the
|
||||
* correct guest pc.
|
||||
*/
|
||||
pc = helper_retaddr;
|
||||
*pc = helper_retaddr;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
@ -97,7 +67,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
* Therefore, adjust to compensate for what will be done later
|
||||
* by cpu_restore_state_from_tb.
|
||||
*/
|
||||
pc += GETPC_ADJ;
|
||||
*pc += GETPC_ADJ;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -113,118 +83,97 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||
*
|
||||
* Like tb_gen_code, release the memory lock before cpu_loop_exit.
|
||||
*/
|
||||
pc = 0;
|
||||
access_type = MMU_INST_FETCH;
|
||||
mmap_unlock();
|
||||
break;
|
||||
*pc = 0;
|
||||
return MMU_INST_FETCH;
|
||||
}
|
||||
|
||||
/* For synchronous signals we expect to be coming from the vCPU
|
||||
* thread (so current_cpu should be valid) and either from running
|
||||
* code or during translation which can fault as we cross pages.
|
||||
*
|
||||
* If neither is true then something has gone wrong and we should
|
||||
* abort rather than try and restart the vCPU execution.
|
||||
*/
|
||||
if (!cpu || !cpu->running) {
|
||||
printf("qemu:%s received signal outside vCPU context @ pc=0x%"
|
||||
PRIxPTR "\n", __func__, pc);
|
||||
abort();
|
||||
return is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* handle_sigsegv_accerr_write:
|
||||
* @cpu: the cpu context
|
||||
* @old_set: the sigset_t from the signal ucontext_t
|
||||
* @host_pc: the host pc, adjusted for the signal
|
||||
* @guest_addr: the guest address of the fault
|
||||
*
|
||||
* Return true if the write fault has been handled, and should be re-tried.
|
||||
*
|
||||
* Note that it is important that we don't call page_unprotect() unless
|
||||
* this is really a "write to nonwriteable page" fault, because
|
||||
* page_unprotect() assumes that if it is called for an access to
|
||||
* a page that's writeable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writeable;
|
||||
* so we will retry the access. If we were to call page_unprotect()
|
||||
* for some other kind of fault that should really be passed to the
|
||||
* guest, we'd end up in an infinite loop of retrying the faulting access.
|
||||
*/
|
||||
bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
|
||||
uintptr_t host_pc, abi_ptr guest_addr)
|
||||
{
|
||||
switch (page_unprotect(guest_addr, host_pc)) {
|
||||
case 0:
|
||||
/*
|
||||
* Fault not caused by a page marked unwritable to protect
|
||||
* cached translations, must be the guest binary's problem.
|
||||
*/
|
||||
return false;
|
||||
case 1:
|
||||
/*
|
||||
* Fault caused by protection of cached translation; TBs
|
||||
* invalidated, so resume execution.
|
||||
*/
|
||||
return true;
|
||||
case 2:
|
||||
/*
|
||||
* Fault caused by protection of cached translation, and the
|
||||
* currently executing TB was modified and must be exited immediately.
|
||||
*/
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
cpu_loop_exit_noexc(cpu);
|
||||
/* NORETURN */
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
|
||||
pc, address, is_write, *(unsigned long *)old_set);
|
||||
#endif
|
||||
/* XXX: locking issue */
|
||||
/* Note that it is important that we don't call page_unprotect() unless
|
||||
* this is really a "write to nonwriteable page" fault, because
|
||||
* page_unprotect() assumes that if it is called for an access to
|
||||
* a page that's writeable this means we had two threads racing and
|
||||
* another thread got there first and already made the page writeable;
|
||||
* so we will retry the access. If we were to call page_unprotect()
|
||||
* for some other kind of fault that should really be passed to the
|
||||
* guest, we'd end up in an infinite loop of retrying the faulting
|
||||
* access.
|
||||
*/
|
||||
if (is_write && info->si_signo == SIGSEGV && info->si_code == SEGV_ACCERR &&
|
||||
h2g_valid(address)) {
|
||||
switch (page_unprotect(h2g(address), pc)) {
|
||||
case 0:
|
||||
/* Fault not caused by a page marked unwritable to protect
|
||||
* cached translations, must be the guest binary's problem.
|
||||
*/
|
||||
break;
|
||||
case 1:
|
||||
/* Fault caused by protection of cached translation; TBs
|
||||
* invalidated, so resume execution. Retain helper_retaddr
|
||||
* for a possible second fault.
|
||||
*/
|
||||
return 1;
|
||||
case 2:
|
||||
/* Fault caused by protection of cached translation, and the
|
||||
* currently executing TB was modified and must be exited
|
||||
* immediately. Clear helper_retaddr for next execution.
|
||||
*/
|
||||
clear_helper_retaddr();
|
||||
cpu_exit_tb_from_sighandler(cpu, old_set);
|
||||
/* NORETURN */
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert forcefully to guest address space, invalid addresses
|
||||
are still valid segv ones */
|
||||
address = h2g_nocheck(address);
|
||||
|
||||
/*
|
||||
* There is no way the target can handle this other than raising
|
||||
* an exception. Undo signal and retaddr state prior to longjmp.
|
||||
*/
|
||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||
clear_helper_retaddr();
|
||||
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
cc->tcg_ops->tlb_fill(cpu, address, 0, access_type,
|
||||
MMU_USER_IDX, false, pc);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static int probe_access_internal(CPUArchState *env, target_ulong addr,
|
||||
int fault_size, MMUAccessType access_type,
|
||||
bool nonfault, uintptr_t ra)
|
||||
{
|
||||
int flags;
|
||||
int acc_flag;
|
||||
bool maperr;
|
||||
|
||||
switch (access_type) {
|
||||
case MMU_DATA_STORE:
|
||||
flags = PAGE_WRITE;
|
||||
acc_flag = PAGE_WRITE_ORG;
|
||||
break;
|
||||
case MMU_DATA_LOAD:
|
||||
flags = PAGE_READ;
|
||||
acc_flag = PAGE_READ;
|
||||
break;
|
||||
case MMU_INST_FETCH:
|
||||
flags = PAGE_EXEC;
|
||||
acc_flag = PAGE_EXEC;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!guest_addr_valid_untagged(addr) ||
|
||||
page_check_range(addr, 1, flags) < 0) {
|
||||
if (nonfault) {
|
||||
return TLB_INVALID_MASK;
|
||||
} else {
|
||||
CPUState *cpu = env_cpu(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
cc->tcg_ops->tlb_fill(cpu, addr, fault_size, access_type,
|
||||
MMU_USER_IDX, false, ra);
|
||||
g_assert_not_reached();
|
||||
if (guest_addr_valid_untagged(addr)) {
|
||||
int page_flags = page_get_flags(addr);
|
||||
if (page_flags & acc_flag) {
|
||||
return 0; /* success */
|
||||
}
|
||||
maperr = !(page_flags & PAGE_VALID);
|
||||
} else {
|
||||
maperr = true;
|
||||
}
|
||||
return 0;
|
||||
|
||||
if (nonfault) {
|
||||
return TLB_INVALID_MASK;
|
||||
}
|
||||
|
||||
cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra);
|
||||
}
|
||||
|
||||
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
||||
@ -250,640 +199,6 @@ void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
return size ? g2h(env_cpu(env), addr) : NULL;
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <ucontext.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
#define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <ucontext.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_eip))
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <machine/trap.h>
|
||||
#define EIP_sig(context) ((context)->sc_eip)
|
||||
#define TRAP_sig(context) ((context)->sc_trapno)
|
||||
#define ERROR_sig(context) ((context)->sc_err)
|
||||
#define MASK_sig(context) ((context)->sc_mask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#else
|
||||
#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP 0xe
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
ucontext_t *uc = puc;
|
||||
#elif defined(__OpenBSD__)
|
||||
struct sigcontext *uc = puc;
|
||||
#else
|
||||
ucontext_t *uc = puc;
|
||||
#endif
|
||||
unsigned long pc;
|
||||
int trapno;
|
||||
|
||||
#ifndef REG_EIP
|
||||
/* for glibc 2.1 */
|
||||
#define REG_EIP EIP
|
||||
#define REG_ERR ERR
|
||||
#define REG_TRAPNO TRAPNO
|
||||
#endif
|
||||
pc = EIP_sig(uc);
|
||||
trapno = TRAP_sig(uc);
|
||||
return handle_cpu_signal(pc, info,
|
||||
trapno == PAGE_FAULT_TRAP ?
|
||||
(ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
&MASK_sig(uc));
|
||||
}
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <machine/trap.h>
|
||||
#define PC_sig(context) _UC_MACHINE_PC(context)
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <machine/trap.h>
|
||||
#define PC_sig(context) ((context)->sc_rip)
|
||||
#define TRAP_sig(context) ((context)->sc_trapno)
|
||||
#define ERROR_sig(context) ((context)->sc_err)
|
||||
#define MASK_sig(context) ((context)->sc_mask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <ucontext.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
#define PC_sig(context) (*((unsigned long *)&(context)->uc_mcontext.mc_rip))
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP T_PAGEFLT
|
||||
#else
|
||||
#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
|
||||
#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
|
||||
#define MASK_sig(context) ((context)->uc_sigmask)
|
||||
#define PAGE_FAULT_TRAP 0xe
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
unsigned long pc;
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
ucontext_t *uc = puc;
|
||||
#elif defined(__OpenBSD__)
|
||||
struct sigcontext *uc = puc;
|
||||
#else
|
||||
ucontext_t *uc = puc;
|
||||
#endif
|
||||
|
||||
pc = PC_sig(uc);
|
||||
return handle_cpu_signal(pc, info,
|
||||
TRAP_sig(uc) == PAGE_FAULT_TRAP ?
|
||||
(ERROR_sig(uc) >> 1) & 1 : 0,
|
||||
&MASK_sig(uc));
|
||||
}
|
||||
|
||||
#elif defined(_ARCH_PPC)
|
||||
|
||||
/***********************************************************************
|
||||
* signal context platform-specific definitions
|
||||
* From Wine
|
||||
*/
|
||||
#ifdef linux
|
||||
/* All Registers access - only for local access */
|
||||
#define REG_sig(reg_name, context) \
|
||||
((context)->uc_mcontext.regs->reg_name)
|
||||
/* Gpr Registers access */
|
||||
#define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
|
||||
/* Program counter */
|
||||
#define IAR_sig(context) REG_sig(nip, context)
|
||||
/* Machine State Register (Supervisor) */
|
||||
#define MSR_sig(context) REG_sig(msr, context)
|
||||
/* Count register */
|
||||
#define CTR_sig(context) REG_sig(ctr, context)
|
||||
/* User's integer exception register */
|
||||
#define XER_sig(context) REG_sig(xer, context)
|
||||
/* Link register */
|
||||
#define LR_sig(context) REG_sig(link, context)
|
||||
/* Condition register */
|
||||
#define CR_sig(context) REG_sig(ccr, context)
|
||||
|
||||
/* Float Registers access */
|
||||
#define FLOAT_sig(reg_num, context) \
|
||||
(((double *)((char *)((context)->uc_mcontext.regs + 48 * 4)))[reg_num])
|
||||
#define FPSCR_sig(context) \
|
||||
(*(int *)((char *)((context)->uc_mcontext.regs + (48 + 32 * 2) * 4)))
|
||||
/* Exception Registers access */
|
||||
#define DAR_sig(context) REG_sig(dar, context)
|
||||
#define DSISR_sig(context) REG_sig(dsisr, context)
|
||||
#define TRAP_sig(context) REG_sig(trap, context)
|
||||
#endif /* linux */
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <ucontext.h>
|
||||
#define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
|
||||
#define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
|
||||
#define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
|
||||
#define XER_sig(context) ((context)->uc_mcontext.mc_xer)
|
||||
#define LR_sig(context) ((context)->uc_mcontext.mc_lr)
|
||||
#define CR_sig(context) ((context)->uc_mcontext.mc_cr)
|
||||
/* Exception Registers access */
|
||||
#define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
|
||||
#define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
|
||||
#define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
|
||||
#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
ucontext_t *uc = puc;
|
||||
#else
|
||||
ucontext_t *uc = puc;
|
||||
#endif
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
|
||||
pc = IAR_sig(uc);
|
||||
is_write = 0;
|
||||
#if 0
|
||||
/* ppc 4xx case */
|
||||
if (DSISR_sig(uc) & 0x00800000) {
|
||||
is_write = 1;
|
||||
}
|
||||
#else
|
||||
if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000)) {
|
||||
is_write = 1;
|
||||
}
|
||||
#endif
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__alpha__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
uint32_t *pc = uc->uc_mcontext.sc_pc;
|
||||
uint32_t insn = *pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
switch (insn >> 26) {
|
||||
case 0x0d: /* stw */
|
||||
case 0x0e: /* stb */
|
||||
case 0x0f: /* stq_u */
|
||||
case 0x24: /* stf */
|
||||
case 0x25: /* stg */
|
||||
case 0x26: /* sts */
|
||||
case 0x27: /* stt */
|
||||
case 0x2c: /* stl */
|
||||
case 0x2d: /* stq */
|
||||
case 0x2e: /* stl_c */
|
||||
case 0x2f: /* stq_c */
|
||||
is_write = 1;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
int is_write;
|
||||
uint32_t insn;
|
||||
#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
|
||||
uint32_t *regs = (uint32_t *)(info + 1);
|
||||
void *sigmask = (regs + 20);
|
||||
/* XXX: is there a standard glibc define ? */
|
||||
unsigned long pc = regs[1];
|
||||
#else
|
||||
#ifdef __linux__
|
||||
struct sigcontext *sc = puc;
|
||||
unsigned long pc = sc->sigc_regs.tpc;
|
||||
void *sigmask = (void *)sc->sigc_mask;
|
||||
#elif defined(__OpenBSD__)
|
||||
struct sigcontext *uc = puc;
|
||||
unsigned long pc = uc->sc_pc;
|
||||
void *sigmask = (void *)(long)uc->sc_mask;
|
||||
#elif defined(__NetBSD__)
|
||||
ucontext_t *uc = puc;
|
||||
unsigned long pc = _UC_MACHINE_PC(uc);
|
||||
void *sigmask = (void *)&uc->uc_sigmask;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
is_write = 0;
|
||||
insn = *(uint32_t *)pc;
|
||||
if ((insn >> 30) == 3) {
|
||||
switch ((insn >> 19) & 0x3f) {
|
||||
case 0x05: /* stb */
|
||||
case 0x15: /* stba */
|
||||
case 0x06: /* sth */
|
||||
case 0x16: /* stha */
|
||||
case 0x04: /* st */
|
||||
case 0x14: /* sta */
|
||||
case 0x07: /* std */
|
||||
case 0x17: /* stda */
|
||||
case 0x0e: /* stx */
|
||||
case 0x1e: /* stxa */
|
||||
case 0x24: /* stf */
|
||||
case 0x34: /* stfa */
|
||||
case 0x27: /* stdf */
|
||||
case 0x37: /* stdfa */
|
||||
case 0x26: /* stqf */
|
||||
case 0x36: /* stqfa */
|
||||
case 0x25: /* stfsr */
|
||||
case 0x3c: /* casa */
|
||||
case 0x3e: /* casxa */
|
||||
is_write = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handle_cpu_signal(pc, info, is_write, sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__arm__)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#include <ucontext.h>
|
||||
#include <sys/siginfo.h>
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
#if defined(__NetBSD__)
|
||||
ucontext_t *uc = puc;
|
||||
siginfo_t *si = pinfo;
|
||||
#else
|
||||
ucontext_t *uc = puc;
|
||||
#endif
|
||||
unsigned long pc;
|
||||
uint32_t fsr;
|
||||
int is_write;
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
pc = uc->uc_mcontext.__gregs[_REG_R15];
|
||||
#elif defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
|
||||
pc = uc->uc_mcontext.gregs[R15];
|
||||
#else
|
||||
pc = uc->uc_mcontext.arm_pc;
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
fsr = si->si_trap;
|
||||
#else
|
||||
fsr = uc->uc_mcontext.error_code;
|
||||
#endif
|
||||
/*
|
||||
* In the FSR, bit 11 is WnR, assuming a v6 or
|
||||
* later processor. On v5 we will always report
|
||||
* this as a read, which will fail later.
|
||||
*/
|
||||
is_write = extract32(fsr, 11, 1);
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
|
||||
#include <ucontext.h>
|
||||
#include <sys/siginfo.h>
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
ucontext_t *uc = puc;
|
||||
siginfo_t *si = pinfo;
|
||||
unsigned long pc;
|
||||
int is_write;
|
||||
uint32_t esr;
|
||||
|
||||
pc = uc->uc_mcontext.__gregs[_REG_PC];
|
||||
esr = si->si_trap;
|
||||
|
||||
/*
|
||||
* siginfo_t::si_trap is the ESR value, for data aborts ESR.EC
|
||||
* is 0b10010x: then bit 6 is the WnR bit
|
||||
*/
|
||||
is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
|
||||
return handle_cpu_signal(pc, si, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifndef ESR_MAGIC
|
||||
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
|
||||
#define ESR_MAGIC 0x45535201
|
||||
struct esr_context {
|
||||
struct _aarch64_ctx head;
|
||||
uint64_t esr;
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
|
||||
{
|
||||
return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
|
||||
}
|
||||
|
||||
static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
|
||||
{
|
||||
return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
|
||||
}
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
uintptr_t pc = uc->uc_mcontext.pc;
|
||||
bool is_write;
|
||||
struct _aarch64_ctx *hdr;
|
||||
struct esr_context const *esrctx = NULL;
|
||||
|
||||
/* Find the esr_context, which has the WnR bit in it */
|
||||
for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
|
||||
if (hdr->magic == ESR_MAGIC) {
|
||||
esrctx = (struct esr_context const *)hdr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (esrctx) {
|
||||
/* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit */
|
||||
uint64_t esr = esrctx->esr;
|
||||
is_write = extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
|
||||
} else {
|
||||
/*
|
||||
* Fall back to parsing instructions; will only be needed
|
||||
* for really ancient (pre-3.16) kernels.
|
||||
*/
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
|
||||
is_write = ((insn & 0xbfff0000) == 0x0c000000 /* C3.3.1 */
|
||||
|| (insn & 0xbfe00000) == 0x0c800000 /* C3.3.2 */
|
||||
|| (insn & 0xbfdf0000) == 0x0d000000 /* C3.3.3 */
|
||||
|| (insn & 0xbfc00000) == 0x0d800000 /* C3.3.4 */
|
||||
|| (insn & 0x3f400000) == 0x08000000 /* C3.3.6 */
|
||||
|| (insn & 0x3bc00000) == 0x39000000 /* C3.3.13 */
|
||||
|| (insn & 0x3fc00000) == 0x3d800000 /* ... 128bit */
|
||||
/* Ignore bits 10, 11 & 21, controlling indexing. */
|
||||
|| (insn & 0x3bc00000) == 0x38000000 /* C3.3.8-12 */
|
||||
|| (insn & 0x3fe00000) == 0x3c800000 /* ... 128bit */
|
||||
/* Ignore bits 23 & 24, controlling indexing. */
|
||||
|| (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */
|
||||
}
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__s390__)
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
unsigned long pc;
|
||||
uint16_t *pinsn;
|
||||
int is_write = 0;
|
||||
|
||||
pc = uc->uc_mcontext.psw.addr;
|
||||
|
||||
/*
|
||||
* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
|
||||
* of the normal 2 arguments. The 4th argument contains the "Translation-
|
||||
* Exception Identification for DAT Exceptions" from the hardware (aka
|
||||
* "int_parm_long"), which does in fact contain the is_write value.
|
||||
* The rt signal handler, as far as I can tell, does not give this value
|
||||
* at all. Not that we could get to it from here even if it were.
|
||||
* So fall back to parsing instructions. Treat read-modify-write ones as
|
||||
* writes, which is not fully correct, but for tracking self-modifying code
|
||||
* this is better than treating them as reads. Checking si_addr page flags
|
||||
* might be a viable improvement, albeit a racy one.
|
||||
*/
|
||||
/* ??? This is not even close to complete. */
|
||||
pinsn = (uint16_t *)pc;
|
||||
switch (pinsn[0] >> 8) {
|
||||
case 0x50: /* ST */
|
||||
case 0x42: /* STC */
|
||||
case 0x40: /* STH */
|
||||
case 0xba: /* CS */
|
||||
case 0xbb: /* CDS */
|
||||
is_write = 1;
|
||||
break;
|
||||
case 0xc4: /* RIL format insns */
|
||||
switch (pinsn[0] & 0xf) {
|
||||
case 0xf: /* STRL */
|
||||
case 0xb: /* STGRL */
|
||||
case 0x7: /* STHRL */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
case 0xc8: /* SSF format insns */
|
||||
switch (pinsn[0] & 0xf) {
|
||||
case 0x2: /* CSST */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
case 0xe3: /* RXY format insns */
|
||||
switch (pinsn[2] & 0xff) {
|
||||
case 0x50: /* STY */
|
||||
case 0x24: /* STG */
|
||||
case 0x72: /* STCY */
|
||||
case 0x70: /* STHY */
|
||||
case 0x8e: /* STPQ */
|
||||
case 0x3f: /* STRVH */
|
||||
case 0x3e: /* STRV */
|
||||
case 0x2f: /* STRVG */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
case 0xeb: /* RSY format insns */
|
||||
switch (pinsn[2] & 0xff) {
|
||||
case 0x14: /* CSY */
|
||||
case 0x30: /* CSG */
|
||||
case 0x31: /* CDSY */
|
||||
case 0x3e: /* CDSG */
|
||||
case 0xe4: /* LANG */
|
||||
case 0xe6: /* LAOG */
|
||||
case 0xe7: /* LAXG */
|
||||
case 0xe8: /* LAAG */
|
||||
case 0xea: /* LAALG */
|
||||
case 0xf4: /* LAN */
|
||||
case 0xf6: /* LAO */
|
||||
case 0xf7: /* LAX */
|
||||
case 0xfa: /* LAAL */
|
||||
case 0xf8: /* LAA */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#if defined(__misp16) || defined(__mips_micromips)
|
||||
#error "Unsupported encoding"
|
||||
#endif
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
uintptr_t pc = uc->uc_mcontext.pc;
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* Detect all store instructions at program counter. */
|
||||
switch((insn >> 26) & 077) {
|
||||
case 050: /* SB */
|
||||
case 051: /* SH */
|
||||
case 052: /* SWL */
|
||||
case 053: /* SW */
|
||||
case 054: /* SDL */
|
||||
case 055: /* SDR */
|
||||
case 056: /* SWR */
|
||||
case 070: /* SC */
|
||||
case 071: /* SWC1 */
|
||||
case 074: /* SCD */
|
||||
case 075: /* SDC1 */
|
||||
case 077: /* SD */
|
||||
#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
|
||||
case 072: /* SWC2 */
|
||||
case 076: /* SDC2 */
|
||||
#endif
|
||||
is_write = 1;
|
||||
break;
|
||||
case 023: /* COP1X */
|
||||
/* Required in all versions of MIPS64 since
|
||||
MIPS64r1 and subsequent versions of MIPS32r2. */
|
||||
switch (insn & 077) {
|
||||
case 010: /* SWXC1 */
|
||||
case 011: /* SDXC1 */
|
||||
case 015: /* SUXC1 */
|
||||
is_write = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
int cpu_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc)
|
||||
{
|
||||
siginfo_t *info = pinfo;
|
||||
ucontext_t *uc = puc;
|
||||
greg_t pc = uc->uc_mcontext.__gregs[REG_PC];
|
||||
uint32_t insn = *(uint32_t *)pc;
|
||||
int is_write = 0;
|
||||
|
||||
/* Detect store by reading the instruction at the program
|
||||
counter. Note: we currently only generate 32-bit
|
||||
instructions so we thus only detect 32-bit stores */
|
||||
switch (((insn >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((insn >> 2) & 0b11111)) {
|
||||
case 8:
|
||||
switch (((insn >> 12) & 0b111)) {
|
||||
case 0: /* sb */
|
||||
case 1: /* sh */
|
||||
case 2: /* sw */
|
||||
case 3: /* sd */
|
||||
case 4: /* sq */
|
||||
is_write = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
switch (((insn >> 12) & 0b111)) {
|
||||
case 2: /* fsw */
|
||||
case 3: /* fsd */
|
||||
case 4: /* fsq */
|
||||
is_write = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for compressed instructions */
|
||||
switch (((insn >> 13) & 0b111)) {
|
||||
case 7:
|
||||
switch (insn & 0b11) {
|
||||
case 0: /*c.sd */
|
||||
case 2: /* c.sdsp */
|
||||
is_write = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
switch (insn & 0b11) {
|
||||
case 0: /* c.sw */
|
||||
case 3: /* c.swsp */
|
||||
is_write = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return handle_cpu_signal(pc, info, is_write, &uc->uc_sigmask);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error host CPU specific signal handler needed
|
||||
|
||||
#endif
|
||||
|
||||
/* The softmmu versions of these helpers are in cputlb.c. */
|
||||
|
||||
/*
|
||||
@ -901,12 +216,27 @@ static void validate_memop(MemOpIdx oi, MemOp expected)
|
||||
#endif
|
||||
}
|
||||
|
||||
void helper_unaligned_ld(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_LOAD, GETPC());
|
||||
}
|
||||
|
||||
void helper_unaligned_st(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_STORE, GETPC());
|
||||
}
|
||||
|
||||
static void *cpu_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, uintptr_t ra, MMUAccessType type)
|
||||
{
|
||||
MemOp mop = get_memop(oi);
|
||||
int a_bits = get_alignment_bits(mop);
|
||||
void *ret;
|
||||
|
||||
/* TODO: Enforce guest required alignment. */
|
||||
/* Enforce guest required alignment. */
|
||||
if (unlikely(addr & ((1 << a_bits) - 1))) {
|
||||
cpu_loop_exit_sigbus(env_cpu(env), addr, type, ra);
|
||||
}
|
||||
|
||||
ret = g2h(env_cpu(env), addr);
|
||||
set_helper_retaddr(ra);
|
||||
@ -1160,11 +490,22 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
MemOpIdx oi, int size, int prot,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
MemOp mop = get_memop(oi);
|
||||
int a_bits = get_alignment_bits(mop);
|
||||
void *ret;
|
||||
|
||||
/* Enforce guest required alignment. */
|
||||
if (unlikely(addr & ((1 << a_bits) - 1))) {
|
||||
MMUAccessType t = prot == PAGE_READ ? MMU_DATA_LOAD : MMU_DATA_STORE;
|
||||
cpu_loop_exit_sigbus(env_cpu(env), addr, t, retaddr);
|
||||
}
|
||||
|
||||
/* Enforce qemu required alignment. */
|
||||
if (unlikely(addr & (size - 1))) {
|
||||
cpu_loop_exit_atomic(env_cpu(env), retaddr);
|
||||
}
|
||||
void *ret = g2h(env_cpu(env), addr);
|
||||
|
||||
ret = g2h(env_cpu(env), addr);
|
||||
set_helper_retaddr(retaddr);
|
||||
return ret;
|
||||
}
|
||||
|
8
configure
vendored
8
configure
vendored
@ -570,11 +570,7 @@ elif check_define __s390__ ; then
|
||||
cpu="s390"
|
||||
fi
|
||||
elif check_define __riscv ; then
|
||||
if check_define _LP64 ; then
|
||||
cpu="riscv64"
|
||||
else
|
||||
cpu="riscv32"
|
||||
fi
|
||||
cpu="riscv"
|
||||
elif check_define __arm__ ; then
|
||||
cpu="arm"
|
||||
elif check_define __aarch64__ ; then
|
||||
@ -587,7 +583,7 @@ ARCH=
|
||||
# Normalise host CPU name and set ARCH.
|
||||
# Note that this case should only have supported host CPUs, not guests.
|
||||
case "$cpu" in
|
||||
ppc|ppc64|s390x|sparc64|x32|riscv32|riscv64)
|
||||
ppc|ppc64|s390x|sparc64|x32|riscv)
|
||||
;;
|
||||
ppc64le)
|
||||
ARCH="ppc64"
|
||||
|
@ -664,16 +664,55 @@ static inline tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env,
|
||||
}
|
||||
|
||||
/**
|
||||
* cpu_signal_handler
|
||||
* @signum: host signal number
|
||||
* @pinfo: host siginfo_t
|
||||
* @puc: host ucontext_t
|
||||
* adjust_signal_pc:
|
||||
* @pc: raw pc from the host signal ucontext_t.
|
||||
* @is_write: host memory operation was write, or read-modify-write.
|
||||
*
|
||||
* To be called from the SIGBUS and SIGSEGV signal handler to inform the
|
||||
* virtual cpu of exceptions. Returns true if the signal was handled by
|
||||
* the virtual CPU.
|
||||
* Alter @pc as required for unwinding. Return the type of the
|
||||
* guest memory access -- host reads may be for guest execution.
|
||||
*/
|
||||
int cpu_signal_handler(int signum, void *pinfo, void *puc);
|
||||
MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write);
|
||||
|
||||
/**
|
||||
* handle_sigsegv_accerr_write:
|
||||
* @cpu: the cpu context
|
||||
* @old_set: the sigset_t from the signal ucontext_t
|
||||
* @host_pc: the host pc, adjusted for the signal
|
||||
* @host_addr: the host address of the fault
|
||||
*
|
||||
* Return true if the write fault has been handled, and should be re-tried.
|
||||
*/
|
||||
bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set,
|
||||
uintptr_t host_pc, abi_ptr guest_addr);
|
||||
|
||||
/**
|
||||
* cpu_loop_exit_sigsegv:
|
||||
* @cpu: the cpu context
|
||||
* @addr: the guest address of the fault
|
||||
* @access_type: access was read/write/execute
|
||||
* @maperr: true for invalid page, false for permission fault
|
||||
* @ra: host pc for unwinding
|
||||
*
|
||||
* Use the TCGCPUOps hook to record cpu state, do guest operating system
|
||||
* specific things to raise SIGSEGV, and jump to the main cpu loop.
|
||||
*/
|
||||
void QEMU_NORETURN cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
|
||||
/**
|
||||
* cpu_loop_exit_sigbus:
|
||||
* @cpu: the cpu context
|
||||
* @addr: the guest address of the alignment fault
|
||||
* @access_type: access was read/write/execute
|
||||
* @ra: host pc for unwinding
|
||||
*
|
||||
* Use the TCGCPUOps hook to record cpu state, do guest operating system
|
||||
* specific things to raise SIGBUS, and jump to the main cpu loop.
|
||||
*/
|
||||
void QEMU_NORETURN cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr,
|
||||
MMUAccessType access_type,
|
||||
uintptr_t ra);
|
||||
|
||||
#else
|
||||
static inline void mmap_lock(void) {}
|
||||
|
@ -35,18 +35,6 @@ struct TCGCPUOps {
|
||||
void (*cpu_exec_enter)(CPUState *cpu);
|
||||
/** @cpu_exec_exit: Callback for cpu_exec cleanup */
|
||||
void (*cpu_exec_exit)(CPUState *cpu);
|
||||
/**
|
||||
* @tlb_fill: Handle a softmmu tlb miss or user-only address fault
|
||||
*
|
||||
* For system mode, if the access is valid, call tlb_set_page
|
||||
* and return true; if the access is invalid, and probe is
|
||||
* true, return false; otherwise raise an exception and do
|
||||
* not return. For user-only mode, always raise an exception
|
||||
* and do not return.
|
||||
*/
|
||||
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
/** @debug_excp_handler: Callback for handling debug exceptions */
|
||||
void (*debug_excp_handler)(CPUState *cpu);
|
||||
|
||||
@ -68,6 +56,16 @@ struct TCGCPUOps {
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
/** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */
|
||||
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
|
||||
/**
|
||||
* @tlb_fill: Handle a softmmu tlb miss
|
||||
*
|
||||
* If the access is valid, call tlb_set_page and return true;
|
||||
* if the access is invalid and probe is true, return false;
|
||||
* otherwise raise an exception and do not return.
|
||||
*/
|
||||
bool (*tlb_fill)(CPUState *cpu, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
/**
|
||||
* @do_transaction_failed: Callback for handling failed memory transactions
|
||||
* (ie bus faults or external aborts; not MMU faults)
|
||||
@ -111,6 +109,55 @@ struct TCGCPUOps {
|
||||
*/
|
||||
bool (*io_recompile_replay_branch)(CPUState *cpu,
|
||||
const TranslationBlock *tb);
|
||||
#else
|
||||
/**
|
||||
* record_sigsegv:
|
||||
* @cpu: cpu context
|
||||
* @addr: faulting guest address
|
||||
* @access_type: access was read/write/execute
|
||||
* @maperr: true for invalid page, false for permission fault
|
||||
* @ra: host pc for unwinding
|
||||
*
|
||||
* We are about to raise SIGSEGV with si_code set for @maperr,
|
||||
* and si_addr set for @addr. Record anything further needed
|
||||
* for the signal ucontext_t.
|
||||
*
|
||||
* If the emulated kernel does not provide anything to the signal
|
||||
* handler with anything besides the user context registers, and
|
||||
* the siginfo_t, then this hook need do nothing and may be omitted.
|
||||
* Otherwise, record the data and return; the caller will raise
|
||||
* the signal, unwind the cpu state, and return to the main loop.
|
||||
*
|
||||
* If it is simpler to re-use the sysemu tlb_fill code, @ra is provided
|
||||
* so that a "normal" cpu exception can be raised. In this case,
|
||||
* the signal must be raised by the architecture cpu_loop.
|
||||
*/
|
||||
void (*record_sigsegv)(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
/**
|
||||
* record_sigbus:
|
||||
* @cpu: cpu context
|
||||
* @addr: misaligned guest address
|
||||
* @access_type: access was read/write/execute
|
||||
* @ra: host pc for unwinding
|
||||
*
|
||||
* We are about to raise SIGBUS with si_code BUS_ADRALN,
|
||||
* and si_addr set for @addr. Record anything further needed
|
||||
* for the signal ucontext_t.
|
||||
*
|
||||
* If the emulated kernel does not provide the signal handler with
|
||||
* anything besides the user context registers, and the siginfo_t,
|
||||
* then this hook need do nothing and may be omitted.
|
||||
* Otherwise, record the data and return; the caller will raise
|
||||
* the signal, unwind the cpu state, and return to the main loop.
|
||||
*
|
||||
* If it is simpler to re-use the sysemu do_unaligned_access code,
|
||||
* @ra is provided so that a "normal" cpu exception can be raised.
|
||||
* In this case, the signal must be raised by the architecture cpu_loop.
|
||||
*/
|
||||
void (*record_sigbus)(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, uintptr_t ra);
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
#endif /* NEED_CPU_H */
|
||||
|
||||
|
@ -70,5 +70,10 @@ void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val,
|
||||
void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val,
|
||||
MemOpIdx oi, uintptr_t retaddr);
|
||||
|
||||
#else
|
||||
|
||||
void QEMU_NORETURN helper_unaligned_ld(CPUArchState *env, target_ulong addr);
|
||||
void QEMU_NORETURN helper_unaligned_st(CPUArchState *env, target_ulong addr);
|
||||
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
#endif /* TCG_LDST_H */
|
||||
|
@ -79,7 +79,7 @@
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr, ec, fsc, si_code;
|
||||
int trapnr, ec, fsc, si_code, si_signo;
|
||||
abi_long ret;
|
||||
|
||||
for (;;) {
|
||||
@ -121,20 +121,26 @@ void cpu_loop(CPUARMState *env)
|
||||
fsc = extract32(env->exception.syndrome, 0, 6);
|
||||
switch (fsc) {
|
||||
case 0x04 ... 0x07: /* Translation fault, level {0-3} */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
|
||||
case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_ACCERR;
|
||||
break;
|
||||
case 0x11: /* Synchronous Tag Check Fault */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_MTESERR;
|
||||
break;
|
||||
case 0x21: /* Alignment fault */
|
||||
si_signo = TARGET_SIGBUS;
|
||||
si_code = TARGET_BUS_ADRALN;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
force_sig_fault(TARGET_SIGSEGV, si_code, env->exception.vaddress);
|
||||
force_sig_fault(si_signo, si_code, env->exception.vaddress);
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
case EXCP_BKPT:
|
||||
|
@ -54,21 +54,6 @@ void cpu_loop(CPUAlphaState *env)
|
||||
fprintf(stderr, "External interrupt. Exit\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case EXCP_MMFAULT:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = (page_get_flags(env->trap_arg0) & PAGE_VALID
|
||||
? TARGET_SEGV_ACCERR : TARGET_SEGV_MAPERR);
|
||||
info._sifields._sigfault._addr = env->trap_arg0;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_UNALIGN:
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_BUS_ADRALN;
|
||||
info._sifields._sigfault._addr = env->trap_arg0;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_OPCDEC:
|
||||
do_sigill:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "cpu_loop-common.h"
|
||||
#include "signal-common.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#include "target/arm/syndrome.h"
|
||||
|
||||
#define get_user_code_u32(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u32((x), (gaddr)); \
|
||||
@ -280,7 +281,7 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode)
|
||||
void cpu_loop(CPUARMState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr;
|
||||
int trapnr, si_signo, si_code;
|
||||
unsigned int n, insn;
|
||||
abi_ulong ret;
|
||||
|
||||
@ -423,9 +424,30 @@ void cpu_loop(CPUARMState *env)
|
||||
break;
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
/* XXX: check env->error_code */
|
||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
|
||||
env->exception.vaddress);
|
||||
/* For user-only we don't set TTBCR_EAE, so look at the FSR. */
|
||||
switch (env->exception.fsr & 0x1f) {
|
||||
case 0x1: /* Alignment */
|
||||
si_signo = TARGET_SIGBUS;
|
||||
si_code = TARGET_BUS_ADRALN;
|
||||
break;
|
||||
case 0x3: /* Access flag fault, level 1 */
|
||||
case 0x6: /* Access flag fault, level 2 */
|
||||
case 0x9: /* Domain fault, level 1 */
|
||||
case 0xb: /* Domain fault, level 2 */
|
||||
case 0xd: /* Permision fault, level 1 */
|
||||
case 0xf: /* Permision fault, level 2 */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_ACCERR;
|
||||
break;
|
||||
case 0x5: /* Translation fault, level 1 */
|
||||
case 0x7: /* Translation fault, level 2 */
|
||||
si_signo = TARGET_SIGSEGV;
|
||||
si_code = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
force_sig_fault(si_signo, si_code, env->exception.vaddress);
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
case EXCP_BKPT:
|
||||
|
@ -37,16 +37,6 @@ void cpu_loop(CPUCRISState *env)
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case 0xaa:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->pregs[PR_EDA];
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
|
@ -28,8 +28,7 @@
|
||||
void cpu_loop(CPUHexagonState *env)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int trapnr, signum, sigcode;
|
||||
target_ulong sigaddr;
|
||||
int trapnr;
|
||||
target_ulong syscallnum;
|
||||
target_ulong ret;
|
||||
|
||||
@ -39,10 +38,6 @@ void cpu_loop(CPUHexagonState *env)
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
signum = 0;
|
||||
sigcode = 0;
|
||||
sigaddr = 0;
|
||||
|
||||
switch (trapnr) {
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
@ -65,12 +60,6 @@ void cpu_loop(CPUHexagonState *env)
|
||||
env->gpr[0] = ret;
|
||||
}
|
||||
break;
|
||||
case HEX_EXCP_FETCH_NO_UPAGE:
|
||||
case HEX_EXCP_PRIV_NO_UREAD:
|
||||
case HEX_EXCP_PRIV_NO_UWRITE:
|
||||
signum = TARGET_SIGSEGV;
|
||||
sigcode = TARGET_SEGV_MAPERR;
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
@ -79,17 +68,6 @@ void cpu_loop(CPUHexagonState *env)
|
||||
trapnr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (signum) {
|
||||
target_siginfo_t info = {
|
||||
.si_signo = signum,
|
||||
.si_errno = 0,
|
||||
.si_code = sigcode,
|
||||
._sifields._sigfault._addr = sigaddr
|
||||
};
|
||||
queue_signal(env, info.si_signo, QEMU_SI_KILL, &info);
|
||||
}
|
||||
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
|
74
linux-user/host/aarch64/host-signal.h
Normal file
74
linux-user/host/aarch64/host-signal.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef AARCH64_HOST_SIGNAL_H
|
||||
#define AARCH64_HOST_SIGNAL_H
|
||||
|
||||
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
|
||||
#ifndef ESR_MAGIC
|
||||
#define ESR_MAGIC 0x45535201
|
||||
struct esr_context {
|
||||
struct _aarch64_ctx head;
|
||||
uint64_t esr;
|
||||
};
|
||||
#endif
|
||||
|
||||
static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
|
||||
{
|
||||
return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
|
||||
}
|
||||
|
||||
static inline struct _aarch64_ctx *next_ctx(struct _aarch64_ctx *hdr)
|
||||
{
|
||||
return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
|
||||
}
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
struct _aarch64_ctx *hdr;
|
||||
uint32_t insn;
|
||||
|
||||
/* Find the esr_context, which has the WnR bit in it */
|
||||
for (hdr = first_ctx(uc); hdr->magic; hdr = next_ctx(hdr)) {
|
||||
if (hdr->magic == ESR_MAGIC) {
|
||||
struct esr_context const *ec = (struct esr_context const *)hdr;
|
||||
uint64_t esr = ec->esr;
|
||||
|
||||
/* For data aborts ESR.EC is 0b10010x: then bit 6 is the WnR bit */
|
||||
return extract32(esr, 27, 5) == 0x12 && extract32(esr, 6, 1) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to parsing instructions; will only be needed
|
||||
* for really ancient (pre-3.16) kernels.
|
||||
*/
|
||||
insn = *(uint32_t *)host_signal_pc(uc);
|
||||
|
||||
return (insn & 0xbfff0000) == 0x0c000000 /* C3.3.1 */
|
||||
|| (insn & 0xbfe00000) == 0x0c800000 /* C3.3.2 */
|
||||
|| (insn & 0xbfdf0000) == 0x0d000000 /* C3.3.3 */
|
||||
|| (insn & 0xbfc00000) == 0x0d800000 /* C3.3.4 */
|
||||
|| (insn & 0x3f400000) == 0x08000000 /* C3.3.6 */
|
||||
|| (insn & 0x3bc00000) == 0x39000000 /* C3.3.13 */
|
||||
|| (insn & 0x3fc00000) == 0x3d800000 /* ... 128bit */
|
||||
/* Ignore bits 10, 11 & 21, controlling indexing. */
|
||||
|| (insn & 0x3bc00000) == 0x38000000 /* C3.3.8-12 */
|
||||
|| (insn & 0x3fe00000) == 0x3c800000 /* ... 128bit */
|
||||
/* Ignore bits 23 & 24, controlling indexing. */
|
||||
|| (insn & 0x3a400000) == 0x28000000; /* C3.3.7,14-16 */
|
||||
}
|
||||
|
||||
#endif
|
42
linux-user/host/alpha/host-signal.h
Normal file
42
linux-user/host/alpha/host-signal.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef ALPHA_HOST_SIGNAL_H
|
||||
#define ALPHA_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.sc_pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
uint32_t *pc = (uint32_t *)host_signal_pc(uc);
|
||||
uint32_t insn = *pc;
|
||||
|
||||
/* XXX: need kernel patch to get write flag faster */
|
||||
switch (insn >> 26) {
|
||||
case 0x0d: /* stw */
|
||||
case 0x0e: /* stb */
|
||||
case 0x0f: /* stq_u */
|
||||
case 0x24: /* stf */
|
||||
case 0x25: /* stg */
|
||||
case 0x26: /* sts */
|
||||
case 0x27: /* stt */
|
||||
case 0x2c: /* stl */
|
||||
case 0x2d: /* stq */
|
||||
case 0x2e: /* stl_c */
|
||||
case 0x2f: /* stq_c */
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
30
linux-user/host/arm/host-signal.h
Normal file
30
linux-user/host/arm/host-signal.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef ARM_HOST_SIGNAL_H
|
||||
#define ARM_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.arm_pc;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
/*
|
||||
* In the FSR, bit 11 is WnR, assuming a v6 or
|
||||
* later processor. On v5 we will always report
|
||||
* this as a read, which will fail later.
|
||||
*/
|
||||
uint32_t fsr = uc->uc_mcontext.error_code;
|
||||
return extract32(fsr, 11, 1);
|
||||
}
|
||||
|
||||
#endif
|
25
linux-user/host/i386/host-signal.h
Normal file
25
linux-user/host/i386/host-signal.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef I386_HOST_SIGNAL_H
|
||||
#define I386_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.gregs[REG_EIP];
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
|
||||
&& (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
|
||||
}
|
||||
|
||||
#endif
|
62
linux-user/host/mips/host-signal.h
Normal file
62
linux-user/host/mips/host-signal.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef MIPS_HOST_SIGNAL_H
|
||||
#define MIPS_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.pc;
|
||||
}
|
||||
|
||||
#if defined(__misp16) || defined(__mips_micromips)
|
||||
#error "Unsupported encoding"
|
||||
#endif
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
uint32_t insn = *(uint32_t *)host_signal_pc(uc);
|
||||
|
||||
/* Detect all store instructions at program counter. */
|
||||
switch ((insn >> 26) & 077) {
|
||||
case 050: /* SB */
|
||||
case 051: /* SH */
|
||||
case 052: /* SWL */
|
||||
case 053: /* SW */
|
||||
case 054: /* SDL */
|
||||
case 055: /* SDR */
|
||||
case 056: /* SWR */
|
||||
case 070: /* SC */
|
||||
case 071: /* SWC1 */
|
||||
case 074: /* SCD */
|
||||
case 075: /* SDC1 */
|
||||
case 077: /* SD */
|
||||
#if !defined(__mips_isa_rev) || __mips_isa_rev < 6
|
||||
case 072: /* SWC2 */
|
||||
case 076: /* SDC2 */
|
||||
#endif
|
||||
return true;
|
||||
case 023: /* COP1X */
|
||||
/*
|
||||
* Required in all versions of MIPS64 since
|
||||
* MIPS64r1 and subsequent versions of MIPS32r2.
|
||||
*/
|
||||
switch (insn & 077) {
|
||||
case 010: /* SWXC1 */
|
||||
case 011: /* SDXC1 */
|
||||
case 015: /* SUXC1 */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
25
linux-user/host/ppc/host-signal.h
Normal file
25
linux-user/host/ppc/host-signal.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC_HOST_SIGNAL_H
|
||||
#define PPC_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.regs->nip;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.regs->trap != 0x400
|
||||
&& (uc->uc_mcontext.regs->dsisr & 0x02000000);
|
||||
}
|
||||
|
||||
#endif
|
1
linux-user/host/ppc64/host-signal.h
Normal file
1
linux-user/host/ppc64/host-signal.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../ppc/host-signal.h"
|
58
linux-user/host/riscv/host-signal.h
Normal file
58
linux-user/host/riscv/host-signal.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef RISCV_HOST_SIGNAL_H
|
||||
#define RISCV_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.__gregs[REG_PC];
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
/*
|
||||
* Detect store by reading the instruction at the program counter.
|
||||
* Do not read more than 16 bits, because we have not yet determined
|
||||
* the size of the instruction.
|
||||
*/
|
||||
const uint16_t *pinsn = (const uint16_t *)host_signal_pc(uc);
|
||||
uint16_t insn = pinsn[0];
|
||||
|
||||
/* 16-bit instructions */
|
||||
switch (insn & 0xe003) {
|
||||
case 0xa000: /* c.fsd */
|
||||
case 0xc000: /* c.sw */
|
||||
case 0xe000: /* c.sd (rv64) / c.fsw (rv32) */
|
||||
case 0xa002: /* c.fsdsp */
|
||||
case 0xc002: /* c.swsp */
|
||||
case 0xe002: /* c.sdsp (rv64) / c.fswsp (rv32) */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 32-bit instructions, major opcodes */
|
||||
switch (insn & 0x7f) {
|
||||
case 0x23: /* store */
|
||||
case 0x27: /* store-fp */
|
||||
return true;
|
||||
case 0x2f: /* amo */
|
||||
/*
|
||||
* The AMO function code is in bits 25-31, unread as yet.
|
||||
* The AMO functions are LR (read), SC (write), and the
|
||||
* rest are all read-modify-write.
|
||||
*/
|
||||
insn = pinsn[1];
|
||||
return (insn >> 11) != 2; /* LR */
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
@ -5,8 +5,8 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef RISCV64_HOSTDEP_H
|
||||
#define RISCV64_HOSTDEP_H
|
||||
#ifndef RISCV_HOSTDEP_H
|
||||
#define RISCV_HOSTDEP_H
|
||||
|
||||
/* We have a safe-syscall.inc.S */
|
||||
#define HAVE_SAFE_SYSCALL
|
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* hostdep.h : things which are dependent on the host architecture
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef RISCV32_HOSTDEP_H
|
||||
#define RISCV32_HOSTDEP_H
|
||||
|
||||
#endif
|
93
linux-user/host/s390/host-signal.h
Normal file
93
linux-user/host/s390/host-signal.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef S390_HOST_SIGNAL_H
|
||||
#define S390_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.psw.addr;
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
uint16_t *pinsn = (uint16_t *)host_signal_pc(uc);
|
||||
|
||||
/*
|
||||
* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
|
||||
* of the normal 2 arguments. The 4th argument contains the "Translation-
|
||||
* Exception Identification for DAT Exceptions" from the hardware (aka
|
||||
* "int_parm_long"), which does in fact contain the is_write value.
|
||||
* The rt signal handler, as far as I can tell, does not give this value
|
||||
* at all. Not that we could get to it from here even if it were.
|
||||
* So fall back to parsing instructions. Treat read-modify-write ones as
|
||||
* writes, which is not fully correct, but for tracking self-modifying code
|
||||
* this is better than treating them as reads. Checking si_addr page flags
|
||||
* might be a viable improvement, albeit a racy one.
|
||||
*/
|
||||
/* ??? This is not even close to complete. */
|
||||
switch (pinsn[0] >> 8) {
|
||||
case 0x50: /* ST */
|
||||
case 0x42: /* STC */
|
||||
case 0x40: /* STH */
|
||||
case 0xba: /* CS */
|
||||
case 0xbb: /* CDS */
|
||||
return true;
|
||||
case 0xc4: /* RIL format insns */
|
||||
switch (pinsn[0] & 0xf) {
|
||||
case 0xf: /* STRL */
|
||||
case 0xb: /* STGRL */
|
||||
case 0x7: /* STHRL */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 0xc8: /* SSF format insns */
|
||||
switch (pinsn[0] & 0xf) {
|
||||
case 0x2: /* CSST */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 0xe3: /* RXY format insns */
|
||||
switch (pinsn[2] & 0xff) {
|
||||
case 0x50: /* STY */
|
||||
case 0x24: /* STG */
|
||||
case 0x72: /* STCY */
|
||||
case 0x70: /* STHY */
|
||||
case 0x8e: /* STPQ */
|
||||
case 0x3f: /* STRVH */
|
||||
case 0x3e: /* STRV */
|
||||
case 0x2f: /* STRVG */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 0xeb: /* RSY format insns */
|
||||
switch (pinsn[2] & 0xff) {
|
||||
case 0x14: /* CSY */
|
||||
case 0x30: /* CSG */
|
||||
case 0x31: /* CDSY */
|
||||
case 0x3e: /* CDSG */
|
||||
case 0xe4: /* LANG */
|
||||
case 0xe6: /* LAOG */
|
||||
case 0xe7: /* LAXG */
|
||||
case 0xe8: /* LAAG */
|
||||
case 0xea: /* LAALG */
|
||||
case 0xf4: /* LAN */
|
||||
case 0xf6: /* LAO */
|
||||
case 0xf7: /* LAX */
|
||||
case 0xfa: /* LAAL */
|
||||
case 0xf8: /* LAA */
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
1
linux-user/host/s390x/host-signal.h
Normal file
1
linux-user/host/s390x/host-signal.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../s390/host-signal.h"
|
54
linux-user/host/sparc/host-signal.h
Normal file
54
linux-user/host/sparc/host-signal.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef SPARC_HOST_SIGNAL_H
|
||||
#define SPARC_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
#ifdef __arch64__
|
||||
return uc->uc_mcontext.mc_gregs[MC_PC];
|
||||
#else
|
||||
return uc->uc_mcontext.gregs[REG_PC];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
uint32_t insn = *(uint32_t *)host_signal_pc(uc);
|
||||
|
||||
if ((insn >> 30) == 3) {
|
||||
switch ((insn >> 19) & 0x3f) {
|
||||
case 0x05: /* stb */
|
||||
case 0x15: /* stba */
|
||||
case 0x06: /* sth */
|
||||
case 0x16: /* stha */
|
||||
case 0x04: /* st */
|
||||
case 0x14: /* sta */
|
||||
case 0x07: /* std */
|
||||
case 0x17: /* stda */
|
||||
case 0x0e: /* stx */
|
||||
case 0x1e: /* stxa */
|
||||
case 0x24: /* stf */
|
||||
case 0x34: /* stfa */
|
||||
case 0x27: /* stdf */
|
||||
case 0x37: /* stdfa */
|
||||
case 0x26: /* stqf */
|
||||
case 0x36: /* stqfa */
|
||||
case 0x25: /* stfsr */
|
||||
case 0x3c: /* casa */
|
||||
case 0x3e: /* casxa */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
1
linux-user/host/sparc64/host-signal.h
Normal file
1
linux-user/host/sparc64/host-signal.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../sparc/host-signal.h"
|
1
linux-user/host/x32/host-signal.h
Normal file
1
linux-user/host/x32/host-signal.h
Normal file
@ -0,0 +1 @@
|
||||
#include "../x86_64/host-signal.h"
|
24
linux-user/host/x86_64/host-signal.h
Normal file
24
linux-user/host/x86_64/host-signal.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* host-signal.h: signal info dependent on the host architecture
|
||||
*
|
||||
* Copyright (C) 2021 Linaro Limited
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef X86_64_HOST_SIGNAL_H
|
||||
#define X86_64_HOST_SIGNAL_H
|
||||
|
||||
static inline uintptr_t host_signal_pc(ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.gregs[REG_RIP];
|
||||
}
|
||||
|
||||
static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
|
||||
{
|
||||
return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
|
||||
&& (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
|
||||
}
|
||||
|
||||
#endif
|
@ -144,29 +144,6 @@ void cpu_loop(CPUHPPAState *env)
|
||||
env->iaoq_f = env->gr[31];
|
||||
env->iaoq_b = env->gr[31] + 4;
|
||||
break;
|
||||
case EXCP_ITLB_MISS:
|
||||
case EXCP_DTLB_MISS:
|
||||
case EXCP_NA_ITLB_MISS:
|
||||
case EXCP_NA_DTLB_MISS:
|
||||
case EXCP_IMP:
|
||||
case EXCP_DMP:
|
||||
case EXCP_DMB:
|
||||
case EXCP_PAGE_REF:
|
||||
case EXCP_DMAR:
|
||||
case EXCP_DMPI:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
info._sifields._sigfault._addr = env->cr[CR_IOR];
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_UNALIGN:
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = env->cr[CR_IOR];
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_ILL:
|
||||
case EXCP_PRIV_OPR:
|
||||
case EXCP_PRIV_REG:
|
||||
|
@ -90,16 +90,6 @@ void cpu_loop(CPUM68KState *env)
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
case EXCP_ACCESS:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->mmu.ar;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_DEBUG:
|
||||
info.si_signo = TARGET_SIGTRAP;
|
||||
info.si_errno = 0;
|
||||
|
@ -37,16 +37,6 @@ void cpu_loop(CPUMBState *env)
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch (trapnr) {
|
||||
case 0xaa:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = 0;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* just indicate that signals should be handled asap */
|
||||
break;
|
||||
|
@ -158,17 +158,6 @@ done_syscall:
|
||||
}
|
||||
env->active_tc.gpr[2] = ret;
|
||||
break;
|
||||
case EXCP_TLBL:
|
||||
case EXCP_TLBS:
|
||||
case EXCP_AdEL:
|
||||
case EXCP_AdES:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->CP0_BadVAddr;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_CpU:
|
||||
case EXCP_RI:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
|
@ -54,15 +54,6 @@ void cpu_loop(CPUOpenRISCState *env)
|
||||
cpu_set_gpr(env, 11, ret);
|
||||
}
|
||||
break;
|
||||
case EXCP_DPF:
|
||||
case EXCP_IPF:
|
||||
case EXCP_RANGE:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_ALIGN:
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
@ -77,13 +68,6 @@ void cpu_loop(CPUOpenRISCState *env)
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_FPE:
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
/* We processed the pending cpu work above. */
|
||||
break;
|
||||
@ -96,6 +80,15 @@ void cpu_loop(CPUOpenRISCState *env)
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
case EXCP_RANGE:
|
||||
/* Requires SR.OVE set, which linux-user won't do. */
|
||||
cpu_abort(cs, "Unexpected RANGE exception");
|
||||
case EXCP_FPE:
|
||||
/*
|
||||
* Requires FPSCR.FPEE set. Writes to FPSCR from usermode not
|
||||
* yet enabled in kernel ABI, so linux-user does not either.
|
||||
*/
|
||||
cpu_abort(cs, "Unexpected FPE exception");
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
@ -162,14 +162,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
cpu_abort(cs, "External interrupt while in user mode. "
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||
/* XXX: check this */
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_BUS_ADRALN;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||
case POWERPC_EXCP_HV_EMU: /* HV emulation */
|
||||
/* XXX: check this */
|
||||
|
@ -87,13 +87,6 @@ void cpu_loop(CPURISCVState *env)
|
||||
sigcode = TARGET_TRAP_BRKPT;
|
||||
sigaddr = env->pc;
|
||||
break;
|
||||
case RISCV_EXCP_INST_PAGE_FAULT:
|
||||
case RISCV_EXCP_LOAD_PAGE_FAULT:
|
||||
case RISCV_EXCP_STORE_PAGE_FAULT:
|
||||
signum = TARGET_SIGSEGV;
|
||||
sigcode = TARGET_SEGV_MAPERR;
|
||||
sigaddr = env->badaddr;
|
||||
break;
|
||||
case RISCV_EXCP_SEMIHOST:
|
||||
env->gpr[xA0] = do_common_semihosting(cs);
|
||||
env->pc += 4;
|
||||
|
@ -24,8 +24,6 @@
|
||||
#include "cpu_loop-common.h"
|
||||
#include "signal-common.h"
|
||||
|
||||
/* s390x masks the fault address it reports in si_addr for SIGSEGV and SIGBUS */
|
||||
#define S390X_FAIL_ADDR_MASK -4096LL
|
||||
|
||||
static int get_pgm_data_si_code(int dxc_code)
|
||||
{
|
||||
@ -111,12 +109,13 @@ void cpu_loop(CPUS390XState *env)
|
||||
n = TARGET_ILL_ILLOPC;
|
||||
goto do_signal_pc;
|
||||
case PGM_PROTECTION:
|
||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_ACCERR,
|
||||
env->__excp_addr);
|
||||
break;
|
||||
case PGM_ADDRESSING:
|
||||
sig = TARGET_SIGSEGV;
|
||||
/* XXX: check env->error_code */
|
||||
n = TARGET_SEGV_MAPERR;
|
||||
addr = env->__excp_addr & S390X_FAIL_ADDR_MASK;
|
||||
goto do_signal;
|
||||
force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,
|
||||
env->__excp_addr);
|
||||
break;
|
||||
case PGM_EXECUTE:
|
||||
case PGM_SPECIFICATION:
|
||||
case PGM_SPECIAL_OP:
|
||||
|
@ -65,14 +65,6 @@ void cpu_loop(CPUSH4State *env)
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case 0xa0:
|
||||
case 0xc0:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->tea;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
arch_interrupt = false;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/resource.h>
|
||||
@ -29,6 +30,7 @@
|
||||
#include "loader.h"
|
||||
#include "trace.h"
|
||||
#include "signal-common.h"
|
||||
#include "host-signal.h"
|
||||
|
||||
static struct target_sigaction sigact_table[TARGET_NSIG];
|
||||
|
||||
@ -686,9 +688,38 @@ void force_sigsegv(int oldsig)
|
||||
}
|
||||
force_sig(TARGET_SIGSEGV);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
if (tcg_ops->record_sigsegv) {
|
||||
tcg_ops->record_sigsegv(cpu, addr, access_type, maperr, ra);
|
||||
}
|
||||
|
||||
force_sig_fault(TARGET_SIGSEGV,
|
||||
maperr ? TARGET_SEGV_MAPERR : TARGET_SEGV_ACCERR,
|
||||
addr);
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit_restore(cpu, ra);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (tcg_ops->record_sigbus) {
|
||||
tcg_ops->record_sigbus(cpu, addr, access_type, ra);
|
||||
}
|
||||
|
||||
force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRALN, addr);
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit_restore(cpu, ra);
|
||||
}
|
||||
|
||||
/* abort execution with signal */
|
||||
static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
||||
{
|
||||
@ -769,41 +800,101 @@ static inline void rewind_if_in_safe_syscall(void *puc)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
void *puc)
|
||||
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
|
||||
{
|
||||
CPUArchState *env = thread_cpu->env_ptr;
|
||||
CPUState *cpu = env_cpu(env);
|
||||
TaskState *ts = cpu->opaque;
|
||||
|
||||
int sig;
|
||||
target_siginfo_t tinfo;
|
||||
ucontext_t *uc = puc;
|
||||
struct emulated_sigtable *k;
|
||||
int guest_sig;
|
||||
uintptr_t pc = 0;
|
||||
bool sync_sig = false;
|
||||
|
||||
/* the CPU emulator uses some host signals to detect exceptions,
|
||||
we forward to it some signals */
|
||||
if ((host_signum == SIGSEGV || host_signum == SIGBUS)
|
||||
&& info->si_code > 0) {
|
||||
if (cpu_signal_handler(host_signum, info, puc))
|
||||
return;
|
||||
/*
|
||||
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
|
||||
* handling wrt signal blocking and unwinding.
|
||||
*/
|
||||
if ((host_sig == SIGSEGV || host_sig == SIGBUS) && info->si_code > 0) {
|
||||
MMUAccessType access_type;
|
||||
uintptr_t host_addr;
|
||||
abi_ptr guest_addr;
|
||||
bool is_write;
|
||||
|
||||
host_addr = (uintptr_t)info->si_addr;
|
||||
|
||||
/*
|
||||
* Convert forcefully to guest address space: addresses outside
|
||||
* reserved_va are still valid to report via SEGV_MAPERR.
|
||||
*/
|
||||
guest_addr = h2g_nocheck(host_addr);
|
||||
|
||||
pc = host_signal_pc(uc);
|
||||
is_write = host_signal_write(info, uc);
|
||||
access_type = adjust_signal_pc(&pc, is_write);
|
||||
|
||||
if (host_sig == SIGSEGV) {
|
||||
bool maperr = true;
|
||||
|
||||
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
|
||||
/* If this was a write to a TB protected page, restart. */
|
||||
if (is_write &&
|
||||
handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask,
|
||||
pc, guest_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* With reserved_va, the whole address space is PROT_NONE,
|
||||
* which means that we may get ACCERR when we want MAPERR.
|
||||
*/
|
||||
if (page_get_flags(guest_addr) & PAGE_VALID) {
|
||||
maperr = false;
|
||||
} else {
|
||||
info->si_code = SEGV_MAPERR;
|
||||
}
|
||||
}
|
||||
|
||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||
cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
|
||||
} else {
|
||||
sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
|
||||
if (info->si_code == BUS_ADRALN) {
|
||||
cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
|
||||
}
|
||||
}
|
||||
|
||||
sync_sig = true;
|
||||
}
|
||||
|
||||
/* get target signal number */
|
||||
sig = host_to_target_signal(host_signum);
|
||||
if (sig < 1 || sig > TARGET_NSIG)
|
||||
guest_sig = host_to_target_signal(host_sig);
|
||||
if (guest_sig < 1 || guest_sig > TARGET_NSIG) {
|
||||
return;
|
||||
trace_user_host_signal(env, host_signum, sig);
|
||||
}
|
||||
trace_user_host_signal(env, host_sig, guest_sig);
|
||||
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
k = &ts->sigtab[guest_sig - 1];
|
||||
k->info = tinfo;
|
||||
k->pending = guest_sig;
|
||||
ts->signal_pending = 1;
|
||||
|
||||
/*
|
||||
* For synchronous signals, unwind the cpu state to the faulting
|
||||
* insn and then exit back to the main loop so that the signal
|
||||
* is delivered immediately.
|
||||
*/
|
||||
if (sync_sig) {
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit_restore(cpu, pc);
|
||||
}
|
||||
|
||||
rewind_if_in_safe_syscall(puc);
|
||||
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
k = &ts->sigtab[sig - 1];
|
||||
k->info = tinfo;
|
||||
k->pending = sig;
|
||||
ts->signal_pending = 1;
|
||||
|
||||
/* Block host signals until target signal handler entered. We
|
||||
/*
|
||||
* Block host signals until target signal handler entered. We
|
||||
* can't block SIGSEGV or SIGBUS while we're executing guest
|
||||
* code in case the guest code provokes one in the window between
|
||||
* now and it getting out to the main loop. Signals will be
|
||||
|
@ -219,17 +219,6 @@ void cpu_loop (CPUSPARCState *env)
|
||||
case TT_WIN_UNF: /* window underflow */
|
||||
restore_window(env);
|
||||
break;
|
||||
case TT_TFAULT:
|
||||
case TT_DFAULT:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->mmuregs[4];
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
#else
|
||||
case TT_SPILL: /* window overflow */
|
||||
save_window(env);
|
||||
@ -237,20 +226,6 @@ void cpu_loop (CPUSPARCState *env)
|
||||
case TT_FILL: /* window underflow */
|
||||
restore_window(env);
|
||||
break;
|
||||
case TT_TFAULT:
|
||||
case TT_DFAULT:
|
||||
{
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
/* XXX: check env->error_code */
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
if (trapnr == TT_DFAULT)
|
||||
info._sifields._sigfault._addr = env->dmmu.mmuregs[4];
|
||||
else
|
||||
info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
#ifndef TARGET_ABI32
|
||||
case 0x16e:
|
||||
flush_windows(env);
|
||||
|
@ -226,15 +226,6 @@ void cpu_loop(CPUXtensaState *env)
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
|
||||
case LOAD_PROHIBITED_CAUSE:
|
||||
case STORE_PROHIBITED_CAUSE:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_ACCERR;
|
||||
info._sifields._sigfault._addr = env->sregs[EXCVADDR];
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
|
||||
g_assert_not_reached();
|
||||
|
@ -55,7 +55,7 @@ have_block = have_system or have_tools
|
||||
python = import('python').find_installation()
|
||||
|
||||
supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux']
|
||||
supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64',
|
||||
supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv', 'x86', 'x86_64',
|
||||
'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64']
|
||||
|
||||
cpu = host_machine.cpu_family()
|
||||
@ -351,8 +351,6 @@ if not get_option('tcg').disabled()
|
||||
tcg_arch = 'i386'
|
||||
elif config_host['ARCH'] == 'ppc64'
|
||||
tcg_arch = 'ppc'
|
||||
elif config_host['ARCH'] in ['riscv32', 'riscv64']
|
||||
tcg_arch = 'riscv'
|
||||
endif
|
||||
add_project_arguments('-iquote', meson.current_source_dir() / 'tcg' / tcg_arch,
|
||||
language: ['c', 'cpp', 'objc'])
|
||||
|
@ -218,9 +218,12 @@ static const struct SysemuCPUOps alpha_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps alpha_tcg_ops = {
|
||||
.initialize = alpha_translate_init,
|
||||
.tlb_fill = alpha_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = alpha_cpu_record_sigsegv,
|
||||
.record_sigbus = alpha_cpu_record_sigbus,
|
||||
#else
|
||||
.tlb_fill = alpha_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = alpha_cpu_exec_interrupt,
|
||||
.do_interrupt = alpha_cpu_do_interrupt,
|
||||
.do_transaction_failed = alpha_cpu_do_transaction_failed,
|
||||
|
@ -282,9 +282,6 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int alpha_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
|
||||
#define cpu_list alpha_cpu_list
|
||||
|
||||
@ -439,9 +436,6 @@ void alpha_translate_init(void);
|
||||
#define CPU_RESOLVING_TYPE TYPE_ALPHA_CPU
|
||||
|
||||
void alpha_cpu_list(void);
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void QEMU_NORETURN dynamic_excp(CPUAlphaState *, uintptr_t, int, int);
|
||||
void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t);
|
||||
|
||||
@ -449,7 +443,20 @@ uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env);
|
||||
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val);
|
||||
uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
|
||||
void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr);
|
||||
void alpha_cpu_record_sigbus(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type, uintptr_t retaddr);
|
||||
#else
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
vaddr addr, unsigned size,
|
||||
MMUAccessType access_type,
|
||||
|
@ -120,15 +120,44 @@ void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
target_ulong mmcsr, cause;
|
||||
|
||||
cs->exception_index = EXCP_MMFAULT;
|
||||
/* Assuming !maperr, infer the missing protection. */
|
||||
switch (access_type) {
|
||||
case MMU_DATA_LOAD:
|
||||
mmcsr = MM_K_FOR;
|
||||
cause = 0;
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
mmcsr = MM_K_FOW;
|
||||
cause = 1;
|
||||
break;
|
||||
case MMU_INST_FETCH:
|
||||
mmcsr = MM_K_FOE;
|
||||
cause = -1;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (maperr) {
|
||||
if (address < BIT_ULL(TARGET_VIRT_ADDR_SPACE_BITS - 1)) {
|
||||
/* Userspace address, therefore page not mapped. */
|
||||
mmcsr = MM_K_TNV;
|
||||
} else {
|
||||
/* Kernel or invalid address. */
|
||||
mmcsr = MM_K_ACV;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the arguments that PALcode would give to the kernel. */
|
||||
cpu->env.trap_arg0 = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
cpu->env.trap_arg1 = mmcsr;
|
||||
cpu->env.trap_arg2 = cause;
|
||||
}
|
||||
#else
|
||||
/* Returns the OSF/1 entMM failure indication, or -1 on success. */
|
||||
|
@ -23,18 +23,12 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
/* Softmmu support */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
static void do_unaligned_access(CPUAlphaState *env, vaddr addr, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
CPUAlphaState *env = &cpu->env;
|
||||
uint64_t pc;
|
||||
uint32_t insn;
|
||||
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
cpu_restore_state(env_cpu(env), retaddr, true);
|
||||
|
||||
pc = env->pc;
|
||||
insn = cpu_ldl_code(env, pc);
|
||||
@ -42,6 +36,26 @@ void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
env->trap_arg0 = addr;
|
||||
env->trap_arg1 = insn >> 26; /* opcode */
|
||||
env->trap_arg2 = (insn >> 21) & 31; /* dest regno */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void alpha_cpu_record_sigbus(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
CPUAlphaState *env = &cpu->env;
|
||||
|
||||
do_unaligned_access(env, addr, retaddr);
|
||||
}
|
||||
#else
|
||||
void alpha_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||
CPUAlphaState *env = &cpu->env;
|
||||
|
||||
do_unaligned_access(env, addr, retaddr);
|
||||
cs->exception_index = EXCP_UNALIGN;
|
||||
env->error_code = 0;
|
||||
cpu_loop_exit(cs);
|
||||
|
@ -2031,10 +2031,13 @@ static const struct SysemuCPUOps arm_sysemu_ops = {
|
||||
static const struct TCGCPUOps arm_tcg_ops = {
|
||||
.initialize = arm_translate_init,
|
||||
.synchronize_from_tb = arm_cpu_synchronize_from_tb,
|
||||
.tlb_fill = arm_cpu_tlb_fill,
|
||||
.debug_excp_handler = arm_debug_excp_handler,
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = arm_cpu_record_sigsegv,
|
||||
.record_sigbus = arm_cpu_record_sigbus,
|
||||
#else
|
||||
.tlb_fill = arm_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
|
||||
.do_interrupt = arm_cpu_do_interrupt,
|
||||
.do_transaction_failed = arm_cpu_do_transaction_failed,
|
||||
|
@ -898,10 +898,13 @@ static void pxa270c5_initfn(Object *obj)
|
||||
static const struct TCGCPUOps arm_v7m_tcg_ops = {
|
||||
.initialize = arm_translate_init,
|
||||
.synchronize_from_tb = arm_cpu_synchronize_from_tb,
|
||||
.tlb_fill = arm_cpu_tlb_fill,
|
||||
.debug_excp_handler = arm_debug_excp_handler,
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = arm_cpu_record_sigsegv,
|
||||
.record_sigbus = arm_cpu_record_sigbus,
|
||||
#else
|
||||
.tlb_fill = arm_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
|
||||
.do_interrupt = arm_v7m_cpu_do_interrupt,
|
||||
.do_transaction_failed = arm_cpu_do_transaction_failed,
|
||||
|
@ -544,9 +544,17 @@ static inline bool arm_extabort_type(MemTxResult result)
|
||||
return result != MEMTX_DECODE_ERROR;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void arm_cpu_record_sigsegv(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
void arm_cpu_record_sigbus(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, uintptr_t ra);
|
||||
#else
|
||||
bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#endif
|
||||
|
||||
static inline int arm_to_core_mmu_idx(ARMMMUIdx mmu_idx)
|
||||
{
|
||||
|
@ -84,10 +84,8 @@ static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx,
|
||||
uintptr_t index;
|
||||
|
||||
if (!(flags & (ptr_access == MMU_DATA_STORE ? PAGE_WRITE_ORG : PAGE_READ))) {
|
||||
/* SIGSEGV */
|
||||
arm_cpu_tlb_fill(env_cpu(env), ptr, ptr_size, ptr_access,
|
||||
ptr_mmu_idx, false, ra);
|
||||
g_assert_not_reached();
|
||||
cpu_loop_exit_sigsegv(env_cpu(env), ptr, ptr_access,
|
||||
!(flags & PAGE_VALID), ra);
|
||||
}
|
||||
|
||||
/* Require both MAP_ANON and PROT_MTE for the page. */
|
||||
|
@ -6118,7 +6118,7 @@ DO_LDN_2(4, dd, MO_64)
|
||||
* linux-user/ in its get_user/put_user macros.
|
||||
*
|
||||
* TODO: Construct some helpers, written in assembly, that interact with
|
||||
* handle_cpu_signal to produce memory ops which can properly report errors
|
||||
* host_signal_handler to produce memory ops which can properly report errors
|
||||
* without racing.
|
||||
*/
|
||||
|
||||
|
@ -147,28 +147,12 @@ void arm_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
arm_deliver_fault(cpu, addr, access_type, mmu_idx, &fi);
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
||||
bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
ARMMMUFaultInfo fi = {};
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int flags = page_get_flags(useronly_clean_ptr(address));
|
||||
if (flags & PAGE_VALID) {
|
||||
fi.type = ARMFault_Permission;
|
||||
} else {
|
||||
fi.type = ARMFault_Translation;
|
||||
}
|
||||
fi.level = 3;
|
||||
|
||||
/* now we have a real cpu fault */
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
|
||||
#else
|
||||
hwaddr phys_addr;
|
||||
target_ulong page_size;
|
||||
int prot, ret;
|
||||
@ -210,5 +194,29 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void arm_cpu_record_sigsegv(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra)
|
||||
{
|
||||
ARMMMUFaultInfo fi = {
|
||||
.type = maperr ? ARMFault_Translation : ARMFault_Permission,
|
||||
.level = 3,
|
||||
};
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
|
||||
/*
|
||||
* We report both ESR and FAR to signal handlers.
|
||||
* For now, it's easiest to deliver the fault normally.
|
||||
*/
|
||||
cpu_restore_state(cs, ra, true);
|
||||
arm_deliver_fault(cpu, addr, access_type, MMU_USER_IDX, &fi);
|
||||
}
|
||||
|
||||
void arm_cpu_record_sigbus(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type, uintptr_t ra)
|
||||
{
|
||||
arm_cpu_do_unaligned_access(cs, addr, access_type, MMU_USER_IDX, ra);
|
||||
}
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
|
@ -205,9 +205,9 @@ static const struct SysemuCPUOps cris_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps crisv10_tcg_ops = {
|
||||
.initialize = cris_initialize_crisv10_tcg,
|
||||
.tlb_fill = cris_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = cris_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = cris_cpu_exec_interrupt,
|
||||
.do_interrupt = crisv10_cpu_do_interrupt,
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
@ -215,9 +215,9 @@ static const struct TCGCPUOps crisv10_tcg_ops = {
|
||||
|
||||
static const struct TCGCPUOps crisv32_tcg_ops = {
|
||||
.initialize = cris_initialize_tcg,
|
||||
.tlb_fill = cris_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = cris_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = cris_cpu_exec_interrupt,
|
||||
.do_interrupt = cris_cpu_do_interrupt,
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -189,6 +189,10 @@ extern const VMStateDescription vmstate_cris_cpu;
|
||||
void cris_cpu_do_interrupt(CPUState *cpu);
|
||||
void crisv10_cpu_do_interrupt(CPUState *cpu);
|
||||
bool cris_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#endif
|
||||
|
||||
void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||
@ -251,10 +255,6 @@ static inline int cpu_mmu_index (CPUCRISState *env, bool ifetch)
|
||||
return !!(env->pregs[PR_CCS] & U_FLAG);
|
||||
}
|
||||
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
/* Support function regs. */
|
||||
#define SFR_RW_GC_CFG 0][0
|
||||
#define SFR_RW_MM_CFG env->pregs[PR_SRS]][0
|
||||
|
@ -39,22 +39,6 @@
|
||||
#define D_LOG(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
bool cris_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
CRISCPU *cpu = CRIS_CPU(cs);
|
||||
|
||||
cs->exception_index = 0xaa;
|
||||
cpu->env.pregs[PR_EDA] = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
|
||||
|
||||
static void cris_shift_ccs(CPUCRISState *env)
|
||||
{
|
||||
uint32_t ccs;
|
||||
@ -304,5 +288,3 @@ bool cris_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -2,13 +2,16 @@ cris_ss = ss.source_set()
|
||||
cris_ss.add(files(
|
||||
'cpu.c',
|
||||
'gdbstub.c',
|
||||
'helper.c',
|
||||
'op_helper.c',
|
||||
'translate.c',
|
||||
))
|
||||
|
||||
cris_softmmu_ss = ss.source_set()
|
||||
cris_softmmu_ss.add(files('mmu.c', 'machine.c'))
|
||||
cris_softmmu_ss.add(files(
|
||||
'helper.c',
|
||||
'machine.c',
|
||||
'mmu.c',
|
||||
))
|
||||
|
||||
target_arch += {'cris': cris_ss}
|
||||
target_softmmu_arch += {'cris': cris_softmmu_ss}
|
||||
|
@ -245,34 +245,11 @@ static void hexagon_cpu_init(Object *obj)
|
||||
qdev_property_add_static(DEVICE(obj), &hexagon_lldb_stack_adjust_property);
|
||||
}
|
||||
|
||||
static bool hexagon_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
cs->exception_index = HEX_EXCP_FETCH_NO_UPAGE;
|
||||
break;
|
||||
case MMU_DATA_LOAD:
|
||||
cs->exception_index = HEX_EXCP_PRIV_NO_UREAD;
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
cs->exception_index = HEX_EXCP_PRIV_NO_UWRITE;
|
||||
break;
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
#else
|
||||
#error System mode not implemented for Hexagon
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "hw/core/tcg-cpu-ops.h"
|
||||
|
||||
static const struct TCGCPUOps hexagon_tcg_ops = {
|
||||
.initialize = hexagon_translate_init,
|
||||
.synchronize_from_tb = hexagon_cpu_synchronize_from_tb,
|
||||
.tlb_fill = hexagon_tlb_fill,
|
||||
};
|
||||
|
||||
static void hexagon_cpu_class_init(ObjectClass *c, void *data)
|
||||
|
@ -145,9 +145,9 @@ static const struct SysemuCPUOps hppa_sysemu_ops = {
|
||||
static const struct TCGCPUOps hppa_tcg_ops = {
|
||||
.initialize = hppa_translate_init,
|
||||
.synchronize_from_tb = hppa_cpu_synchronize_from_tb,
|
||||
.tlb_fill = hppa_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = hppa_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = hppa_cpu_exec_interrupt,
|
||||
.do_interrupt = hppa_cpu_do_interrupt,
|
||||
.do_unaligned_access = hppa_cpu_do_unaligned_access,
|
||||
|
@ -323,10 +323,10 @@ hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
||||
int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void hppa_cpu_dump_state(CPUState *cs, FILE *f, int);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void hppa_cpu_do_interrupt(CPUState *cpu);
|
||||
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
|
||||
|
@ -24,20 +24,6 @@
|
||||
#include "hw/core/cpu.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
HPPACPU *cpu = HPPA_CPU(cs);
|
||||
|
||||
/* ??? Test between data page fault and data memory protection trap,
|
||||
which would affect si_code. */
|
||||
cs->exception_index = EXCP_DMP;
|
||||
cpu->env.cr[CR_IOR] = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#else
|
||||
static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
|
||||
{
|
||||
int i;
|
||||
@ -392,4 +378,3 @@ int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
|
||||
hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr);
|
||||
return ent ? ent->ar_type : -1;
|
||||
}
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
@ -7,13 +7,15 @@ hppa_ss.add(files(
|
||||
'gdbstub.c',
|
||||
'helper.c',
|
||||
'int_helper.c',
|
||||
'mem_helper.c',
|
||||
'op_helper.c',
|
||||
'translate.c',
|
||||
))
|
||||
|
||||
hppa_softmmu_ss = ss.source_set()
|
||||
hppa_softmmu_ss.add(files('machine.c'))
|
||||
hppa_softmmu_ss.add(files(
|
||||
'machine.c',
|
||||
'mem_helper.c',
|
||||
))
|
||||
|
||||
target_arch += {'hppa': hppa_ss}
|
||||
target_softmmu_arch += {'hppa': hppa_softmmu_ss}
|
||||
|
@ -43,9 +43,15 @@ bool x86_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
#endif
|
||||
|
||||
/* helper.c */
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
#else
|
||||
bool x86_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#endif
|
||||
|
||||
void breakpoint_handler(CPUState *cs);
|
||||
|
||||
|
@ -72,10 +72,11 @@ static const struct TCGCPUOps x86_tcg_ops = {
|
||||
.synchronize_from_tb = x86_cpu_synchronize_from_tb,
|
||||
.cpu_exec_enter = x86_cpu_exec_enter,
|
||||
.cpu_exec_exit = x86_cpu_exec_exit,
|
||||
.tlb_fill = x86_cpu_tlb_fill,
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.fake_user_interrupt = x86_cpu_do_interrupt,
|
||||
.record_sigsegv = x86_cpu_record_sigsegv,
|
||||
#else
|
||||
.tlb_fill = x86_cpu_tlb_fill,
|
||||
.do_interrupt = x86_cpu_do_interrupt,
|
||||
.cpu_exec_interrupt = x86_cpu_exec_interrupt,
|
||||
.debug_excp_handler = breakpoint_handler,
|
||||
|
@ -22,18 +22,29 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/helper-tcg.h"
|
||||
|
||||
bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
||||
/*
|
||||
* The error_code that hw reports as part of the exception frame
|
||||
* is copied to linux sigcontext.err. The exception_index is
|
||||
* copied to linux sigcontext.trapno. Short of inventing a new
|
||||
* place to store the trapno, we cannot let our caller raise the
|
||||
* signal and set exception_index to EXCP_INTERRUPT.
|
||||
*/
|
||||
env->cr[2] = addr;
|
||||
env->error_code = (access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT;
|
||||
env->error_code |= PG_ERROR_U_MASK;
|
||||
env->error_code = ((access_type == MMU_DATA_STORE) << PG_ERROR_W_BIT)
|
||||
| (maperr ? 0 : PG_ERROR_P_MASK)
|
||||
| PG_ERROR_U_MASK;
|
||||
cs->exception_index = EXCP0E_PAGE;
|
||||
|
||||
/* Disable do_interrupt_user. */
|
||||
env->exception_is_int = 0;
|
||||
env->exception_next_eip = -1;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
|
||||
cpu_loop_exit_restore(cs, ra);
|
||||
}
|
||||
|
@ -515,9 +515,9 @@ static const struct SysemuCPUOps m68k_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps m68k_tcg_ops = {
|
||||
.initialize = m68k_tcg_init,
|
||||
.tlb_fill = m68k_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = m68k_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = m68k_cpu_exec_interrupt,
|
||||
.do_interrupt = m68k_cpu_do_interrupt,
|
||||
.do_transaction_failed = m68k_cpu_transaction_failed,
|
||||
|
@ -978,16 +978,12 @@ void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType qemu_access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
M68kCPU *cpu = M68K_CPU(cs);
|
||||
CPUM68KState *env = &cpu->env;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
hwaddr physical;
|
||||
int prot;
|
||||
int access_type;
|
||||
@ -1051,12 +1047,12 @@ bool m68k_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
if (!(access_type & ACCESS_STORE)) {
|
||||
env->mmu.ssw |= M68K_RW_040;
|
||||
}
|
||||
#endif
|
||||
|
||||
cs->exception_index = EXCP_ACCESS;
|
||||
env->mmu.ar = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
uint32_t HELPER(bitrev)(uint32_t x)
|
||||
{
|
||||
|
@ -365,9 +365,9 @@ static const struct SysemuCPUOps mb_sysemu_ops = {
|
||||
static const struct TCGCPUOps mb_tcg_ops = {
|
||||
.initialize = mb_tcg_init,
|
||||
.synchronize_from_tb = mb_cpu_synchronize_from_tb,
|
||||
.tlb_fill = mb_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = mb_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = mb_cpu_exec_interrupt,
|
||||
.do_interrupt = mb_cpu_do_interrupt,
|
||||
.do_transaction_failed = mb_cpu_transaction_failed,
|
||||
|
@ -394,10 +394,6 @@ void mb_tcg_init(void);
|
||||
#define MMU_USER_IDX 2
|
||||
/* See NB_MMU_MODES further up the file. */
|
||||
|
||||
bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
typedef CPUMBState CPUArchState;
|
||||
typedef MicroBlazeCPU ArchCPU;
|
||||
|
||||
@ -415,6 +411,10 @@ static inline void cpu_get_tb_cpu_state(CPUMBState *env, target_ulong *pc,
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
|
||||
unsigned size, MMUAccessType access_type,
|
||||
int mmu_idx, MemTxAttrs attrs,
|
||||
|
@ -24,18 +24,7 @@
|
||||
#include "qemu/host-utils.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
cs->exception_index = 0xaa;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu,
|
||||
MMUAccessType access_type)
|
||||
{
|
||||
|
@ -722,6 +722,7 @@ static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static void record_unaligned_ess(DisasContext *dc, int rd,
|
||||
MemOp size, bool store)
|
||||
{
|
||||
@ -734,6 +735,7 @@ static void record_unaligned_ess(DisasContext *dc, int rd,
|
||||
|
||||
tcg_set_insn_start_param(dc->insn_start, 1, iflags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
|
||||
int mem_index, bool rev)
|
||||
@ -755,12 +757,19 @@ static bool do_load(DisasContext *dc, int rd, TCGv addr, MemOp mop,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For system mode, enforce alignment if the cpu configuration
|
||||
* requires it. For user-mode, the Linux kernel will have fixed up
|
||||
* any unaligned access, so emulate that by *not* setting MO_ALIGN.
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (size > MO_8 &&
|
||||
(dc->tb_flags & MSR_EE) &&
|
||||
dc->cfg->unaligned_exceptions) {
|
||||
record_unaligned_ess(dc, rd, size, false);
|
||||
mop |= MO_ALIGN;
|
||||
}
|
||||
#endif
|
||||
|
||||
tcg_gen_qemu_ld_i32(reg_for_write(dc, rd), addr, mem_index, mop);
|
||||
|
||||
@ -901,12 +910,19 @@ static bool do_store(DisasContext *dc, int rd, TCGv addr, MemOp mop,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For system mode, enforce alignment if the cpu configuration
|
||||
* requires it. For user-mode, the Linux kernel will have fixed up
|
||||
* any unaligned access, so emulate that by *not* setting MO_ALIGN.
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (size > MO_8 &&
|
||||
(dc->tb_flags & MSR_EE) &&
|
||||
dc->cfg->unaligned_exceptions) {
|
||||
record_unaligned_ess(dc, rd, size, true);
|
||||
mop |= MO_ALIGN;
|
||||
}
|
||||
#endif
|
||||
|
||||
tcg_gen_qemu_st_i32(reg_for_read(dc, rd), addr, mem_index, mop);
|
||||
|
||||
|
@ -539,9 +539,9 @@ static const struct SysemuCPUOps mips_sysemu_ops = {
|
||||
static const struct TCGCPUOps mips_tcg_ops = {
|
||||
.initialize = mips_tcg_init,
|
||||
.synchronize_from_tb = mips_cpu_synchronize_from_tb,
|
||||
.tlb_fill = mips_cpu_tlb_fill,
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
.tlb_fill = mips_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = mips_cpu_exec_interrupt,
|
||||
.do_interrupt = mips_cpu_do_interrupt,
|
||||
.do_transaction_failed = mips_cpu_do_transaction_failed,
|
||||
|
@ -28,9 +28,6 @@ mips_ss.add(when: 'TARGET_MIPS64', if_true: files(
|
||||
'mxu_translate.c',
|
||||
))
|
||||
|
||||
if have_user
|
||||
subdir('user')
|
||||
endif
|
||||
if have_system
|
||||
subdir('sysemu')
|
||||
endif
|
||||
|
@ -18,9 +18,6 @@
|
||||
void mips_tcg_init(void);
|
||||
|
||||
void mips_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb);
|
||||
bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
@ -60,6 +57,10 @@ void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
MemTxResult response, uintptr_t retaddr);
|
||||
void cpu_mips_tlb_flush(CPUMIPSState *env);
|
||||
|
||||
bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +0,0 @@
|
||||
mips_user_ss.add(files(
|
||||
'tlb_helper.c',
|
||||
))
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* MIPS TLB (Translation lookaside buffer) helpers.
|
||||
*
|
||||
* Copyright (c) 2004-2005 Jocelyn Mayer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "internal.h"
|
||||
|
||||
static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,
|
||||
MMUAccessType access_type)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
env->error_code = 0;
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
env->error_code |= EXCP_INST_NOTAVAIL;
|
||||
}
|
||||
|
||||
/* Reference to kernel address from user mode or supervisor mode */
|
||||
/* Reference to supervisor address from user mode */
|
||||
if (access_type == MMU_DATA_STORE) {
|
||||
cs->exception_index = EXCP_AdES;
|
||||
} else {
|
||||
cs->exception_index = EXCP_AdEL;
|
||||
}
|
||||
|
||||
/* Raise exception */
|
||||
if (!(env->hflags & MIPS_HFLAG_DM)) {
|
||||
env->CP0_BadVAddr = address;
|
||||
}
|
||||
}
|
||||
|
||||
bool mips_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||
CPUMIPSState *env = &cpu->env;
|
||||
|
||||
/* data access */
|
||||
raise_mmu_exception(env, address, access_type);
|
||||
do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
|
||||
}
|
@ -216,9 +216,11 @@ static const struct SysemuCPUOps nios2_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps nios2_tcg_ops = {
|
||||
.initialize = nios2_tcg_init,
|
||||
.tlb_fill = nios2_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = nios2_cpu_record_sigsegv,
|
||||
#else
|
||||
.tlb_fill = nios2_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = nios2_cpu_exec_interrupt,
|
||||
.do_interrupt = nios2_cpu_do_interrupt,
|
||||
.do_unaligned_access = nios2_cpu_do_unaligned_access,
|
||||
|
@ -218,9 +218,15 @@ static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch)
|
||||
MMU_SUPERVISOR_IDX;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void nios2_cpu_record_sigsegv(CPUState *cpu, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
#else
|
||||
bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
#endif
|
||||
|
||||
static inline int cpu_interrupts_enabled(CPUNios2State *env)
|
||||
{
|
||||
|
@ -38,10 +38,11 @@ void nios2_cpu_do_interrupt(CPUState *cs)
|
||||
env->regs[R_EA] = env->regs[R_PC] + 4;
|
||||
}
|
||||
|
||||
bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
void nios2_cpu_record_sigsegv(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr)
|
||||
{
|
||||
/* FIXME: Disentangle kuser page from linux-user sigsegv handling. */
|
||||
cs->exception_index = 0xaa;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
@ -186,9 +186,9 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps openrisc_tcg_ops = {
|
||||
.initialize = openrisc_translate_init,
|
||||
.tlb_fill = openrisc_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = openrisc_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = openrisc_cpu_exec_interrupt,
|
||||
.do_interrupt = openrisc_cpu_do_interrupt,
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -317,14 +317,15 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||
int openrisc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||
int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||
void openrisc_translate_init(void);
|
||||
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
int print_insn_or1k(bfd_vma addr, disassemble_info *info);
|
||||
|
||||
#define cpu_list cpu_openrisc_list
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
extern const VMStateDescription vmstate_openrisc_cpu;
|
||||
|
||||
void openrisc_cpu_do_interrupt(CPUState *cpu);
|
||||
|
@ -10,7 +10,6 @@ openrisc_ss.add(files(
|
||||
'fpu_helper.c',
|
||||
'gdbstub.c',
|
||||
'interrupt_helper.c',
|
||||
'mmu.c',
|
||||
'sys_helper.c',
|
||||
'translate.c',
|
||||
))
|
||||
@ -19,6 +18,7 @@ openrisc_softmmu_ss = ss.source_set()
|
||||
openrisc_softmmu_ss.add(files(
|
||||
'interrupt.c',
|
||||
'machine.c',
|
||||
'mmu.c',
|
||||
))
|
||||
|
||||
target_arch += {'openrisc': openrisc_ss}
|
||||
|
@ -23,11 +23,8 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "hw/loader.h"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
|
||||
target_ulong address)
|
||||
{
|
||||
@ -94,7 +91,6 @@ static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
|
||||
return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
|
||||
int exception)
|
||||
@ -112,8 +108,6 @@ bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
{
|
||||
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
||||
int excp = EXCP_DPF;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
int prot;
|
||||
hwaddr phys_addr;
|
||||
|
||||
@ -138,13 +132,11 @@ bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
if (probe) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
raise_mmu_exception(cpu, addr, excp);
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
{
|
||||
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
||||
@ -177,4 +169,3 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
return phys_addr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1302,9 +1302,6 @@ extern const VMStateDescription vmstate_ppc_cpu;
|
||||
|
||||
/*****************************************************************************/
|
||||
void ppc_translate_init(void);
|
||||
bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void ppc_store_sdr1(CPUPPCState *env, target_ulong value);
|
||||
|
@ -9014,9 +9014,11 @@ static const struct SysemuCPUOps ppc_sysemu_ops = {
|
||||
|
||||
static const struct TCGCPUOps ppc_tcg_ops = {
|
||||
.initialize = ppc_translate_init,
|
||||
.tlb_fill = ppc_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = ppc_cpu_record_sigsegv,
|
||||
#else
|
||||
.tlb_fill = ppc_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = ppc_cpu_exec_interrupt,
|
||||
.do_interrupt = ppc_cpu_do_interrupt,
|
||||
.cpu_exec_enter = ppc_cpu_exec_enter,
|
||||
|
@ -454,13 +454,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
break;
|
||||
}
|
||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||
/* Get rS/rD and rA from faulting opcode */
|
||||
/*
|
||||
* Note: the opcode fields will not be set properly for a
|
||||
* direct store load/store, but nobody cares as nobody
|
||||
* actually uses direct store segments.
|
||||
* Get rS/rD and rA from faulting opcode.
|
||||
* Note: We will only invoke ALIGN for atomic operations,
|
||||
* so all instructions are X-form.
|
||||
*/
|
||||
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
|
||||
{
|
||||
uint32_t insn = cpu_ldl_code(env, env->nip);
|
||||
env->spr[SPR_DSISR] |= (insn & 0x03FF0000) >> 16;
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||
switch (env->error_code & ~0xF) {
|
||||
@ -1452,24 +1454,31 @@ void helper_book3s_msgsndp(CPUPPCState *env, target_ulong rb)
|
||||
|
||||
book3s_msgsnd_common(pir, PPC_INTERRUPT_DOORBELL);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_TCG */
|
||||
#endif
|
||||
#endif /* TARGET_PPC64 */
|
||||
|
||||
#ifdef CONFIG_TCG
|
||||
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
CPUPPCState *env = cs->env_ptr;
|
||||
uint32_t insn;
|
||||
|
||||
/* Restore state and reload the insn we executed, for filling in DSISR. */
|
||||
cpu_restore_state(cs, retaddr, true);
|
||||
insn = cpu_ldl_code(env, env->nip);
|
||||
switch (env->mmu_model) {
|
||||
case POWERPC_MMU_SOFT_4xx:
|
||||
case POWERPC_MMU_SOFT_4xx_Z:
|
||||
env->spr[SPR_40x_DEAR] = vaddr;
|
||||
break;
|
||||
case POWERPC_MMU_BOOKE:
|
||||
case POWERPC_MMU_BOOKE206:
|
||||
env->spr[SPR_BOOKE_DEAR] = vaddr;
|
||||
break;
|
||||
default:
|
||||
env->spr[SPR_DAR] = vaddr;
|
||||
break;
|
||||
}
|
||||
|
||||
cs->exception_index = POWERPC_EXCP_ALIGN;
|
||||
env->error_code = insn & 0x03FF0000;
|
||||
cpu_loop_exit(cs);
|
||||
env->error_code = 0;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_TCG */
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -211,11 +211,6 @@ void helper_compute_fprf_float16(CPUPPCState *env, float16 arg);
|
||||
void helper_compute_fprf_float32(CPUPPCState *env, float32 arg);
|
||||
void helper_compute_fprf_float128(CPUPPCState *env, float128 arg);
|
||||
|
||||
/* Raise a data fault alignment exception for the specified virtual address */
|
||||
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
|
||||
/* translate.c */
|
||||
|
||||
int ppc_fixup_cpu(PowerPCCPU *cpu);
|
||||
@ -283,5 +278,17 @@ static inline void pte_invalidate(target_ulong *pte0)
|
||||
#define PTE_PTEM_MASK 0x7FFFFFBF
|
||||
#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void ppc_cpu_record_sigsegv(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t ra);
|
||||
#else
|
||||
bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
#endif
|
||||
|
||||
#endif /* PPC_INTERNAL_H */
|
||||
|
@ -21,16 +21,23 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
bool ppc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
void ppc_cpu_record_sigsegv(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int exception, error_code;
|
||||
|
||||
/*
|
||||
* Both DSISR and the "trap number" (exception vector offset,
|
||||
* looked up from exception_index) are present in the linux-user
|
||||
* signal frame.
|
||||
* FIXME: we don't actually populate the trap number properly.
|
||||
* It would be easiest to fill in an env->trap value now.
|
||||
*/
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
exception = POWERPC_EXCP_ISI;
|
||||
error_code = 0x40000000;
|
||||
|
@ -694,9 +694,9 @@ static const struct SysemuCPUOps riscv_sysemu_ops = {
|
||||
static const struct TCGCPUOps riscv_tcg_ops = {
|
||||
.initialize = riscv_translate_init,
|
||||
.synchronize_from_tb = riscv_cpu_synchronize_from_tb,
|
||||
.tlb_fill = riscv_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = riscv_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = riscv_cpu_exec_interrupt,
|
||||
.do_interrupt = riscv_cpu_do_interrupt,
|
||||
.do_transaction_failed = riscv_cpu_do_transaction_failed,
|
||||
|
@ -814,7 +814,6 @@ void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
riscv_cpu_two_stage_lookup(mmu_idx);
|
||||
riscv_raise_exception(env, cs->exception_index, retaddr);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
@ -822,7 +821,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
{
|
||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||
CPURISCVState *env = &cpu->env;
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
vaddr im_address;
|
||||
hwaddr pa = 0;
|
||||
int prot, prot2, prot_pmp;
|
||||
@ -954,25 +952,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
#else
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
cs->exception_index = RISCV_EXCP_INST_PAGE_FAULT;
|
||||
break;
|
||||
case MMU_DATA_LOAD:
|
||||
cs->exception_index = RISCV_EXCP_LOAD_PAGE_FAULT;
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
cs->exception_index = RISCV_EXCP_STORE_PAGE_FAULT;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
env->badaddr = address;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
#endif
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
/*
|
||||
* Handle Traps
|
||||
|
@ -266,9 +266,12 @@ static void s390_cpu_reset_full(DeviceState *dev)
|
||||
|
||||
static const struct TCGCPUOps s390_tcg_ops = {
|
||||
.initialize = s390x_translate_init,
|
||||
.tlb_fill = s390_cpu_tlb_fill,
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
.record_sigsegv = s390_cpu_record_sigsegv,
|
||||
.record_sigbus = s390_cpu_record_sigbus,
|
||||
#else
|
||||
.tlb_fill = s390_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = s390_cpu_exec_interrupt,
|
||||
.do_interrupt = s390_cpu_do_interrupt,
|
||||
.debug_excp_handler = s390x_cpu_debug_excp_handler,
|
||||
|
@ -270,12 +270,21 @@ ObjectClass *s390_cpu_class_by_name(const char *name);
|
||||
void s390x_cpu_debug_excp_handler(CPUState *cs);
|
||||
void s390_cpu_do_interrupt(CPUState *cpu);
|
||||
bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
void s390_cpu_record_sigsegv(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr);
|
||||
void s390_cpu_record_sigbus(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type, uintptr_t retaddr);
|
||||
#else
|
||||
bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
#endif
|
||||
|
||||
|
||||
/* fpu_helper.c */
|
||||
|
@ -82,6 +82,19 @@ void HELPER(data_exception)(CPUS390XState *env, uint32_t dxc)
|
||||
tcg_s390_data_exception(env, dxc, GETPC());
|
||||
}
|
||||
|
||||
/*
|
||||
* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
|
||||
* this is only for the atomic operations, for which we want to raise a
|
||||
* specification exception.
|
||||
*/
|
||||
static void QEMU_NORETURN do_unaligned_access(CPUState *cs, uintptr_t retaddr)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
|
||||
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
void s390_cpu_do_interrupt(CPUState *cs)
|
||||
@ -89,19 +102,29 @@ void s390_cpu_do_interrupt(CPUState *cs)
|
||||
cs->exception_index = -1;
|
||||
}
|
||||
|
||||
bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
void s390_cpu_record_sigsegv(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type,
|
||||
bool maperr, uintptr_t retaddr)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
|
||||
trigger_pgm_exception(&cpu->env, PGM_ADDRESSING);
|
||||
/* On real machines this value is dropped into LowMem. Since this
|
||||
is userland, simply put this someplace that cpu_loop can find it. */
|
||||
cpu->env.__excp_addr = address;
|
||||
trigger_pgm_exception(&cpu->env, maperr ? PGM_ADDRESSING : PGM_PROTECTION);
|
||||
/*
|
||||
* On real machines this value is dropped into LowMem. Since this
|
||||
* is userland, simply put this someplace that cpu_loop can find it.
|
||||
* S390 only gives the page of the fault, not the exact address.
|
||||
* C.f. the construction of TEC in mmu_translate().
|
||||
*/
|
||||
cpu->env.__excp_addr = address & TARGET_PAGE_MASK;
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
void s390_cpu_record_sigbus(CPUState *cs, vaddr address,
|
||||
MMUAccessType access_type, uintptr_t retaddr)
|
||||
{
|
||||
do_unaligned_access(cs, retaddr);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
|
||||
static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
|
||||
@ -589,17 +612,11 @@ void s390x_cpu_debug_excp_handler(CPUState *cs)
|
||||
}
|
||||
}
|
||||
|
||||
/* Unaligned accesses are only diagnosed with MO_ALIGN. At the moment,
|
||||
this is only for the atomic operations, for which we want to raise a
|
||||
specification exception. */
|
||||
void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
CPUS390XState *env = &cpu->env;
|
||||
|
||||
tcg_s390_program_interrupt(env, PGM_SPECIFICATION, retaddr);
|
||||
do_unaligned_access(cs, retaddr);
|
||||
}
|
||||
|
||||
static void QEMU_NORETURN monitor_event(CPUS390XState *env,
|
||||
|
@ -141,20 +141,12 @@ static int s390_probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool nonfault, void **phost, uintptr_t ra)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
return probe_access_flags(env, addr, access_type, mmu_idx,
|
||||
nonfault, phost, ra);
|
||||
#else
|
||||
int flags;
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
flags = page_get_flags(addr);
|
||||
if (!(flags & (access_type == MMU_DATA_LOAD ? PAGE_READ : PAGE_WRITE_ORG))) {
|
||||
env->__excp_addr = addr;
|
||||
flags = (flags & PAGE_VALID) ? PGM_PROTECTION : PGM_ADDRESSING;
|
||||
if (nonfault) {
|
||||
return flags;
|
||||
}
|
||||
tcg_s390_program_interrupt(env, flags, ra);
|
||||
}
|
||||
*phost = g2h(env_cpu(env), addr);
|
||||
#else
|
||||
/*
|
||||
* For !CONFIG_USER_ONLY, we cannot rely on TLB_INVALID_MASK or haddr==NULL
|
||||
* to detect if there was an exception during tlb_fill().
|
||||
@ -173,8 +165,8 @@ static int s390_probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
(access_type == MMU_DATA_STORE
|
||||
? BP_MEM_WRITE : BP_MEM_READ), ra);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int access_prepare_nf(S390Access *access, CPUS390XState *env,
|
||||
|
@ -236,9 +236,9 @@ static const struct SysemuCPUOps sh4_sysemu_ops = {
|
||||
static const struct TCGCPUOps superh_tcg_ops = {
|
||||
.initialize = sh4_translate_init,
|
||||
.synchronize_from_tb = superh_cpu_synchronize_from_tb,
|
||||
.tlb_fill = superh_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = superh_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = superh_cpu_exec_interrupt,
|
||||
.do_interrupt = superh_cpu_do_interrupt,
|
||||
.do_unaligned_access = superh_cpu_do_unaligned_access,
|
||||
|
@ -213,12 +213,12 @@ void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||
uintptr_t retaddr) QEMU_NORETURN;
|
||||
|
||||
void sh4_translate_init(void);
|
||||
void sh4_cpu_list(void);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr);
|
||||
|
||||
void sh4_cpu_list(void);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void superh_cpu_do_interrupt(CPUState *cpu);
|
||||
bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||
void cpu_sh4_invalidate_tlb(CPUSH4State *s);
|
||||
|
@ -796,8 +796,6 @@ bool superh_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
||||
bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
@ -806,11 +804,6 @@ bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
CPUSH4State *env = &cpu->env;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
ret = (access_type == MMU_DATA_STORE ? MMU_DTLB_VIOLATION_WRITE :
|
||||
access_type == MMU_INST_FETCH ? MMU_ITLB_VIOLATION :
|
||||
MMU_DTLB_VIOLATION_READ);
|
||||
#else
|
||||
target_ulong physical;
|
||||
int prot;
|
||||
|
||||
@ -829,7 +822,6 @@ bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
if (ret != MMU_DTLB_MULTIPLE && ret != MMU_ITLB_MULTIPLE) {
|
||||
env->pteh = (env->pteh & PTEH_ASID_MASK) | (address & PTEH_VPN_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
env->tea = address;
|
||||
switch (ret) {
|
||||
@ -868,3 +860,4 @@ bool superh_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
@ -29,6 +29,9 @@ void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
CPUSH4State *env = cs->env_ptr;
|
||||
|
||||
env->tea = addr;
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
case MMU_DATA_LOAD:
|
||||
@ -37,6 +40,8 @@ void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
case MMU_DATA_STORE:
|
||||
cs->exception_index = 0x100;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
@ -865,9 +865,9 @@ static const struct SysemuCPUOps sparc_sysemu_ops = {
|
||||
static const struct TCGCPUOps sparc_tcg_ops = {
|
||||
.initialize = sparc_tcg_init,
|
||||
.synchronize_from_tb = sparc_cpu_synchronize_from_tb,
|
||||
.tlb_fill = sparc_cpu_tlb_fill,
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
.tlb_fill = sparc_cpu_tlb_fill,
|
||||
.cpu_exec_interrupt = sparc_cpu_exec_interrupt,
|
||||
.do_interrupt = sparc_cpu_do_interrupt,
|
||||
.do_transaction_failed = sparc_cpu_do_transaction_failed,
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
//#define DEBUG_MMU
|
||||
//#define DEBUG_MXCC
|
||||
//#define DEBUG_UNALIGNED
|
||||
//#define DEBUG_UNASSIGNED
|
||||
//#define DEBUG_ASI
|
||||
//#define DEBUG_CACHE_CONTROL
|
||||
@ -364,10 +363,6 @@ static void do_check_align(CPUSPARCState *env, target_ulong addr,
|
||||
uint32_t align, uintptr_t ra)
|
||||
{
|
||||
if (addr & align) {
|
||||
#ifdef DEBUG_UNALIGNED
|
||||
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
|
||||
"\n", addr, env->pc);
|
||||
#endif
|
||||
cpu_raise_exception_ra(env, TT_UNALIGNED, ra);
|
||||
}
|
||||
}
|
||||
@ -1958,20 +1953,3 @@ void sparc_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
|
||||
is_asi, size, retaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
#ifdef DEBUG_UNALIGNED
|
||||
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
|
||||
"\n", addr, env->pc);
|
||||
#endif
|
||||
cpu_raise_exception_ra(env, TT_UNALIGNED, retaddr);
|
||||
}
|
||||
#endif
|
||||
|
@ -6,7 +6,6 @@ sparc_ss.add(files(
|
||||
'gdbstub.c',
|
||||
'helper.c',
|
||||
'ldst_helper.c',
|
||||
'mmu_helper.c',
|
||||
'translate.c',
|
||||
'win_helper.c',
|
||||
))
|
||||
@ -16,6 +15,7 @@ sparc_ss.add(when: 'TARGET_SPARC64', if_true: files('int64_helper.c', 'vis_helpe
|
||||
sparc_softmmu_ss = ss.source_set()
|
||||
sparc_softmmu_ss.add(files(
|
||||
'machine.c',
|
||||
'mmu_helper.c',
|
||||
'monitor.c',
|
||||
))
|
||||
|
||||
|
@ -25,30 +25,6 @@
|
||||
|
||||
/* Sparc MMU emulation */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
if (access_type == MMU_INST_FETCH) {
|
||||
cs->exception_index = TT_TFAULT;
|
||||
} else {
|
||||
cs->exception_index = TT_DFAULT;
|
||||
#ifdef TARGET_SPARC64
|
||||
env->dmmu.mmuregs[4] = address;
|
||||
#else
|
||||
env->mmuregs[4] = address;
|
||||
#endif
|
||||
}
|
||||
cpu_loop_exit_restore(cs, retaddr);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
/*
|
||||
* Sparc V8 Reference MMU (SRMMU)
|
||||
@ -526,16 +502,60 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t build_sfsr(CPUSPARCState *env, int mmu_idx, int rw)
|
||||
{
|
||||
uint64_t sfsr = SFSR_VALID_BIT;
|
||||
|
||||
switch (mmu_idx) {
|
||||
case MMU_PHYS_IDX:
|
||||
sfsr |= SFSR_CT_NOTRANS;
|
||||
break;
|
||||
case MMU_USER_IDX:
|
||||
case MMU_KERNEL_IDX:
|
||||
sfsr |= SFSR_CT_PRIMARY;
|
||||
break;
|
||||
case MMU_USER_SECONDARY_IDX:
|
||||
case MMU_KERNEL_SECONDARY_IDX:
|
||||
sfsr |= SFSR_CT_SECONDARY;
|
||||
break;
|
||||
case MMU_NUCLEUS_IDX:
|
||||
sfsr |= SFSR_CT_NUCLEUS;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (rw == 1) {
|
||||
sfsr |= SFSR_WRITE_BIT;
|
||||
} else if (rw == 4) {
|
||||
sfsr |= SFSR_NF_BIT;
|
||||
}
|
||||
|
||||
if (env->pstate & PS_PRIV) {
|
||||
sfsr |= SFSR_PR_BIT;
|
||||
}
|
||||
|
||||
if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
|
||||
sfsr |= SFSR_OW_BIT; /* overflow (not read before another fault) */
|
||||
}
|
||||
|
||||
/* FIXME: ASI field in SFSR must be set */
|
||||
|
||||
return sfsr;
|
||||
}
|
||||
|
||||
static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical,
|
||||
int *prot, MemTxAttrs *attrs,
|
||||
target_ulong address, int rw, int mmu_idx)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned int i;
|
||||
uint64_t sfsr;
|
||||
uint64_t context;
|
||||
uint64_t sfsr = 0;
|
||||
bool is_user = false;
|
||||
|
||||
sfsr = build_sfsr(env, mmu_idx, rw);
|
||||
|
||||
switch (mmu_idx) {
|
||||
case MMU_PHYS_IDX:
|
||||
g_assert_not_reached();
|
||||
@ -544,29 +564,18 @@ static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical,
|
||||
/* fallthru */
|
||||
case MMU_KERNEL_IDX:
|
||||
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||
sfsr |= SFSR_CT_PRIMARY;
|
||||
break;
|
||||
case MMU_USER_SECONDARY_IDX:
|
||||
is_user = true;
|
||||
/* fallthru */
|
||||
case MMU_KERNEL_SECONDARY_IDX:
|
||||
context = env->dmmu.mmu_secondary_context & 0x1fff;
|
||||
sfsr |= SFSR_CT_SECONDARY;
|
||||
break;
|
||||
case MMU_NUCLEUS_IDX:
|
||||
sfsr |= SFSR_CT_NUCLEUS;
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
context = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rw == 1) {
|
||||
sfsr |= SFSR_WRITE_BIT;
|
||||
} else if (rw == 4) {
|
||||
sfsr |= SFSR_NF_BIT;
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
/* ctx match, vaddr match, valid? */
|
||||
if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
|
||||
@ -616,22 +625,9 @@ static int get_physical_address_data(CPUSPARCState *env, hwaddr *physical,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
|
||||
sfsr |= SFSR_OW_BIT; /* overflow (not read before
|
||||
another fault) */
|
||||
}
|
||||
|
||||
if (env->pstate & PS_PRIV) {
|
||||
sfsr |= SFSR_PR_BIT;
|
||||
}
|
||||
|
||||
/* FIXME: ASI field in SFSR must be set */
|
||||
env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
|
||||
|
||||
env->dmmu.sfsr = sfsr;
|
||||
env->dmmu.sfar = address; /* Fault address register */
|
||||
|
||||
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -926,4 +922,23 @@ hwaddr sparc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
|
||||
}
|
||||
return phys_addr;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||
CPUSPARCState *env = &cpu->env;
|
||||
|
||||
#ifdef TARGET_SPARC64
|
||||
env->dmmu.sfsr = build_sfsr(env, mmu_idx, access_type);
|
||||
env->dmmu.sfar = addr;
|
||||
#else
|
||||
env->mmuregs[4] = addr;
|
||||
#endif
|
||||
|
||||
cpu_raise_exception_ra(env, TT_UNALIGNED, retaddr);
|
||||
}
|
||||
#endif /* !CONFIG_USER_ONLY */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user