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-y += op_helper.o helper.o | ||||||
| libobj-$(CONFIG_NEED_MMU) += mmu.o | libobj-$(CONFIG_NEED_MMU) += mmu.o | ||||||
| libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.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
 | # NOTE: the disassembler code is only needed for debugging
 | ||||||
| libobj-y += disas.o | 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-s390x-y = s390-virtio-bus.o s390-virtio.o | ||||||
| 
 | 
 | ||||||
|  | obj-alpha-y = alpha_palcode.o | ||||||
|  | 
 | ||||||
| main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) | main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) | ||||||
| 
 | 
 | ||||||
| vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) | vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) | ||||||
|  |  | ||||||
|  | @ -21,11 +21,9 @@ | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| 
 | 
 | ||||||
| #include "qemu.h" |  | ||||||
| #include "cpu.h" | #include "cpu.h" | ||||||
| #include "exec-all.h" | #include "exec-all.h" | ||||||
| 
 | 
 | ||||||
| #if !defined (CONFIG_USER_ONLY) |  | ||||||
| /* Shared handlers */ | /* Shared handlers */ | ||||||
| static void pal_reset (CPUState *env); | static void pal_reset (CPUState *env); | ||||||
| /* Console handlers */ | /* 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; |     uint64_t physical, page_size, end; | ||||||
|     int prot, zbits, ret; |     int prot, zbits, ret; | ||||||
| 
 | 
 | ||||||
| #if defined(CONFIG_USER_ONLY) |     ret = virtual_to_physical(env, &physical, &zbits, &prot, | ||||||
|         ret = 2; |                               address, mmu_idx, rw); | ||||||
| #else | 
 | ||||||
|         ret = virtual_to_physical(env, &physical, &zbits, &prot, |  | ||||||
|                                   address, mmu_idx, rw); |  | ||||||
| #endif |  | ||||||
|     switch (ret) { |     switch (ret) { | ||||||
|     case 0: |     case 0: | ||||||
|         /* No fault */ |         /* No fault */ | ||||||
|  | @ -1050,73 +1045,3 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| #endif | #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]; |     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 */ | #endif /* TARGET_SIGNAL_H */ | ||||||
|  |  | ||||||
|  | @ -2351,6 +2351,7 @@ void cpu_loop (CPUState *env) | ||||||
| { | { | ||||||
|     int trapnr; |     int trapnr; | ||||||
|     target_siginfo_t info; |     target_siginfo_t info; | ||||||
|  |     abi_long sysret; | ||||||
| 
 | 
 | ||||||
|     while (1) { |     while (1) { | ||||||
|         trapnr = cpu_alpha_exec (env); |         trapnr = cpu_alpha_exec (env); | ||||||
|  | @ -2365,16 +2366,22 @@ void cpu_loop (CPUState *env) | ||||||
|             exit(1); |             exit(1); | ||||||
|             break; |             break; | ||||||
|         case EXCP_ARITH: |         case EXCP_ARITH: | ||||||
|             fprintf(stderr, "Arithmetic trap.\n"); |             info.si_signo = TARGET_SIGFPE; | ||||||
|             exit(1); |             info.si_errno = 0; | ||||||
|  |             info.si_code = TARGET_FPE_FLTINV; | ||||||
|  |             info._sifields._sigfault._addr = env->pc; | ||||||
|  |             queue_signal(env, info.si_signo, &info); | ||||||
|             break; |             break; | ||||||
|         case EXCP_HW_INTERRUPT: |         case EXCP_HW_INTERRUPT: | ||||||
|             fprintf(stderr, "External interrupt. Exit\n"); |             fprintf(stderr, "External interrupt. Exit\n"); | ||||||
|             exit(1); |             exit(1); | ||||||
|             break; |             break; | ||||||
|         case EXCP_DFAULT: |         case EXCP_DFAULT: | ||||||
|             fprintf(stderr, "MMU data fault\n"); |             info.si_signo = TARGET_SIGSEGV; | ||||||
|             exit(1); |             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; |             break; | ||||||
|         case EXCP_DTB_MISS_PAL: |         case EXCP_DTB_MISS_PAL: | ||||||
|             fprintf(stderr, "MMU data TLB miss in PALcode\n"); |             fprintf(stderr, "MMU data TLB miss in PALcode\n"); | ||||||
|  | @ -2393,36 +2400,116 @@ void cpu_loop (CPUState *env) | ||||||
|             exit(1); |             exit(1); | ||||||
|             break; |             break; | ||||||
|         case EXCP_UNALIGN: |         case EXCP_UNALIGN: | ||||||
|             fprintf(stderr, "Unaligned access\n"); |             info.si_signo = TARGET_SIGBUS; | ||||||
|             exit(1); |             info.si_errno = 0; | ||||||
|  |             info.si_code = TARGET_BUS_ADRALN; | ||||||
|  |             info._sifields._sigfault._addr = env->pc; | ||||||
|  |             queue_signal(env, info.si_signo, &info); | ||||||
|             break; |             break; | ||||||
|         case EXCP_OPCDEC: |         case EXCP_OPCDEC: | ||||||
|             fprintf(stderr, "Invalid instruction\n"); |         do_sigill: | ||||||
|             exit(1); |             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; |             break; | ||||||
|         case EXCP_FEN: |         case EXCP_FEN: | ||||||
|             fprintf(stderr, "Floating-point not allowed\n"); |             /* No-op.  Linux simply re-enables the FPU.  */ | ||||||
|             exit(1); |  | ||||||
|             break; |             break; | ||||||
|         case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): |         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; |             break; | ||||||
|         case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): |         case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): | ||||||
|             fprintf(stderr, "Privileged call to PALcode\n"); |             goto do_sigill; | ||||||
|             exit(1); |  | ||||||
|             break; |  | ||||||
|         case EXCP_DEBUG: |         case EXCP_DEBUG: | ||||||
|             { |             info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); | ||||||
|                 int sig; |             if (info.si_signo) { | ||||||
| 
 |                 info.si_errno = 0; | ||||||
|                 sig = gdb_handlesig (env, TARGET_SIGTRAP); |                 info.si_code = TARGET_TRAP_BRKPT; | ||||||
|                 if (sig) |                 queue_signal(env, info.si_signo, &info); | ||||||
|                   { |  | ||||||
|                     info.si_signo = sig; |  | ||||||
|                     info.si_errno = 0; |  | ||||||
|                     info.si_code = TARGET_TRAP_BRKPT; |  | ||||||
|                     queue_signal(env, info.si_signo, &info); |  | ||||||
|                   } |  | ||||||
|             } |             } | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
|  |  | ||||||
|  | @ -4410,6 +4410,273 @@ badframe: | ||||||
|     return 0; |     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 | #else | ||||||
| 
 | 
 | ||||||
| static void setup_frame(int sig, struct target_sigaction *ka, | 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 | #ifdef TARGET_NR_sigaction | ||||||
|     case 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_old_sigaction *old_act; | ||||||
|             struct target_sigaction act, oact, *pact; |  | ||||||
|             if (arg2) { |             if (arg2) { | ||||||
|                 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) |                 if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) | ||||||
|                     goto efault; |                     goto efault; | ||||||
|                 act._sa_handler = old_act->_sa_handler; |                 act._sa_handler = old_act->_sa_handler; | ||||||
|                 target_siginitset(&act.sa_mask, old_act->sa_mask); |                 target_siginitset(&act.sa_mask, old_act->sa_mask); | ||||||
|                 act.sa_flags = old_act->sa_flags; |                 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); |                 unlock_user_struct(old_act, arg2, 0); | ||||||
|                 pact = &act; |                 pact = &act; | ||||||
|             } else { |  | ||||||
|                 pact = NULL; |  | ||||||
|             } |             } | ||||||
|             ret = get_errno(do_sigaction(arg1, pact, &oact)); |             ret = get_errno(do_sigaction(arg1, pact, &oact)); | ||||||
|             if (!is_error(ret) && arg3) { |             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_handler = oact._sa_handler; | ||||||
|                 old_act->sa_mask = oact.sa_mask.sig[0]; |                 old_act->sa_mask = oact.sa_mask.sig[0]; | ||||||
|                 old_act->sa_flags = oact.sa_flags; |                 old_act->sa_flags = oact.sa_flags; | ||||||
|                 old_act->sa_restorer = oact.sa_restorer; |  | ||||||
|                 unlock_user_struct(old_act, arg3, 1); |                 unlock_user_struct(old_act, arg3, 1); | ||||||
|             } |             } | ||||||
| #else | #elif defined(TARGET_MIPS) | ||||||
| 	    struct target_sigaction act, oact, *pact, *old_act; | 	    struct target_sigaction act, oact, *pact, *old_act; | ||||||
| 
 | 
 | ||||||
| 	    if (arg2) { | 	    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; | 		old_act->sa_mask.sig[3] = 0; | ||||||
| 		unlock_user_struct(old_act, arg3, 1); | 		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 | #endif | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| #endif | #endif | ||||||
|     case TARGET_NR_rt_sigaction: |     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 *act; | ||||||
|             struct target_sigaction *oact; |             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); |                 unlock_user_struct(act, arg2, 0); | ||||||
|             if (oact) |             if (oact) | ||||||
|                 unlock_user_struct(oact, arg3, 1); |                 unlock_user_struct(oact, arg3, 1); | ||||||
|  | #endif | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
| #ifdef TARGET_NR_sgetmask /* not on alpha */ | #ifdef TARGET_NR_sgetmask /* not on alpha */ | ||||||
|  |  | ||||||
|  | @ -472,8 +472,28 @@ int do_sigaction(int sig, const struct target_sigaction *act, | ||||||
| 
 | 
 | ||||||
| #endif | #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 { | struct target_sigaction { | ||||||
| 	uint32_t	sa_flags; | 	uint32_t	sa_flags; | ||||||
| #if defined(TARGET_ABI_MIPSN32) | #if defined(TARGET_ABI_MIPSN32) | ||||||
|  | @ -483,7 +503,6 @@ struct target_sigaction { | ||||||
| #endif | #endif | ||||||
| 	target_sigset_t	sa_mask; | 	target_sigset_t	sa_mask; | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| #else | #else | ||||||
| struct target_old_sigaction { | struct target_old_sigaction { | ||||||
|         abi_ulong _sa_handler; |         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); | void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); | ||||||
| int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); | 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); | int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); | ||||||
| void pal_init (CPUState *env); |  | ||||||
| #if !defined (CONFIG_USER_ONLY) | #if !defined (CONFIG_USER_ONLY) | ||||||
|  | void pal_init (CPUState *env); | ||||||
| void call_pal (CPUState *env); | void call_pal (CPUState *env); | ||||||
| #else |  | ||||||
| void call_pal (CPUState *env, int palcode); |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) | 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; |     env->ps |= 1 << 3; | ||||||
|     cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD |     cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD | ||||||
|                                | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); |                                | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); | ||||||
| #endif | #else | ||||||
|     pal_init(env); |     pal_init(env); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     /* Initialize IPR */ |     /* Initialize IPR */ | ||||||
| #if defined (CONFIG_USER_ONLY) | #if defined (CONFIG_USER_ONLY) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Richard Henderson
						Richard Henderson