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

excp_helper.c (4782B)


      1/*
      2 *  x86 exception helpers
      3 *
      4 *  Copyright (c) 2003 Fabrice Bellard
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library 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 GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "cpu.h"
     22#include "exec/exec-all.h"
     23#include "qemu/log.h"
     24#include "sysemu/runstate.h"
     25#include "exec/helper-proto.h"
     26#include "helper-tcg.h"
     27
     28void QEMU_NORETURN helper_raise_interrupt(CPUX86State *env, int intno,
     29                                          int next_eip_addend)
     30{
     31    raise_interrupt(env, intno, 1, 0, next_eip_addend);
     32}
     33
     34void QEMU_NORETURN helper_raise_exception(CPUX86State *env, int exception_index)
     35{
     36    raise_exception(env, exception_index);
     37}
     38
     39/*
     40 * Check nested exceptions and change to double or triple fault if
     41 * needed. It should only be called, if this is not an interrupt.
     42 * Returns the new exception number.
     43 */
     44static int check_exception(CPUX86State *env, int intno, int *error_code,
     45                           uintptr_t retaddr)
     46{
     47    int first_contributory = env->old_exception == 0 ||
     48                              (env->old_exception >= 10 &&
     49                               env->old_exception <= 13);
     50    int second_contributory = intno == 0 ||
     51                               (intno >= 10 && intno <= 13);
     52
     53    qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
     54                env->old_exception, intno);
     55
     56#if !defined(CONFIG_USER_ONLY)
     57    if (env->old_exception == EXCP08_DBLE) {
     58        if (env->hflags & HF_GUEST_MASK) {
     59            cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */
     60        }
     61
     62        qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
     63
     64        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
     65        return EXCP_HLT;
     66    }
     67#endif
     68
     69    if ((first_contributory && second_contributory)
     70        || (env->old_exception == EXCP0E_PAGE &&
     71            (second_contributory || (intno == EXCP0E_PAGE)))) {
     72        intno = EXCP08_DBLE;
     73        *error_code = 0;
     74    }
     75
     76    if (second_contributory || (intno == EXCP0E_PAGE) ||
     77        (intno == EXCP08_DBLE)) {
     78        env->old_exception = intno;
     79    }
     80
     81    return intno;
     82}
     83
     84/*
     85 * Signal an interruption. It is executed in the main CPU loop.
     86 * is_int is TRUE if coming from the int instruction. next_eip is the
     87 * env->eip value AFTER the interrupt instruction. It is only relevant if
     88 * is_int is TRUE.
     89 */
     90static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
     91                                           int is_int, int error_code,
     92                                           int next_eip_addend,
     93                                           uintptr_t retaddr)
     94{
     95    CPUState *cs = env_cpu(env);
     96
     97    if (!is_int) {
     98        cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
     99                                      error_code, retaddr);
    100        intno = check_exception(env, intno, &error_code, retaddr);
    101    } else {
    102        cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr);
    103    }
    104
    105    cs->exception_index = intno;
    106    env->error_code = error_code;
    107    env->exception_is_int = is_int;
    108    env->exception_next_eip = env->eip + next_eip_addend;
    109    cpu_loop_exit_restore(cs, retaddr);
    110}
    111
    112/* shortcuts to generate exceptions */
    113
    114void QEMU_NORETURN raise_interrupt(CPUX86State *env, int intno, int is_int,
    115                                   int error_code, int next_eip_addend)
    116{
    117    raise_interrupt2(env, intno, is_int, error_code, next_eip_addend, 0);
    118}
    119
    120void QEMU_NORETURN raise_exception_err(CPUX86State *env, int exception_index,
    121                                       int error_code)
    122{
    123    raise_interrupt2(env, exception_index, 0, error_code, 0, 0);
    124}
    125
    126void QEMU_NORETURN raise_exception_err_ra(CPUX86State *env, int exception_index,
    127                                          int error_code, uintptr_t retaddr)
    128{
    129    raise_interrupt2(env, exception_index, 0, error_code, 0, retaddr);
    130}
    131
    132void QEMU_NORETURN raise_exception(CPUX86State *env, int exception_index)
    133{
    134    raise_interrupt2(env, exception_index, 0, 0, 0, 0);
    135}
    136
    137void QEMU_NORETURN raise_exception_ra(CPUX86State *env, int exception_index,
    138                                      uintptr_t retaddr)
    139{
    140    raise_interrupt2(env, exception_index, 0, 0, 0, retaddr);
    141}