qemu/linux-user/hexagon/signal.c
<<
>>
Prefs
   1/*
   2 *  Emulation of Linux signals
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   5 *  Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License as published by
   9 *  the Free Software Foundation; either version 2 of the License, or
  10 *  (at your option) any later version.
  11 *
  12 *  This program is distributed in the hope that it will be useful,
  13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *  GNU General Public License for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License
  18 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20#include "qemu/osdep.h"
  21#include "qemu.h"
  22#include "signal-common.h"
  23#include "linux-user/trace.h"
  24
  25struct target_sigcontext {
  26    target_ulong r0,  r1,  r2,  r3;
  27    target_ulong r4,  r5,  r6,  r7;
  28    target_ulong r8,  r9, r10, r11;
  29    target_ulong r12, r13, r14, r15;
  30    target_ulong r16, r17, r18, r19;
  31    target_ulong r20, r21, r22, r23;
  32    target_ulong r24, r25, r26, r27;
  33    target_ulong r28, r29, r30, r31;
  34    target_ulong sa0;
  35    target_ulong lc0;
  36    target_ulong sa1;
  37    target_ulong lc1;
  38    target_ulong m0;
  39    target_ulong m1;
  40    target_ulong usr;
  41    target_ulong p3_0;
  42    target_ulong gp;
  43    target_ulong ugp;
  44    target_ulong pc;
  45    target_ulong cause;
  46    target_ulong badva;
  47    target_ulong pad1;
  48    target_ulong pad2;
  49    target_ulong pad3;
  50};
  51
  52struct target_ucontext {
  53    unsigned long uc_flags;
  54    target_ulong uc_link; /* target pointer */
  55    target_stack_t uc_stack;
  56    struct target_sigcontext uc_mcontext;
  57    target_sigset_t uc_sigmask;
  58};
  59
  60struct target_rt_sigframe {
  61    uint32_t tramp[2];
  62    struct target_siginfo info;
  63    struct target_ucontext uc;
  64};
  65
  66static abi_ulong get_sigframe(struct target_sigaction *ka,
  67                              CPUHexagonState *regs, size_t framesize)
  68{
  69    abi_ulong sp = get_sp_from_cpustate(regs);
  70
  71    /* This is the X/Open sanctioned signal stack switching.  */
  72    sp = target_sigsp(sp, ka) - framesize;
  73
  74    sp = QEMU_ALIGN_DOWN(sp, 8);
  75
  76    return sp;
  77}
  78
  79static void setup_sigcontext(struct target_sigcontext *sc, CPUHexagonState *env)
  80{
  81    __put_user(env->gpr[HEX_REG_R00], &sc->r0);
  82    __put_user(env->gpr[HEX_REG_R01], &sc->r1);
  83    __put_user(env->gpr[HEX_REG_R02], &sc->r2);
  84    __put_user(env->gpr[HEX_REG_R03], &sc->r3);
  85    __put_user(env->gpr[HEX_REG_R04], &sc->r4);
  86    __put_user(env->gpr[HEX_REG_R05], &sc->r5);
  87    __put_user(env->gpr[HEX_REG_R06], &sc->r6);
  88    __put_user(env->gpr[HEX_REG_R07], &sc->r7);
  89    __put_user(env->gpr[HEX_REG_R08], &sc->r8);
  90    __put_user(env->gpr[HEX_REG_R09], &sc->r9);
  91    __put_user(env->gpr[HEX_REG_R10], &sc->r10);
  92    __put_user(env->gpr[HEX_REG_R11], &sc->r11);
  93    __put_user(env->gpr[HEX_REG_R12], &sc->r12);
  94    __put_user(env->gpr[HEX_REG_R13], &sc->r13);
  95    __put_user(env->gpr[HEX_REG_R14], &sc->r14);
  96    __put_user(env->gpr[HEX_REG_R15], &sc->r15);
  97    __put_user(env->gpr[HEX_REG_R16], &sc->r16);
  98    __put_user(env->gpr[HEX_REG_R17], &sc->r17);
  99    __put_user(env->gpr[HEX_REG_R18], &sc->r18);
 100    __put_user(env->gpr[HEX_REG_R19], &sc->r19);
 101    __put_user(env->gpr[HEX_REG_R20], &sc->r20);
 102    __put_user(env->gpr[HEX_REG_R21], &sc->r21);
 103    __put_user(env->gpr[HEX_REG_R22], &sc->r22);
 104    __put_user(env->gpr[HEX_REG_R23], &sc->r23);
 105    __put_user(env->gpr[HEX_REG_R24], &sc->r24);
 106    __put_user(env->gpr[HEX_REG_R25], &sc->r25);
 107    __put_user(env->gpr[HEX_REG_R26], &sc->r26);
 108    __put_user(env->gpr[HEX_REG_R27], &sc->r27);
 109    __put_user(env->gpr[HEX_REG_R28], &sc->r28);
 110    __put_user(env->gpr[HEX_REG_R29], &sc->r29);
 111    __put_user(env->gpr[HEX_REG_R30], &sc->r30);
 112    __put_user(env->gpr[HEX_REG_R31], &sc->r31);
 113    __put_user(env->gpr[HEX_REG_SA0], &sc->sa0);
 114    __put_user(env->gpr[HEX_REG_LC0], &sc->lc0);
 115    __put_user(env->gpr[HEX_REG_SA1], &sc->sa1);
 116    __put_user(env->gpr[HEX_REG_LC1], &sc->lc1);
 117    __put_user(env->gpr[HEX_REG_M0], &sc->m0);
 118    __put_user(env->gpr[HEX_REG_M1], &sc->m1);
 119    __put_user(env->gpr[HEX_REG_USR], &sc->usr);
 120    __put_user(env->gpr[HEX_REG_P3_0], &sc->p3_0);
 121    __put_user(env->gpr[HEX_REG_GP], &sc->gp);
 122    __put_user(env->gpr[HEX_REG_UGP], &sc->ugp);
 123    __put_user(env->gpr[HEX_REG_PC], &sc->pc);
 124}
 125
 126static void setup_ucontext(struct target_ucontext *uc,
 127                           CPUHexagonState *env, target_sigset_t *set)
 128{
 129    __put_user(0,    &(uc->uc_flags));
 130    __put_user(0,    &(uc->uc_link));
 131
 132    target_save_altstack(&uc->uc_stack, env);
 133
 134    int i;
 135    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
 136        __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
 137    }
 138
 139    setup_sigcontext(&uc->uc_mcontext, env);
 140}
 141
 142static inline void install_sigtramp(uint32_t *tramp)
 143{
 144    __put_user(0x7800d166, tramp + 0); /*  { r6=#__NR_rt_sigreturn } */
 145    __put_user(0x5400c004, tramp + 1); /*  { trap0(#1) } */
 146}
 147
 148void setup_rt_frame(int sig, struct target_sigaction *ka,
 149                    target_siginfo_t *info,
 150                    target_sigset_t *set, CPUHexagonState *env)
 151{
 152    abi_ulong frame_addr;
 153    struct target_rt_sigframe *frame;
 154
 155    frame_addr = get_sigframe(ka, env, sizeof(*frame));
 156    trace_user_setup_rt_frame(env, frame_addr);
 157
 158    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
 159        goto badframe;
 160    }
 161
 162    setup_ucontext(&frame->uc, env, set);
 163    tswap_siginfo(&frame->info, info);
 164    install_sigtramp(frame->tramp);
 165
 166    env->gpr[HEX_REG_PC] = ka->_sa_handler;
 167    env->gpr[HEX_REG_SP] = frame_addr;
 168    env->gpr[HEX_REG_R00] = sig;
 169    env->gpr[HEX_REG_R01] =
 170        frame_addr + offsetof(struct target_rt_sigframe, info);
 171    env->gpr[HEX_REG_R02] =
 172        frame_addr + offsetof(struct target_rt_sigframe, uc);
 173    env->gpr[HEX_REG_LR] =
 174        frame_addr + offsetof(struct target_rt_sigframe, tramp);
 175
 176    return;
 177
 178badframe:
 179    unlock_user_struct(frame, frame_addr, 1);
 180    if (sig == TARGET_SIGSEGV) {
 181        ka->_sa_handler = TARGET_SIG_DFL;
 182    }
 183    force_sig(TARGET_SIGSEGV);
 184}
 185
 186static void restore_sigcontext(CPUHexagonState *env,
 187                               struct target_sigcontext *sc)
 188{
 189    __get_user(env->gpr[HEX_REG_R00], &sc->r0);
 190    __get_user(env->gpr[HEX_REG_R01], &sc->r1);
 191    __get_user(env->gpr[HEX_REG_R02], &sc->r2);
 192    __get_user(env->gpr[HEX_REG_R03], &sc->r3);
 193    __get_user(env->gpr[HEX_REG_R04], &sc->r4);
 194    __get_user(env->gpr[HEX_REG_R05], &sc->r5);
 195    __get_user(env->gpr[HEX_REG_R06], &sc->r6);
 196    __get_user(env->gpr[HEX_REG_R07], &sc->r7);
 197    __get_user(env->gpr[HEX_REG_R08], &sc->r8);
 198    __get_user(env->gpr[HEX_REG_R09], &sc->r9);
 199    __get_user(env->gpr[HEX_REG_R10], &sc->r10);
 200    __get_user(env->gpr[HEX_REG_R11], &sc->r11);
 201    __get_user(env->gpr[HEX_REG_R12], &sc->r12);
 202    __get_user(env->gpr[HEX_REG_R13], &sc->r13);
 203    __get_user(env->gpr[HEX_REG_R14], &sc->r14);
 204    __get_user(env->gpr[HEX_REG_R15], &sc->r15);
 205    __get_user(env->gpr[HEX_REG_R16], &sc->r16);
 206    __get_user(env->gpr[HEX_REG_R17], &sc->r17);
 207    __get_user(env->gpr[HEX_REG_R18], &sc->r18);
 208    __get_user(env->gpr[HEX_REG_R19], &sc->r19);
 209    __get_user(env->gpr[HEX_REG_R20], &sc->r20);
 210    __get_user(env->gpr[HEX_REG_R21], &sc->r21);
 211    __get_user(env->gpr[HEX_REG_R22], &sc->r22);
 212    __get_user(env->gpr[HEX_REG_R23], &sc->r23);
 213    __get_user(env->gpr[HEX_REG_R24], &sc->r24);
 214    __get_user(env->gpr[HEX_REG_R25], &sc->r25);
 215    __get_user(env->gpr[HEX_REG_R26], &sc->r26);
 216    __get_user(env->gpr[HEX_REG_R27], &sc->r27);
 217    __get_user(env->gpr[HEX_REG_R28], &sc->r28);
 218    __get_user(env->gpr[HEX_REG_R29], &sc->r29);
 219    __get_user(env->gpr[HEX_REG_R30], &sc->r30);
 220    __get_user(env->gpr[HEX_REG_R31], &sc->r31);
 221    __get_user(env->gpr[HEX_REG_SA0], &sc->sa0);
 222    __get_user(env->gpr[HEX_REG_LC0], &sc->lc0);
 223    __get_user(env->gpr[HEX_REG_SA1], &sc->sa1);
 224    __get_user(env->gpr[HEX_REG_LC1], &sc->lc1);
 225    __get_user(env->gpr[HEX_REG_M0], &sc->m0);
 226    __get_user(env->gpr[HEX_REG_M1], &sc->m1);
 227    __get_user(env->gpr[HEX_REG_USR], &sc->usr);
 228    __get_user(env->gpr[HEX_REG_P3_0], &sc->p3_0);
 229    __get_user(env->gpr[HEX_REG_GP], &sc->gp);
 230    __get_user(env->gpr[HEX_REG_UGP], &sc->ugp);
 231    __get_user(env->gpr[HEX_REG_PC], &sc->pc);
 232}
 233
 234static void restore_ucontext(CPUHexagonState *env, struct target_ucontext *uc)
 235{
 236    sigset_t blocked;
 237    target_sigset_t target_set;
 238    int i;
 239
 240    target_sigemptyset(&target_set);
 241    for (i = 0; i < TARGET_NSIG_WORDS; i++) {
 242        __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
 243    }
 244
 245    target_to_host_sigset_internal(&blocked, &target_set);
 246    set_sigmask(&blocked);
 247
 248    restore_sigcontext(env, &uc->uc_mcontext);
 249}
 250
 251long do_rt_sigreturn(CPUHexagonState *env)
 252{
 253    struct target_rt_sigframe *frame;
 254    abi_ulong frame_addr;
 255
 256    frame_addr = env->gpr[HEX_REG_SP];
 257    trace_user_do_sigreturn(env, frame_addr);
 258    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
 259        goto badframe;
 260    }
 261
 262    restore_ucontext(env, &frame->uc);
 263    target_restore_altstack(&frame->uc.uc_stack, env);
 264
 265    unlock_user_struct(frame, frame_addr, 0);
 266    return -TARGET_QEMU_ESIGRETURN;
 267
 268badframe:
 269    unlock_user_struct(frame, frame_addr, 0);
 270    force_sig(TARGET_SIGSEGV);
 271    return 0;
 272}
 273