1 /* 2 * Emulation of Linux signals 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #include "qemu/osdep.h" 20 #include "qemu.h" 21 #include "user-internals.h" 22 #include "signal-common.h" 23 #include "linux-user/trace.h" 24 25 typedef struct target_sigcontext { 26 struct target_pt_regs regs; 27 abi_ulong oldmask; 28 } target_sigcontext; 29 30 typedef struct target_ucontext { 31 abi_ulong tuc_flags; 32 abi_ulong tuc_link; 33 target_stack_t tuc_stack; 34 target_sigcontext tuc_mcontext; 35 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 36 } target_ucontext; 37 38 typedef struct target_rt_sigframe { 39 struct target_siginfo info; 40 target_ucontext uc; 41 uint32_t retcode[4]; /* trampoline code */ 42 } target_rt_sigframe; 43 44 static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc) 45 { 46 int i; 47 abi_ulong v; 48 49 for (i = 0; i < 32; ++i) { 50 __get_user(v, &sc->regs.gpr[i]); 51 cpu_set_gpr(env, i, v); 52 } 53 __get_user(env->pc, &sc->regs.pc); 54 55 /* Make sure the supervisor flag is clear. */ 56 __get_user(v, &sc->regs.sr); 57 cpu_set_sr(env, v & ~SR_SM); 58 } 59 60 /* Set up a signal frame. */ 61 62 static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env) 63 { 64 int i; 65 66 for (i = 0; i < 32; ++i) { 67 __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]); 68 } 69 70 __put_user(env->pc, &sc->regs.pc); 71 __put_user(cpu_get_sr(env), &sc->regs.sr); 72 } 73 74 static inline abi_ulong get_sigframe(struct target_sigaction *ka, 75 CPUOpenRISCState *env, 76 size_t frame_size) 77 { 78 target_ulong sp = get_sp_from_cpustate(env); 79 80 /* Honor redzone now. If we swap to signal stack, no need to waste 81 * the 128 bytes by subtracting afterward. 82 */ 83 sp -= 128; 84 85 sp = target_sigsp(sp, ka); 86 sp -= frame_size; 87 sp = QEMU_ALIGN_DOWN(sp, 4); 88 89 return sp; 90 } 91 92 void setup_rt_frame(int sig, struct target_sigaction *ka, 93 target_siginfo_t *info, 94 target_sigset_t *set, CPUOpenRISCState *env) 95 { 96 abi_ulong frame_addr; 97 target_rt_sigframe *frame; 98 int i; 99 100 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 101 trace_user_setup_rt_frame(env, frame_addr); 102 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 103 goto give_sigsegv; 104 } 105 106 if (ka->sa_flags & SA_SIGINFO) { 107 tswap_siginfo(&frame->info, info); 108 } 109 110 __put_user(0, &frame->uc.tuc_flags); 111 __put_user(0, &frame->uc.tuc_link); 112 113 target_save_altstack(&frame->uc.tuc_stack, env); 114 setup_sigcontext(&frame->uc.tuc_mcontext, env); 115 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 116 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 117 } 118 119 /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */ 120 __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0); 121 __put_user(0x20000001, frame->retcode + 1); 122 __put_user(0x15000000, frame->retcode + 2); 123 __put_user(0x15000000, frame->retcode + 3); 124 125 /* Set up registers for signal handler */ 126 cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode)); 127 cpu_set_gpr(env, 3, sig); 128 cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info)); 129 cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc)); 130 cpu_set_gpr(env, 1, frame_addr); 131 132 /* For debugging convenience, set ppc to the insn that faulted. */ 133 env->ppc = env->pc; 134 /* When setting the PC for the signal handler, exit delay slot. */ 135 env->pc = ka->_sa_handler; 136 env->dflag = 0; 137 return; 138 139 give_sigsegv: 140 unlock_user_struct(frame, frame_addr, 1); 141 force_sigsegv(sig); 142 } 143 144 long do_rt_sigreturn(CPUOpenRISCState *env) 145 { 146 abi_ulong frame_addr = get_sp_from_cpustate(env); 147 target_rt_sigframe *frame; 148 sigset_t set; 149 150 trace_user_do_rt_sigreturn(env, 0); 151 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 152 goto badframe; 153 } 154 if (frame_addr & 3) { 155 goto badframe; 156 } 157 158 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 159 set_sigmask(&set); 160 161 restore_sigcontext(env, &frame->uc.tuc_mcontext); 162 target_restore_altstack(&frame->uc.tuc_stack, env); 163 164 unlock_user_struct(frame, frame_addr, 0); 165 return cpu_get_gpr(env, 11); 166 167 badframe: 168 unlock_user_struct(frame, frame_addr, 0); 169 force_sig(TARGET_SIGSEGV); 170 return 0; 171 } 172