alpha-linux-user: Implement signals.
Move userland PALcode handling into linux-user main loop so that we can send signals from there. This also makes alpha_palcode.c system-level only, so don't build it for userland. Add defines for GENTRAP PALcall mapping to signals. Signed-off-by: Richard Henderson <rth@twiddle.net> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
		
							parent
							
								
									f24518b502
								
							
						
					
					
						commit
						6049f4f831
					
				|  | @ -51,7 +51,6 @@ libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o | |||
| libobj-y += op_helper.o helper.o | ||||
| libobj-$(CONFIG_NEED_MMU) += mmu.o | ||||
| libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o | ||||
| libobj-$(TARGET_ALPHA) += alpha_palcode.o | ||||
| 
 | ||||
| # NOTE: the disassembler code is only needed for debugging
 | ||||
| libobj-y += disas.o | ||||
|  | @ -312,6 +311,8 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o | |||
| 
 | ||||
| obj-s390x-y = s390-virtio-bus.o s390-virtio.o | ||||
| 
 | ||||
| obj-alpha-y = alpha_palcode.o | ||||
| 
 | ||||
| main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) | ||||
| 
 | ||||
| vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) | ||||
|  |  | |||
|  | @ -21,11 +21,9 @@ | |||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| #include "qemu.h" | ||||
| #include "cpu.h" | ||||
| #include "exec-all.h" | ||||
| 
 | ||||
| #if !defined (CONFIG_USER_ONLY) | ||||
| /* Shared handlers */ | ||||
| static void pal_reset (CPUState *env); | ||||
| /* Console handlers */ | ||||
|  | @ -997,12 +995,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | |||
|     uint64_t physical, page_size, end; | ||||
|     int prot, zbits, ret; | ||||
| 
 | ||||
| #if defined(CONFIG_USER_ONLY) | ||||
|         ret = 2; | ||||
| #else | ||||
|     ret = virtual_to_physical(env, &physical, &zbits, &prot, | ||||
|                               address, mmu_idx, rw); | ||||
| #endif | ||||
| 
 | ||||
|     switch (ret) { | ||||
|     case 0: | ||||
|         /* No fault */ | ||||
|  | @ -1050,73 +1045,3 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | |||
|     return ret; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #else /* !defined (CONFIG_USER_ONLY) */ | ||||
| void pal_init (CPUState *env) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void call_pal (CPUState *env, int palcode) | ||||
| { | ||||
|     target_long ret; | ||||
| 
 | ||||
|     switch (palcode) { | ||||
|     case 0x80: | ||||
|         /* BPT */ | ||||
|         qemu_log("BPT\n"); | ||||
|         /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT.  */ | ||||
|         exit(1); | ||||
|     case 0x81: | ||||
|         /* BUGCHK */ | ||||
|         qemu_log("BUGCHK\n"); | ||||
|         /* FIXME: Sends SIGTRAP, si_code=SI_FAULT.  */ | ||||
|         exit(1); | ||||
|     case 0x83: | ||||
|         /* CALLSYS */ | ||||
|         qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); | ||||
|         ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1], | ||||
|                          env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], | ||||
|                          env->ir[IR_A5]); | ||||
|         if (ret >= 0) { | ||||
|             env->ir[IR_A3] = 0; | ||||
|             env->ir[IR_V0] = ret; | ||||
|         } else { | ||||
|             env->ir[IR_A3] = 1; | ||||
|             env->ir[IR_V0] = -ret; | ||||
|         } | ||||
|         break; | ||||
|     case 0x86: | ||||
|         /* IMB */ | ||||
|         qemu_log("IMB\n"); | ||||
|         /* ??? We can probably elide the code using page_unprotect that is
 | ||||
|            checking for self-modifying code.  Instead we could simply call | ||||
|            tb_flush here.  Until we work out the changes required to turn | ||||
|            off the extra write protection, this can be a no-op.  */ | ||||
|         break; | ||||
|     case 0x9E: | ||||
|         /* RDUNIQUE */ | ||||
|         qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); | ||||
|         /* Handled in the translator for usermode.  */ | ||||
|         abort(); | ||||
|     case 0x9F: | ||||
|         /* WRUNIQUE */ | ||||
|         qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]); | ||||
|         /* Handled in the translator for usermode.  */ | ||||
|         abort(); | ||||
|     case 0xAA: | ||||
|         /* GENTRAP */ | ||||
|         qemu_log("GENTRAP: " TARGET_FMT_lx "\n", env->ir[IR_A0]); | ||||
|         /* FIXME: This is supposed to send a signal:
 | ||||
|            SIGFPE: | ||||
|              GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV, | ||||
|              GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND | ||||
|            SIGTRAP: | ||||
|              others | ||||
|            with various settings of si_code.  */ | ||||
|         exit(1); | ||||
|     default: | ||||
|         qemu_log("%s: unhandled palcode %02x\n", __func__, palcode); | ||||
|         exit(1); | ||||
|     } | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -26,4 +26,31 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state) | |||
|     return state->ir[IR_SP]; | ||||
| } | ||||
| 
 | ||||
| /* From <asm/gentrap.h>.  */ | ||||
| #define TARGET_GEN_INTOVF      -1      /* integer overflow */ | ||||
| #define TARGET_GEN_INTDIV      -2      /* integer division by zero */ | ||||
| #define TARGET_GEN_FLTOVF      -3      /* fp overflow */ | ||||
| #define TARGET_GEN_FLTDIV      -4      /* fp division by zero */ | ||||
| #define TARGET_GEN_FLTUND      -5      /* fp underflow */ | ||||
| #define TARGET_GEN_FLTINV      -6      /* invalid fp operand */ | ||||
| #define TARGET_GEN_FLTINE      -7      /* inexact fp operand */ | ||||
| #define TARGET_GEN_DECOVF      -8      /* decimal overflow (for COBOL??) */ | ||||
| #define TARGET_GEN_DECDIV      -9      /* decimal division by zero */ | ||||
| #define TARGET_GEN_DECINV      -10     /* invalid decimal operand */ | ||||
| #define TARGET_GEN_ROPRAND     -11     /* reserved operand */ | ||||
| #define TARGET_GEN_ASSERTERR   -12     /* assertion error */ | ||||
| #define TARGET_GEN_NULPTRERR   -13     /* null pointer error */ | ||||
| #define TARGET_GEN_STKOVF      -14     /* stack overflow */ | ||||
| #define TARGET_GEN_STRLENERR   -15     /* string length error */ | ||||
| #define TARGET_GEN_SUBSTRERR   -16     /* substring error */ | ||||
| #define TARGET_GEN_RANGERR     -17     /* range error */ | ||||
| #define TARGET_GEN_SUBRNG      -18 | ||||
| #define TARGET_GEN_SUBRNG1     -19 | ||||
| #define TARGET_GEN_SUBRNG2     -20 | ||||
| #define TARGET_GEN_SUBRNG3     -21 | ||||
| #define TARGET_GEN_SUBRNG4     -22 | ||||
| #define TARGET_GEN_SUBRNG5     -23 | ||||
| #define TARGET_GEN_SUBRNG6     -24 | ||||
| #define TARGET_GEN_SUBRNG7     -25 | ||||
| 
 | ||||
| #endif /* TARGET_SIGNAL_H */ | ||||
|  |  | |||
|  | @ -2351,6 +2351,7 @@ void cpu_loop (CPUState *env) | |||
| { | ||||
|     int trapnr; | ||||
|     target_siginfo_t info; | ||||
|     abi_long sysret; | ||||
| 
 | ||||
|     while (1) { | ||||
|         trapnr = cpu_alpha_exec (env); | ||||
|  | @ -2365,16 +2366,22 @@ void cpu_loop (CPUState *env) | |||
|             exit(1); | ||||
|             break; | ||||
|         case EXCP_ARITH: | ||||
|             fprintf(stderr, "Arithmetic trap.\n"); | ||||
|             exit(1); | ||||
|             info.si_signo = TARGET_SIGFPE; | ||||
|             info.si_errno = 0; | ||||
|             info.si_code = TARGET_FPE_FLTINV; | ||||
|             info._sifields._sigfault._addr = env->pc; | ||||
|             queue_signal(env, info.si_signo, &info); | ||||
|             break; | ||||
|         case EXCP_HW_INTERRUPT: | ||||
|             fprintf(stderr, "External interrupt. Exit\n"); | ||||
|             exit(1); | ||||
|             break; | ||||
|         case EXCP_DFAULT: | ||||
|             fprintf(stderr, "MMU data fault\n"); | ||||
|             exit(1); | ||||
|             info.si_signo = TARGET_SIGSEGV; | ||||
|             info.si_errno = 0; | ||||
|             info.si_code = 0;  /* ??? SEGV_MAPERR vs SEGV_ACCERR.  */ | ||||
|             info._sifields._sigfault._addr = env->pc; | ||||
|             queue_signal(env, info.si_signo, &info); | ||||
|             break; | ||||
|         case EXCP_DTB_MISS_PAL: | ||||
|             fprintf(stderr, "MMU data TLB miss in PALcode\n"); | ||||
|  | @ -2393,37 +2400,117 @@ void cpu_loop (CPUState *env) | |||
|             exit(1); | ||||
|             break; | ||||
|         case EXCP_UNALIGN: | ||||
|             fprintf(stderr, "Unaligned access\n"); | ||||
|             exit(1); | ||||
|             info.si_signo = TARGET_SIGBUS; | ||||
|             info.si_errno = 0; | ||||
|             info.si_code = TARGET_BUS_ADRALN; | ||||
|             info._sifields._sigfault._addr = env->pc; | ||||
|             queue_signal(env, info.si_signo, &info); | ||||
|             break; | ||||
|         case EXCP_OPCDEC: | ||||
|             fprintf(stderr, "Invalid instruction\n"); | ||||
|             exit(1); | ||||
|         do_sigill: | ||||
|             info.si_signo = TARGET_SIGILL; | ||||
|             info.si_errno = 0; | ||||
|             info.si_code = TARGET_ILL_ILLOPC; | ||||
|             info._sifields._sigfault._addr = env->pc; | ||||
|             queue_signal(env, info.si_signo, &info); | ||||
|             break; | ||||
|         case EXCP_FEN: | ||||
|             fprintf(stderr, "Floating-point not allowed\n"); | ||||
|             exit(1); | ||||
|             /* No-op.  Linux simply re-enables the FPU.  */ | ||||
|             break; | ||||
|         case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): | ||||
|             call_pal(env, (trapnr >> 6) | 0x80); | ||||
|             switch ((trapnr >> 6) | 0x80) { | ||||
|             case 0x80: | ||||
|                 /* BPT */ | ||||
|                 info.si_signo = TARGET_SIGTRAP; | ||||
|                 info.si_errno = 0; | ||||
|                 info.si_code = TARGET_TRAP_BRKPT; | ||||
|                 info._sifields._sigfault._addr = env->pc; | ||||
|                 queue_signal(env, info.si_signo, &info); | ||||
|                 break; | ||||
|             case 0x81: | ||||
|                 /* BUGCHK */ | ||||
|                 info.si_signo = TARGET_SIGTRAP; | ||||
|                 info.si_errno = 0; | ||||
|                 info.si_code = 0; | ||||
|                 info._sifields._sigfault._addr = env->pc; | ||||
|                 queue_signal(env, info.si_signo, &info); | ||||
|                 break; | ||||
|             case 0x83: | ||||
|                 /* CALLSYS */ | ||||
|                 trapnr = env->ir[IR_V0]; | ||||
|                 sysret = do_syscall(env, trapnr, | ||||
|                                     env->ir[IR_A0], env->ir[IR_A1], | ||||
|                                     env->ir[IR_A2], env->ir[IR_A3], | ||||
|                                     env->ir[IR_A4], env->ir[IR_A5]); | ||||
| 		if (trapnr != TARGET_NR_sigreturn | ||||
|                     && trapnr != TARGET_NR_rt_sigreturn) { | ||||
|                     env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret); | ||||
|                     env->ir[IR_A3] = (sysret < 0); | ||||
|                 } | ||||
|                 break; | ||||
|             case 0x86: | ||||
|                 /* IMB */ | ||||
|                 /* ??? We can probably elide the code using page_unprotect
 | ||||
|                    that is checking for self-modifying code.  Instead we | ||||
|                    could simply call tb_flush here.  Until we work out the | ||||
|                    changes required to turn off the extra write protection, | ||||
|                    this can be a no-op.  */ | ||||
|                 break; | ||||
|             case 0x9E: | ||||
|                 /* RDUNIQUE */ | ||||
|                 /* Handled in the translator for usermode.  */ | ||||
|                 abort(); | ||||
|             case 0x9F: | ||||
|                 /* WRUNIQUE */ | ||||
|                 /* Handled in the translator for usermode.  */ | ||||
|                 abort(); | ||||
|             case 0xAA: | ||||
|                 /* GENTRAP */ | ||||
|                 info.si_signo = TARGET_SIGFPE; | ||||
|                 switch (env->ir[IR_A0]) { | ||||
|                 case TARGET_GEN_INTOVF: | ||||
|                     info.si_code = TARGET_FPE_INTOVF; | ||||
|                     break; | ||||
|                 case TARGET_GEN_INTDIV: | ||||
|                     info.si_code = TARGET_FPE_INTDIV; | ||||
|                     break; | ||||
|                 case TARGET_GEN_FLTOVF: | ||||
|                     info.si_code = TARGET_FPE_FLTOVF; | ||||
|                     break; | ||||
|                 case TARGET_GEN_FLTUND: | ||||
|                     info.si_code = TARGET_FPE_FLTUND; | ||||
|                     break; | ||||
|                 case TARGET_GEN_FLTINV: | ||||
|                     info.si_code = TARGET_FPE_FLTINV; | ||||
|                     break; | ||||
|                 case TARGET_GEN_FLTINE: | ||||
|                     info.si_code = TARGET_FPE_FLTRES; | ||||
|                     break; | ||||
|                 case TARGET_GEN_ROPRAND: | ||||
|                     info.si_code = 0; | ||||
|                     break; | ||||
|                 default: | ||||
|                     info.si_signo = TARGET_SIGTRAP; | ||||
|                     info.si_code = 0; | ||||
|                     break; | ||||
|                 } | ||||
|                 info.si_errno = 0; | ||||
|                 info._sifields._sigfault._addr = env->pc; | ||||
|                 queue_signal(env, info.si_signo, &info); | ||||
|                 break; | ||||
|             default: | ||||
|                 goto do_sigill; | ||||
|             } | ||||
|             break; | ||||
|         case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): | ||||
|             fprintf(stderr, "Privileged call to PALcode\n"); | ||||
|             exit(1); | ||||
|             break; | ||||
|             goto do_sigill; | ||||
|         case EXCP_DEBUG: | ||||
|             { | ||||
|                 int sig; | ||||
| 
 | ||||
|                 sig = gdb_handlesig (env, TARGET_SIGTRAP); | ||||
|                 if (sig) | ||||
|                   { | ||||
|                     info.si_signo = sig; | ||||
|             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); | ||||
|             if (info.si_signo) { | ||||
|                 info.si_errno = 0; | ||||
|                 info.si_code = TARGET_TRAP_BRKPT; | ||||
|                 queue_signal(env, info.si_signo, &info); | ||||
|             } | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             printf ("Unhandled trap: 0x%x\n", trapnr); | ||||
|  |  | |||
|  | @ -4410,6 +4410,273 @@ badframe: | |||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| #elif defined(TARGET_ALPHA) | ||||
| 
 | ||||
| struct target_sigcontext { | ||||
|     abi_long sc_onstack; | ||||
|     abi_long sc_mask; | ||||
|     abi_long sc_pc; | ||||
|     abi_long sc_ps; | ||||
|     abi_long sc_regs[32]; | ||||
|     abi_long sc_ownedfp; | ||||
|     abi_long sc_fpregs[32]; | ||||
|     abi_ulong sc_fpcr; | ||||
|     abi_ulong sc_fp_control; | ||||
|     abi_ulong sc_reserved1; | ||||
|     abi_ulong sc_reserved2; | ||||
|     abi_ulong sc_ssize; | ||||
|     abi_ulong sc_sbase; | ||||
|     abi_ulong sc_traparg_a0; | ||||
|     abi_ulong sc_traparg_a1; | ||||
|     abi_ulong sc_traparg_a2; | ||||
|     abi_ulong sc_fp_trap_pc; | ||||
|     abi_ulong sc_fp_trigger_sum; | ||||
|     abi_ulong sc_fp_trigger_inst; | ||||
| }; | ||||
| 
 | ||||
| struct target_ucontext { | ||||
|     abi_ulong uc_flags; | ||||
|     abi_ulong uc_link; | ||||
|     abi_ulong uc_osf_sigmask; | ||||
|     target_stack_t uc_stack; | ||||
|     struct target_sigcontext uc_mcontext; | ||||
|     target_sigset_t uc_sigmask; | ||||
| }; | ||||
| 
 | ||||
| struct target_sigframe { | ||||
|     struct target_sigcontext sc; | ||||
|     unsigned int retcode[3]; | ||||
| }; | ||||
| 
 | ||||
| struct target_rt_sigframe { | ||||
|     target_siginfo_t info; | ||||
|     struct target_ucontext uc; | ||||
|     unsigned int retcode[3]; | ||||
| }; | ||||
| 
 | ||||
| #define INSN_MOV_R30_R16        0x47fe0410 | ||||
| #define INSN_LDI_R0             0x201f0000 | ||||
| #define INSN_CALLSYS            0x00000083 | ||||
| 
 | ||||
| static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env, | ||||
|                             abi_ulong frame_addr, target_sigset_t *set) | ||||
| { | ||||
|     int i, err = 0; | ||||
| 
 | ||||
|     err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); | ||||
|     err |= __put_user(set->sig[0], &sc->sc_mask); | ||||
|     err |= __put_user(env->pc, &sc->sc_pc); | ||||
|     err |= __put_user(8, &sc->sc_ps); | ||||
| 
 | ||||
|     for (i = 0; i < 31; ++i) { | ||||
|         err |= __put_user(env->ir[i], &sc->sc_regs[i]); | ||||
|     } | ||||
|     err |= __put_user(0, &sc->sc_regs[31]); | ||||
| 
 | ||||
|     for (i = 0; i < 31; ++i) { | ||||
|         err |= __put_user(env->fir[i], &sc->sc_fpregs[i]); | ||||
|     } | ||||
|     err |= __put_user(0, &sc->sc_fpregs[31]); | ||||
|     err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); | ||||
| 
 | ||||
|     err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */ | ||||
|     err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */ | ||||
|     err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */ | ||||
| 
 | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) | ||||
| { | ||||
|     uint64_t fpcr; | ||||
|     int i, err = 0; | ||||
| 
 | ||||
|     err |= __get_user(env->pc, &sc->sc_pc); | ||||
| 
 | ||||
|     for (i = 0; i < 31; ++i) { | ||||
|         err |= __get_user(env->ir[i], &sc->sc_regs[i]); | ||||
|     } | ||||
|     for (i = 0; i < 31; ++i) { | ||||
|         err |= __get_user(env->fir[i], &sc->sc_fpregs[i]); | ||||
|     } | ||||
| 
 | ||||
|     err |= __get_user(fpcr, &sc->sc_fpcr); | ||||
|     cpu_alpha_store_fpcr(env, fpcr); | ||||
| 
 | ||||
|     return err; | ||||
| } | ||||
| 
 | ||||
| static inline abi_ulong get_sigframe(struct target_sigaction *sa, | ||||
|                                      CPUState *env, unsigned long framesize) | ||||
| { | ||||
|     abi_ulong sp = env->ir[IR_SP]; | ||||
| 
 | ||||
|     /* This is the X/Open sanctioned signal stack switching.  */ | ||||
|     if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { | ||||
|         sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; | ||||
|     } | ||||
|     return (sp - framesize) & -32; | ||||
| } | ||||
| 
 | ||||
| static void setup_frame(int sig, struct target_sigaction *ka, | ||||
|                         target_sigset_t *set, CPUState *env) | ||||
| { | ||||
|     abi_ulong frame_addr, r26; | ||||
|     struct target_sigframe *frame; | ||||
|     int err = 0; | ||||
| 
 | ||||
|     frame_addr = get_sigframe(ka, env, sizeof(*frame)); | ||||
|     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { | ||||
|         goto give_sigsegv; | ||||
|     } | ||||
| 
 | ||||
|     err |= setup_sigcontext(&frame->sc, env, frame_addr, set); | ||||
| 
 | ||||
|     if (ka->sa_restorer) { | ||||
|         r26 = ka->sa_restorer; | ||||
|     } else { | ||||
|         err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); | ||||
|         err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, | ||||
|                           &frame->retcode[1]); | ||||
|         err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); | ||||
|         /* imb() */ | ||||
|         r26 = frame_addr; | ||||
|     } | ||||
| 
 | ||||
|     unlock_user_struct(frame, frame_addr, 1); | ||||
| 
 | ||||
|     if (err) { | ||||
|     give_sigsegv: | ||||
|         if (sig == TARGET_SIGSEGV) { | ||||
|             ka->_sa_handler = TARGET_SIG_DFL; | ||||
|         } | ||||
|         force_sig(TARGET_SIGSEGV); | ||||
|     } | ||||
| 
 | ||||
|     env->ir[IR_RA] = r26; | ||||
|     env->ir[IR_PV] = env->pc = ka->_sa_handler; | ||||
|     env->ir[IR_A0] = sig; | ||||
|     env->ir[IR_A1] = 0; | ||||
|     env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); | ||||
|     env->ir[IR_SP] = frame_addr; | ||||
| } | ||||
| 
 | ||||
| static void setup_rt_frame(int sig, struct target_sigaction *ka, | ||||
|                            target_siginfo_t *info, | ||||
| 			   target_sigset_t *set, CPUState *env) | ||||
| { | ||||
|     abi_ulong frame_addr, r26; | ||||
|     struct target_rt_sigframe *frame; | ||||
|     int i, err = 0; | ||||
| 
 | ||||
|     frame_addr = get_sigframe(ka, env, sizeof(*frame)); | ||||
|     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { | ||||
|         goto give_sigsegv; | ||||
|     } | ||||
| 
 | ||||
|     err |= copy_siginfo_to_user(&frame->info, info); | ||||
| 
 | ||||
|     err |= __put_user(0, &frame->uc.uc_flags); | ||||
|     err |= __put_user(0, &frame->uc.uc_link); | ||||
|     err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); | ||||
|     err |= __put_user(target_sigaltstack_used.ss_sp, | ||||
|                       &frame->uc.uc_stack.ss_sp); | ||||
|     err |= __put_user(sas_ss_flags(env->ir[IR_SP]), | ||||
|                       &frame->uc.uc_stack.ss_flags); | ||||
|     err |= __put_user(target_sigaltstack_used.ss_size, | ||||
|                       &frame->uc.uc_stack.ss_size); | ||||
|     err |= setup_sigcontext(&frame->uc.uc_mcontext, env, frame_addr, set); | ||||
|     for (i = 0; i < TARGET_NSIG_WORDS; ++i) { | ||||
|         err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); | ||||
|     } | ||||
| 
 | ||||
|     if (ka->sa_restorer) { | ||||
|         r26 = ka->sa_restorer; | ||||
|     } else { | ||||
|         err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); | ||||
|         err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, | ||||
|                           &frame->retcode[1]); | ||||
|         err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); | ||||
|         /* imb(); */ | ||||
|         r26 = frame_addr; | ||||
|     } | ||||
| 
 | ||||
|     if (err) { | ||||
|     give_sigsegv: | ||||
|        if (sig == TARGET_SIGSEGV) { | ||||
|             ka->_sa_handler = TARGET_SIG_DFL; | ||||
|         } | ||||
|         force_sig(TARGET_SIGSEGV); | ||||
|     } | ||||
| 
 | ||||
|     env->ir[IR_RA] = r26; | ||||
|     env->ir[IR_PV] = env->pc = ka->_sa_handler; | ||||
|     env->ir[IR_A0] = sig; | ||||
|     env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); | ||||
|     env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); | ||||
|     env->ir[IR_SP] = frame_addr; | ||||
| } | ||||
| 
 | ||||
| long do_sigreturn(CPUState *env) | ||||
| { | ||||
|     struct target_sigcontext *sc; | ||||
|     abi_ulong sc_addr = env->ir[IR_A0]; | ||||
|     target_sigset_t target_set; | ||||
|     sigset_t set; | ||||
| 
 | ||||
|     if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { | ||||
|         goto badframe; | ||||
|     } | ||||
| 
 | ||||
|     target_sigemptyset(&target_set); | ||||
|     if (__get_user(target_set.sig[0], &sc->sc_mask)) { | ||||
|         goto badframe; | ||||
|     } | ||||
| 
 | ||||
|     target_to_host_sigset_internal(&set, &target_set); | ||||
|     sigprocmask(SIG_SETMASK, &set, NULL); | ||||
| 
 | ||||
|     if (restore_sigcontext(env, sc)) { | ||||
|         goto badframe; | ||||
|     } | ||||
|     unlock_user_struct(sc, sc_addr, 0); | ||||
|     return env->ir[IR_V0]; | ||||
| 
 | ||||
|  badframe: | ||||
|     unlock_user_struct(sc, sc_addr, 0); | ||||
|     force_sig(TARGET_SIGSEGV); | ||||
| } | ||||
| 
 | ||||
| long do_rt_sigreturn(CPUState *env) | ||||
| { | ||||
|     abi_ulong frame_addr = env->ir[IR_A0]; | ||||
|     struct target_rt_sigframe *frame; | ||||
|     sigset_t set; | ||||
| 
 | ||||
|     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { | ||||
|         goto badframe; | ||||
|     } | ||||
|     target_to_host_sigset(&set, &frame->uc.uc_sigmask); | ||||
|     sigprocmask(SIG_SETMASK, &set, NULL); | ||||
| 
 | ||||
|     if (restore_sigcontext(env, &frame->uc.uc_mcontext)) { | ||||
|         goto badframe; | ||||
|     } | ||||
|     if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, | ||||
|                                              uc.uc_stack), | ||||
|                        0, env->ir[IR_SP]) == -EFAULT) { | ||||
|         goto badframe; | ||||
|     } | ||||
| 
 | ||||
|     unlock_user_struct(frame, frame_addr, 0); | ||||
|     return env->ir[IR_V0]; | ||||
| 
 | ||||
| 
 | ||||
|  badframe: | ||||
|     unlock_user_struct(frame, frame_addr, 0); | ||||
|     force_sig(TARGET_SIGSEGV); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| static void setup_frame(int sig, struct target_sigaction *ka, | ||||
|  |  | |||
|  | @ -4775,20 +4775,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | |||
| #ifdef TARGET_NR_sigaction | ||||
|     case TARGET_NR_sigaction: | ||||
|         { | ||||
| #if !defined(TARGET_MIPS) | ||||
| #if defined(TARGET_ALPHA) | ||||
|             struct target_sigaction act, oact, *pact = 0; | ||||
|             struct target_old_sigaction *old_act; | ||||
|             struct target_sigaction act, oact, *pact; | ||||
|             if (arg2) { | ||||
|                 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) | ||||
|                     goto efault; | ||||
|                 act._sa_handler = old_act->_sa_handler; | ||||
|                 target_siginitset(&act.sa_mask, old_act->sa_mask); | ||||
|                 act.sa_flags = old_act->sa_flags; | ||||
|                 act.sa_restorer = old_act->sa_restorer; | ||||
|                 act.sa_restorer = 0; | ||||
|                 unlock_user_struct(old_act, arg2, 0); | ||||
|                 pact = &act; | ||||
|             } else { | ||||
|                 pact = NULL; | ||||
|             } | ||||
|             ret = get_errno(do_sigaction(arg1, pact, &oact)); | ||||
|             if (!is_error(ret) && arg3) { | ||||
|  | @ -4797,10 +4795,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | |||
|                 old_act->_sa_handler = oact._sa_handler; | ||||
|                 old_act->sa_mask = oact.sa_mask.sig[0]; | ||||
|                 old_act->sa_flags = oact.sa_flags; | ||||
|                 old_act->sa_restorer = oact.sa_restorer; | ||||
|                 unlock_user_struct(old_act, arg3, 1); | ||||
|             } | ||||
| #else | ||||
| #elif defined(TARGET_MIPS) | ||||
| 	    struct target_sigaction act, oact, *pact, *old_act; | ||||
| 
 | ||||
| 	    if (arg2) { | ||||
|  | @ -4828,12 +4825,61 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | |||
| 		old_act->sa_mask.sig[3] = 0; | ||||
| 		unlock_user_struct(old_act, arg3, 1); | ||||
| 	    } | ||||
| #else | ||||
|             struct target_old_sigaction *old_act; | ||||
|             struct target_sigaction act, oact, *pact; | ||||
|             if (arg2) { | ||||
|                 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) | ||||
|                     goto efault; | ||||
|                 act._sa_handler = old_act->_sa_handler; | ||||
|                 target_siginitset(&act.sa_mask, old_act->sa_mask); | ||||
|                 act.sa_flags = old_act->sa_flags; | ||||
|                 act.sa_restorer = old_act->sa_restorer; | ||||
|                 unlock_user_struct(old_act, arg2, 0); | ||||
|                 pact = &act; | ||||
|             } else { | ||||
|                 pact = NULL; | ||||
|             } | ||||
|             ret = get_errno(do_sigaction(arg1, pact, &oact)); | ||||
|             if (!is_error(ret) && arg3) { | ||||
|                 if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) | ||||
|                     goto efault; | ||||
|                 old_act->_sa_handler = oact._sa_handler; | ||||
|                 old_act->sa_mask = oact.sa_mask.sig[0]; | ||||
|                 old_act->sa_flags = oact.sa_flags; | ||||
|                 old_act->sa_restorer = oact.sa_restorer; | ||||
|                 unlock_user_struct(old_act, arg3, 1); | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
|         break; | ||||
| #endif | ||||
|     case TARGET_NR_rt_sigaction: | ||||
|         { | ||||
| #if defined(TARGET_ALPHA) | ||||
|             struct target_sigaction act, oact, *pact = 0; | ||||
|             struct target_rt_sigaction *rt_act; | ||||
|             /* ??? arg4 == sizeof(sigset_t).  */ | ||||
|             if (arg2) { | ||||
|                 if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1)) | ||||
|                     goto efault; | ||||
|                 act._sa_handler = rt_act->_sa_handler; | ||||
|                 act.sa_mask = rt_act->sa_mask; | ||||
|                 act.sa_flags = rt_act->sa_flags; | ||||
|                 act.sa_restorer = arg5; | ||||
|                 unlock_user_struct(rt_act, arg2, 0); | ||||
|                 pact = &act; | ||||
|             } | ||||
|             ret = get_errno(do_sigaction(arg1, pact, &oact)); | ||||
|             if (!is_error(ret) && arg3) { | ||||
|                 if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0)) | ||||
|                     goto efault; | ||||
|                 rt_act->_sa_handler = oact._sa_handler; | ||||
|                 rt_act->sa_mask = oact.sa_mask; | ||||
|                 rt_act->sa_flags = oact.sa_flags; | ||||
|                 unlock_user_struct(rt_act, arg3, 1); | ||||
|             } | ||||
| #else | ||||
|             struct target_sigaction *act; | ||||
|             struct target_sigaction *oact; | ||||
| 
 | ||||
|  | @ -4855,6 +4901,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | |||
|                 unlock_user_struct(act, arg2, 0); | ||||
|             if (oact) | ||||
|                 unlock_user_struct(oact, arg3, 1); | ||||
| #endif | ||||
|         } | ||||
|         break; | ||||
| #ifdef TARGET_NR_sgetmask /* not on alpha */ | ||||
|  |  | |||
|  | @ -472,8 +472,28 @@ int do_sigaction(int sig, const struct target_sigaction *act, | |||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| #if defined(TARGET_MIPS) | ||||
| #if defined(TARGET_ALPHA) | ||||
| struct target_old_sigaction { | ||||
|     abi_ulong _sa_handler; | ||||
|     abi_ulong sa_mask; | ||||
|     abi_ulong sa_flags; | ||||
| }; | ||||
| 
 | ||||
| struct target_rt_sigaction { | ||||
|     abi_ulong _sa_handler; | ||||
|     abi_ulong sa_flags; | ||||
|     target_sigset_t sa_mask; | ||||
| }; | ||||
| 
 | ||||
| /* This is the struct used inside the kernel.  The ka_restorer
 | ||||
|    field comes from the 5th argument to sys_rt_sigaction.  */ | ||||
| struct target_sigaction { | ||||
|     abi_ulong _sa_handler; | ||||
|     abi_ulong sa_flags; | ||||
|     target_sigset_t sa_mask; | ||||
|     abi_ulong sa_restorer; | ||||
| }; | ||||
| #elif defined(TARGET_MIPS) | ||||
| struct target_sigaction { | ||||
| 	uint32_t	sa_flags; | ||||
| #if defined(TARGET_ABI_MIPSN32) | ||||
|  | @ -483,7 +503,6 @@ struct target_sigaction { | |||
| #endif | ||||
| 	target_sigset_t	sa_mask; | ||||
| }; | ||||
| 
 | ||||
| #else | ||||
| struct target_old_sigaction { | ||||
|         abi_ulong _sa_handler; | ||||
|  |  | |||
|  | @ -511,11 +511,9 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env); | |||
| void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); | ||||
| int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); | ||||
| int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); | ||||
| void pal_init (CPUState *env); | ||||
| #if !defined (CONFIG_USER_ONLY) | ||||
| void pal_init (CPUState *env); | ||||
| void call_pal (CPUState *env); | ||||
| #else | ||||
| void call_pal (CPUState *env, int palcode); | ||||
| #endif | ||||
| 
 | ||||
| static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) | ||||
|  |  | |||
|  | @ -3094,8 +3094,9 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) | |||
|     env->ps |= 1 << 3; | ||||
|     cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD | ||||
|                                | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); | ||||
| #endif | ||||
| #else | ||||
|     pal_init(env); | ||||
| #endif | ||||
| 
 | ||||
|     /* Initialize IPR */ | ||||
| #if defined (CONFIG_USER_ONLY) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Richard Henderson
						Richard Henderson