1befb7447SLaurent Vivier /* 2befb7447SLaurent Vivier * Emulation of Linux signals 3befb7447SLaurent Vivier * 4befb7447SLaurent Vivier * Copyright (c) 2003 Fabrice Bellard 5befb7447SLaurent Vivier * 6befb7447SLaurent Vivier * This program is free software; you can redistribute it and/or modify 7befb7447SLaurent Vivier * it under the terms of the GNU General Public License as published by 8befb7447SLaurent Vivier * the Free Software Foundation; either version 2 of the License, or 9befb7447SLaurent Vivier * (at your option) any later version. 10befb7447SLaurent Vivier * 11befb7447SLaurent Vivier * This program is distributed in the hope that it will be useful, 12befb7447SLaurent Vivier * but WITHOUT ANY WARRANTY; without even the implied warranty of 13befb7447SLaurent Vivier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14befb7447SLaurent Vivier * GNU General Public License for more details. 15befb7447SLaurent Vivier * 16befb7447SLaurent Vivier * You should have received a copy of the GNU General Public License 17befb7447SLaurent Vivier * along with this program; if not, see <http://www.gnu.org/licenses/>. 18befb7447SLaurent Vivier */ 19f9fb3ba3SLaurent Vivier #include "qemu/osdep.h" 20f9fb3ba3SLaurent Vivier #include "qemu.h" 21f9fb3ba3SLaurent Vivier #include "target_signal.h" 22f9fb3ba3SLaurent Vivier #include "signal-common.h" 23f9fb3ba3SLaurent Vivier #include "linux-user/trace.h" 24f9fb3ba3SLaurent Vivier 25f9fb3ba3SLaurent Vivier struct target_sigcontext { 26f9fb3ba3SLaurent Vivier struct target_pt_regs regs; /* needs to be first */ 27f9fb3ba3SLaurent Vivier uint32_t oldmask; 28f9fb3ba3SLaurent Vivier }; 29f9fb3ba3SLaurent Vivier 30f9fb3ba3SLaurent Vivier struct target_stack_t { 31f9fb3ba3SLaurent Vivier abi_ulong ss_sp; 32f9fb3ba3SLaurent Vivier int ss_flags; 33f9fb3ba3SLaurent Vivier unsigned int ss_size; 34f9fb3ba3SLaurent Vivier }; 35f9fb3ba3SLaurent Vivier 36f9fb3ba3SLaurent Vivier struct target_ucontext { 37f9fb3ba3SLaurent Vivier abi_ulong tuc_flags; 38f9fb3ba3SLaurent Vivier abi_ulong tuc_link; 39f9fb3ba3SLaurent Vivier struct target_stack_t tuc_stack; 40f9fb3ba3SLaurent Vivier struct target_sigcontext tuc_mcontext; 41f9fb3ba3SLaurent Vivier uint32_t tuc_extramask[TARGET_NSIG_WORDS - 1]; 42f9fb3ba3SLaurent Vivier }; 43f9fb3ba3SLaurent Vivier 44f9fb3ba3SLaurent Vivier /* Signal frames. */ 45f9fb3ba3SLaurent Vivier struct target_signal_frame { 46f9fb3ba3SLaurent Vivier struct target_ucontext uc; 47f9fb3ba3SLaurent Vivier uint32_t extramask[TARGET_NSIG_WORDS - 1]; 48f9fb3ba3SLaurent Vivier uint32_t tramp[2]; 49f9fb3ba3SLaurent Vivier }; 50f9fb3ba3SLaurent Vivier 51f9fb3ba3SLaurent Vivier struct rt_signal_frame { 52f9fb3ba3SLaurent Vivier siginfo_t info; 53f9fb3ba3SLaurent Vivier ucontext_t uc; 54f9fb3ba3SLaurent Vivier uint32_t tramp[2]; 55f9fb3ba3SLaurent Vivier }; 56f9fb3ba3SLaurent Vivier 57f9fb3ba3SLaurent Vivier static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 58f9fb3ba3SLaurent Vivier { 59f9fb3ba3SLaurent Vivier __put_user(env->regs[0], &sc->regs.r0); 60f9fb3ba3SLaurent Vivier __put_user(env->regs[1], &sc->regs.r1); 61f9fb3ba3SLaurent Vivier __put_user(env->regs[2], &sc->regs.r2); 62f9fb3ba3SLaurent Vivier __put_user(env->regs[3], &sc->regs.r3); 63f9fb3ba3SLaurent Vivier __put_user(env->regs[4], &sc->regs.r4); 64f9fb3ba3SLaurent Vivier __put_user(env->regs[5], &sc->regs.r5); 65f9fb3ba3SLaurent Vivier __put_user(env->regs[6], &sc->regs.r6); 66f9fb3ba3SLaurent Vivier __put_user(env->regs[7], &sc->regs.r7); 67f9fb3ba3SLaurent Vivier __put_user(env->regs[8], &sc->regs.r8); 68f9fb3ba3SLaurent Vivier __put_user(env->regs[9], &sc->regs.r9); 69f9fb3ba3SLaurent Vivier __put_user(env->regs[10], &sc->regs.r10); 70f9fb3ba3SLaurent Vivier __put_user(env->regs[11], &sc->regs.r11); 71f9fb3ba3SLaurent Vivier __put_user(env->regs[12], &sc->regs.r12); 72f9fb3ba3SLaurent Vivier __put_user(env->regs[13], &sc->regs.r13); 73f9fb3ba3SLaurent Vivier __put_user(env->regs[14], &sc->regs.r14); 74f9fb3ba3SLaurent Vivier __put_user(env->regs[15], &sc->regs.r15); 75f9fb3ba3SLaurent Vivier __put_user(env->regs[16], &sc->regs.r16); 76f9fb3ba3SLaurent Vivier __put_user(env->regs[17], &sc->regs.r17); 77f9fb3ba3SLaurent Vivier __put_user(env->regs[18], &sc->regs.r18); 78f9fb3ba3SLaurent Vivier __put_user(env->regs[19], &sc->regs.r19); 79f9fb3ba3SLaurent Vivier __put_user(env->regs[20], &sc->regs.r20); 80f9fb3ba3SLaurent Vivier __put_user(env->regs[21], &sc->regs.r21); 81f9fb3ba3SLaurent Vivier __put_user(env->regs[22], &sc->regs.r22); 82f9fb3ba3SLaurent Vivier __put_user(env->regs[23], &sc->regs.r23); 83f9fb3ba3SLaurent Vivier __put_user(env->regs[24], &sc->regs.r24); 84f9fb3ba3SLaurent Vivier __put_user(env->regs[25], &sc->regs.r25); 85f9fb3ba3SLaurent Vivier __put_user(env->regs[26], &sc->regs.r26); 86f9fb3ba3SLaurent Vivier __put_user(env->regs[27], &sc->regs.r27); 87f9fb3ba3SLaurent Vivier __put_user(env->regs[28], &sc->regs.r28); 88f9fb3ba3SLaurent Vivier __put_user(env->regs[29], &sc->regs.r29); 89f9fb3ba3SLaurent Vivier __put_user(env->regs[30], &sc->regs.r30); 90f9fb3ba3SLaurent Vivier __put_user(env->regs[31], &sc->regs.r31); 91f9fb3ba3SLaurent Vivier __put_user(env->sregs[SR_PC], &sc->regs.pc); 92f9fb3ba3SLaurent Vivier } 93f9fb3ba3SLaurent Vivier 94f9fb3ba3SLaurent Vivier static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env) 95f9fb3ba3SLaurent Vivier { 96f9fb3ba3SLaurent Vivier __get_user(env->regs[0], &sc->regs.r0); 97f9fb3ba3SLaurent Vivier __get_user(env->regs[1], &sc->regs.r1); 98f9fb3ba3SLaurent Vivier __get_user(env->regs[2], &sc->regs.r2); 99f9fb3ba3SLaurent Vivier __get_user(env->regs[3], &sc->regs.r3); 100f9fb3ba3SLaurent Vivier __get_user(env->regs[4], &sc->regs.r4); 101f9fb3ba3SLaurent Vivier __get_user(env->regs[5], &sc->regs.r5); 102f9fb3ba3SLaurent Vivier __get_user(env->regs[6], &sc->regs.r6); 103f9fb3ba3SLaurent Vivier __get_user(env->regs[7], &sc->regs.r7); 104f9fb3ba3SLaurent Vivier __get_user(env->regs[8], &sc->regs.r8); 105f9fb3ba3SLaurent Vivier __get_user(env->regs[9], &sc->regs.r9); 106f9fb3ba3SLaurent Vivier __get_user(env->regs[10], &sc->regs.r10); 107f9fb3ba3SLaurent Vivier __get_user(env->regs[11], &sc->regs.r11); 108f9fb3ba3SLaurent Vivier __get_user(env->regs[12], &sc->regs.r12); 109f9fb3ba3SLaurent Vivier __get_user(env->regs[13], &sc->regs.r13); 110f9fb3ba3SLaurent Vivier __get_user(env->regs[14], &sc->regs.r14); 111f9fb3ba3SLaurent Vivier __get_user(env->regs[15], &sc->regs.r15); 112f9fb3ba3SLaurent Vivier __get_user(env->regs[16], &sc->regs.r16); 113f9fb3ba3SLaurent Vivier __get_user(env->regs[17], &sc->regs.r17); 114f9fb3ba3SLaurent Vivier __get_user(env->regs[18], &sc->regs.r18); 115f9fb3ba3SLaurent Vivier __get_user(env->regs[19], &sc->regs.r19); 116f9fb3ba3SLaurent Vivier __get_user(env->regs[20], &sc->regs.r20); 117f9fb3ba3SLaurent Vivier __get_user(env->regs[21], &sc->regs.r21); 118f9fb3ba3SLaurent Vivier __get_user(env->regs[22], &sc->regs.r22); 119f9fb3ba3SLaurent Vivier __get_user(env->regs[23], &sc->regs.r23); 120f9fb3ba3SLaurent Vivier __get_user(env->regs[24], &sc->regs.r24); 121f9fb3ba3SLaurent Vivier __get_user(env->regs[25], &sc->regs.r25); 122f9fb3ba3SLaurent Vivier __get_user(env->regs[26], &sc->regs.r26); 123f9fb3ba3SLaurent Vivier __get_user(env->regs[27], &sc->regs.r27); 124f9fb3ba3SLaurent Vivier __get_user(env->regs[28], &sc->regs.r28); 125f9fb3ba3SLaurent Vivier __get_user(env->regs[29], &sc->regs.r29); 126f9fb3ba3SLaurent Vivier __get_user(env->regs[30], &sc->regs.r30); 127f9fb3ba3SLaurent Vivier __get_user(env->regs[31], &sc->regs.r31); 128f9fb3ba3SLaurent Vivier __get_user(env->sregs[SR_PC], &sc->regs.pc); 129f9fb3ba3SLaurent Vivier } 130f9fb3ba3SLaurent Vivier 131f9fb3ba3SLaurent Vivier static abi_ulong get_sigframe(struct target_sigaction *ka, 132f9fb3ba3SLaurent Vivier CPUMBState *env, int frame_size) 133f9fb3ba3SLaurent Vivier { 134f9fb3ba3SLaurent Vivier abi_ulong sp = env->regs[1]; 135f9fb3ba3SLaurent Vivier 136*465e237bSLaurent Vivier sp = target_sigsp(sp, ka); 137f9fb3ba3SLaurent Vivier 138f9fb3ba3SLaurent Vivier return ((sp - frame_size) & -8UL); 139f9fb3ba3SLaurent Vivier } 140f9fb3ba3SLaurent Vivier 141f9fb3ba3SLaurent Vivier void setup_frame(int sig, struct target_sigaction *ka, 142f9fb3ba3SLaurent Vivier target_sigset_t *set, CPUMBState *env) 143f9fb3ba3SLaurent Vivier { 144f9fb3ba3SLaurent Vivier struct target_signal_frame *frame; 145f9fb3ba3SLaurent Vivier abi_ulong frame_addr; 146f9fb3ba3SLaurent Vivier int i; 147f9fb3ba3SLaurent Vivier 148f9fb3ba3SLaurent Vivier frame_addr = get_sigframe(ka, env, sizeof *frame); 149f9fb3ba3SLaurent Vivier trace_user_setup_frame(env, frame_addr); 150f9fb3ba3SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) 151f9fb3ba3SLaurent Vivier goto badframe; 152f9fb3ba3SLaurent Vivier 153f9fb3ba3SLaurent Vivier /* Save the mask. */ 154f9fb3ba3SLaurent Vivier __put_user(set->sig[0], &frame->uc.tuc_mcontext.oldmask); 155f9fb3ba3SLaurent Vivier 156f9fb3ba3SLaurent Vivier for(i = 1; i < TARGET_NSIG_WORDS; i++) { 157f9fb3ba3SLaurent Vivier __put_user(set->sig[i], &frame->extramask[i - 1]); 158f9fb3ba3SLaurent Vivier } 159f9fb3ba3SLaurent Vivier 160f9fb3ba3SLaurent Vivier setup_sigcontext(&frame->uc.tuc_mcontext, env); 161f9fb3ba3SLaurent Vivier 162f9fb3ba3SLaurent Vivier /* Set up to return from userspace. If provided, use a stub 163f9fb3ba3SLaurent Vivier already in userspace. */ 164f9fb3ba3SLaurent Vivier /* minus 8 is offset to cater for "rtsd r15,8" offset */ 165f9fb3ba3SLaurent Vivier if (ka->sa_flags & TARGET_SA_RESTORER) { 166f9fb3ba3SLaurent Vivier env->regs[15] = ((unsigned long)ka->sa_restorer)-8; 167f9fb3ba3SLaurent Vivier } else { 168f9fb3ba3SLaurent Vivier uint32_t t; 169f9fb3ba3SLaurent Vivier /* Note, these encodings are _big endian_! */ 170f9fb3ba3SLaurent Vivier /* addi r12, r0, __NR_sigreturn */ 171f9fb3ba3SLaurent Vivier t = 0x31800000UL | TARGET_NR_sigreturn; 172f9fb3ba3SLaurent Vivier __put_user(t, frame->tramp + 0); 173f9fb3ba3SLaurent Vivier /* brki r14, 0x8 */ 174f9fb3ba3SLaurent Vivier t = 0xb9cc0008UL; 175f9fb3ba3SLaurent Vivier __put_user(t, frame->tramp + 1); 176f9fb3ba3SLaurent Vivier 177f9fb3ba3SLaurent Vivier /* Return from sighandler will jump to the tramp. 178f9fb3ba3SLaurent Vivier Negative 8 offset because return is rtsd r15, 8 */ 179f9fb3ba3SLaurent Vivier env->regs[15] = frame_addr + offsetof(struct target_signal_frame, tramp) 180f9fb3ba3SLaurent Vivier - 8; 181f9fb3ba3SLaurent Vivier } 182f9fb3ba3SLaurent Vivier 183f9fb3ba3SLaurent Vivier /* Set up registers for signal handler */ 184f9fb3ba3SLaurent Vivier env->regs[1] = frame_addr; 185f9fb3ba3SLaurent Vivier /* Signal handler args: */ 186f9fb3ba3SLaurent Vivier env->regs[5] = sig; /* Arg 0: signum */ 187f9fb3ba3SLaurent Vivier env->regs[6] = 0; 188f9fb3ba3SLaurent Vivier /* arg 1: sigcontext */ 189f9fb3ba3SLaurent Vivier env->regs[7] = frame_addr += offsetof(typeof(*frame), uc); 190f9fb3ba3SLaurent Vivier 191f9fb3ba3SLaurent Vivier /* Offset of 4 to handle microblaze rtid r14, 0 */ 192f9fb3ba3SLaurent Vivier env->sregs[SR_PC] = (unsigned long)ka->_sa_handler; 193f9fb3ba3SLaurent Vivier 194f9fb3ba3SLaurent Vivier unlock_user_struct(frame, frame_addr, 1); 195f9fb3ba3SLaurent Vivier return; 196f9fb3ba3SLaurent Vivier badframe: 197f9fb3ba3SLaurent Vivier force_sigsegv(sig); 198f9fb3ba3SLaurent Vivier } 199f9fb3ba3SLaurent Vivier 200f9fb3ba3SLaurent Vivier void setup_rt_frame(int sig, struct target_sigaction *ka, 201f9fb3ba3SLaurent Vivier target_siginfo_t *info, 202f9fb3ba3SLaurent Vivier target_sigset_t *set, CPUMBState *env) 203f9fb3ba3SLaurent Vivier { 204f9fb3ba3SLaurent Vivier fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n"); 205f9fb3ba3SLaurent Vivier } 206f9fb3ba3SLaurent Vivier 207f9fb3ba3SLaurent Vivier long do_sigreturn(CPUMBState *env) 208f9fb3ba3SLaurent Vivier { 209f9fb3ba3SLaurent Vivier struct target_signal_frame *frame; 210f9fb3ba3SLaurent Vivier abi_ulong frame_addr; 211f9fb3ba3SLaurent Vivier target_sigset_t target_set; 212f9fb3ba3SLaurent Vivier sigset_t set; 213f9fb3ba3SLaurent Vivier int i; 214f9fb3ba3SLaurent Vivier 215f9fb3ba3SLaurent Vivier frame_addr = env->regs[R_SP]; 216f9fb3ba3SLaurent Vivier trace_user_do_sigreturn(env, frame_addr); 217f9fb3ba3SLaurent Vivier /* Make sure the guest isn't playing games. */ 218f9fb3ba3SLaurent Vivier if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) 219f9fb3ba3SLaurent Vivier goto badframe; 220f9fb3ba3SLaurent Vivier 221f9fb3ba3SLaurent Vivier /* Restore blocked signals */ 222f9fb3ba3SLaurent Vivier __get_user(target_set.sig[0], &frame->uc.tuc_mcontext.oldmask); 223f9fb3ba3SLaurent Vivier for(i = 1; i < TARGET_NSIG_WORDS; i++) { 224f9fb3ba3SLaurent Vivier __get_user(target_set.sig[i], &frame->extramask[i - 1]); 225f9fb3ba3SLaurent Vivier } 226f9fb3ba3SLaurent Vivier target_to_host_sigset_internal(&set, &target_set); 227f9fb3ba3SLaurent Vivier set_sigmask(&set); 228f9fb3ba3SLaurent Vivier 229f9fb3ba3SLaurent Vivier restore_sigcontext(&frame->uc.tuc_mcontext, env); 230f9fb3ba3SLaurent Vivier /* We got here through a sigreturn syscall, our path back is via an 231f9fb3ba3SLaurent Vivier rtb insn so setup r14 for that. */ 232f9fb3ba3SLaurent Vivier env->regs[14] = env->sregs[SR_PC]; 233f9fb3ba3SLaurent Vivier 234f9fb3ba3SLaurent Vivier unlock_user_struct(frame, frame_addr, 0); 235f9fb3ba3SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 236f9fb3ba3SLaurent Vivier badframe: 237f9fb3ba3SLaurent Vivier force_sig(TARGET_SIGSEGV); 238f9fb3ba3SLaurent Vivier return -TARGET_QEMU_ESIGRETURN; 239f9fb3ba3SLaurent Vivier } 240f9fb3ba3SLaurent Vivier 241f9fb3ba3SLaurent Vivier long do_rt_sigreturn(CPUMBState *env) 242f9fb3ba3SLaurent Vivier { 243f9fb3ba3SLaurent Vivier trace_user_do_rt_sigreturn(env, 0); 244f9fb3ba3SLaurent Vivier fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n"); 245f9fb3ba3SLaurent Vivier return -TARGET_ENOSYS; 246f9fb3ba3SLaurent Vivier } 247