qemu/target/i386/hvf/x86.c
<<
>>
Prefs
   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 "x86_decode.h"
  23#include "x86_emu.h"
  24#include "vmcs.h"
  25#include "vmx.h"
  26#include "x86_mmu.h"
  27#include "x86_descr.h"
  28
  29/* static uint32_t x86_segment_access_rights(struct x86_segment_descriptor *var)
  30{
  31   uint32_t ar;
  32
  33   if (!var->p) {
  34       ar = 1 << 16;
  35       return ar;
  36   }
  37
  38   ar = var->type & 15;
  39   ar |= (var->s & 1) << 4;
  40   ar |= (var->dpl & 3) << 5;
  41   ar |= (var->p & 1) << 7;
  42   ar |= (var->avl & 1) << 12;
  43   ar |= (var->l & 1) << 13;
  44   ar |= (var->db & 1) << 14;
  45   ar |= (var->g & 1) << 15;
  46   return ar;
  47}*/
  48
  49bool x86_read_segment_descriptor(struct CPUState *cpu,
  50                                 struct x86_segment_descriptor *desc,
  51                                 x68_segment_selector sel)
  52{
  53    target_ulong base;
  54    uint32_t limit;
  55
  56    memset(desc, 0, sizeof(*desc));
  57
  58    /* valid gdt descriptors start from index 1 */
  59    if (!sel.index && GDT_SEL == sel.ti) {
  60        return false;
  61    }
  62
  63    if (GDT_SEL == sel.ti) {
  64        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
  65        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
  66    } else {
  67        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
  68        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
  69    }
  70
  71    if (sel.index * 8 >= limit) {
  72        return false;
  73    }
  74
  75    vmx_read_mem(cpu, desc, base + sel.index * 8, sizeof(*desc));
  76    return true;
  77}
  78
  79bool x86_write_segment_descriptor(struct CPUState *cpu,
  80                                  struct x86_segment_descriptor *desc,
  81                                  x68_segment_selector sel)
  82{
  83    target_ulong base;
  84    uint32_t limit;
  85    
  86    if (GDT_SEL == sel.ti) {
  87        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_BASE);
  88        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_GDTR_LIMIT);
  89    } else {
  90        base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_BASE);
  91        limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_LDTR_LIMIT);
  92    }
  93    
  94    if (sel.index * 8 >= limit) {
  95        printf("%s: gdt limit\n", __func__);
  96        return false;
  97    }
  98    vmx_write_mem(cpu, base + sel.index * 8, desc, sizeof(*desc));
  99    return true;
 100}
 101
 102bool x86_read_call_gate(struct CPUState *cpu, struct x86_call_gate *idt_desc,
 103                        int gate)
 104{
 105    target_ulong base  = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_BASE);
 106    uint32_t limit = rvmcs(cpu->hvf->fd, VMCS_GUEST_IDTR_LIMIT);
 107
 108    memset(idt_desc, 0, sizeof(*idt_desc));
 109    if (gate * 8 >= limit) {
 110        printf("%s: idt limit\n", __func__);
 111        return false;
 112    }
 113
 114    vmx_read_mem(cpu, idt_desc, base + gate * 8, sizeof(*idt_desc));
 115    return true;
 116}
 117
 118bool x86_is_protected(struct CPUState *cpu)
 119{
 120    uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
 121    return cr0 & CR0_PE_MASK;
 122}
 123
 124bool x86_is_real(struct CPUState *cpu)
 125{
 126    return !x86_is_protected(cpu);
 127}
 128
 129bool x86_is_v8086(struct CPUState *cpu)
 130{
 131    X86CPU *x86_cpu = X86_CPU(cpu);
 132    CPUX86State *env = &x86_cpu->env;
 133    return x86_is_protected(cpu) && (env->eflags & VM_MASK);
 134}
 135
 136bool x86_is_long_mode(struct CPUState *cpu)
 137{
 138    return rvmcs(cpu->hvf->fd, VMCS_GUEST_IA32_EFER) & MSR_EFER_LMA;
 139}
 140
 141bool x86_is_long64_mode(struct CPUState *cpu)
 142{
 143    struct vmx_segment desc;
 144    vmx_read_segment_descriptor(cpu, &desc, R_CS);
 145
 146    return x86_is_long_mode(cpu) && ((desc.ar >> 13) & 1);
 147}
 148
 149bool x86_is_paging_mode(struct CPUState *cpu)
 150{
 151    uint64_t cr0 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR0);
 152    return cr0 & CR0_PG_MASK;
 153}
 154
 155bool x86_is_pae_enabled(struct CPUState *cpu)
 156{
 157    uint64_t cr4 = rvmcs(cpu->hvf->fd, VMCS_GUEST_CR4);
 158    return cr4 & CR4_PAE_MASK;
 159}
 160
 161target_ulong linear_addr(struct CPUState *cpu, target_ulong addr, X86Seg seg)
 162{
 163    return vmx_read_segment_base(cpu, seg) + addr;
 164}
 165
 166target_ulong linear_addr_size(struct CPUState *cpu, target_ulong addr, int size,
 167                              X86Seg seg)
 168{
 169    switch (size) {
 170    case 2:
 171        addr = (uint16_t)addr;
 172        break;
 173    case 4:
 174        addr = (uint32_t)addr;
 175        break;
 176    default:
 177        break;
 178    }
 179    return linear_addr(cpu, addr, seg);
 180}
 181
 182target_ulong linear_rip(struct CPUState *cpu, target_ulong rip)
 183{
 184    return linear_addr(cpu, rip, R_CS);
 185}
 186