qemu/linux-user/microblaze/signal.c
<<
>>
Prefs
   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
  24struct target_sigcontext {
  25    struct target_pt_regs regs;  /* needs to be first */
  26    uint32_t oldmask;
  27};
  28
  29struct target_stack_t {
  30    abi_ulong ss_sp;
  31    int ss_flags;
  32    unsigned int ss_size;
  33};
  34
  35struct target_ucontext {
  36    abi_ulong tuc_flags;
  37    abi_ulong tuc_link;
  38    target_stack_t tuc_stack;
  39    struct target_sigcontext tuc_mcontext;
  40    target_sigset_t tuc_sigmask;
  41};
  42
  43/* Signal frames. */
  44struct target_rt_sigframe {
  45    target_siginfo_t info;
  46    struct target_ucontext uc;
  47    uint32_t tramp[2];
  48};
  49
  50static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
  51{
  52    __put_user(env->regs[0], &sc->regs.r0);
  53    __put_user(env->regs[1], &sc->regs.r1);
  54    __put_user(env->regs[2], &sc->regs.r2);
  55    __put_user(env->regs[3], &sc->regs.r3);
  56    __put_user(env->regs[4], &sc->regs.r4);
  57    __put_user(env->regs[5], &sc->regs.r5);
  58    __put_user(env->regs[6], &sc->regs.r6);
  59    __put_user(env->regs[7], &sc->regs.r7);
  60    __put_user(env->regs[8], &sc->regs.r8);
  61    __put_user(env->regs[9], &sc->regs.r9);
  62    __put_user(env->regs[10], &sc->regs.r10);
  63    __put_user(env->regs[11], &sc->regs.r11);
  64    __put_user(env->regs[12], &sc->regs.r12);
  65    __put_user(env->regs[13], &sc->regs.r13);
  66    __put_user(env->regs[14], &sc->regs.r14);
  67    __put_user(env->regs[15], &sc->regs.r15);
  68    __put_user(env->regs[16], &sc->regs.r16);
  69    __put_user(env->regs[17], &sc->regs.r17);
  70    __put_user(env->regs[18], &sc->regs.r18);
  71    __put_user(env->regs[19], &sc->regs.r19);
  72    __put_user(env->regs[20], &sc->regs.r20);
  73    __put_user(env->regs[21], &sc->regs.r21);
  74    __put_user(env->regs[22], &sc->regs.r22);
  75    __put_user(env->regs[23], &sc->regs.r23);
  76    __put_user(env->regs[24], &sc->regs.r24);
  77    __put_user(env->regs[25], &sc->regs.r25);
  78    __put_user(env->regs[26], &sc->regs.r26);
  79    __put_user(env->regs[27], &sc->regs.r27);
  80    __put_user(env->regs[28], &sc->regs.r28);
  81    __put_user(env->regs[29], &sc->regs.r29);
  82    __put_user(env->regs[30], &sc->regs.r30);
  83    __put_user(env->regs[31], &sc->regs.r31);
  84    __put_user(env->pc, &sc->regs.pc);
  85}
  86
  87static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
  88{
  89    __get_user(env->regs[0], &sc->regs.r0);
  90    __get_user(env->regs[1], &sc->regs.r1);
  91    __get_user(env->regs[2], &sc->regs.r2);
  92    __get_user(env->regs[3], &sc->regs.r3);
  93    __get_user(env->regs[4], &sc->regs.r4);
  94    __get_user(env->regs[5], &sc->regs.r5);
  95    __get_user(env->regs[6], &sc->regs.r6);
  96    __get_user(env->regs[7], &sc->regs.r7);
  97    __get_user(env->regs[8], &sc->regs.r8);
  98    __get_user(env->regs[9], &sc->regs.r9);
  99    __get_user(env->regs[10], &sc->regs.r10);
 100    __get_user(env->regs[11], &sc->regs.r11);
 101    __get_user(env->regs[12], &sc->regs.r12);
 102    __get_user(env->regs[13], &sc->regs.r13);
 103    __get_user(env->regs[14], &sc->regs.r14);
 104    __get_user(env->regs[15], &sc->regs.r15);
 105    __get_user(env->regs[16], &sc->regs.r16);
 106    __get_user(env->regs[17], &sc->regs.r17);
 107    __get_user(env->regs[18], &sc->regs.r18);
 108    __get_user(env->regs[19], &sc->regs.r19);
 109    __get_user(env->regs[20], &sc->regs.r20);
 110    __get_user(env->regs[21], &sc->regs.r21);
 111    __get_user(env->regs[22], &sc->regs.r22);
 112    __get_user(env->regs[23], &sc->regs.r23);
 113    __get_user(env->regs[24], &sc->regs.r24);
 114    __get_user(env->regs[25], &sc->regs.r25);
 115    __get_user(env->regs[26], &sc->regs.r26);
 116    __get_user(env->regs[27], &sc->regs.r27);
 117    __get_user(env->regs[28], &sc->regs.r28);
 118    __get_user(env->regs[29], &sc->regs.r29);
 119    __get_user(env->regs[30], &sc->regs.r30);
 120    __get_user(env->regs[31], &sc->regs.r31);
 121    __get_user(env->pc, &sc->regs.pc);
 122}
 123
 124static abi_ulong get_sigframe(struct target_sigaction *ka,
 125                              CPUMBState *env, int frame_size)
 126{
 127    abi_ulong sp = env->regs[1];
 128
 129    sp = target_sigsp(sp, ka);
 130
 131    return ((sp - frame_size) & -8UL);
 132}
 133
 134void setup_rt_frame(int sig, struct target_sigaction *ka,
 135                    target_siginfo_t *info,
 136                    target_sigset_t *set, CPUMBState *env)
 137{
 138    struct target_rt_sigframe *frame;
 139    abi_ulong frame_addr;
 140
 141    frame_addr = get_sigframe(ka, env, sizeof *frame);
 142    trace_user_setup_rt_frame(env, frame_addr);
 143
 144    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
 145        force_sigsegv(sig);
 146        return;
 147    }
 148
 149    tswap_siginfo(&frame->info, info);
 150
 151    __put_user(0, &frame->uc.tuc_flags);
 152    __put_user(0, &frame->uc.tuc_link);
 153
 154    target_save_altstack(&frame->uc.tuc_stack, env);
 155    setup_sigcontext(&frame->uc.tuc_mcontext, env);
 156
 157    for (int i = 0; i < TARGET_NSIG_WORDS; i++) {
 158        __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
 159    }
 160
 161    /* Kernel does not use SA_RESTORER. */
 162
 163    /* addi r12, r0, __NR_sigreturn */
 164    __put_user(0x31800000U | TARGET_NR_rt_sigreturn, frame->tramp + 0);
 165    /* brki r14, 0x8 */
 166    __put_user(0xb9cc0008U, frame->tramp + 1);
 167
 168    /*
 169     * Return from sighandler will jump to the tramp.
 170     * Negative 8 offset because return is rtsd r15, 8
 171     */
 172    env->regs[15] =
 173        frame_addr + offsetof(struct target_rt_sigframe, tramp) - 8;
 174
 175    /* Set up registers for signal handler */
 176    env->regs[1] = frame_addr;
 177
 178    /* Signal handler args: */
 179    env->regs[5] = sig;
 180    env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info);
 181    env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc);
 182
 183    /* Offset to handle microblaze rtid r14, 0 */
 184    env->pc = (unsigned long)ka->_sa_handler;
 185
 186    unlock_user_struct(frame, frame_addr, 1);
 187}
 188
 189
 190long do_sigreturn(CPUMBState *env)
 191{
 192    return -TARGET_ENOSYS;
 193}
 194
 195long do_rt_sigreturn(CPUMBState *env)
 196{
 197    struct target_rt_sigframe *frame = NULL;
 198    abi_ulong frame_addr = env->regs[1];
 199    sigset_t set;
 200
 201    trace_user_do_rt_sigreturn(env, frame_addr);
 202
 203    if  (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
 204        goto badframe;
 205    }
 206
 207    target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
 208    set_sigmask(&set);
 209
 210    restore_sigcontext(&frame->uc.tuc_mcontext, env);
 211
 212    if (do_sigaltstack(frame_addr +
 213                       offsetof(struct target_rt_sigframe, uc.tuc_stack),
 214                       0, get_sp_from_cpustate(env)) == -EFAULT) {
 215        goto badframe;
 216    }
 217
 218    unlock_user_struct(frame, frame_addr, 0);
 219    return -TARGET_QEMU_ESIGRETURN;
 220
 221 badframe:
 222    unlock_user_struct(frame, frame_addr, 0);
 223    force_sig(TARGET_SIGSEGV);
 224    return -TARGET_QEMU_ESIGRETURN;
 225}
 226