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 "signal-common.h" 22 #include "linux-user/trace.h" 23 24 typedef struct target_sigcontext { 25 struct target_pt_regs regs; 26 abi_ulong oldmask; 27 } target_sigcontext; 28 29 typedef struct target_ucontext { 30 abi_ulong tuc_flags; 31 abi_ulong tuc_link; 32 target_stack_t tuc_stack; 33 target_sigcontext tuc_mcontext; 34 target_sigset_t tuc_sigmask; /* mask last for extensibility */ 35 } target_ucontext; 36 37 typedef struct target_rt_sigframe { 38 struct target_siginfo info; 39 target_ucontext uc; 40 uint32_t retcode[4]; /* trampoline code */ 41 } target_rt_sigframe; 42 43 static void restore_sigcontext(CPUOpenRISCState *env, target_sigcontext *sc) 44 { 45 int i; 46 abi_ulong v; 47 48 for (i = 0; i < 32; ++i) { 49 __get_user(v, &sc->regs.gpr[i]); 50 cpu_set_gpr(env, i, v); 51 } 52 __get_user(env->pc, &sc->regs.pc); 53 54 /* Make sure the supervisor flag is clear. */ 55 __get_user(v, &sc->regs.sr); 56 cpu_set_sr(env, v & ~SR_SM); 57 } 58 59 /* Set up a signal frame. */ 60 61 static void setup_sigcontext(target_sigcontext *sc, CPUOpenRISCState *env) 62 { 63 int i; 64 65 for (i = 0; i < 32; ++i) { 66 __put_user(cpu_get_gpr(env, i), &sc->regs.gpr[i]); 67 } 68 69 __put_user(env->pc, &sc->regs.pc); 70 __put_user(cpu_get_sr(env), &sc->regs.sr); 71 } 72 73 static inline abi_ulong get_sigframe(struct target_sigaction *ka, 74 CPUOpenRISCState *env, 75 size_t frame_size) 76 { 77 target_ulong sp = get_sp_from_cpustate(env); 78 79 /* Honor redzone now. If we swap to signal stack, no need to waste 80 * the 128 bytes by subtracting afterward. 81 */ 82 sp -= 128; 83 84 sp = target_sigsp(sp, ka); 85 sp -= frame_size; 86 sp = QEMU_ALIGN_DOWN(sp, 4); 87 88 return sp; 89 } 90 91 void setup_rt_frame(int sig, struct target_sigaction *ka, 92 target_siginfo_t *info, 93 target_sigset_t *set, CPUOpenRISCState *env) 94 { 95 abi_ulong frame_addr; 96 target_rt_sigframe *frame; 97 int i; 98 99 frame_addr = get_sigframe(ka, env, sizeof(*frame)); 100 trace_user_setup_rt_frame(env, frame_addr); 101 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { 102 goto give_sigsegv; 103 } 104 105 if (ka->sa_flags & SA_SIGINFO) { 106 tswap_siginfo(&frame->info, info); 107 } 108 109 __put_user(0, &frame->uc.tuc_flags); 110 __put_user(0, &frame->uc.tuc_link); 111 112 target_save_altstack(&frame->uc.tuc_stack, env); 113 setup_sigcontext(&frame->uc.tuc_mcontext, env); 114 for (i = 0; i < TARGET_NSIG_WORDS; ++i) { 115 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]); 116 } 117 118 /* This is l.ori r11,r0,__NR_sigreturn; l.sys 1; l.nop; l.nop */ 119 __put_user(0xa9600000 | TARGET_NR_rt_sigreturn, frame->retcode + 0); 120 __put_user(0x20000001, frame->retcode + 1); 121 __put_user(0x15000000, frame->retcode + 2); 122 __put_user(0x15000000, frame->retcode + 3); 123 124 /* Set up registers for signal handler */ 125 cpu_set_gpr(env, 9, frame_addr + offsetof(target_rt_sigframe, retcode)); 126 cpu_set_gpr(env, 3, sig); 127 cpu_set_gpr(env, 4, frame_addr + offsetof(target_rt_sigframe, info)); 128 cpu_set_gpr(env, 5, frame_addr + offsetof(target_rt_sigframe, uc)); 129 cpu_set_gpr(env, 1, frame_addr); 130 131 /* For debugging convenience, set ppc to the insn that faulted. */ 132 env->ppc = env->pc; 133 /* When setting the PC for the signal handler, exit delay slot. */ 134 env->pc = ka->_sa_handler; 135 env->dflag = 0; 136 return; 137 138 give_sigsegv: 139 unlock_user_struct(frame, frame_addr, 1); 140 force_sigsegv(sig); 141 } 142 143 long do_rt_sigreturn(CPUOpenRISCState *env) 144 { 145 abi_ulong frame_addr = get_sp_from_cpustate(env); 146 target_rt_sigframe *frame; 147 sigset_t set; 148 149 trace_user_do_rt_sigreturn(env, 0); 150 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { 151 goto badframe; 152 } 153 if (frame_addr & 3) { 154 goto badframe; 155 } 156 157 target_to_host_sigset(&set, &frame->uc.tuc_sigmask); 158 set_sigmask(&set); 159 160 restore_sigcontext(env, &frame->uc.tuc_mcontext); 161 target_restore_altstack(&frame->uc.tuc_stack, env); 162 163 unlock_user_struct(frame, frame_addr, 0); 164 return cpu_get_gpr(env, 11); 165 166 badframe: 167 unlock_user_struct(frame, frame_addr, 0); 168 force_sig(TARGET_SIGSEGV); 169 return 0; 170 } 171