X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=user-exec.c;h=a8f95fa1e1432046ce35f9ab381fbfeb38acda41;hb=b8dc35b2526278296390fffa80b5c82573ed178a;hp=82bfa66ce303efdfc94701e657674a95b7ce7ea4;hpb=f0ef1cf4d6c996d90df6e4a32a82423d180f3e4d;p=mirror_qemu.git diff --git a/user-exec.c b/user-exec.c index 82bfa66ce3..a8f95fa1e1 100644 --- a/user-exec.c +++ b/user-exec.c @@ -16,11 +16,14 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ -#include "config.h" +#include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" +#include "exec/exec-all.h" #include "tcg.h" #include "qemu/bitops.h" +#include "exec/cpu_ldst.h" +#include "translate-all.h" #undef EAX #undef ECX @@ -31,47 +34,20 @@ #undef ESI #undef EDI #undef EIP -#include #ifdef __linux__ #include #endif //#define DEBUG_SIGNAL -static void exception_action(CPUArchState *env1) -{ -#if defined(TARGET_I386) - raise_exception_err(env1, env1->exception_index, env1->error_code); -#else - cpu_loop_exit(env1); -#endif -} - /* exit the current TB from a signal handler. The host registers are restored in a state compatible with the CPU emulator */ -void cpu_resume_from_signal(CPUArchState *env1, void *puc) +static void cpu_exit_tb_from_sighandler(CPUState *cpu, sigset_t *old_set) { -#ifdef __linux__ - struct ucontext *uc = puc; -#elif defined(__OpenBSD__) - struct sigcontext *uc = puc; -#endif - - if (puc) { - /* XXX: use siglongjmp ? */ -#ifdef __linux__ -#ifdef __ia64 - sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL); -#else - sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL); -#endif -#elif defined(__OpenBSD__) - sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL); -#endif - } - env1->exception_index = -1; - siglongjmp(env1->jmp_env, 1); + /* 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 @@ -79,42 +55,76 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) 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, unsigned long address, - int is_write, sigset_t *old_set, - void *puc) + int is_write, sigset_t *old_set) { - CPUArchState *env; + CPUState *cpu = current_cpu; + CPUClass *cc; int ret; + /* 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(); + } + #if defined(DEBUG_SIGNAL) - qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", - pc, address, is_write, *(unsigned long *)old_set); + 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 */ - if (is_write && h2g_valid(address) - && page_unprotect(h2g(address), pc, puc)) { - return 1; + if (is_write && 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 + */ + return 1; + case 2: + /* Fault caused by protection of cached translation, and the + * currently executing TB was modified and must be exited + * immediately. + */ + cpu_exit_tb_from_sighandler(cpu, old_set); + g_assert_not_reached(); + default: + g_assert_not_reached(); + } } /* Convert forcefully to guest address space, invalid addresses are still valid segv ones */ address = h2g_nocheck(address); - env = current_cpu->env_ptr; + cc = CPU_GET_CLASS(cpu); /* see if it is an MMU fault */ - ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX); + g_assert(cc->handle_mmu_fault); + ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX); if (ret < 0) { return 0; /* not an MMU fault */ } if (ret == 0) { return 1; /* the MMU fault was handled without causing real CPU fault */ } - /* now we have a real cpu fault */ - cpu_restore_state(env, pc); - /* we restore the process signal mask as the sigreturn should - do it (XXX: use sigsetjmp) */ + /* Now we have a real cpu fault. Since this is the exact location of + * the exception, we must undo the adjustment done by cpu_restore_state + * for handling call return addresses. */ + cpu_restore_state(cpu, pc + GETPC_ADJ); + sigprocmask(SIG_SETMASK, old_set, NULL); - exception_action(env); + cpu_loop_exit(cpu); /* never comes here */ return 1; @@ -122,14 +132,7 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, #if defined(__i386__) -#if defined(__APPLE__) -#include - -#define EIP_sig(context) (*((unsigned long *)&(context)->uc_mcontext->ss.eip)) -#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) -#define ERROR_sig(context) ((context)->uc_mcontext->es.err) -#define MASK_sig(context) ((context)->uc_sigmask) -#elif defined(__NetBSD__) +#if defined(__NetBSD__) #include #define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP]) @@ -180,7 +183,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, return handle_cpu_signal(pc, (unsigned long)info->si_addr, trapno == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0, - &MASK_sig(uc), puc); + &MASK_sig(uc)); } #elif defined(__x86_64__) @@ -226,7 +229,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, return handle_cpu_signal(pc, (unsigned long)info->si_addr, TRAP_sig(uc) == 0xe ? (ERROR_sig(uc) >> 1) & 1 : 0, - &MASK_sig(uc), puc); + &MASK_sig(uc)); } #elif defined(_ARCH_PPC) @@ -279,44 +282,6 @@ int cpu_signal_handler(int host_signum, void *pinfo, #define TRAP_sig(context) ((context)->uc_mcontext.mc_exc) #endif /* __FreeBSD__|| __FreeBSD_kernel__ */ -#ifdef __APPLE__ -#include -typedef struct ucontext SIGCONTEXT; -/* All Registers access - only for local access */ -#define REG_sig(reg_name, context) \ - ((context)->uc_mcontext->ss.reg_name) -#define FLOATREG_sig(reg_name, context) \ - ((context)->uc_mcontext->fs.reg_name) -#define EXCEPREG_sig(reg_name, context) \ - ((context)->uc_mcontext->es.reg_name) -#define VECREG_sig(reg_name, context) \ - ((context)->uc_mcontext->vs.reg_name) -/* Gpr Registers access */ -#define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) -/* Program counter */ -#define IAR_sig(context) REG_sig(srr0, context) -/* Machine State Register (Supervisor) */ -#define MSR_sig(context) REG_sig(srr1, context) -#define CTR_sig(context) REG_sig(ctr, context) -/* Link register */ -#define XER_sig(context) REG_sig(xer, context) -/* User's integer exception register */ -#define LR_sig(context) REG_sig(lr, context) -/* Condition register */ -#define CR_sig(context) REG_sig(cr, context) -/* Float Registers access */ -#define FLOAT_sig(reg_num, context) \ - FLOATREG_sig(fpregs[reg_num], context) -#define FPSCR_sig(context) \ - ((double)FLOATREG_sig(fpscr, context)) -/* Exception Registers access */ -/* Fault registers for coredump */ -#define DAR_sig(context) EXCEPREG_sig(dar, context) -#define DSISR_sig(context) EXCEPREG_sig(dsisr, context) -/* number of powerpc exception taken */ -#define TRAP_sig(context) EXCEPREG_sig(exception, context) -#endif /* __APPLE__ */ - int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { @@ -342,7 +307,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, } #endif return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask); } #elif defined(__alpha__) @@ -373,7 +338,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, } return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask); } #elif defined(__sparc__) @@ -397,6 +362,10 @@ int cpu_signal_handler(int host_signum, void *pinfo, 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 @@ -429,20 +398,30 @@ int cpu_signal_handler(int host_signum, void *pinfo, } } return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, sigmask, NULL); + is_write, sigmask); } #elif defined(__arm__) +#if defined(__NetBSD__) +#include +#endif + int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; +#if defined(__NetBSD__) + ucontext_t *uc = puc; +#else struct ucontext *uc = puc; +#endif unsigned long pc; int is_write; -#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3)) +#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; @@ -454,40 +433,35 @@ int cpu_signal_handler(int host_signum, void *pinfo, is_write = extract32(uc->uc_mcontext.error_code, 11, 1); return handle_cpu_signal(pc, (unsigned long)info->si_addr, is_write, - &uc->uc_sigmask, puc); + &uc->uc_sigmask); } #elif defined(__aarch64__) -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - uint64_t pc; - int is_write = 0; /* XXX how to determine? */ - - pc = uc->uc_mcontext.pc; - return handle_cpu_signal(pc, (uint64_t)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#elif defined(__mc68000) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; struct ucontext *uc = puc; - unsigned long pc; - int is_write; + uintptr_t pc = uc->uc_mcontext.pc; + uint32_t insn = *(uint32_t *)pc; + bool is_write; - pc = uc->uc_mcontext.gregs[16]; - /* XXX: compute is_write */ - is_write = 0; - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, - &uc->uc_sigmask, puc); + /* XXX: need kernel patch to get write flag faster. */ + 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 */ + /* Ingore 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, (uintptr_t)info->si_addr, + is_write, &uc->uc_sigmask); } #elif defined(__ia64) @@ -522,7 +496,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, void *puc) } return handle_cpu_signal(ip, (unsigned long)info->si_addr, is_write, - (sigset_t *)&uc->uc_sigmask, puc); + (sigset_t *)&uc->uc_sigmask); } #elif defined(__s390__) @@ -575,7 +549,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, break; } return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask); } #elif defined(__mips__) @@ -591,49 +565,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, /* XXX: compute is_write */ is_write = 0; return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); -} - -#elif defined(__hppa__) - -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) -{ - siginfo_t *info = pinfo; - struct ucontext *uc = puc; - unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; - uint32_t insn = *(uint32_t *)pc; - int is_write = 0; - - /* XXX: need kernel patch to get write flag faster. */ - switch (insn >> 26) { - case 0x1a: /* STW */ - case 0x19: /* STH */ - case 0x18: /* STB */ - case 0x1b: /* STWM */ - is_write = 1; - break; - - case 0x09: /* CSTWX, FSTWX, FSTWS */ - case 0x0b: /* CSTDX, FSTDX, FSTDS */ - /* Distinguish from coprocessor load ... */ - is_write = (insn >> 9) & 1; - break; - - case 0x03: - switch ((insn >> 6) & 15) { - case 0xa: /* STWS */ - case 0x9: /* STHS */ - case 0x8: /* STBS */ - case 0xe: /* STWAS */ - case 0xc: /* STBYS */ - is_write = 1; - } - break; - } - - return handle_cpu_signal(pc, (unsigned long)info->si_addr, - is_write, &uc->uc_sigmask, puc); + is_write, &uc->uc_sigmask); } #else