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

seg_helper.c (3582B)


      1/*
      2 *  x86 segmentation related helpers (user-mode code):
      3 *  TSS, interrupts, system calls, jumps and call/task gates, descriptors
      4 *
      5 *  Copyright (c) 2003 Fabrice Bellard
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License as published by the Free Software Foundation; either
     10 * version 2.1 of the License, or (at your option) any later version.
     11 *
     12 * This library 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 GNU
     15 * Lesser General Public License for more details.
     16 *
     17 * You should have received a copy of the GNU Lesser General Public
     18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "cpu.h"
     23#include "exec/helper-proto.h"
     24#include "exec/exec-all.h"
     25#include "exec/cpu_ldst.h"
     26#include "tcg/helper-tcg.h"
     27#include "tcg/seg_helper.h"
     28
     29#ifdef TARGET_X86_64
     30void helper_syscall(CPUX86State *env, int next_eip_addend)
     31{
     32    CPUState *cs = env_cpu(env);
     33
     34    cs->exception_index = EXCP_SYSCALL;
     35    env->exception_is_int = 0;
     36    env->exception_next_eip = env->eip + next_eip_addend;
     37    cpu_loop_exit(cs);
     38}
     39#endif /* TARGET_X86_64 */
     40
     41/*
     42 * fake user mode interrupt. is_int is TRUE if coming from the int
     43 * instruction. next_eip is the env->eip value AFTER the interrupt
     44 * instruction. It is only relevant if is_int is TRUE or if intno
     45 * is EXCP_SYSCALL.
     46 */
     47static void do_interrupt_user(CPUX86State *env, int intno, int is_int,
     48                              int error_code, target_ulong next_eip)
     49{
     50    if (is_int) {
     51        SegmentCache *dt;
     52        target_ulong ptr;
     53        int dpl, cpl, shift;
     54        uint32_t e2;
     55
     56        dt = &env->idt;
     57        if (env->hflags & HF_LMA_MASK) {
     58            shift = 4;
     59        } else {
     60            shift = 3;
     61        }
     62        ptr = dt->base + (intno << shift);
     63        e2 = cpu_ldl_kernel(env, ptr + 4);
     64
     65        dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     66        cpl = env->hflags & HF_CPL_MASK;
     67        /* check privilege if software int */
     68        if (dpl < cpl) {
     69            raise_exception_err(env, EXCP0D_GPF, (intno << shift) + 2);
     70        }
     71    }
     72
     73    /* Since we emulate only user space, we cannot do more than
     74       exiting the emulation with the suitable exception and error
     75       code. So update EIP for INT 0x80 and EXCP_SYSCALL. */
     76    if (is_int || intno == EXCP_SYSCALL) {
     77        env->eip = next_eip;
     78    }
     79}
     80
     81void x86_cpu_do_interrupt(CPUState *cs)
     82{
     83    X86CPU *cpu = X86_CPU(cs);
     84    CPUX86State *env = &cpu->env;
     85
     86    /* if user mode only, we simulate a fake exception
     87       which will be handled outside the cpu execution
     88       loop */
     89    do_interrupt_user(env, cs->exception_index,
     90                      env->exception_is_int,
     91                      env->error_code,
     92                      env->exception_next_eip);
     93    /* successfully delivered */
     94    env->old_exception = -1;
     95}
     96
     97void cpu_x86_load_seg(CPUX86State *env, X86Seg seg_reg, int selector)
     98{
     99    if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
    100        int dpl = (env->eflags & VM_MASK) ? 3 : 0;
    101        selector &= 0xffff;
    102        cpu_x86_load_seg_cache(env, seg_reg, selector,
    103                               (selector << 4), 0xffff,
    104                               DESC_P_MASK | DESC_S_MASK | DESC_W_MASK |
    105                               DESC_A_MASK | (dpl << DESC_DPL_SHIFT));
    106    } else {
    107        helper_load_seg(env, seg_reg, selector);
    108    }
    109}