qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

signal.c (8111B)


      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 struct target_sigcontext {
     26     abi_ulong sc_pc;
     27     abi_ulong sc_ps;
     28     abi_ulong sc_lbeg;
     29     abi_ulong sc_lend;
     30     abi_ulong sc_lcount;
     31     abi_ulong sc_sar;
     32     abi_ulong sc_acclo;
     33     abi_ulong sc_acchi;
     34     abi_ulong sc_a[16];
     35     abi_ulong sc_xtregs;
     36 };
     37 
     38 struct target_ucontext {
     39     abi_ulong tuc_flags;
     40     abi_ulong tuc_link;
     41     target_stack_t tuc_stack;
     42     struct target_sigcontext tuc_mcontext;
     43     target_sigset_t tuc_sigmask;
     44 };
     45 
     46 struct target_rt_sigframe {
     47     target_siginfo_t info;
     48     struct target_ucontext uc;
     49     /* TODO: xtregs */
     50     uint8_t retcode[6];
     51     abi_ulong window[4];
     52 };
     53 
     54 static abi_ulong get_sigframe(struct target_sigaction *sa,
     55                               CPUXtensaState *env,
     56                               unsigned long framesize)
     57 {
     58     abi_ulong sp;
     59 
     60     sp = target_sigsp(get_sp_from_cpustate(env), sa);
     61 
     62     return (sp - framesize) & -16;
     63 }
     64 
     65 static int flush_window_regs(CPUXtensaState *env)
     66 {
     67     uint32_t wb = env->sregs[WINDOW_BASE];
     68     uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
     69     unsigned d = ctz32(ws) + 1;
     70     unsigned i;
     71     int ret = 0;
     72 
     73     for (i = d; i < env->config->nareg / 4; i += d) {
     74         uint32_t ssp, osp;
     75         unsigned j;
     76 
     77         ws >>= d;
     78         xtensa_rotate_window(env, d);
     79 
     80         if (ws & 0x1) {
     81             ssp = env->regs[5];
     82             d = 1;
     83         } else if (ws & 0x2) {
     84             ssp = env->regs[9];
     85             ret |= get_user_ual(osp, env->regs[1] - 12);
     86             osp -= 32;
     87             d = 2;
     88         } else if (ws & 0x4) {
     89             ssp = env->regs[13];
     90             ret |= get_user_ual(osp, env->regs[1] - 12);
     91             osp -= 48;
     92             d = 3;
     93         } else {
     94             g_assert_not_reached();
     95         }
     96 
     97         for (j = 0; j < 4; ++j) {
     98             ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4);
     99         }
    100         for (j = 4; j < d * 4; ++j) {
    101             ret |= put_user_ual(env->regs[j], osp - 16 + j * 4);
    102         }
    103     }
    104     xtensa_rotate_window(env, d);
    105     g_assert(env->sregs[WINDOW_BASE] == wb);
    106     return ret == 0;
    107 }
    108 
    109 static int setup_sigcontext(struct target_rt_sigframe *frame,
    110                             CPUXtensaState *env)
    111 {
    112     struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
    113     int i;
    114 
    115     __put_user(env->pc, &sc->sc_pc);
    116     __put_user(env->sregs[PS], &sc->sc_ps);
    117     __put_user(env->sregs[LBEG], &sc->sc_lbeg);
    118     __put_user(env->sregs[LEND], &sc->sc_lend);
    119     __put_user(env->sregs[LCOUNT], &sc->sc_lcount);
    120     if (!flush_window_regs(env)) {
    121         return 0;
    122     }
    123     for (i = 0; i < 16; ++i) {
    124         __put_user(env->regs[i], sc->sc_a + i);
    125     }
    126     __put_user(0, &sc->sc_xtregs);
    127     /* TODO: xtregs */
    128     return 1;
    129 }
    130 
    131 static void install_sigtramp(uint8_t *tramp)
    132 {
    133 #if TARGET_BIG_ENDIAN
    134     /* Generate instruction:  MOVI a2, __NR_rt_sigreturn */
    135     __put_user(0x22, &tramp[0]);
    136     __put_user(0x0a, &tramp[1]);
    137     __put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
    138     /* Generate instruction:  SYSCALL */
    139     __put_user(0x00, &tramp[3]);
    140     __put_user(0x05, &tramp[4]);
    141     __put_user(0x00, &tramp[5]);
    142 #else
    143     /* Generate instruction:  MOVI a2, __NR_rt_sigreturn */
    144     __put_user(0x22, &tramp[0]);
    145     __put_user(0xa0, &tramp[1]);
    146     __put_user(TARGET_NR_rt_sigreturn, &tramp[2]);
    147     /* Generate instruction:  SYSCALL */
    148     __put_user(0x00, &tramp[3]);
    149     __put_user(0x50, &tramp[4]);
    150     __put_user(0x00, &tramp[5]);
    151 #endif
    152 }
    153 
    154 void setup_rt_frame(int sig, struct target_sigaction *ka,
    155                     target_siginfo_t *info,
    156                     target_sigset_t *set, CPUXtensaState *env)
    157 {
    158     abi_ulong frame_addr;
    159     struct target_rt_sigframe *frame;
    160     uint32_t ra;
    161     bool abi_call0;
    162     unsigned base;
    163     int i;
    164 
    165     frame_addr = get_sigframe(ka, env, sizeof(*frame));
    166     trace_user_setup_rt_frame(env, frame_addr);
    167 
    168     if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    169         goto give_sigsegv;
    170     }
    171 
    172     if (ka->sa_flags & SA_SIGINFO) {
    173         tswap_siginfo(&frame->info, info);
    174     }
    175 
    176     __put_user(0, &frame->uc.tuc_flags);
    177     __put_user(0, &frame->uc.tuc_link);
    178     target_save_altstack(&frame->uc.tuc_stack, env);
    179     if (!setup_sigcontext(frame, env)) {
    180         unlock_user_struct(frame, frame_addr, 0);
    181         goto give_sigsegv;
    182     }
    183     for (i = 0; i < TARGET_NSIG_WORDS; ++i) {
    184         __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
    185     }
    186 
    187     if (ka->sa_flags & TARGET_SA_RESTORER) {
    188         ra = ka->sa_restorer;
    189     } else {
    190         /* Not used, but retain for ABI compatibility. */
    191         install_sigtramp(frame->retcode);
    192         ra = default_rt_sigreturn;
    193     }
    194     memset(env->regs, 0, sizeof(env->regs));
    195     env->pc = ka->_sa_handler;
    196     env->regs[1] = frame_addr;
    197     env->sregs[WINDOW_BASE] = 0;
    198     env->sregs[WINDOW_START] = 1;
    199 
    200     abi_call0 = (env->sregs[PS] & PS_WOE) == 0;
    201     env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT);
    202 
    203     if (abi_call0) {
    204         base = 0;
    205         env->regs[base] = ra;
    206     } else {
    207         env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT);
    208         base = 4;
    209         env->regs[base] = (ra & 0x3fffffff) | 0x40000000;
    210     }
    211     env->regs[base + 2] = sig;
    212     env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe,
    213                                                 info);
    214     env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, uc);
    215     unlock_user_struct(frame, frame_addr, 1);
    216     return;
    217 
    218 give_sigsegv:
    219     force_sigsegv(sig);
    220     return;
    221 }
    222 
    223 static void restore_sigcontext(CPUXtensaState *env,
    224                                struct target_rt_sigframe *frame)
    225 {
    226     struct target_sigcontext *sc = &frame->uc.tuc_mcontext;
    227     uint32_t ps;
    228     int i;
    229 
    230     __get_user(env->pc, &sc->sc_pc);
    231     __get_user(ps, &sc->sc_ps);
    232     __get_user(env->sregs[LBEG], &sc->sc_lbeg);
    233     __get_user(env->sregs[LEND], &sc->sc_lend);
    234     __get_user(env->sregs[LCOUNT], &sc->sc_lcount);
    235 
    236     env->sregs[WINDOW_BASE] = 0;
    237     env->sregs[WINDOW_START] = 1;
    238     env->sregs[PS] = deposit32(env->sregs[PS],
    239                                PS_CALLINC_SHIFT,
    240                                PS_CALLINC_LEN,
    241                                extract32(ps, PS_CALLINC_SHIFT,
    242                                          PS_CALLINC_LEN));
    243     for (i = 0; i < 16; ++i) {
    244         __get_user(env->regs[i], sc->sc_a + i);
    245     }
    246     /* TODO: xtregs */
    247 }
    248 
    249 long do_rt_sigreturn(CPUXtensaState *env)
    250 {
    251     abi_ulong frame_addr = env->regs[1];
    252     struct target_rt_sigframe *frame;
    253     sigset_t set;
    254 
    255     trace_user_do_rt_sigreturn(env, frame_addr);
    256     if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
    257         goto badframe;
    258     }
    259     target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
    260     set_sigmask(&set);
    261 
    262     restore_sigcontext(env, frame);
    263     target_restore_altstack(&frame->uc.tuc_stack, env);
    264 
    265     unlock_user_struct(frame, frame_addr, 0);
    266     return -QEMU_ESIGRETURN;
    267 
    268 badframe:
    269     unlock_user_struct(frame, frame_addr, 0);
    270     force_sig(TARGET_SIGSEGV);
    271     return -QEMU_ESIGRETURN;
    272 }
    273 
    274 void setup_sigtramp(abi_ulong sigtramp_page)
    275 {
    276     uint8_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 6, 0);
    277     assert(tramp != NULL);
    278 
    279     default_rt_sigreturn = sigtramp_page;
    280     install_sigtramp(tramp);
    281     unlock_user(tramp, sigtramp_page, 6);
    282 }