cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

signal.c (11574B)


      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# if defined(TARGET_ABI_MIPSO32)
     26struct target_sigcontext {
     27    uint32_t   sc_regmask;     /* Unused */
     28    uint32_t   sc_status;
     29    uint64_t   sc_pc;
     30    uint64_t   sc_regs[32];
     31    uint64_t   sc_fpregs[32];
     32    uint32_t   sc_ownedfp;     /* Unused */
     33    uint32_t   sc_fpc_csr;
     34    uint32_t   sc_fpc_eir;     /* Unused */
     35    uint32_t   sc_used_math;
     36    uint32_t   sc_dsp;         /* dsp status, was sc_ssflags */
     37    uint32_t   pad0;
     38    uint64_t   sc_mdhi;
     39    uint64_t   sc_mdlo;
     40    target_ulong   sc_hi1;         /* Was sc_cause */
     41    target_ulong   sc_lo1;         /* Was sc_badvaddr */
     42    target_ulong   sc_hi2;         /* Was sc_sigset[4] */
     43    target_ulong   sc_lo2;
     44    target_ulong   sc_hi3;
     45    target_ulong   sc_lo3;
     46};
     47# else /* N32 || N64 */
     48struct target_sigcontext {
     49    uint64_t sc_regs[32];
     50    uint64_t sc_fpregs[32];
     51    uint64_t sc_mdhi;
     52    uint64_t sc_hi1;
     53    uint64_t sc_hi2;
     54    uint64_t sc_hi3;
     55    uint64_t sc_mdlo;
     56    uint64_t sc_lo1;
     57    uint64_t sc_lo2;
     58    uint64_t sc_lo3;
     59    uint64_t sc_pc;
     60    uint32_t sc_fpc_csr;
     61    uint32_t sc_used_math;
     62    uint32_t sc_dsp;
     63    uint32_t sc_reserved;
     64};
     65# endif /* O32 */
     66
     67struct sigframe {
     68    uint32_t sf_ass[4];                 /* argument save space for o32 */
     69    uint32_t sf_code[2];                        /* signal trampoline */
     70    struct target_sigcontext sf_sc;
     71    target_sigset_t sf_mask;
     72};
     73
     74struct target_ucontext {
     75    abi_ulong tuc_flags;
     76    abi_ulong tuc_link;
     77    target_stack_t tuc_stack;
     78    struct target_sigcontext tuc_mcontext;
     79    target_sigset_t tuc_sigmask;
     80};
     81
     82struct target_rt_sigframe {
     83    uint32_t rs_ass[4];               /* argument save space for o32 */
     84    uint32_t rs_code[2];              /* signal trampoline */
     85    struct target_siginfo rs_info;
     86    struct target_ucontext rs_uc;
     87};
     88
     89/* Install trampoline to jump back from signal handler */
     90static void install_sigtramp(uint32_t *tramp, unsigned int syscall)
     91{
     92    /*
     93     * Set up the return code ...
     94     *
     95     *         li      v0, __NR__foo_sigreturn
     96     *         syscall
     97     */
     98
     99    __put_user(0x24020000 + syscall, tramp + 0);
    100    __put_user(0x0000000c          , tramp + 1);
    101}
    102
    103static inline void setup_sigcontext(CPUMIPSState *regs,
    104                                    struct target_sigcontext *sc)
    105{
    106    int i;
    107
    108    __put_user(exception_resume_pc(regs), &sc->sc_pc);
    109    regs->hflags &= ~MIPS_HFLAG_BMASK;
    110
    111    __put_user(0, &sc->sc_regs[0]);
    112    for (i = 1; i < 32; ++i) {
    113        __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
    114    }
    115
    116    __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
    117    __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
    118
    119    /* Rather than checking for dsp existence, always copy.  The storage
    120       would just be garbage otherwise.  */
    121    __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
    122    __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
    123    __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
    124    __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
    125    __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
    126    __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
    127    {
    128        uint32_t dsp = cpu_rddsp(0x3ff, regs);
    129        __put_user(dsp, &sc->sc_dsp);
    130    }
    131
    132    __put_user(1, &sc->sc_used_math);
    133
    134    for (i = 0; i < 32; ++i) {
    135        __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
    136    }
    137}
    138
    139static inline void
    140restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
    141{
    142    int i;
    143
    144    __get_user(regs->CP0_EPC, &sc->sc_pc);
    145
    146    __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
    147    __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
    148
    149    for (i = 1; i < 32; ++i) {
    150        __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
    151    }
    152
    153    __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
    154    __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
    155    __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
    156    __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
    157    __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
    158    __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
    159    {
    160        uint32_t dsp;
    161        __get_user(dsp, &sc->sc_dsp);
    162        cpu_wrdsp(dsp, 0x3ff, regs);
    163    }
    164
    165    for (i = 0; i < 32; ++i) {
    166        __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
    167    }
    168}
    169
    170/*
    171 * Determine which stack to use..
    172 */
    173static inline abi_ulong
    174get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
    175{
    176    unsigned long sp;
    177
    178    /*
    179     * FPU emulator may have its own trampoline active just
    180     * above the user stack, 16-bytes before the next lowest
    181     * 16 byte boundary.  Try to avoid trashing it.
    182     */
    183    sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka);
    184
    185    return (sp - frame_size) & ~7;
    186}
    187
    188static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
    189{
    190    if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
    191        env->hflags &= ~MIPS_HFLAG_M16;
    192        env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
    193        env->active_tc.PC &= ~(target_ulong) 1;
    194    }
    195}
    196
    197# if defined(TARGET_ABI_MIPSO32)
    198/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
    199void setup_frame(int sig, struct target_sigaction * ka,
    200                 target_sigset_t *set, CPUMIPSState *regs)
    201{
    202    struct sigframe *frame;
    203    abi_ulong frame_addr;
    204    int i;
    205
    206    frame_addr = get_sigframe(ka, regs, sizeof(*frame));
    207    trace_user_setup_frame(regs, frame_addr);
    208    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    209        goto give_sigsegv;
    210    }
    211
    212    setup_sigcontext(regs, &frame->sf_sc);
    213
    214    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
    215        __put_user(set->sig[i], &frame->sf_mask.sig[i]);
    216    }
    217
    218    /*
    219    * Arguments to signal handler:
    220    *
    221    *   a0 = signal number
    222    *   a1 = 0 (should be cause)
    223    *   a2 = pointer to struct sigcontext
    224    *
    225    * $25 and PC point to the signal handler, $29 points to the
    226    * struct sigframe.
    227    */
    228    regs->active_tc.gpr[ 4] = sig;
    229    regs->active_tc.gpr[ 5] = 0;
    230    regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
    231    regs->active_tc.gpr[29] = frame_addr;
    232    regs->active_tc.gpr[31] = default_sigreturn;
    233    /* The original kernel code sets CP0_EPC to the handler
    234    * since it returns to userland using eret
    235    * we cannot do this here, and we must set PC directly */
    236    regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
    237    mips_set_hflags_isa_mode_from_pc(regs);
    238    unlock_user_struct(frame, frame_addr, 1);
    239    return;
    240
    241give_sigsegv:
    242    force_sigsegv(sig);
    243}
    244
    245long do_sigreturn(CPUMIPSState *regs)
    246{
    247    struct sigframe *frame;
    248    abi_ulong frame_addr;
    249    sigset_t blocked;
    250    target_sigset_t target_set;
    251    int i;
    252
    253    frame_addr = regs->active_tc.gpr[29];
    254    trace_user_do_sigreturn(regs, frame_addr);
    255    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
    256        goto badframe;
    257
    258    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
    259        __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
    260    }
    261
    262    target_to_host_sigset_internal(&blocked, &target_set);
    263    set_sigmask(&blocked);
    264
    265    restore_sigcontext(regs, &frame->sf_sc);
    266
    267#if 0
    268    /*
    269     * Don't let your children do this ...
    270     */
    271    __asm__ __volatile__(
    272        "move\t$29, %0\n\t"
    273        "j\tsyscall_exit"
    274        :/* no outputs */
    275        :"r" (&regs));
    276    /* Unreached */
    277#endif
    278
    279    regs->active_tc.PC = regs->CP0_EPC;
    280    mips_set_hflags_isa_mode_from_pc(regs);
    281    /* I am not sure this is right, but it seems to work
    282    * maybe a problem with nested signals ? */
    283    regs->CP0_EPC = 0;
    284    return -TARGET_QEMU_ESIGRETURN;
    285
    286badframe:
    287    force_sig(TARGET_SIGSEGV);
    288    return -TARGET_QEMU_ESIGRETURN;
    289}
    290# endif /* O32 */
    291
    292void setup_rt_frame(int sig, struct target_sigaction *ka,
    293                    target_siginfo_t *info,
    294                    target_sigset_t *set, CPUMIPSState *env)
    295{
    296    struct target_rt_sigframe *frame;
    297    abi_ulong frame_addr;
    298    int i;
    299
    300    frame_addr = get_sigframe(ka, env, sizeof(*frame));
    301    trace_user_setup_rt_frame(env, frame_addr);
    302    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
    303        goto give_sigsegv;
    304    }
    305
    306    tswap_siginfo(&frame->rs_info, info);
    307
    308    __put_user(0, &frame->rs_uc.tuc_flags);
    309    __put_user(0, &frame->rs_uc.tuc_link);
    310    target_save_altstack(&frame->rs_uc.tuc_stack, env);
    311
    312    setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
    313
    314    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
    315        __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
    316    }
    317
    318    /*
    319    * Arguments to signal handler:
    320    *
    321    *   a0 = signal number
    322    *   a1 = pointer to siginfo_t
    323    *   a2 = pointer to ucontext_t
    324    *
    325    * $25 and PC point to the signal handler, $29 points to the
    326    * struct sigframe.
    327    */
    328    env->active_tc.gpr[ 4] = sig;
    329    env->active_tc.gpr[ 5] = frame_addr
    330                             + offsetof(struct target_rt_sigframe, rs_info);
    331    env->active_tc.gpr[ 6] = frame_addr
    332                             + offsetof(struct target_rt_sigframe, rs_uc);
    333    env->active_tc.gpr[29] = frame_addr;
    334    env->active_tc.gpr[31] = default_rt_sigreturn;
    335
    336    /*
    337     * The original kernel code sets CP0_EPC to the handler
    338     * since it returns to userland using eret
    339     * we cannot do this here, and we must set PC directly
    340     */
    341    env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
    342    mips_set_hflags_isa_mode_from_pc(env);
    343    unlock_user_struct(frame, frame_addr, 1);
    344    return;
    345
    346give_sigsegv:
    347    unlock_user_struct(frame, frame_addr, 1);
    348    force_sigsegv(sig);
    349}
    350
    351long do_rt_sigreturn(CPUMIPSState *env)
    352{
    353    struct target_rt_sigframe *frame;
    354    abi_ulong frame_addr;
    355    sigset_t blocked;
    356
    357    frame_addr = env->active_tc.gpr[29];
    358    trace_user_do_rt_sigreturn(env, frame_addr);
    359    if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
    360        goto badframe;
    361    }
    362
    363    target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
    364    set_sigmask(&blocked);
    365
    366    restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
    367    target_restore_altstack(&frame->rs_uc.tuc_stack, env);
    368
    369    env->active_tc.PC = env->CP0_EPC;
    370    mips_set_hflags_isa_mode_from_pc(env);
    371    /* I am not sure this is right, but it seems to work
    372    * maybe a problem with nested signals ? */
    373    env->CP0_EPC = 0;
    374    return -TARGET_QEMU_ESIGRETURN;
    375
    376badframe:
    377    force_sig(TARGET_SIGSEGV);
    378    return -TARGET_QEMU_ESIGRETURN;
    379}
    380
    381void setup_sigtramp(abi_ulong sigtramp_page)
    382{
    383    uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0);
    384    assert(tramp != NULL);
    385
    386#ifdef TARGET_ARCH_HAS_SETUP_FRAME
    387    default_sigreturn = sigtramp_page;
    388    install_sigtramp(tramp, TARGET_NR_sigreturn);
    389#endif
    390
    391    default_rt_sigreturn = sigtramp_page + 8;
    392    install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn);
    393
    394    unlock_user(tramp, sigtramp_page, 2 * 8);
    395}