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

x86.c (4925B)


      1/*
      2 * Copyright (C) 2016 Veertu Inc,
      3 * Copyright (C) 2017 Google Inc,
      4 *
      5 * This program is free software; you can redistribute it and/or
      6 * modify it under the terms of the GNU Lesser General Public
      7 * License as published by the Free Software Foundation; either
      8 * version 2.1 of the License, or (at your option) any later version.
      9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13 * Lesser General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU Lesser General Public
     16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
     17 */
     18
     19#include "qemu/osdep.h"
     20
     21#include "cpu.h"
     22#include "qemu-common.h"
     23#include "x86_decode.h"
     24#include "x86_emu.h"
     25#include "vmcs.h"
     26#include "vmx.h"
     27#include "x86_mmu.h"
     28#include "x86_descr.h"
     29
     30/* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var)
     31{
     32   uint32_t ar;
     33
     34   if (!var->p) {
     35       ar = 1 << 16;
     36       return ar;
     37   }
     38
     39   ar = var->type & 15;
     40   ar |= (var->s & 1) << 4;
     41   ar |= (var->dpl & 3) << 5;
     42   ar |= (var->p & 1) << 7;
     43   ar |= (var->avl & 1) << 12;
     44   ar |= (var->l & 1) << 13;
     45   ar |= (var->db & 1) << 14;
     46   ar |= (var->g & 1) << 15;
     47   return ar;
     48}*/
     49
     50bool x86_read_segment_descriptor(struct CPUState *cpu,
     51                                 struct x86_segment_descriptor *desc,
     52                                 x68_segment_selector sel)
     53{
     54    target_ulong base;
     55    uint32_t limit;
     56
     57    memset(desc, 0, sizeof(*desc));
     58
     59    /* valid gdt descriptors start from index 1 */
     60    if (!sel.index && GDT_SEL == sel.ti) {
     61        return false;
     62    }
     63
     64    if (GDT_SEL == sel.ti) {
     65        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
     66        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
     67    } else {
     68        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
     69        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
     70    }
     71
     72    if (sel.index * 8 >= limit) {
     73        return false;
     74    }
     75
     76    vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc));
     77    return true;
     78}
     79
     80bool x86_write_segment_descriptor(struct CPUState *cpu,
     81                                  struct x86_segment_descriptor *desc,
     82                                  x68_segment_selector sel)
     83{
     84    target_ulong base;
     85    uint32_t limit;
     86    
     87    if (GDT_SEL == sel.ti) {
     88        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
     89        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
     90    } else {
     91        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
     92        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
     93    }
     94    
     95    if (sel.index * 8 >= limit) {
     96        printf("%s: gdt limit\n", __func__);
     97        return false;
     98    }
     99    vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc));
    100    return true;
    101}
    102
    103bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
    104                        int gate)
    105{
    106    target_ulong base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_BASE);
    107    uint32_t limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_LIMIT);
    108
    109    memset(idt_desc, 0, sizeof(*idt_desc));
    110    if (gate * 8 >= limit) {
    111        printf("%s: idt limit\n", __func__);
    112        return false;
    113    }
    114
    115    vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc));
    116    return true;
    117}
    118
    119bool x86_is_protected(struct CPUState *cpu)
    120{
    121    uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
    122    return cr0 & CR0_PE;
    123}
    124
    125bool x86_is_real(struct CPUState *cpu)
    126{
    127    return !x86_is_protected(cpu);
    128}
    129
    130bool x86_is_v8086(struct CPUState *cpu)
    131{
    132    X86CPU *x86_cpu = X86_CPU(cpu);
    133    CPUX86State *env = &x86_cpu->env;
    134    return x86_is_protected(cpu) && (env->eflags & VM_MASK);
    135}
    136
    137bool x86_is_long_mode(struct CPUState *cpu)
    138{
    139    return rvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
    140}
    141
    142bool x86_is_long64_mode(struct CPUState *cpu)
    143{
    144    struct vmx_segment desc;
    145    vmx_read_segment_descriptor(cpu, &desc, R_CS);
    146
    147    return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
    148}
    149
    150bool x86_is_paging_mode(struct CPUState *cpu)
    151{
    152    uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
    153    return cr0 & CR0_PG;
    154}
    155
    156bool x86_is_pae_enabled(struct CPUState *cpu)
    157{
    158    uint64_t cr4 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR4);
    159    return cr4 & CR4_PAE;
    160}
    161
    162target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, X86Seg seg)
    163{
    164    return vmx_read_segment_base(cpu, seg) + addr;
    165}
    166
    167target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size,
    168                              X86Seg seg)
    169{
    170    switch (size) {
    171    case 2:
    172        addr = (uint16_t)addr;
    173        break;
    174    case 4:
    175        addr = (uint32_t)addr;
    176        break;
    177    default:
    178        break;
    179    }
    180    return linear_addr(cpu, addr, seg);
    181}
    182
    183target_ulong linear_rip(struct CPUState *cpu, target_ulong rip)
    184{
    185    return linear_addr(cpu, rip, R_CS);
    186}