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

exc_helper.c (8744B)


      1/*
      2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
      3 * All rights reserved.
      4 *
      5 * Redistribution and use in source and binary forms, with or without
      6 * modification, are permitted provided that the following conditions are met:
      7 *     * Redistributions of source code must retain the above copyright
      8 *       notice, this list of conditions and the following disclaimer.
      9 *     * Redistributions in binary form must reproduce the above copyright
     10 *       notice, this list of conditions and the following disclaimer in the
     11 *       documentation and/or other materials provided with the distribution.
     12 *     * Neither the name of the Open Source and Linux Lab nor the
     13 *       names of its contributors may be used to endorse or promote products
     14 *       derived from this software without specific prior written permission.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
     20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27
     28#include "qemu/osdep.h"
     29#include "qemu/main-loop.h"
     30#include "cpu.h"
     31#include "exec/helper-proto.h"
     32#include "qemu/host-utils.h"
     33#include "exec/exec-all.h"
     34
     35void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
     36{
     37    CPUState *cs = env_cpu(env);
     38
     39    cs->exception_index = excp;
     40    if (excp == EXCP_YIELD) {
     41        env->yield_needed = 0;
     42    }
     43    cpu_loop_exit(cs);
     44}
     45
     46void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
     47{
     48    uint32_t vector;
     49
     50    env->pc = pc;
     51    if (env->sregs[PS] & PS_EXCM) {
     52        if (env->config->ndepc) {
     53            env->sregs[DEPC] = pc;
     54        } else {
     55            env->sregs[EPC1] = pc;
     56        }
     57        vector = EXC_DOUBLE;
     58    } else {
     59        env->sregs[EPC1] = pc;
     60        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
     61    }
     62
     63    env->sregs[EXCCAUSE] = cause;
     64    env->sregs[PS] |= PS_EXCM;
     65
     66    HELPER(exception)(env, vector);
     67}
     68
     69void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
     70                                   uint32_t pc, uint32_t cause, uint32_t vaddr)
     71{
     72    env->sregs[EXCVADDR] = vaddr;
     73    HELPER(exception_cause)(env, pc, cause);
     74}
     75
     76void debug_exception_env(CPUXtensaState *env, uint32_t cause)
     77{
     78    if (xtensa_get_cintlevel(env) < env->config->debug_level) {
     79        HELPER(debug_exception)(env, env->pc, cause);
     80    }
     81}
     82
     83void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
     84{
     85    unsigned level = env->config->debug_level;
     86
     87    env->pc = pc;
     88    env->sregs[DEBUGCAUSE] = cause;
     89    env->sregs[EPC1 + level - 1] = pc;
     90    env->sregs[EPS2 + level - 2] = env->sregs[PS];
     91    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM |
     92        (level << PS_INTLEVEL_SHIFT);
     93    HELPER(exception)(env, EXC_DEBUG);
     94}
     95
     96#ifndef CONFIG_USER_ONLY
     97
     98void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
     99{
    100    CPUState *cpu = env_cpu(env);
    101
    102    env->pc = pc;
    103    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
    104        (intlevel << PS_INTLEVEL_SHIFT);
    105
    106    qemu_mutex_lock_iothread();
    107    check_interrupts(env);
    108    qemu_mutex_unlock_iothread();
    109
    110    if (env->pending_irq_level) {
    111        cpu_loop_exit(cpu);
    112        return;
    113    }
    114
    115    cpu->halted = 1;
    116    HELPER(exception)(env, EXCP_HLT);
    117}
    118
    119void HELPER(check_interrupts)(CPUXtensaState *env)
    120{
    121    qemu_mutex_lock_iothread();
    122    check_interrupts(env);
    123    qemu_mutex_unlock_iothread();
    124}
    125
    126void HELPER(intset)(CPUXtensaState *env, uint32_t v)
    127{
    128    qatomic_or(&env->sregs[INTSET],
    129              v & env->config->inttype_mask[INTTYPE_SOFTWARE]);
    130}
    131
    132static void intclear(CPUXtensaState *env, uint32_t v)
    133{
    134    qatomic_and(&env->sregs[INTSET], ~v);
    135}
    136
    137void HELPER(intclear)(CPUXtensaState *env, uint32_t v)
    138{
    139    intclear(env, v & (env->config->inttype_mask[INTTYPE_SOFTWARE] |
    140                       env->config->inttype_mask[INTTYPE_EDGE]));
    141}
    142
    143static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
    144{
    145    if (xtensa_option_enabled(env->config,
    146                              XTENSA_OPTION_RELOCATABLE_VECTOR)) {
    147        return vector - env->config->vecbase + env->sregs[VECBASE];
    148    } else {
    149        return vector;
    150    }
    151}
    152
    153/*!
    154 * Handle penging IRQ.
    155 * For the high priority interrupt jump to the corresponding interrupt vector.
    156 * For the level-1 interrupt convert it to either user, kernel or double
    157 * exception with the 'level-1 interrupt' exception cause.
    158 */
    159static void handle_interrupt(CPUXtensaState *env)
    160{
    161    int level = env->pending_irq_level;
    162
    163    if ((level > xtensa_get_cintlevel(env) &&
    164         level <= env->config->nlevel &&
    165         (env->config->level_mask[level] &
    166          env->sregs[INTSET] & env->sregs[INTENABLE])) ||
    167        level == env->config->nmi_level) {
    168        CPUState *cs = env_cpu(env);
    169
    170        if (level > 1) {
    171            env->sregs[EPC1 + level - 1] = env->pc;
    172            env->sregs[EPS2 + level - 2] = env->sregs[PS];
    173            env->sregs[PS] =
    174                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
    175            env->pc = relocated_vector(env,
    176                                       env->config->interrupt_vector[level]);
    177            if (level == env->config->nmi_level) {
    178                intclear(env, env->config->inttype_mask[INTTYPE_NMI]);
    179            }
    180        } else {
    181            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
    182
    183            if (env->sregs[PS] & PS_EXCM) {
    184                if (env->config->ndepc) {
    185                    env->sregs[DEPC] = env->pc;
    186                } else {
    187                    env->sregs[EPC1] = env->pc;
    188                }
    189                cs->exception_index = EXC_DOUBLE;
    190            } else {
    191                env->sregs[EPC1] = env->pc;
    192                cs->exception_index =
    193                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
    194            }
    195            env->sregs[PS] |= PS_EXCM;
    196        }
    197    }
    198}
    199
    200/* Called from cpu_handle_interrupt with BQL held */
    201void xtensa_cpu_do_interrupt(CPUState *cs)
    202{
    203    XtensaCPU *cpu = XTENSA_CPU(cs);
    204    CPUXtensaState *env = &cpu->env;
    205
    206    if (cs->exception_index == EXC_IRQ) {
    207        qemu_log_mask(CPU_LOG_INT,
    208                      "%s(EXC_IRQ) level = %d, cintlevel = %d, "
    209                      "pc = %08x, a0 = %08x, ps = %08x, "
    210                      "intset = %08x, intenable = %08x, "
    211                      "ccount = %08x\n",
    212                      __func__, env->pending_irq_level,
    213                      xtensa_get_cintlevel(env),
    214                      env->pc, env->regs[0], env->sregs[PS],
    215                      env->sregs[INTSET], env->sregs[INTENABLE],
    216                      env->sregs[CCOUNT]);
    217        handle_interrupt(env);
    218    }
    219
    220    switch (cs->exception_index) {
    221    case EXC_WINDOW_OVERFLOW4:
    222    case EXC_WINDOW_UNDERFLOW4:
    223    case EXC_WINDOW_OVERFLOW8:
    224    case EXC_WINDOW_UNDERFLOW8:
    225    case EXC_WINDOW_OVERFLOW12:
    226    case EXC_WINDOW_UNDERFLOW12:
    227    case EXC_KERNEL:
    228    case EXC_USER:
    229    case EXC_DOUBLE:
    230    case EXC_DEBUG:
    231        qemu_log_mask(CPU_LOG_INT, "%s(%d) "
    232                      "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
    233                      __func__, cs->exception_index,
    234                      env->pc, env->regs[0], env->sregs[PS],
    235                      env->sregs[CCOUNT]);
    236        if (env->config->exception_vector[cs->exception_index]) {
    237            uint32_t vector;
    238
    239            vector = env->config->exception_vector[cs->exception_index];
    240            env->pc = relocated_vector(env, vector);
    241        } else {
    242            qemu_log_mask(CPU_LOG_INT,
    243                          "%s(pc = %08x) bad exception_index: %d\n",
    244                          __func__, env->pc, cs->exception_index);
    245        }
    246        break;
    247
    248    case EXC_IRQ:
    249        break;
    250
    251    default:
    252        qemu_log("%s(pc = %08x) unknown exception_index: %d\n",
    253                 __func__, env->pc, cs->exception_index);
    254        break;
    255    }
    256    check_interrupts(env);
    257}
    258
    259bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
    260{
    261    if (interrupt_request & CPU_INTERRUPT_HARD) {
    262        cs->exception_index = EXC_IRQ;
    263        xtensa_cpu_do_interrupt(cs);
    264        return true;
    265    }
    266    return false;
    267}
    268
    269#endif /* !CONFIG_USER_ONLY */