2009-01-31 13:43:24 +03:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2009-10-08 18:33:08 +04:00
|
|
|
|
// $Id: vmx.cc,v 1.26 2009-10-08 14:33:08 sshwarts Exp $
|
2009-01-31 13:43:24 +03:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Copyright (c) 2009 Stanislav Shwartsman
|
|
|
|
|
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
|
|
|
|
//
|
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
|
|
|
|
#include "bochs.h"
|
|
|
|
|
#include "cpu.h"
|
|
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
|
|
|
|
|
|
|
|
|
#include "iodev/iodev.h"
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64==0
|
|
|
|
|
#define RIP EIP
|
|
|
|
|
#define RSP ESP
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
|
|
|
|
|
#define VMCSPTR_VALID() (BX_CPU_THIS_PTR vmcsptr != BX_INVALID_VMCSPTR)
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// VMCS access
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static unsigned vmcs_map[16][1+VMX_HIGHEST_VMCS_ENCODING];
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::init_VMCS(void)
|
|
|
|
|
{
|
|
|
|
|
static bx_bool vmcs_map_ready = 0;
|
|
|
|
|
|
|
|
|
|
if (vmcs_map_ready) return;
|
|
|
|
|
vmcs_map_ready = 1;
|
|
|
|
|
|
|
|
|
|
for (unsigned type=0; type<16; type++) {
|
|
|
|
|
for (unsigned field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
|
2009-03-28 16:42:09 +03:00
|
|
|
|
vmcs_map[type][field] = 0xffffffff;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-28 16:42:09 +03:00
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
// try to build generic VMCS map
|
2009-01-31 13:43:24 +03:00
|
|
|
|
for (unsigned type=0; type<16; type++) {
|
|
|
|
|
for (unsigned field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
|
2009-03-28 16:42:09 +03:00
|
|
|
|
// allocate 32 fields of 4 byte each per type
|
|
|
|
|
if (vmcs_map[type][field] != 0xffffffff) {
|
|
|
|
|
BX_PANIC(("VMCS type %d field %d is already initialized", type, field));
|
|
|
|
|
}
|
|
|
|
|
vmcs_map[type][field] = VMCS_DATA_OFFSET + (type*64 + field) * 4;
|
|
|
|
|
if(vmcs_map[type][field] >= VMX_VMCS_AREA_SIZE) {
|
|
|
|
|
BX_PANIC(("VMCS type %d field %d is out of VMCS boundaries", type, field));
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-03-28 16:42:09 +03:00
|
|
|
|
#else
|
2009-01-31 13:43:24 +03:00
|
|
|
|
// define your own VMCS format
|
|
|
|
|
#include "vmcs.h"
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
void BX_CPU_C::set_VMCSPTR(Bit64u vmxptr)
|
|
|
|
|
{
|
|
|
|
|
BX_CPU_THIS_PTR vmcsptr = vmxptr;
|
|
|
|
|
|
|
|
|
|
if (vmxptr != BX_INVALID_VMCSPTR)
|
|
|
|
|
BX_CPU_THIS_PTR vmcshostptr = (bx_hostpageaddr_t) BX_MEM(0)->getHostMemAddr(BX_CPU_THIS, vmxptr, BX_WRITE);
|
|
|
|
|
else
|
|
|
|
|
BX_CPU_THIS_PTR vmcshostptr = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
Bit16u BX_CPU_C::VMread16(unsigned encoding)
|
|
|
|
|
{
|
|
|
|
|
Bit16u field;
|
|
|
|
|
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMread16: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
|
|
|
|
BX_ASSERT(VMCS_FIELD_WIDTH(encoding) == VMCS_FIELD_WIDTH_16BIT);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit16u *hostAddr = (Bit16u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
ReadHostDWordFromLittleEndian(hostAddr, field);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_read_physical(pAddr, 2, (Bit8u*)(&field));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_READ, (Bit8u*)(&field));
|
|
|
|
|
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write 16-bit value into VMCS 16-bit field
|
|
|
|
|
void BX_CPU_C::VMwrite16(unsigned encoding, Bit16u val_16)
|
|
|
|
|
{
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMwrite16: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
|
|
|
|
BX_ASSERT(VMCS_FIELD_WIDTH(encoding) == VMCS_FIELD_WIDTH_16BIT);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit16u *hostAddr = (Bit16u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
pageWriteStampTable.decWriteStamp(pAddr);
|
|
|
|
|
WriteHostWordToLittleEndian(hostAddr, val_16);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_write_physical(pAddr, 2, (Bit8u*)(&val_16));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_WRITE, (Bit8u*)(&val_16));
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit32u BX_CPU_C::VMread32(unsigned encoding)
|
|
|
|
|
{
|
|
|
|
|
Bit32u field;
|
|
|
|
|
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMread32: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit32u *hostAddr = (Bit32u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
ReadHostDWordFromLittleEndian(hostAddr, field);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_read_physical(pAddr, 4, (Bit8u*)(&field));
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_READ, (Bit8u*)(&field));
|
|
|
|
|
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write 32-bit value into VMCS field
|
|
|
|
|
void BX_CPU_C::VMwrite32(unsigned encoding, Bit32u val_32)
|
|
|
|
|
{
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMwrite32: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit32u *hostAddr = (Bit32u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
pageWriteStampTable.decWriteStamp(pAddr);
|
|
|
|
|
WriteHostDWordToLittleEndian(hostAddr, val_32);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_write_physical(pAddr, 4, (Bit8u*)(&val_32));
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_WRITE, (Bit8u*)(&val_32));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit64u BX_CPU_C::VMread64(unsigned encoding)
|
|
|
|
|
{
|
|
|
|
|
BX_ASSERT(!IS_VMCS_FIELD_HI(encoding));
|
|
|
|
|
|
|
|
|
|
Bit64u field;
|
|
|
|
|
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMread64: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit64u *hostAddr = (Bit64u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
ReadHostQWordFromLittleEndian(hostAddr, field);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_read_physical(pAddr, 8, (Bit8u*)(&field));
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_READ, (Bit8u*)(&field));
|
|
|
|
|
|
|
|
|
|
return field;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write 64-bit value into VMCS field
|
|
|
|
|
void BX_CPU_C::VMwrite64(unsigned encoding, Bit64u val_64)
|
|
|
|
|
{
|
|
|
|
|
BX_ASSERT(!IS_VMCS_FIELD_HI(encoding));
|
|
|
|
|
|
|
|
|
|
unsigned offset = vmcs_map[VMCS_FIELD_INDEX(encoding)][VMCS_FIELD(encoding)];
|
|
|
|
|
if(offset >= VMX_VMCS_AREA_SIZE)
|
|
|
|
|
BX_PANIC(("VMwrite64: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + offset;
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
if (BX_CPU_THIS_PTR vmcshostptr) {
|
|
|
|
|
Bit64u *hostAddr = (Bit64u*) (BX_CPU_THIS_PTR vmcshostptr | offset);
|
|
|
|
|
pageWriteStampTable.decWriteStamp(pAddr);
|
|
|
|
|
WriteHostQWordToLittleEndian(hostAddr, val_64);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
access_write_physical(pAddr, 8, (Bit8u*)(&val_64));
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_WRITE, (Bit8u*)(&val_64));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// VMfail/VMsucceed
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
BX_CPP_INLINE void BX_CPU_C::VMsucceed(void)
|
|
|
|
|
{
|
|
|
|
|
setEFlagsOSZAPC(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_CPP_INLINE void BX_CPU_C::VMfailInvalid(void)
|
|
|
|
|
{
|
|
|
|
|
setEFlagsOSZAPC(EFlagsCFMask);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_CPP_INLINE void BX_CPU_C::VMfail(Bit32u error_code)
|
|
|
|
|
{
|
|
|
|
|
if (VMCSPTR_VALID()) { // executed only if there is a current VMCS
|
|
|
|
|
setEFlagsOSZAPC(EFlagsZFMask);
|
|
|
|
|
VMwrite32(VMCS_32BIT_INSTRUCTION_ERROR, error_code);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
setEFlagsOSZAPC(EFlagsCFMask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMabort(VMX_vmabort_code error_code)
|
|
|
|
|
{
|
|
|
|
|
Bit32u abort = error_code;
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + VMCS_VMX_ABORT_FIELD_ADDR;
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_write_physical(pAddr, 4, &abort);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_WRITE, (Bit8u*)(&abort));
|
|
|
|
|
shutdown();
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-06 14:21:49 +04:00
|
|
|
|
unsigned BX_CPU_C::VMXReadRevisionID(bx_phy_address pAddr)
|
|
|
|
|
{
|
|
|
|
|
Bit32u revision;
|
|
|
|
|
access_read_physical(pAddr + VMCS_REVISION_ID_FIELD_ADDR, 4, &revision);
|
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr + VMCS_REVISION_ID_FIELD_ADDR, 4,
|
|
|
|
|
BX_READ, (Bit8u*)(&revision));
|
|
|
|
|
|
|
|
|
|
return revision;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// VMenter
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
2009-02-20 11:12:51 +03:00
|
|
|
|
extern struct BxExceptionInfo exceptions_info[];
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
#define VMENTRY_INJECTING_EVENT(vmentry_interr_info) (vmentry_interr_info & 0x80000000)
|
|
|
|
|
|
|
|
|
|
VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
|
|
|
|
{
|
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load VM-execution control fields to VMCS Cache
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
vm->vmexec_ctrls1 = VMread32(VMCS_32BIT_CONTROL_PIN_BASED_EXEC_CONTROLS);
|
|
|
|
|
vm->vmexec_ctrls2 = VMread32(VMCS_32BIT_CONTROL_PROCESSOR_BASED_EXEC_CONTROLS);
|
|
|
|
|
vm->vm_exceptions_bitmap = VMread32(VMCS_32BIT_CONTROL_EXECUTION_BITMAP);
|
|
|
|
|
vm->vm_pf_mask = VMread32(VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MASK);
|
|
|
|
|
vm->vm_pf_match = VMread32(VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MATCH);
|
|
|
|
|
vm->io_bitmap_addr[0] = VMread64(VMCS_64BIT_CONTROL_IO_BITMAP_A);
|
|
|
|
|
vm->io_bitmap_addr[1] = VMread64(VMCS_64BIT_CONTROL_IO_BITMAP_B);
|
|
|
|
|
vm->tsc_offset = VMread64(VMCS_64BIT_CONTROL_TSC_OFFSET);
|
|
|
|
|
vm->msr_bitmap_addr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_MSR_BITMAPS);
|
|
|
|
|
vm->vm_cr0_mask = VMread64(VMCS_CONTROL_CR0_GUEST_HOST_MASK);
|
|
|
|
|
vm->vm_cr4_mask = VMread64(VMCS_CONTROL_CR4_GUEST_HOST_MASK);
|
|
|
|
|
vm->vm_cr0_read_shadow = VMread64(VMCS_CONTROL_CR0_READ_SHADOW);
|
|
|
|
|
vm->vm_cr4_read_shadow = VMread64(VMCS_CONTROL_CR4_READ_SHADOW);
|
|
|
|
|
|
|
|
|
|
vm->vm_cr3_target_cnt = VMread32(VMCS_32BIT_CONTROL_CR3_TARGET_COUNT);
|
|
|
|
|
for (int n=0; n<VMX_CR3_TARGET_MAX_CNT; n++)
|
|
|
|
|
vm->vm_cr3_target_value[n] = VMread64(VMCS_CR3_TARGET0 + 2*n);
|
|
|
|
|
|
|
|
|
|
vm->vm_tpr_threshold = VMread32(VMCS_32BIT_CONTROL_TPR_THRESHOLD);
|
|
|
|
|
vm->virtual_apic_page_addr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR);
|
2009-05-30 19:09:38 +04:00
|
|
|
|
vm->executive_vmcsptr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check VM-execution control fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (~vm->vmexec_ctrls1 & VMX_MSR_VMX_PINBASED_CTRLS_LO) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX pin-based controls allowed 0-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls1 & ~VMX_MSR_VMX_PINBASED_CTRLS_HI) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX pin-based controls allowed 1-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (~vm->vmexec_ctrls2 & VMX_MSR_VMX_PROCBASED_CTRLS_LO) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX proc-based controls allowed 0-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls2 & ~VMX_MSR_VMX_PROCBASED_CTRLS_HI) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX proc-based controls allowed 1-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vm_cr3_target_cnt > VMX_CR3_TARGET_MAX_CNT) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: too may CR3 targets %d", vm->vm_cr3_target_cnt));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_IO_BITMAPS) {
|
|
|
|
|
// I/O bitmaps control enabled
|
|
|
|
|
for (int bitmap=0; bitmap < 2; bitmap++) {
|
|
|
|
|
if (vm->io_bitmap_addr[bitmap] & 0xfff) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: I/O bitmap %c must be 4K aligned", 'A' + bitmap));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (! IsValidPhyAddr(vm->io_bitmap_addr[bitmap])) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: I/O bitmap %c phy addr malformed", 'A' + bitmap));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_MSR_BITMAPS) {
|
|
|
|
|
// MSR bitmaps control enabled
|
|
|
|
|
if ((vm->msr_bitmap_addr & 0xfff) != 0 || ! IsValidPhyAddr(vm->msr_bitmap_addr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: MSR bitmap phy addr malformed"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! (vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VIRTUAL_NMI)) {
|
|
|
|
|
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_NMI_WINDOW_VMEXIT) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: misconfigured virtual NMI control"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_TPR_SHADOW) {
|
|
|
|
|
if ((vm->virtual_apic_page_addr & 0xfff) != 0 || ! IsValidPhyAddr(vm->virtual_apic_page_addr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: virtual apic phy addr malformed"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
2009-09-30 09:57:21 +04:00
|
|
|
|
|
|
|
|
|
if (vm->vm_tpr_threshold & 0xfffffff0) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: TPR threshold too big"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vm_tpr_threshold > VMX_Read_TPR_Shadow()) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: TPR threshold > TPR shadow"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
VM entries perform the following checks on the VM-execution control fields:
|
|
|
|
|
|
|
|
|
|
If the "use TPR shadow" VM-execution control is 1, the virtual-APIC address must
|
|
|
|
|
satisfy the following checks:
|
|
|
|
|
The following items describe the treatment of bytes 81H-83H on the virtual-
|
|
|
|
|
APIC page (see Section 20.6.8) if all of the above checks are satisfied and the
|
|
|
|
|
"use TPR shadow" VM-execution control is 1, treatment depends upon the
|
|
|
|
|
setting of the "virtualize APIC accesses" VM-execution control:2
|
|
|
|
|
- If the "virtualize APIC accesses" VM-execution control is 0, the bytes may be
|
|
|
|
|
cleared. (If the bytes are not cleared, they are left unmodified.)
|
|
|
|
|
- If the "virtualize APIC accesses" VM-execution control is 1, the bytes are
|
|
|
|
|
cleared.
|
|
|
|
|
- Any clearing of the bytes occurs even if the VM entry subsequently fails.
|
|
|
|
|
If the "use TPR shadow" VM-execution control is 1, bits 31:4 of the TPR threshold
|
|
|
|
|
VM-execution control field must be 0.
|
|
|
|
|
The following check is performed if the "use TPR shadow" VM-execution control is
|
|
|
|
|
1 and the "virtualize APIC accesses" VM-execution control is 0: the value of
|
|
|
|
|
bits 3:0 of the TPR threshold VM-execution control field should not be greater
|
|
|
|
|
than the value of bits 7:4 in byte 80H on the virtual-APIC page (see Section
|
|
|
|
|
20.6.8).
|
|
|
|
|
If the "virtualize APIC-accesses" VM-execution control is 1, the APIC-access
|
|
|
|
|
address must satisfy the following checks:
|
|
|
|
|
- Bits 11:0 of the address must be 0.
|
|
|
|
|
- On processors that support Intel 64 architecture, the address should not set
|
|
|
|
|
any bits beyond the processor's physical-address width.
|
|
|
|
|
- On processors that support the IA-32 architecture, the address should not set
|
|
|
|
|
any bits in the range 63:32.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load VM-exit control fields to VMCS Cache
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
vm->vmexit_ctrls = VMread32(VMCS_32BIT_CONTROL_VMEXIT_CONTROLS);
|
|
|
|
|
vm->vmexit_msr_store_cnt = VMread32(VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT);
|
|
|
|
|
vm->vmexit_msr_store_addr = VMread64(VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR);
|
|
|
|
|
vm->vmexit_msr_load_cnt = VMread32(VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT);
|
|
|
|
|
vm->vmexit_msr_load_addr = VMread64(VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check VM-exit control fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (~vm->vmexit_ctrls & VMX_MSR_VMX_VMEXIT_CTRLS_LO) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit controls allowed 0-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexit_ctrls & ~VMX_MSR_VMX_VMEXIT_CTRLS_HI) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit controls allowed 1-settings"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexit_msr_store_cnt > 0) {
|
|
|
|
|
if ((vm->vmexit_msr_store_addr & 0xf) != 0 || ! IsValidPhyAddr(vm->vmexit_msr_store_addr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMEXIT CTRL: msr store addr malformed"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit64u last_byte = vm->vmexit_msr_store_addr + (vm->vmexit_msr_store_cnt * 16) - 1;
|
|
|
|
|
if (! IsValidPhyAddr(last_byte)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMEXIT CTRL: msr store addr too high"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmexit_msr_load_cnt > 0) {
|
|
|
|
|
if ((vm->vmexit_msr_load_addr & 0xf) != 0 || ! IsValidPhyAddr(vm->vmexit_msr_load_addr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMEXIT CTRL: msr load addr malformed"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit64u last_byte = (Bit64u) vm->vmexit_msr_load_addr + (vm->vmexit_msr_load_cnt * 16) - 1;
|
|
|
|
|
if (! IsValidPhyAddr(last_byte)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMEXIT CTRL: msr load addr too high"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load VM-entry control fields to VMCS Cache
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
vm->vmentry_ctrls = VMread32(VMCS_32BIT_CONTROL_VMENTRY_CONTROLS);
|
|
|
|
|
vm->vmentry_msr_load_cnt = VMread32(VMCS_32BIT_CONTROL_VMENTRY_MSR_LOAD_COUNT);
|
|
|
|
|
vm->vmentry_msr_load_addr = VMread64(VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check VM-entry control fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
if (~vm->vmentry_ctrls & VMX_MSR_VMX_VMENTRY_CTRLS_LO) {
|
2009-05-21 14:39:40 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmentry controls allowed 0-settings"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vm->vmentry_ctrls & ~VMX_MSR_VMX_VMENTRY_CTRLS_HI) {
|
2009-05-21 14:39:40 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmentry controls allowed 1-settings"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-30 19:09:38 +04:00
|
|
|
|
if (vm->vmentry_ctrls & VMX_VMENTRY_CTRL1_DEACTIVATE_DUAL_MONITOR_TREATMENT) {
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_smm) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY from outside SMM with dual-monitor treatment enabled"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (vm->vmentry_msr_load_cnt > 0) {
|
|
|
|
|
if ((vm->vmentry_msr_load_addr & 0xf) != 0 || ! IsValidPhyAddr(vm->vmentry_msr_load_addr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMENTRY CTRL: msr load addr malformed"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit64u last_byte = vm->vmentry_msr_load_addr + (vm->vmentry_msr_load_cnt * 16) - 1;
|
|
|
|
|
if (! IsValidPhyAddr(last_byte)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS VMENTRY CTRL: msr load addr too high"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Check VM-entry event injection info
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
vm->vmentry_interr_info = VMread32(VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO);
|
|
|
|
|
vm->vmentry_excep_err_code = VMread32(VMCS_32BIT_CONTROL_VMENTRY_EXCEPTION_ERR_CODE);
|
|
|
|
|
vm->vmentry_instr_length = VMread32(VMCS_32BIT_CONTROL_VMENTRY_INSTRUCTION_LENGTH);
|
|
|
|
|
|
|
|
|
|
if (VMENTRY_INJECTING_EVENT(vm->vmentry_interr_info)) {
|
|
|
|
|
|
|
|
|
|
/* the VMENTRY injecting event to the guest */
|
|
|
|
|
unsigned vector = vm->vmentry_interr_info & 0xff;
|
|
|
|
|
unsigned event_type = (vm->vmentry_interr_info >> 8) & 7;
|
|
|
|
|
unsigned push_error = (vm->vmentry_interr_info >> 11) & 1;
|
|
|
|
|
unsigned error_code = push_error ? vm->vmentry_excep_err_code : 0;
|
|
|
|
|
|
|
|
|
|
unsigned push_error_reference = 0;
|
|
|
|
|
if (event_type == BX_HARDWARE_EXCEPTION && vector < BX_CPU_HANDLED_EXCEPTIONS &&
|
|
|
|
|
exceptions_info[vector].push_error) push_error_reference = 1;
|
|
|
|
|
|
|
|
|
|
if (vm->vmentry_interr_info & 0x7ffff000) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY broken interruption info field"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (event_type) {
|
|
|
|
|
case BX_EXTERNAL_INTERRUPT:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BX_NMI:
|
|
|
|
|
if (vector != 2) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad injected event vector %d", vector));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BX_HARDWARE_EXCEPTION:
|
|
|
|
|
if (vector > 31) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad injected event vector %d", vector));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BX_SOFTWARE_INTERRUPT:
|
|
|
|
|
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
|
|
|
|
|
case BX_SOFTWARE_EXCEPTION:
|
|
|
|
|
if (vm->vmentry_instr_length == 0 || vm->vmentry_instr_length > 15) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad injected event instr length"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad injected event type %d", event_type));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (push_error != push_error_reference) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad injected event vector %d", vector));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (error_code & 0x7fff0000) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMENTRY bad error code 0x%08x for injected event %d", error_code, vector));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return VMXERR_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VMX_error_code BX_CPU_C::VMenterLoadCheckHostState(void)
|
|
|
|
|
{
|
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
VMCS_HOST_STATE *host_state = &vm->host_state;
|
|
|
|
|
bx_bool x86_64_host = 0, x86_64_guest = 0;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM Host State Checks Related to Address-Space Size
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Bit32u vmexit_ctrls = vm->vmexit_ctrls;
|
|
|
|
|
if (vmexit_ctrls & VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE) {
|
|
|
|
|
x86_64_host = 1;
|
|
|
|
|
}
|
|
|
|
|
Bit32u vmentry_ctrls = vm->vmentry_ctrls;
|
|
|
|
|
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_X86_64_GUEST) {
|
|
|
|
|
x86_64_guest = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! long_mode()) {
|
|
|
|
|
if (x86_64_host || x86_64_guest) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS x86-64 guest(%d)/host(%d) controls invalid on VMENTRY", x86_64_guest, x86_64_host));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (! x86_64_host) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS x86-64 host control invalid on VMENTRY"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check VM Host State to VMCS Cache
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
host_state->cr0 = (bx_address) VMread64(VMCS_HOST_CR0);
|
|
|
|
|
if (~host_state->cr0 & VMX_MSR_CR0_FIXED0) {
|
2009-03-27 12:37:48 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host state invalid CR0 0x%08x", (Bit32u) host_state->cr0));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (host_state->cr0 & ~VMX_MSR_CR0_FIXED1) {
|
2009-03-27 12:37:48 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host state invalid CR0 0x%08x", (Bit32u) host_state->cr0));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host_state->cr3 = (bx_address) VMread64(VMCS_HOST_CR3);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
2009-09-30 09:57:21 +04:00
|
|
|
|
if (! IsValidPhyAddr(host_state->cr3)) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host state invalid CR3"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
host_state->cr4 = (bx_address) VMread64(VMCS_HOST_CR4);
|
|
|
|
|
if (~host_state->cr4 & VMX_MSR_CR4_FIXED0) {
|
2009-03-28 16:42:09 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host state invalid CR4 0x" FMT_ADDRX, host_state->cr4));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (host_state->cr4 & ~VMX_MSR_CR4_FIXED1) {
|
2009-03-28 16:42:09 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host state invalid CR4 0x" FMT_ADDRX, host_state->cr4));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int n=0; n<6; n++) {
|
2009-07-21 15:56:26 +04:00
|
|
|
|
host_state->segreg_selector[n] = VMread16(VMCS_16BIT_HOST_ES_SELECTOR + 2*n);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (host_state->segreg_selector[n] & 7) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host segreg %d TI/RPL != 0", n));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (host_state->segreg_selector[BX_SEG_REG_CS] == 0) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host CS selector 0"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! x86_64_host && host_state->segreg_selector[BX_SEG_REG_SS] == 0) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host SS selector 0"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
host_state->tr_selector = VMread16(VMCS_16BIT_HOST_TR_SELECTOR);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (! host_state->tr_selector || (host_state->tr_selector & 7) != 0) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS invalid host TR selector"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host_state->tr_base = (bx_address) VMread64(VMCS_HOST_TR_BASE);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(host_state->tr_base)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host TR BASE non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
host_state->fs_base = (bx_address) VMread64(VMCS_HOST_FS_BASE);
|
|
|
|
|
host_state->gs_base = (bx_address) VMread64(VMCS_HOST_GS_BASE);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(host_state->fs_base)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host FS BASE non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (! IsCanonical(host_state->gs_base)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host GS BASE non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
host_state->gdtr_base = (bx_address) VMread64(VMCS_HOST_GDTR_BASE);
|
|
|
|
|
host_state->idtr_base = (bx_address) VMread64(VMCS_HOST_IDTR_BASE);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(host_state->gdtr_base)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host GDTR BASE non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (! IsCanonical(host_state->idtr_base)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host IDTR BASE non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
host_state->sysenter_esp_msr = (bx_address) VMread64(VMCS_HOST_IA32_SYSENTER_ESP_MSR);
|
|
|
|
|
host_state->sysenter_eip_msr = (bx_address) VMread64(VMCS_HOST_IA32_SYSENTER_EIP_MSR);
|
|
|
|
|
host_state->sysenter_cs_msr = (Bit16u) VMread32(VMCS_32BIT_HOST_IA32_SYSENTER_CS_MSR);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(host_state->sysenter_esp_msr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host SYSENTER_ESP_MSR non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! IsCanonical(host_state->sysenter_eip_msr)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host SYSENTER_EIP_MSR non canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
host_state->rsp = (bx_address) VMread64(VMCS_HOST_RSP);
|
|
|
|
|
host_state->rip = (bx_address) VMread64(VMCS_HOST_RIP);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (x86_64_host) {
|
|
|
|
|
if ((host_state->cr4 & (1<<5)) == 0) { // PAE
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host CR4.PAE=0 with x86-64 host"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
if (! IsCanonical(host_state->rip)) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host RIP non-canonical"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (GET32H(host_state->rip) != 0) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS host RIP > 32 bit"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return VMXERR_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_CPP_INLINE bx_bool IsLimitAccessRightsConsistent(Bit32u limit, Bit32u ar)
|
|
|
|
|
{
|
|
|
|
|
bx_bool g = (ar >> 15) & 1;
|
|
|
|
|
|
|
|
|
|
// access rights reserved bits set
|
|
|
|
|
if (ar & 0xfffe0f00) return 0;
|
|
|
|
|
|
|
|
|
|
if (g) {
|
|
|
|
|
// if any of the bits in limit[11:00] are '0 <=> G must be '0
|
|
|
|
|
if ((limit & 0xfff) != 0xfff)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// if any of the bits in limit[31:20] are '1 <=> G must be '1
|
|
|
|
|
if ((limit & 0xfff00000) != 0)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
|
|
|
|
{
|
|
|
|
|
static const char *segname[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
|
|
|
|
|
|
|
|
|
|
VMCS_GUEST_STATE guest;
|
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
|
|
|
|
|
*qualification = VMENTER_ERR_NO_ERROR;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
guest.rflags = VMread64(VMCS_GUEST_RFLAGS);
|
|
|
|
|
// RFLAGS reserved bits [63:22], bit 15, bit 5, bit 3 must be zero
|
|
|
|
|
if (guest.rflags & BX_CONST64(0xFFFFFFFFFFC08028)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: RFLAGS reserved bits are set"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
// RFLAGS[1] must be always set
|
|
|
|
|
if ((guest.rflags & 0x2) == 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: RFLAGS[1] cleared"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bx_bool v8086_guest = 0;
|
|
|
|
|
if (guest.rflags & EFlagsVMMask)
|
|
|
|
|
v8086_guest = 1;
|
|
|
|
|
|
|
|
|
|
bx_bool x86_64_guest = 0; // can't be 1 if X86_64 is not supported (checked before)
|
|
|
|
|
Bit32u vmentry_ctrls = vm->vmentry_ctrls;
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_X86_64_GUEST) {
|
|
|
|
|
BX_DEBUG(("VMENTER to x86-64 guest"));
|
|
|
|
|
x86_64_guest = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (x86_64_guest && v8086_guest) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: Enter to x86-64 guest with RFLAGS.VM"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guest.cr0 = VMread64(VMCS_GUEST_CR0);
|
|
|
|
|
if (~guest.cr0 & VMX_MSR_CR0_FIXED0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR0"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.cr0 & ~VMX_MSR_CR0_FIXED1) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR0"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guest.cr3 = VMread64(VMCS_GUEST_CR3);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
2009-09-30 09:57:21 +04:00
|
|
|
|
if (! IsValidPhyAddr(guest.cr3)) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR3"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
guest.cr4 = VMread64(VMCS_GUEST_CR4);
|
|
|
|
|
if (~guest.cr4 & VMX_MSR_CR4_FIXED0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR4"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.cr4 & ~VMX_MSR_CR4_FIXED1) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR4"));
|
|
|
|
|
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (x86_64_guest && (guest.cr4 & (1<<5)) == 0) { // PAE
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest CR4.PAE=0 in x86-64 mode"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS) {
|
|
|
|
|
guest.dr7 = VMread64(VMCS_GUEST_DR7);
|
|
|
|
|
if (GET32H(guest.dr7)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest invalid DR7"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS - Segment Registers
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
for (int n=0; n<6; n++) {
|
2009-07-21 15:56:26 +04:00
|
|
|
|
Bit16u selector = VMread16(VMCS_16BIT_GUEST_ES_SELECTOR + 2*n);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
bx_address base = (bx_address) VMread64(VMCS_GUEST_ES_BASE + 2*n);
|
|
|
|
|
Bit32u limit = VMread32(VMCS_32BIT_GUEST_ES_LIMIT + 2*n);
|
|
|
|
|
Bit32u ar = VMread32(VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS + 2*n) >> 8;
|
|
|
|
|
bx_bool invalid = (ar >> 16) & 1;
|
|
|
|
|
|
|
|
|
|
if (set_segment_ar_data(&guest.sregs[n], !invalid,
|
|
|
|
|
(Bit16u) selector, base, limit, (Bit16u) ar));
|
|
|
|
|
|
|
|
|
|
if (v8086_guest) {
|
|
|
|
|
// guest in V8086 mode
|
2009-07-21 15:56:26 +04:00
|
|
|
|
if (base != ((bx_address)(selector << 4))) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS v8086 guest bad %s.BASE", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (limit != 0xffff) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS v8086 guest %s.LIMIT != 0xFFFF", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
// present, expand-up read/write accessed, segment, DPL=3
|
|
|
|
|
if (ar != 0xF3) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS v8086 guest %s.AR != 0xF3", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue; // go to next segment register
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (n >= BX_SEG_REG_FS) {
|
|
|
|
|
if (! IsCanonical(base)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s.BASE non canonical", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (n != BX_SEG_REG_CS && invalid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (n == BX_SEG_REG_SS && (selector & BX_SELECTOR_RPL_MASK) == 0) {
|
|
|
|
|
// SS is allowed to be NULL selector if going to 64-bit guest
|
|
|
|
|
if (x86_64_guest && guest.sregs[BX_SEG_REG_CS].cache.u.segment.l)
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n < BX_SEG_REG_FS) {
|
|
|
|
|
if (GET32H(base) != 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s.BASE > 32 bit", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-02-04 19:05:47 +03:00
|
|
|
|
#endif
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
if (! guest.sregs[n].cache.segment) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s not segment", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! guest.sregs[n].cache.p) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s not present", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! IsLimitAccessRightsConsistent(limit, ar)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s.AR/LIMIT malformed", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n == BX_SEG_REG_CS) {
|
|
|
|
|
// CS checks
|
|
|
|
|
switch (guest.sregs[BX_SEG_REG_CS].cache.type) {
|
|
|
|
|
case BX_CODE_EXEC_ONLY_ACCESSED:
|
|
|
|
|
case BX_CODE_EXEC_READ_ACCESSED:
|
|
|
|
|
// non-conforming segment
|
|
|
|
|
if (guest.sregs[n].selector.rpl != guest.sregs[n].cache.dpl) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming CS.RPL <> CS.DPL"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case BX_CODE_EXEC_ONLY_CONFORMING_ACCESSED:
|
|
|
|
|
case BX_CODE_EXEC_READ_CONFORMING_ACCESSED:
|
|
|
|
|
// conforming segment
|
|
|
|
|
if (guest.sregs[n].selector.rpl < guest.sregs[n].cache.dpl) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming CS.RPL < CS.DPL"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest CS.TYPE"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (x86_64_guest) {
|
|
|
|
|
if (guest.sregs[BX_SEG_REG_CS].cache.u.segment.d_b && guest.sregs[BX_SEG_REG_CS].cache.u.segment.l) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS x86_64 guest wrong CS.D_B/L"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
else if (n == BX_SEG_REG_SS) {
|
|
|
|
|
// SS checks
|
|
|
|
|
switch (guest.sregs[BX_SEG_REG_SS].cache.type) {
|
|
|
|
|
case BX_DATA_READ_WRITE_ACCESSED:
|
|
|
|
|
case BX_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest SS.TYPE"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// DS, ES, FS, GS
|
|
|
|
|
if ((guest.sregs[n].cache.type & 0x1) == 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest %s not ACCESSED", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.sregs[n].cache.type & 0x8) {
|
|
|
|
|
if ((guest.sregs[n].cache.type & 0x2) == 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest CODE segment %s not READABLE", segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.sregs[n].cache.type < 11) {
|
|
|
|
|
// data segment or non-conforming code segment
|
|
|
|
|
if (guest.sregs[n].selector.rpl > guest.sregs[n].cache.dpl) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming %s.RPL < %s.DPL", segname[n], segname[n]));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! v8086_guest) {
|
|
|
|
|
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_CS].selector.rpl) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest CS.RPL != SS.RPL"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_SS].cache.dpl) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest SS.RPL <> SS.DPL"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS - GDTR/IDTR
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Bit64u gdtr_base = VMread64(VMCS_GUEST_GDTR_BASE);
|
|
|
|
|
Bit32u gdtr_limit = VMread32(VMCS_32BIT_GUEST_GDTR_LIMIT);
|
|
|
|
|
Bit64u idtr_base = VMread64(VMCS_GUEST_IDTR_BASE);
|
|
|
|
|
Bit32u idtr_limit = VMread32(VMCS_32BIT_GUEST_IDTR_LIMIT);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(gdtr_base) || ! IsCanonical(idtr_base)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest IDTR/IDTR.BASE non canonical"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (gdtr_limit > 0xffff || idtr_limit > 0xffff) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest GDTR/IDTR limit > 0xFFFF"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS - LDTR
|
|
|
|
|
//
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
Bit16u ldtr_selector = VMread16(VMCS_16BIT_GUEST_LDTR_SELECTOR);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit64u ldtr_base = VMread64(VMCS_GUEST_LDTR_BASE);
|
|
|
|
|
Bit32u ldtr_limit = VMread32(VMCS_32BIT_GUEST_LDTR_LIMIT);
|
|
|
|
|
Bit32u ldtr_ar = VMread32(VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS) >> 8;
|
|
|
|
|
bx_bool ldtr_invalid = (ldtr_ar >> 16) & 1;
|
|
|
|
|
if (set_segment_ar_data(&guest.ldtr, !ldtr_invalid,
|
|
|
|
|
(Bit16u) ldtr_selector, ldtr_base, ldtr_limit, (Bit16u)(ldtr_ar)))
|
|
|
|
|
{
|
|
|
|
|
// ldtr is valid
|
|
|
|
|
if (guest.ldtr.selector.ti) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest LDTR.TI set"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (guest.ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest incorrect LDTR type"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (guest.ldtr.cache.segment) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest LDTR is not system segment"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (! guest.ldtr.cache.p) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest LDTR not present"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (! IsLimitAccessRightsConsistent(ldtr_limit, ldtr_ar)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest LDTR.AR/LIMIT malformed"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(ldtr_base)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest LDTR.BASE non canonical"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS - TR
|
|
|
|
|
//
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
Bit16u tr_selector = VMread16(VMCS_16BIT_GUEST_TR_SELECTOR);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit64u tr_base = VMread64(VMCS_GUEST_TR_BASE);
|
|
|
|
|
Bit32u tr_limit = VMread32(VMCS_32BIT_GUEST_TR_LIMIT);
|
|
|
|
|
Bit32u tr_ar = VMread32(VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS) >> 8;
|
|
|
|
|
bx_bool tr_invalid = (tr_ar >> 16) & 1;
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(tr_base)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR.BASE non canonical"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
set_segment_ar_data(&guest.tr, !tr_invalid,
|
|
|
|
|
(Bit16u) tr_selector, tr_base, tr_limit, (Bit16u)(tr_ar));
|
|
|
|
|
|
|
|
|
|
if (tr_invalid) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR invalid"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (guest.tr.selector.ti) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR.TI set"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (guest.tr.cache.segment) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR is not system segment"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (! guest.tr.cache.p) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR not present"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (! IsLimitAccessRightsConsistent(tr_limit, tr_ar)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest TR.AR/LIMIT malformed"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(guest.tr.cache.type) {
|
|
|
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
|
|
|
|
break;
|
|
|
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
|
|
|
|
if (! x86_64_guest) break;
|
|
|
|
|
// fall through
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest incorrect TR type"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest State from VMCS - MSRS
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
guest.ia32_debugctl_msr = VMread64(VMCS_64BIT_GUEST_IA32_DEBUGCTL);
|
|
|
|
|
guest.smbase = VMread32(VMCS_32BIT_GUEST_SMBASE);
|
|
|
|
|
|
|
|
|
|
guest.sysenter_esp_msr = VMread64(VMCS_GUEST_IA32_SYSENTER_ESP_MSR);
|
|
|
|
|
guest.sysenter_eip_msr = VMread64(VMCS_GUEST_IA32_SYSENTER_EIP_MSR);
|
|
|
|
|
guest.sysenter_cs_msr = VMread32(VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! IsCanonical(guest.sysenter_esp_msr)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest SYSENTER_ESP_MSR non canonical"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
if (! IsCanonical(guest.sysenter_eip_msr)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest SYSENTER_EIP_MSR non canonical"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
guest.rip = VMread64(VMCS_GUEST_RIP);
|
|
|
|
|
guest.rsp = VMread64(VMCS_GUEST_RSP);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (! x86_64_guest || !guest.sregs[BX_SEG_REG_CS].cache.u.segment.l) {
|
|
|
|
|
if (GET32H(guest.rip) != 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest RIP > 32 bit"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load and Check Guest Non-Registers State from VMCS
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
guest.link_pointer = VMread64(VMCS_64BIT_GUEST_LINK_POINTER);
|
2009-06-06 14:21:49 +04:00
|
|
|
|
if (guest.link_pointer != BX_INVALID_VMCSPTR) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if ((guest.link_pointer & 0xfff) != 0 || ! IsValidPhyAddr(guest.link_pointer)) {
|
|
|
|
|
*qualification = (Bit64u) VMENTER_ERR_GUEST_STATE_LINK_POINTER;
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS link pointer malformed"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
2009-06-06 14:21:49 +04:00
|
|
|
|
|
|
|
|
|
Bit32u revision = VMXReadRevisionID((bx_phy_address) guest.link_pointer);
|
|
|
|
|
if (revision != VMX_VMCS_REVISION_ID) {
|
|
|
|
|
*qualification = (Bit64u) VMENTER_ERR_GUEST_STATE_LINK_POINTER;
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS link pointer incorrect revision ID %d != %d", revision, VMX_VMCS_REVISION_ID));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_smm || (vmentry_ctrls & VMX_VMENTRY_CTRL1_SMM_ENTER) != 0) {
|
|
|
|
|
if (guest.link_pointer == BX_CPU_THIS_PTR vmcsptr) {
|
|
|
|
|
*qualification = (Bit64u) VMENTER_ERR_GUEST_STATE_LINK_POINTER;
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS link pointer equal to current VMCS pointer"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (guest.link_pointer == BX_CPU_THIS_PTR vmxonptr) {
|
|
|
|
|
*qualification = (Bit64u) VMENTER_ERR_GUEST_STATE_LINK_POINTER;
|
|
|
|
|
BX_ERROR(("VMFAIL: VMCS link pointer equal to VMXON pointer"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guest.tmpDR6 = VMread64(VMCS_GUEST_PENDING_DBG_EXCEPTIONS);
|
2009-02-02 01:23:33 +03:00
|
|
|
|
if (guest.tmpDR6 & BX_CONST64(0xFFFFFFFFFFFFAFF0)) {
|
2009-02-02 21:59:44 +03:00
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest tmpDR6 reserved bits"));
|
2009-02-01 23:47:06 +03:00
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guest.activity_state = VMread32(VMCS_32BIT_GUEST_ACTIVITY_STATE);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (guest.activity_state >= BX_VMX_LAST_ACTIVITY_STATE) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest activity state %d", guest.activity_state));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (guest.activity_state == BX_VMX_STATE_HLT) {
|
|
|
|
|
if (guest.sregs[BX_SEG_REG_SS].cache.dpl != 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest HLT state with SS.DPL=%d", guest.sregs[BX_SEG_REG_SS].cache.dpl));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-01 23:47:06 +03:00
|
|
|
|
guest.interruptibility_state = VMread32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (guest.interruptibility_state & ~BX_VMX_INTERRUPTIBILITY_STATE_MASK) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest interruptibility state broken"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_STI) &&
|
|
|
|
|
(guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_MOV_SS))
|
|
|
|
|
{
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest interruptibility state broken"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((guest.rflags & EFlagsIFMask) == 0) {
|
|
|
|
|
if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_STI) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest interrupts can't be blocked by STI when EFLAGS.IF = 0"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (VMENTRY_INJECTING_EVENT(vm->vmentry_interr_info)) {
|
|
|
|
|
unsigned event_type = (vm->vmentry_interr_info >> 8) & 7;
|
|
|
|
|
if (event_type == BX_EXTERNAL_INTERRUPT) {
|
|
|
|
|
if ((guest.interruptibility_state & 3) != 0 || (guest.rflags & EFlagsIFMask) == 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest interrupts blocked when injecting external interrupt"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (event_type == BX_NMI) {
|
|
|
|
|
if ((guest.interruptibility_state & 3) != 0) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS guest interrupts blocked when injecting NMI"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_SMM_ENTER) {
|
|
|
|
|
if (! (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_SMI_BLOCKED)) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS SMM guest should block SMI"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-21 14:39:40 +04:00
|
|
|
|
if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_SMI_BLOCKED) {
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_smm) {
|
|
|
|
|
BX_ERROR(("VMENTER FAIL: VMCS SMI blocked when not in SMM mode"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-15 13:30:56 +04:00
|
|
|
|
#if BX_CPU_LEVEL >= 6
|
2009-05-31 11:49:04 +04:00
|
|
|
|
if (! x86_64_guest && (guest.cr4 & (1 << 5)) != 0 /* PAE */) {
|
|
|
|
|
// CR0.PG is always set in VMX mode
|
|
|
|
|
if (! CheckPDPTR(guest.cr3)) {
|
|
|
|
|
*qualification = VMENTER_ERR_GUEST_STATE_PDPTR_LOADING;
|
|
|
|
|
BX_ERROR(("VMENTER: Guest State PDPTRs Checks Failed"));
|
|
|
|
|
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
//
|
|
|
|
|
// Load Guest State -> VMENTER
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
// set EFER.LMA and EFER.LME before write to CR4
|
|
|
|
|
if (x86_64_guest)
|
|
|
|
|
BX_CPU_THIS_PTR efer.set32(BX_CPU_THIS_PTR efer.get32() | ((1 << 8) | (1 << 10)));
|
|
|
|
|
else
|
|
|
|
|
BX_CPU_THIS_PTR efer.set32(BX_CPU_THIS_PTR efer.get32() & ~((1 << 8) | (1 << 10)));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Bit32u old_cr0 = BX_CPU_THIS_PTR cr0.get32();
|
|
|
|
|
|
|
|
|
|
#define VMX_KEEP_CR0_BITS 0x7FFAFFD0
|
|
|
|
|
|
|
|
|
|
// load CR0, keep bits ET(4), reserved bits 15:6, 17, 28:19, NW(29), CD(30)
|
|
|
|
|
if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (guest.cr0 & ~VMX_KEEP_CR0_BITS))) {
|
|
|
|
|
BX_PANIC(("VMENTER CR0 is broken !"));
|
|
|
|
|
}
|
2009-05-31 11:49:04 +04:00
|
|
|
|
if (!SetCR4(guest.cr4)) { // cannot fail if CR4 checks were correct
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_PANIC(("VMENTER CR4 is broken !"));
|
|
|
|
|
}
|
2009-05-31 11:49:04 +04:00
|
|
|
|
SetCR3(guest.cr3);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS) {
|
|
|
|
|
// always clear bits 15:14 and set bit 10
|
|
|
|
|
BX_CPU_THIS_PTR dr7 = (guest.dr7 & ~0xc000) | 0400;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RIP = BX_CPU_THIS_PTR prev_rip = guest.rip;
|
|
|
|
|
RSP = guest.rsp;
|
|
|
|
|
|
|
|
|
|
// set flags directly, avoid setEFlags side effects
|
|
|
|
|
BX_CPU_THIS_PTR eflags = (Bit32u) guest.rflags;
|
|
|
|
|
BX_CPU_THIS_PTR lf_flags_status = 0; // OSZAPC flags are known.
|
|
|
|
|
|
|
|
|
|
for(unsigned segreg=0; segreg<6; segreg++)
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg] = guest.sregs[segreg];
|
|
|
|
|
|
|
|
|
|
if (v8086_guest) CPL = 3;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = gdtr_base;
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = gdtr_limit;
|
|
|
|
|
BX_CPU_THIS_PTR idtr.base = idtr_base;
|
|
|
|
|
BX_CPU_THIS_PTR idtr.limit = idtr_limit;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR ldtr = guest.ldtr;
|
|
|
|
|
BX_CPU_THIS_PTR tr = guest.tr;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_esp_msr = guest.sysenter_esp_msr;
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_eip_msr = guest.sysenter_eip_msr;
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_cs_msr = guest.sysenter_cs_msr;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Load Guest Non-Registers State -> VMENTER
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR async_event = 0;
|
2009-02-13 23:09:56 +03:00
|
|
|
|
if (guest.rflags & (EFlagsTFMask|EFlagsRFMask))
|
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
if (vm->vmentry_ctrls & VMX_VMENTRY_CTRL1_SMM_ENTER)
|
|
|
|
|
BX_PANIC(("VMENTER: entry to SMM is not implemented yet !"));
|
|
|
|
|
|
|
|
|
|
if (VMENTRY_INJECTING_EVENT(vm->vmentry_interr_info)) {
|
|
|
|
|
// the VMENTRY injecting event to the guest
|
|
|
|
|
BX_CPU_THIS_PTR inhibit_mask = 0; // do not block interrupts
|
2009-02-02 01:23:33 +03:00
|
|
|
|
BX_CPU_THIS_PTR debug_trap = 0;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
else {
|
2009-02-02 21:59:44 +03:00
|
|
|
|
if (guest.tmpDR6 & (1 << 12))
|
|
|
|
|
BX_CPU_THIS_PTR debug_trap = guest.tmpDR6 & 0x0000400F;
|
|
|
|
|
else
|
|
|
|
|
BX_CPU_THIS_PTR debug_trap = guest.tmpDR6 & 0x00004000;
|
2009-02-02 01:23:33 +03:00
|
|
|
|
if (BX_CPU_THIS_PTR debug_trap)
|
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_STI)
|
|
|
|
|
BX_CPU_THIS_PTR inhibit_mask = BX_INHIBIT_INTERRUPTS;
|
|
|
|
|
else if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_BY_MOV_SS)
|
|
|
|
|
BX_CPU_THIS_PTR inhibit_mask = BX_INHIBIT_INTERRUPTS | BX_INHIBIT_DEBUG;
|
|
|
|
|
else BX_CPU_THIS_PTR inhibit_mask = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-03 22:17:15 +03:00
|
|
|
|
if (BX_CPU_THIS_PTR inhibit_mask)
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
2009-02-03 22:17:15 +03:00
|
|
|
|
|
|
|
|
|
if (guest.interruptibility_state & BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED)
|
|
|
|
|
BX_CPU_THIS_PTR disable_NMI = 1;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_INTERRUPT_WINDOW_VMEXIT) {
|
|
|
|
|
BX_CPU_THIS_PTR async_event = 1;
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BX_CPU_THIS_PTR vmx_interrupt_window = 1; // set up interrupt window exiting
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
|
|
|
|
BX_CPU_THIS_PTR monitor.reset_monitor();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
2009-06-21 00:39:51 +04:00
|
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2009-01-31 13:43:24 +03:00
|
|
|
|
handleAlignmentCheck();
|
2009-06-21 00:39:51 +04:00
|
|
|
|
#endif
|
2009-01-31 13:43:24 +03:00
|
|
|
|
handleCpuModeChange();
|
|
|
|
|
|
|
|
|
|
return VMXERR_NO_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMenterInjectEvents(void)
|
|
|
|
|
{
|
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
|
|
|
|
|
if (! VMENTRY_INJECTING_EVENT(vm->vmentry_interr_info))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* the VMENTRY injecting event to the guest */
|
|
|
|
|
unsigned vector = vm->vmentry_interr_info & 0xff;
|
|
|
|
|
unsigned type = (vm->vmentry_interr_info >> 8) & 7;
|
|
|
|
|
unsigned push_error = vm->vmentry_interr_info & (1 << 11);
|
|
|
|
|
unsigned error_code = push_error ? vm->vmentry_excep_err_code : 0;
|
|
|
|
|
|
|
|
|
|
bx_bool is_INT = 0;
|
|
|
|
|
switch(type) {
|
|
|
|
|
case BX_EXTERNAL_INTERRUPT:
|
|
|
|
|
case BX_NMI:
|
|
|
|
|
case BX_HARDWARE_EXCEPTION:
|
|
|
|
|
BX_CPU_THIS_PTR EXT = 1;
|
|
|
|
|
is_INT = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BX_SOFTWARE_INTERRUPT:
|
|
|
|
|
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
|
|
|
|
|
case BX_SOFTWARE_EXCEPTION:
|
|
|
|
|
is_INT = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
BX_PANIC(("VMENTER: unsupported event injection type %d !", type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// keep prev_rip value/unwind in case of event delivery failure
|
|
|
|
|
if (is_INT)
|
|
|
|
|
RIP += vm->vmentry_instr_length;
|
|
|
|
|
|
|
|
|
|
BX_ERROR(("VMENTER: Injecting vector 0x%02x (error_code 0x%04x)", vector, error_code));
|
|
|
|
|
|
|
|
|
|
if (type == BX_HARDWARE_EXCEPTION) {
|
|
|
|
|
// record exception the same way as BX_CPU_C::exception does
|
|
|
|
|
if (vector < BX_CPU_HANDLED_EXCEPTIONS)
|
|
|
|
|
BX_CPU_THIS_PTR curr_exception = exceptions_info[vector].exception_type;
|
|
|
|
|
else // else take default value
|
|
|
|
|
BX_CPU_THIS_PTR curr_exception = exceptions_info[BX_CPU_HANDLED_EXCEPTIONS].exception_type;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR errorno = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm->idt_vector_info = vm->vmentry_interr_info & ~0x80000000;
|
|
|
|
|
vm->idt_vector_error_code = error_code;
|
|
|
|
|
|
|
|
|
|
interrupt(vector, type, push_error, error_code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u BX_CPU_C::LoadMSRs(Bit32u msr_cnt, bx_phy_address pAddr)
|
|
|
|
|
{
|
|
|
|
|
Bit64u msr_lo, msr_hi;
|
|
|
|
|
|
|
|
|
|
for (Bit32u msr = 1; msr <= msr_cnt; msr++) {
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_read_physical(pAddr, 8, &msr_lo);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_READ, (Bit8u*)(&msr_lo));
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_read_physical(pAddr + 8, 8, &msr_hi);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr + 8, 8, BX_READ, (Bit8u*)(&msr_hi));
|
|
|
|
|
|
|
|
|
|
if (GET32H(msr_lo))
|
|
|
|
|
return msr;
|
|
|
|
|
|
|
|
|
|
Bit32u index = GET32L(msr_lo);
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (index == BX_MSR_FSBASE || index == BX_MSR_GSBASE)
|
|
|
|
|
return msr;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (! wrmsr(index, msr_hi))
|
|
|
|
|
return msr;
|
|
|
|
|
|
|
|
|
|
pAddr += 16; // to next MSR
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u BX_CPU_C::StoreMSRs(Bit32u msr_cnt, bx_phy_address pAddr)
|
|
|
|
|
{
|
|
|
|
|
Bit64u msr_lo, msr_hi;
|
|
|
|
|
|
|
|
|
|
for (Bit32u msr = 1; msr <= msr_cnt; msr++) {
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_read_physical(pAddr, 8, &msr_lo);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_READ, (Bit8u*)(&msr_lo));
|
|
|
|
|
|
|
|
|
|
if (GET32H(msr_lo))
|
|
|
|
|
return msr;
|
|
|
|
|
|
|
|
|
|
Bit32u index = GET32L(msr_lo);
|
|
|
|
|
|
|
|
|
|
if (! rdmsr(index, &msr_hi))
|
|
|
|
|
return msr;
|
|
|
|
|
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_write_physical(pAddr + 8, 8, &msr_hi);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr + 8, 8, BX_WRITE, (Bit8u*)(&msr_hi));
|
|
|
|
|
|
|
|
|
|
pAddr += 16; // to next MSR
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// VMexit
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMexitSaveGuestState(void)
|
|
|
|
|
{
|
2009-02-01 23:47:06 +03:00
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMwrite64(VMCS_GUEST_CR0, BX_CPU_THIS_PTR cr0.get32());
|
|
|
|
|
VMwrite64(VMCS_GUEST_CR3, BX_CPU_THIS_PTR cr3);
|
|
|
|
|
VMwrite64(VMCS_GUEST_CR4, BX_CPU_THIS_PTR cr4.get32());
|
2009-02-01 23:47:06 +03:00
|
|
|
|
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_SAVE_DBG_CTRLS)
|
|
|
|
|
VMwrite64(VMCS_GUEST_DR7, BX_CPU_THIS_PTR dr7);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMwrite64(VMCS_GUEST_RIP, RIP);
|
|
|
|
|
VMwrite64(VMCS_GUEST_RSP, RSP);
|
|
|
|
|
VMwrite64(VMCS_GUEST_RFLAGS, BX_CPU_THIS_PTR read_eflags());
|
|
|
|
|
|
|
|
|
|
for (int n=0; n<6; n++) {
|
|
|
|
|
Bit32u selector = BX_CPU_THIS_PTR sregs[n].selector.value;
|
|
|
|
|
bx_bool invalid = !BX_CPU_THIS_PTR sregs[n].cache.valid;
|
|
|
|
|
bx_address base = BX_CPU_THIS_PTR sregs[n].cache.u.segment.base;
|
|
|
|
|
Bit32u limit = BX_CPU_THIS_PTR sregs[n].cache.u.segment.limit_scaled;
|
|
|
|
|
Bit32u ar = get_descriptor_h(&BX_CPU_THIS_PTR sregs[n].cache) & 0x00f0ff00;
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
VMwrite16(VMCS_16BIT_GUEST_ES_SELECTOR + 2*n, selector);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMwrite64(VMCS_GUEST_ES_BASE + 2*n, base);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_ES_LIMIT + 2*n, limit);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS + 2*n, ar | (invalid << 24));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save guest LDTR
|
|
|
|
|
Bit32u ldtr_selector = BX_CPU_THIS_PTR ldtr.selector.value;
|
|
|
|
|
bx_bool ldtr_invalid = !BX_CPU_THIS_PTR ldtr.cache.valid;
|
2009-04-05 23:09:44 +04:00
|
|
|
|
bx_address ldtr_base = BX_CPU_THIS_PTR ldtr.cache.u.segment.base;
|
|
|
|
|
Bit32u ldtr_limit = BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit32u ldtr_ar = get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache) & 0x00f0ff00;
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
VMwrite16(VMCS_16BIT_GUEST_LDTR_SELECTOR, ldtr_selector);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMwrite64(VMCS_GUEST_LDTR_BASE, ldtr_base);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_LDTR_LIMIT, ldtr_limit);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS, ldtr_ar | (ldtr_invalid << 24));
|
|
|
|
|
|
|
|
|
|
// save guest TR
|
|
|
|
|
Bit32u tr_selector = BX_CPU_THIS_PTR tr.selector.value;
|
|
|
|
|
bx_bool tr_invalid = !BX_CPU_THIS_PTR tr.cache.valid;
|
2009-04-05 23:09:44 +04:00
|
|
|
|
bx_address tr_base = BX_CPU_THIS_PTR tr.cache.u.segment.base;
|
|
|
|
|
Bit32u tr_limit = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit32u tr_ar = get_descriptor_h(&BX_CPU_THIS_PTR tr.cache) & 0x00f0ff00;
|
|
|
|
|
|
2009-07-21 15:56:26 +04:00
|
|
|
|
VMwrite16(VMCS_16BIT_GUEST_TR_SELECTOR, tr_selector);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMwrite64(VMCS_GUEST_TR_BASE, tr_base);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_TR_LIMIT, tr_limit);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS, tr_ar | (tr_invalid << 24));
|
|
|
|
|
|
|
|
|
|
VMwrite64(VMCS_GUEST_GDTR_BASE, BX_CPU_THIS_PTR gdtr.base);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_GDTR_LIMIT, BX_CPU_THIS_PTR gdtr.limit);
|
|
|
|
|
VMwrite64(VMCS_GUEST_IDTR_BASE, BX_CPU_THIS_PTR idtr.base);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_IDTR_LIMIT, BX_CPU_THIS_PTR idtr.limit);
|
|
|
|
|
|
|
|
|
|
VMwrite64(VMCS_GUEST_IA32_SYSENTER_ESP_MSR, BX_CPU_THIS_PTR msr.sysenter_esp_msr);
|
|
|
|
|
VMwrite64(VMCS_GUEST_IA32_SYSENTER_EIP_MSR, BX_CPU_THIS_PTR msr.sysenter_eip_msr);
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR, BX_CPU_THIS_PTR msr.sysenter_cs_msr);
|
|
|
|
|
|
2009-02-01 23:47:06 +03:00
|
|
|
|
Bit32u tmpDR6 = BX_CPU_THIS_PTR debug_trap;
|
|
|
|
|
if (tmpDR6 & 0xf) tmpDR6 |= (1 << 12);
|
|
|
|
|
VMwrite64(VMCS_GUEST_PENDING_DBG_EXCEPTIONS, tmpDR6 & 0x0000500f);
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
Bit32u interruptibility_state = 0;
|
2009-05-21 14:39:40 +04:00
|
|
|
|
if (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_INTERRUPTS_SHADOW) {
|
|
|
|
|
if (BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_DEBUG_SHADOW)
|
2009-01-31 13:43:24 +03:00
|
|
|
|
interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_BY_MOV_SS;
|
|
|
|
|
else
|
|
|
|
|
interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_BY_STI;
|
|
|
|
|
}
|
|
|
|
|
if (BX_CPU_THIS_PTR disable_SMI)
|
|
|
|
|
interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_SMI_BLOCKED;
|
|
|
|
|
if (BX_CPU_THIS_PTR disable_NMI)
|
|
|
|
|
interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED;
|
|
|
|
|
VMwrite32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE, interruptibility_state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMexitLoadHostState(void)
|
|
|
|
|
{
|
|
|
|
|
VMCS_HOST_STATE *host_state = &BX_CPU_THIS_PTR vmcs.host_state;
|
|
|
|
|
bx_bool x86_64_host = 0;
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
Bit32u vmexit_ctrls = BX_CPU_THIS_PTR vmcs.vmexit_ctrls;
|
|
|
|
|
if (vmexit_ctrls & VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE) {
|
|
|
|
|
BX_DEBUG(("VMEXIT to x86-64 host"));
|
|
|
|
|
x86_64_host = 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
// set EFER.LMA and EFER.LME before write to CR4
|
|
|
|
|
if (x86_64_host)
|
|
|
|
|
BX_CPU_THIS_PTR efer.set32(BX_CPU_THIS_PTR efer.get32() | ((1 << 8) | (1 << 10)));
|
|
|
|
|
else
|
|
|
|
|
BX_CPU_THIS_PTR efer.set32(BX_CPU_THIS_PTR efer.get32() & ~((1 << 8) | (1 << 10)));
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Bit32u old_cr0 = BX_CPU_THIS_PTR cr0.get32();
|
|
|
|
|
|
|
|
|
|
// ET, CD, NW, 28:19, 17, 15:6, and VMX fixed bits not modified Section 19.8
|
|
|
|
|
if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (host_state->cr0 & ~VMX_KEEP_CR0_BITS))) {
|
|
|
|
|
BX_PANIC(("VMEXIT CR0 is broken !"));
|
|
|
|
|
}
|
|
|
|
|
if (!SetCR4(host_state->cr4)) {
|
|
|
|
|
BX_PANIC(("VMEXIT CR4 is broken !"));
|
|
|
|
|
}
|
2009-05-31 11:49:04 +04:00
|
|
|
|
SetCR3(host_state->cr3);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR dr7 = 0x00000400;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_cs_msr = host_state->sysenter_cs_msr;
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_esp_msr = host_state->sysenter_esp_msr;
|
|
|
|
|
BX_CPU_THIS_PTR msr.sysenter_eip_msr = host_state->sysenter_eip_msr;
|
|
|
|
|
|
|
|
|
|
// CS selector loaded from VMCS
|
|
|
|
|
// valid <= 1
|
|
|
|
|
// base <= 0
|
|
|
|
|
// limit <= 0xffffffff, g <= 1
|
|
|
|
|
// present <= 1
|
|
|
|
|
// dpl <= 0
|
|
|
|
|
// type <= segment, BX_CODE_EXEC_READ_ACCESSED
|
|
|
|
|
// d_b <= loaded from 'host-address space size' VMEXIT control
|
|
|
|
|
// l <= loaded from 'host-address space size' VMEXIT control
|
|
|
|
|
|
|
|
|
|
parse_selector(host_state->segreg_selector[BX_SEG_REG_CS],
|
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xffffffff;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* page granular */
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = !x86_64_host;
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = x86_64_host;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// DATA selector loaded from VMCS
|
|
|
|
|
// valid <= if selector is not all-zero
|
|
|
|
|
// base <= 0
|
|
|
|
|
// limit <= 0xffffffff, g <= 1
|
|
|
|
|
// present <= 1
|
|
|
|
|
// dpl <= 0
|
|
|
|
|
// type <= segment, BX_DATA_READ_WRITE_ACCESSED
|
|
|
|
|
// d_b <= 1
|
|
|
|
|
// l <= 0
|
|
|
|
|
|
|
|
|
|
for (unsigned segreg = 0; segreg < 6; segreg++)
|
|
|
|
|
{
|
|
|
|
|
if (segreg == BX_SEG_REG_CS) continue;
|
|
|
|
|
|
|
|
|
|
parse_selector(host_state->segreg_selector[segreg],
|
|
|
|
|
&BX_CPU_THIS_PTR sregs[segreg].selector);
|
|
|
|
|
|
|
|
|
|
if (! host_state->segreg_selector[segreg]) {
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.valid = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.valid = SegValidCache;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.p = 1;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.dpl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.segment = 1; /* data/code segment */
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.base = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.limit_scaled = 0xffffffff;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.avl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.g = 1; /* page granular */
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.d_b = 1;
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
BX_CPU_THIS_PTR sregs[segreg].cache.u.segment.l = 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SS.DPL always clear
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
|
|
|
|
|
|
if (x86_64_host || BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid)
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base = host_state->fs_base;
|
|
|
|
|
|
|
|
|
|
if (x86_64_host || BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid)
|
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base = host_state->gs_base;
|
|
|
|
|
|
|
|
|
|
// TR selector loaded from VMCS
|
|
|
|
|
parse_selector(host_state->tr_selector, &BX_CPU_THIS_PTR tr.selector);
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 1; /* valid */
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.p = 1; /* present */
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.dpl = 0; /* field not used */
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.segment = 0; /* system segment */
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.type = BX_SYS_SEGMENT_BUSY_386_TSS;
|
2009-04-05 23:09:44 +04:00
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.segment.base = host_state->tr_base;
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled = 0x67;
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.segment.avl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR tr.cache.u.segment.g = 0; /* byte granular */
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
// unusable LDTR
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = 0x0000;
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.index = 0x0000;
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.ti = 0;
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.rpl = 0;
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 0; /* invalid */
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = host_state->gdtr_base;
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR idtr.base = host_state->idtr_base;
|
|
|
|
|
BX_CPU_THIS_PTR idtr.limit = 0xFFFF;
|
|
|
|
|
|
|
|
|
|
RIP = host_state->rip;
|
|
|
|
|
RSP = host_state->rsp;
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR inhibit_mask = 0;
|
|
|
|
|
BX_CPU_THIS_PTR debug_trap = 0;
|
|
|
|
|
|
|
|
|
|
// set flags directly, avoid setEFlags side effects
|
|
|
|
|
BX_CPU_THIS_PTR eflags = 0x2; // Bit1 is always set.
|
|
|
|
|
BX_CPU_THIS_PTR lf_flags_status = 0; // OSZAPC flags are known.
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
|
|
|
|
BX_CPU_THIS_PTR monitor.reset_monitor();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
2009-06-21 00:39:51 +04:00
|
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2009-01-31 13:43:24 +03:00
|
|
|
|
handleAlignmentCheck();
|
2009-06-21 00:39:51 +04:00
|
|
|
|
#endif
|
2009-01-31 13:43:24 +03:00
|
|
|
|
handleCpuModeChange();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMexit(bxInstruction_c *i, Bit32u reason, Bit64u qualification)
|
|
|
|
|
{
|
|
|
|
|
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
|
|
|
|
|
|
|
|
|
// VMEXITs are FAULT-like: restore RIP/RSP to value before VMEXIT occurred
|
|
|
|
|
RIP = BX_CPU_THIS_PTR prev_rip;
|
|
|
|
|
if (BX_CPU_THIS_PTR speculative_rsp)
|
|
|
|
|
RSP = BX_CPU_THIS_PTR prev_rsp;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// STEP 0: Update VMEXIT reason
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
VMwrite32(VMCS_32BIT_VMEXIT_REASON, reason);
|
|
|
|
|
VMwrite64(VMCS_VMEXIT_QUALIFICATION, qualification);
|
|
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
|
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH, i->ilen());
|
|
|
|
|
|
|
|
|
|
reason &= 0xffff; /* keep only basic VMEXIT reason */
|
|
|
|
|
|
|
|
|
|
if (reason != VMX_VMEXIT_EXCEPTION_NMI) {
|
|
|
|
|
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_event) {
|
|
|
|
|
VMwrite32(VMCS_32BIT_IDT_VECTORING_INFO, vm->idt_vector_info | 0x80000000);
|
|
|
|
|
VMwrite32(VMCS_32BIT_IDT_VECTORING_ERR_CODE, vm->idt_vector_error_code);
|
|
|
|
|
BX_CPU_THIS_PTR in_event = 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
VMwrite32(VMCS_32BIT_IDT_VECTORING_INFO, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// STEP 1: Saving Guest State to VMCS
|
|
|
|
|
//
|
|
|
|
|
if (reason != VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE && reason != VMX_VMEXIT_VMENTRY_FAILURE_MSR) {
|
|
|
|
|
// clear VMENTRY interruption info field
|
|
|
|
|
VMwrite32(VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO, vm->vmentry_interr_info & ~0x80000000);
|
|
|
|
|
|
|
|
|
|
VMexitSaveGuestState();
|
|
|
|
|
|
|
|
|
|
Bit32u msr = StoreMSRs(vm->vmexit_msr_store_cnt, vm->vmexit_msr_store_addr);
|
|
|
|
|
if (msr) {
|
|
|
|
|
BX_ERROR(("VMABORT: Error when saving guest MSR number %d", msr));
|
|
|
|
|
VMabort(VMABORT_SAVING_GUEST_MSRS_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// STEP 2: Load Host State
|
|
|
|
|
//
|
|
|
|
|
VMexitLoadHostState();
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// STEP 3: Load Host MSR registers
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
Bit32u msr = LoadMSRs(vm->vmexit_msr_load_cnt, vm->vmexit_msr_load_addr);
|
|
|
|
|
if (msr) {
|
|
|
|
|
BX_ERROR(("VMABORT: Error when loading host MSR number %d", msr));
|
|
|
|
|
VMabort(VMABORT_LOADING_HOST_MSRS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// STEP 4: Go back to VMX host
|
|
|
|
|
//
|
|
|
|
|
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BX_CPU_THIS_PTR disable_INIT = 1; // INIT is disabled in VMX root mode
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_CPU_THIS_PTR in_vmx_guest = 0;
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BX_CPU_THIS_PTR vmx_interrupt_window = 0;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-28 12:26:17 +04:00
|
|
|
|
#endif // BX_SUPPORT_VMX
|
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
// VMX instructions
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMXON(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_VMXE() || ! protected_mode() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx) {
|
|
|
|
|
if (CPL != 0 || ! BX_CPU_THIS_PTR cr0.get_NE() ||
|
|
|
|
|
! BX_CPU_THIS_PTR cr0.get_PE() || BX_GET_ENABLE_A20() == 0 /* ||
|
|
|
|
|
(bit 0 (lock bit) of IA32_FEATURE_CONTROL MSR is clear) ||
|
|
|
|
|
(bit 2 of IA32_FEATURE_CONTROL MSR is clear)*/)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
Bit64u pAddr = read_virtual_qword(i->seg(), eaddr); // keep 64-bit
|
|
|
|
|
if ((pAddr & 0xfff) != 0 || ! IsValidPhyAddr(pAddr)) {
|
|
|
|
|
BX_ERROR(("VMXON: invalid or not page aligned physical address !"));
|
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-06 14:21:49 +04:00
|
|
|
|
Bit32u revision = VMXReadRevisionID((bx_phy_address) pAddr);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (revision != VMX_VMCS_REVISION_ID) {
|
|
|
|
|
BX_ERROR(("VMXON: not expected (%d != %d) VMCS revision id !", revision, VMX_VMCS_REVISION_ID));
|
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR vmcsptr = BX_INVALID_VMCSPTR;
|
2009-05-03 17:02:14 +04:00
|
|
|
|
BX_CPU_THIS_PTR vmcshostptr = 0;
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_CPU_THIS_PTR vmxonptr = pAddr;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_CPU_THIS_PTR in_vmx = 1;
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BX_CPU_THIS_PTR disable_INIT = 1; // INIT is disabled in VMX root mode
|
2009-01-31 13:43:24 +03:00
|
|
|
|
// block and disable A20M;
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
|
|
|
|
BX_CPU_THIS_PTR monitor.reset_monitor();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
VMsucceed();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) { // in VMX non-root operation
|
|
|
|
|
BX_ERROR(("VMEXIT: VMXON in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMXON);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// in VMX root operation mode
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
VMfail(VMXERR_VMXON_IN_VMX_ROOT_OPERATION);
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMXON: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMXOFF(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMXOFF in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMXOFF);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
if dual-monitor treatment of SMIs and SMM is active
|
|
|
|
|
THEN VMfail(VMXERR_VMXOFF_WITH_CONFIGURED_SMM_MONITOR);
|
|
|
|
|
else
|
|
|
|
|
*/
|
|
|
|
|
{
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_CPU_THIS_PTR vmxonptr = BX_INVALID_VMCSPTR;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_CPU_THIS_PTR in_vmx = 0; // leave VMX operation mode
|
|
|
|
|
BX_CPU_THIS_PTR disable_INIT = 0;
|
|
|
|
|
// unblock and enable A20M;
|
|
|
|
|
#if BX_SUPPORT_MONITOR_MWAIT
|
|
|
|
|
BX_CPU_THIS_PTR monitor.reset_monitor();
|
|
|
|
|
#endif
|
|
|
|
|
VMsucceed();
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMXOFF: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMCALL(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMCALL in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMCALL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_smm /*||
|
|
|
|
|
(the logical processor does not support the dual-monitor treatment of SMIs and SMM) ||
|
|
|
|
|
(the valid bit in the IA32_SMM_MONITOR_CTL MSR is clear)*/)
|
|
|
|
|
{
|
|
|
|
|
VMfail(VMXERR_VMCALL_IN_VMX_ROOT_OPERATION);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
if dual-monitor treatment of SMIs and BX_CPU_THIS_PTR in_smm
|
|
|
|
|
THEN perform an SMM VMexit (see Section 24.16.2
|
|
|
|
|
of the IntelR 64 and IA-32 Architectures Software Developer's Manual, Volume 3B);
|
|
|
|
|
*/
|
|
|
|
|
if (! VMCSPTR_VALID()) {
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCALL with invalid VMCS ptr"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u launch_state;
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_read_physical(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4, &launch_state);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4,
|
|
|
|
|
BX_READ, (Bit8u*)(&launch_state));
|
|
|
|
|
|
|
|
|
|
if (launch_state != VMCS_STATE_CLEAR) {
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCALL with launched VMCS"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMCALL_NON_CLEAR_VMCS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BX_PANIC(("VMCALL: not implemented yet"));
|
|
|
|
|
/*
|
|
|
|
|
if VM-exit control fields are not valid (see Section 24.16.6.1 of the IntelR 64 and IA-32 Architectures
|
|
|
|
|
Software Developer's Manual, Volume 3B)
|
|
|
|
|
THEN VMfail(VMXERR_VMCALL_INVALID_VMEXIT_FIELD);
|
|
|
|
|
else
|
|
|
|
|
enter SMM;
|
|
|
|
|
read revision identifier in MSEG;
|
|
|
|
|
if revision identifier does not match that supported by processor
|
|
|
|
|
THEN
|
|
|
|
|
leave SMM;
|
|
|
|
|
VMfailValid(VMXERR_VMCALL_INVALID_MSEG_REVISION_ID);
|
|
|
|
|
else
|
|
|
|
|
read SMM-monitor features field in MSEG (see Section 24.16.6.2,
|
|
|
|
|
in the IntelR 64 and IA-32 Architectures Software Developer's Manual, Volume 3B);
|
|
|
|
|
if features field is invalid
|
|
|
|
|
THEN
|
|
|
|
|
leave SMM;
|
|
|
|
|
VMfailValid(VMXERR_VMCALL_WITH_INVALID_SMM_MONITOR_FEATURES);
|
|
|
|
|
else activate dual-monitor treatment of SMIs and SMM (see Section 24.16.6
|
|
|
|
|
in the IntelR 64 and IA-32 Architectures Software Developer's Manual, Volume 3B);
|
|
|
|
|
FI;
|
|
|
|
|
FI;
|
|
|
|
|
FI;
|
|
|
|
|
*/
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMCALL: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
unsigned vmlaunch = 0;
|
|
|
|
|
if ((i->rm() & 0x7) == 0x2) {
|
|
|
|
|
BX_INFO(("VMLAUNCH VMCS ptr: 0x" FMT_ADDRX64, BX_CPU_THIS_PTR vmcsptr));
|
|
|
|
|
vmlaunch = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMLAUNCH in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, vmlaunch ? VMX_VMEXIT_VMLAUNCH : VMX_VMEXIT_VMRESUME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (! VMCSPTR_VALID()) {
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMLAUNCH with invalid VMCS ptr !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-21 14:39:40 +04:00
|
|
|
|
if ((BX_CPU_THIS_PTR inhibit_mask & BX_INHIBIT_INTERRUPTS_BY_MOVSS_SHADOW) == BX_INHIBIT_INTERRUPTS_BY_MOVSS_SHADOW) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_ERROR(("VMFAIL: VMLAUNCH with interrupts blocked by MOV_SS !"));
|
|
|
|
|
VMfail(VMXERR_VMENTRY_MOV_SS_BLOCKING);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u launch_state;
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_read_physical(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4, &launch_state);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4,
|
|
|
|
|
BX_READ, (Bit8u*)(&launch_state));
|
|
|
|
|
|
|
|
|
|
if (vmlaunch) {
|
|
|
|
|
if (launch_state != VMCS_STATE_CLEAR) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMLAUNCH with non-clear VMCS!"));
|
|
|
|
|
VMfail(VMXERR_VMLAUNCH_NON_CLEAR_VMCS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (launch_state != VMCS_STATE_LAUNCHED) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMRESUME with non-launched VMCS!"));
|
|
|
|
|
VMfail(VMXERR_VMRESUME_NON_LAUNCHED_VMCS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// STEP 1: Load and Check VM-Execution Control Fields
|
|
|
|
|
// STEP 2: Load and Check VM-Exit Control Fields
|
|
|
|
|
// STEP 3: Load and Check VM-Entry Control Fields
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
VMX_error_code error = VMenterLoadCheckVmControls();
|
|
|
|
|
if (error != VMXERR_NO_ERROR) {
|
|
|
|
|
VMfail(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// STEP 4: Load and Check Host State
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
error = VMenterLoadCheckHostState();
|
|
|
|
|
if (error != VMXERR_NO_ERROR) {
|
|
|
|
|
VMfail(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// STEP 5: Load and Check Guest State
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
Bit64u qualification = VMENTER_ERR_NO_ERROR;
|
|
|
|
|
Bit32u state_load_error = VMenterLoadCheckGuestState(&qualification);
|
|
|
|
|
if (state_load_error) {
|
|
|
|
|
BX_ERROR(("VMEXIT: Guest State Checks Failed"));
|
|
|
|
|
VMexit(0, state_load_error | (1 << 31), qualification);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Bit32u msr = LoadMSRs(BX_CPU_THIS_PTR vmcs.vmentry_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmentry_msr_load_addr);
|
|
|
|
|
if (msr) {
|
|
|
|
|
BX_ERROR(("VMEXIT: Error when loading guest MSR 0x%08x", msr));
|
|
|
|
|
VMexit(0, VMX_VMEXIT_VMENTRY_FAILURE_MSR | (1 << 31), msr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// STEP 6: Update VMCS 'launched' state
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
if (vmlaunch) {
|
|
|
|
|
launch_state = VMCS_STATE_LAUNCHED;
|
|
|
|
|
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR;
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_write_physical(pAddr, 4, &launch_state);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_WRITE, (Bit8u*)(&launch_state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Check settings of VMX controls and host-state area;
|
|
|
|
|
if invalid settings
|
|
|
|
|
THEN VMfailValid(VM entry with invalid VMX-control field(s)) or
|
|
|
|
|
VMfailValid(VM entry with invalid host-state field(s)) or
|
|
|
|
|
VMfailValid(VM entry with invalid executive-VMCS pointer)) or
|
|
|
|
|
VMfailValid(VM entry with non-launched executive VMCS) or
|
|
|
|
|
VMfailValid(VM entry with executive-VMCS pointer not VMXON pointer)
|
|
|
|
|
VMfailValid(VM entry with invalid VM-execution control fields in executive VMCS)
|
|
|
|
|
(as appropriate);
|
|
|
|
|
else
|
|
|
|
|
Attempt to load guest state and PDPTRs as appropriate;
|
|
|
|
|
clear address-range monitoring;
|
|
|
|
|
if failure in checking guest state or PDPTRs
|
|
|
|
|
THEN VM entry fails (see Section 22.7, in the
|
|
|
|
|
IntelR 64 and IA-32 Architectures Software Developer's Manual, Volume 3B);
|
|
|
|
|
else
|
|
|
|
|
Attempt to load MSRs from VM-entry MSR-load area;
|
|
|
|
|
if failure
|
|
|
|
|
THEN VM entry fails (see Section 22.7, in the IntelR 64 and IA-32
|
|
|
|
|
Architectures Software Developer's Manual, Volume 3B);
|
|
|
|
|
else {
|
|
|
|
|
if VMLAUNCH
|
|
|
|
|
THEN launch state of VMCS <== "launched";
|
|
|
|
|
if in SMM and "entry to SMM" VM-entry control is 0
|
|
|
|
|
THEN
|
|
|
|
|
if "deactivate dual-monitor treatment" VM-entry control is 0
|
|
|
|
|
THEN SMM-transfer VMCS pointer <== current-VMCS pointer;
|
|
|
|
|
FI;
|
|
|
|
|
if executive-VMCS pointer is VMX pointer
|
|
|
|
|
THEN current-VMCS pointer <== VMCS-link pointer;
|
|
|
|
|
else current-VMCS pointer <== executive-VMCS pointer;
|
|
|
|
|
FI;
|
|
|
|
|
leave SMM;
|
|
|
|
|
FI;
|
|
|
|
|
VMsucceed();
|
|
|
|
|
}
|
|
|
|
|
FI;
|
|
|
|
|
FI;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR in_vmx_guest = 1;
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BX_CPU_THIS_PTR disable_INIT = 0;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
// STEP 7: Inject events to the guest
|
|
|
|
|
///////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
VMenterInjectEvents();
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMLAUNCH/VMRESUME: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMPTRLD(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMPTRLD in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMPTRLD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
Bit64u pAddr = read_virtual_qword(i->seg(), eaddr); // keep 64-bit
|
|
|
|
|
if ((pAddr & 0xfff) != 0 || ! IsValidPhyAddr(pAddr)) {
|
2009-05-30 19:09:38 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: invalid or not page aligned physical address !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMPTRLD_INVALID_PHYSICAL_ADDRESS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-28 12:26:17 +04:00
|
|
|
|
if (pAddr == BX_CPU_THIS_PTR vmxonptr) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMPTRLD with VMXON ptr !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMPTRLD_WITH_VMXON_PTR);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2009-06-06 14:21:49 +04:00
|
|
|
|
Bit32u revision = VMXReadRevisionID((bx_phy_address) pAddr);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (revision != VMX_VMCS_REVISION_ID) {
|
2009-05-30 19:09:38 +04:00
|
|
|
|
BX_ERROR(("VMPTRLD: not expected (%d != %d) VMCS revision id !", revision, VMX_VMCS_REVISION_ID));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
|
|
|
|
|
}
|
2009-05-30 19:09:38 +04:00
|
|
|
|
else {
|
|
|
|
|
set_VMCSPTR(pAddr);
|
|
|
|
|
VMsucceed();
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMPTRLD: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMPTRST(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMPTRST in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMPTRST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
write_virtual_qword(i->seg(), eaddr, BX_CPU_THIS_PTR vmcsptr);
|
|
|
|
|
VMsucceed();
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMPTRST: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMREAD(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMREAD in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMREAD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (! VMCSPTR_VALID()) {
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMREAD with invalid VMCS ptr !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
|
Bit64u enc = BX_READ_64BIT_REG(i->nnn());
|
|
|
|
|
if (enc >> 32) {
|
|
|
|
|
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
unsigned encoding = BX_READ_32BIT_REG(i->nnn());
|
|
|
|
|
|
|
|
|
|
Bit64u field_64;
|
|
|
|
|
|
|
|
|
|
switch(encoding) {
|
|
|
|
|
/* VMCS 16-bit guest-state fields */
|
|
|
|
|
/* binary 0000_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_16BIT_GUEST_ES_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_CS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_SS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_DS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_FS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_GS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_LDTR_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_TR_SELECTOR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 16-bit host-state fields */
|
|
|
|
|
/* binary 0000_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_16BIT_HOST_ES_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_CS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_SS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_DS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_FS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_GS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_TR_SELECTOR:
|
2009-07-21 15:56:26 +04:00
|
|
|
|
field_64 = VMread16(encoding);
|
|
|
|
|
break;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
/* VMCS 32_bit control fields */
|
|
|
|
|
/* binary 0100_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_CONTROL_PIN_BASED_EXEC_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PROCESSOR_BASED_EXEC_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_EXECUTION_BITMAP:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MASK:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MATCH:
|
|
|
|
|
case VMCS_32BIT_CONTROL_CR3_TARGET_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_MSR_LOAD_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_EXCEPTION_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_INSTRUCTION_LENGTH:
|
|
|
|
|
case VMCS_32BIT_CONTROL_TPR_THRESHOLD:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit read only data fields */
|
|
|
|
|
/* binary 0100_01xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_INSTRUCTION_ERROR:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_REASON:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INTERRUPTION_INFO:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_IDT_VECTORING_INFO:
|
|
|
|
|
case VMCS_32BIT_IDT_VECTORING_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INSTRUCTION_INFO:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit guest-state fields */
|
|
|
|
|
/* binary 0100_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_GUEST_ES_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_CS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_SS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_DS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_FS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_GS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_LDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_TR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_GDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_IDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE:
|
|
|
|
|
case VMCS_32BIT_GUEST_ACTIVITY_STATE:
|
|
|
|
|
case VMCS_32BIT_GUEST_SMBASE:
|
|
|
|
|
case VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR:
|
|
|
|
|
field_64 = VMread32(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_CS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_SS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_DS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_FS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_GS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS:
|
|
|
|
|
field_64 = VMread32(encoding) >> 8;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit host-state fields */
|
|
|
|
|
/* binary 0100_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_HOST_IA32_SYSENTER_CS_MSR:
|
|
|
|
|
field_64 = VMread32(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit control fields */
|
|
|
|
|
/* binary 0010_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_A:
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_B:
|
|
|
|
|
case VMCS_64BIT_CONTROL_MSR_BITMAPS:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_TSC_OFFSET:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR:
|
|
|
|
|
field_64 = VMread64(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_A_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_B_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_MSR_BITMAPS_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_TSC_OFFSET_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR_HI:
|
|
|
|
|
field_64 = VMread32(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit guest state fields */
|
|
|
|
|
/* binary 0010_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_GUEST_LINK_POINTER:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_DEBUGCTL:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_PAT:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_EFER:
|
|
|
|
|
field_64 = VMread64(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMCS_64BIT_GUEST_LINK_POINTER_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_DEBUGCTL_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_PAT_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_EFER_HI:
|
|
|
|
|
field_64 = VMread32(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit host state fields */
|
|
|
|
|
/* binary 0010_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_PAT:
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_EFER:
|
|
|
|
|
field_64 = VMread64(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_PAT_HI:
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_EFER_HI:
|
|
|
|
|
field_64 = VMread32(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width control fields */
|
|
|
|
|
/* binary 0110_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_CONTROL_CR0_GUEST_HOST_MASK:
|
|
|
|
|
case VMCS_CONTROL_CR4_GUEST_HOST_MASK:
|
|
|
|
|
case VMCS_CONTROL_CR0_READ_SHADOW:
|
|
|
|
|
case VMCS_CONTROL_CR4_READ_SHADOW:
|
|
|
|
|
case VMCS_CR3_TARGET0:
|
|
|
|
|
case VMCS_CR3_TARGET1:
|
|
|
|
|
case VMCS_CR3_TARGET2:
|
|
|
|
|
case VMCS_CR3_TARGET3:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width read only data fields */
|
|
|
|
|
/* binary 0110_01xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_VMEXIT_QUALIFICATION:
|
|
|
|
|
case VMCS_IO_RCX:
|
|
|
|
|
case VMCS_IO_RSI:
|
|
|
|
|
case VMCS_IO_RDI:
|
|
|
|
|
case VMCS_IO_RIP:
|
|
|
|
|
case VMCS_GUEST_LINEAR_ADDR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width guest state fields */
|
|
|
|
|
/* binary 0110_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_GUEST_CR0:
|
|
|
|
|
case VMCS_GUEST_CR3:
|
|
|
|
|
case VMCS_GUEST_CR4:
|
|
|
|
|
case VMCS_GUEST_ES_BASE:
|
|
|
|
|
case VMCS_GUEST_CS_BASE:
|
|
|
|
|
case VMCS_GUEST_SS_BASE:
|
|
|
|
|
case VMCS_GUEST_DS_BASE:
|
|
|
|
|
case VMCS_GUEST_FS_BASE:
|
|
|
|
|
case VMCS_GUEST_GS_BASE:
|
|
|
|
|
case VMCS_GUEST_LDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_TR_BASE:
|
|
|
|
|
case VMCS_GUEST_GDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_IDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_DR7:
|
|
|
|
|
case VMCS_GUEST_RSP:
|
|
|
|
|
case VMCS_GUEST_RIP:
|
|
|
|
|
case VMCS_GUEST_RFLAGS:
|
|
|
|
|
case VMCS_GUEST_PENDING_DBG_EXCEPTIONS:
|
|
|
|
|
case VMCS_GUEST_IA32_SYSENTER_ESP_MSR:
|
|
|
|
|
case VMCS_GUEST_IA32_SYSENTER_EIP_MSR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width host state fields */
|
|
|
|
|
/* binary 0110_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_HOST_CR0:
|
|
|
|
|
case VMCS_HOST_CR3:
|
|
|
|
|
case VMCS_HOST_CR4:
|
|
|
|
|
case VMCS_HOST_FS_BASE:
|
|
|
|
|
case VMCS_HOST_GS_BASE:
|
|
|
|
|
case VMCS_HOST_TR_BASE:
|
|
|
|
|
case VMCS_HOST_GDTR_BASE:
|
|
|
|
|
case VMCS_HOST_IDTR_BASE:
|
|
|
|
|
case VMCS_HOST_IA32_SYSENTER_ESP_MSR:
|
|
|
|
|
case VMCS_HOST_IA32_SYSENTER_EIP_MSR:
|
|
|
|
|
case VMCS_HOST_RSP:
|
|
|
|
|
case VMCS_HOST_RIP:
|
|
|
|
|
field_64 = VMread64(encoding);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMREAD: not supported field %08x", encoding));
|
|
|
|
|
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
|
if (i->modC0()) {
|
|
|
|
|
BX_WRITE_64BIT_REG(i->rm(), field_64);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
write_virtual_qword_64(i->seg(), eaddr, field_64);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
Bit32u field_32 = GET32L(field_64);
|
|
|
|
|
|
|
|
|
|
if (i->modC0()) {
|
|
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), field_32);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
write_virtual_dword_32(i->seg(), eaddr, field_32);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VMsucceed();
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMREAD: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMWRITE(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMWRITE in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMWRITE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (! VMCSPTR_VALID()) {
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMWRITE with invalid VMCS ptr !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfailInvalid();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned encoding;
|
|
|
|
|
Bit64u val_64;
|
|
|
|
|
Bit32u val_32;
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
|
|
|
|
Bit64u enc_64;
|
|
|
|
|
|
|
|
|
|
if (i->modC0()) {
|
2009-10-08 18:33:08 +04:00
|
|
|
|
val_64 = BX_READ_64BIT_REG(i->rm());
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2009-10-08 18:33:08 +04:00
|
|
|
|
val_64 = read_virtual_qword_64(i->seg(), eaddr);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
2009-10-08 18:33:08 +04:00
|
|
|
|
|
|
|
|
|
enc_64 = BX_READ_64BIT_REG(i->nnn());
|
2009-01-31 13:43:24 +03:00
|
|
|
|
if (enc_64 >> 32) {
|
2009-05-30 19:09:38 +04:00
|
|
|
|
BX_ERROR(("VMWRITE: not supported field !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
encoding = GET32L(enc_64);
|
2009-10-08 18:33:08 +04:00
|
|
|
|
val_32 = GET32L(val_64);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
#endif
|
|
|
|
|
{
|
|
|
|
|
if (i->modC0()) {
|
2009-10-08 18:33:08 +04:00
|
|
|
|
val_32 = BX_READ_32BIT_REG(i->rm());
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Bit32u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2009-10-08 18:33:08 +04:00
|
|
|
|
val_32 = read_virtual_dword_32(i->seg(), eaddr);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
2009-10-08 18:33:08 +04:00
|
|
|
|
encoding = BX_READ_32BIT_REG(i->nnn());
|
|
|
|
|
val_64 = (Bit64u) val_32;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
if (VMCS_FIELD_TYPE(encoding) == VMCS_FIELD_TYPE_READ_ONLY)
|
|
|
|
|
{
|
|
|
|
|
BX_ERROR(("VMWRITE: write to read only field %08x", encoding));
|
|
|
|
|
VMfail(VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
switch(encoding) {
|
|
|
|
|
/* VMCS 16-bit guest-state fields */
|
|
|
|
|
/* binary 0000_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_16BIT_GUEST_ES_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_CS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_SS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_DS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_FS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_GS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_LDTR_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_GUEST_TR_SELECTOR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 16-bit host-state fields */
|
|
|
|
|
/* binary 0000_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_16BIT_HOST_ES_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_CS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_SS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_DS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_FS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_GS_SELECTOR:
|
|
|
|
|
case VMCS_16BIT_HOST_TR_SELECTOR:
|
2009-07-21 15:56:26 +04:00
|
|
|
|
VMwrite16(encoding, val_32 & 0xffff);
|
|
|
|
|
break;
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
/* VMCS 32_bit control fields */
|
|
|
|
|
/* binary 0100_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_CONTROL_PIN_BASED_EXEC_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PROCESSOR_BASED_EXEC_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_EXECUTION_BITMAP:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MASK:
|
|
|
|
|
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MATCH:
|
|
|
|
|
case VMCS_32BIT_CONTROL_CR3_TARGET_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_CONTROLS:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_MSR_LOAD_COUNT:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_EXCEPTION_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_CONTROL_VMENTRY_INSTRUCTION_LENGTH:
|
|
|
|
|
case VMCS_32BIT_CONTROL_TPR_THRESHOLD:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit guest-state fields */
|
|
|
|
|
/* binary 0100_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_GUEST_ES_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_CS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_SS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_DS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_FS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_GS_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_LDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_TR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_GDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_IDTR_LIMIT:
|
|
|
|
|
case VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE:
|
|
|
|
|
case VMCS_32BIT_GUEST_ACTIVITY_STATE:
|
|
|
|
|
case VMCS_32BIT_GUEST_SMBASE:
|
|
|
|
|
case VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR:
|
|
|
|
|
VMwrite32(encoding, val_32);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_CS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_SS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_DS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_FS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_GS_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS:
|
|
|
|
|
case VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS:
|
|
|
|
|
VMwrite32(encoding, val_32 << 8);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit host-state fields */
|
|
|
|
|
/* binary 0100_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_HOST_IA32_SYSENTER_CS_MSR:
|
|
|
|
|
VMwrite32(encoding, val_32);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit control fields */
|
|
|
|
|
/* binary 0010_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_A_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_B_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_MSR_BITMAPS_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_TSC_OFFSET_HI:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR_HI:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit guest state fields */
|
|
|
|
|
/* binary 0010_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_GUEST_LINK_POINTER_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_DEBUGCTL_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_PAT_HI:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_EFER_HI:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit host state fields */
|
|
|
|
|
/* binary 0010_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_PAT_HI:
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_EFER_HI:
|
|
|
|
|
VMwrite32(encoding, val_32);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit control fields */
|
|
|
|
|
/* binary 0010_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_A:
|
|
|
|
|
case VMCS_64BIT_CONTROL_IO_BITMAP_B:
|
|
|
|
|
case VMCS_64BIT_CONTROL_MSR_BITMAPS:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR:
|
|
|
|
|
case VMCS_64BIT_CONTROL_TSC_OFFSET:
|
|
|
|
|
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit guest state fields */
|
|
|
|
|
/* binary 0010_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_GUEST_LINK_POINTER:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_DEBUGCTL:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_PAT:
|
|
|
|
|
case VMCS_64BIT_GUEST_IA32_EFER:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS 64-bit host state fields */
|
|
|
|
|
/* binary 0010_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_PAT:
|
|
|
|
|
case VMCS_64BIT_HOST_IA32_EFER:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width control fields */
|
|
|
|
|
/* binary 0110_00xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_CONTROL_CR0_GUEST_HOST_MASK:
|
|
|
|
|
case VMCS_CONTROL_CR4_GUEST_HOST_MASK:
|
|
|
|
|
case VMCS_CONTROL_CR0_READ_SHADOW:
|
|
|
|
|
case VMCS_CONTROL_CR4_READ_SHADOW:
|
|
|
|
|
case VMCS_CR3_TARGET0:
|
|
|
|
|
case VMCS_CR3_TARGET1:
|
|
|
|
|
case VMCS_CR3_TARGET2:
|
|
|
|
|
case VMCS_CR3_TARGET3:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width guest state fields */
|
|
|
|
|
/* binary 0110_10xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_GUEST_CR0:
|
|
|
|
|
case VMCS_GUEST_CR3:
|
|
|
|
|
case VMCS_GUEST_CR4:
|
|
|
|
|
case VMCS_GUEST_ES_BASE:
|
|
|
|
|
case VMCS_GUEST_CS_BASE:
|
|
|
|
|
case VMCS_GUEST_SS_BASE:
|
|
|
|
|
case VMCS_GUEST_DS_BASE:
|
|
|
|
|
case VMCS_GUEST_FS_BASE:
|
|
|
|
|
case VMCS_GUEST_GS_BASE:
|
|
|
|
|
case VMCS_GUEST_LDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_TR_BASE:
|
|
|
|
|
case VMCS_GUEST_GDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_IDTR_BASE:
|
|
|
|
|
case VMCS_GUEST_DR7:
|
|
|
|
|
case VMCS_GUEST_RSP:
|
|
|
|
|
case VMCS_GUEST_RIP:
|
|
|
|
|
case VMCS_GUEST_RFLAGS:
|
|
|
|
|
case VMCS_GUEST_PENDING_DBG_EXCEPTIONS:
|
|
|
|
|
case VMCS_GUEST_IA32_SYSENTER_ESP_MSR:
|
|
|
|
|
case VMCS_GUEST_IA32_SYSENTER_EIP_MSR:
|
|
|
|
|
// fall through
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width host state fields */
|
|
|
|
|
/* binary 0110_11xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_HOST_CR0:
|
|
|
|
|
case VMCS_HOST_CR3:
|
|
|
|
|
case VMCS_HOST_CR4:
|
|
|
|
|
case VMCS_HOST_FS_BASE:
|
|
|
|
|
case VMCS_HOST_GS_BASE:
|
|
|
|
|
case VMCS_HOST_TR_BASE:
|
|
|
|
|
case VMCS_HOST_GDTR_BASE:
|
|
|
|
|
case VMCS_HOST_IDTR_BASE:
|
|
|
|
|
case VMCS_HOST_IA32_SYSENTER_ESP_MSR:
|
|
|
|
|
case VMCS_HOST_IA32_SYSENTER_EIP_MSR:
|
|
|
|
|
case VMCS_HOST_RSP:
|
|
|
|
|
case VMCS_HOST_RIP:
|
|
|
|
|
VMwrite64(encoding, val_64);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* VMCS 32-bit read only data fields */
|
|
|
|
|
/* binary 0100_01xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_32BIT_INSTRUCTION_ERROR:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_REASON:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INTERRUPTION_INFO:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_IDT_VECTORING_INFO:
|
|
|
|
|
case VMCS_32BIT_IDT_VECTORING_ERR_CODE:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH:
|
|
|
|
|
case VMCS_32BIT_VMEXIT_INSTRUCTION_INFO:
|
|
|
|
|
|
|
|
|
|
/* VMCS natural width read only data fields */
|
|
|
|
|
/* binary 0110_01xx_xxxx_xxx0 */
|
|
|
|
|
case VMCS_VMEXIT_QUALIFICATION:
|
|
|
|
|
case VMCS_IO_RCX:
|
|
|
|
|
case VMCS_IO_RSI:
|
|
|
|
|
case VMCS_IO_RDI:
|
|
|
|
|
case VMCS_IO_RIP:
|
|
|
|
|
case VMCS_GUEST_LINEAR_ADDR:
|
2009-05-30 19:09:38 +04:00
|
|
|
|
BX_ERROR(("VMWRITE: write to read/only field %08x", encoding));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
BX_ERROR(("VMWRITE: write to not supported field %08x", encoding));
|
|
|
|
|
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VMsucceed();
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMWRITE: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BX_CPU_C::VMCLEAR(bxInstruction_c *i)
|
|
|
|
|
{
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
if (! BX_CPU_THIS_PTR in_vmx || BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
|
BX_ERROR(("VMEXIT: VMCLEAR in VMX non-root operation"));
|
|
|
|
|
VMexit_Instruction(i, VMX_VMEXIT_VMCLEAR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CPL != 0)
|
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
|
|
|
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
|
|
|
|
Bit64u pAddr = read_virtual_qword(i->seg(), eaddr); // keep 64-bit
|
|
|
|
|
if ((pAddr & 0xfff) != 0 || ! IsValidPhyAddr(pAddr)) {
|
2009-05-21 14:39:40 +04:00
|
|
|
|
BX_ERROR(("VMFAIL: VMCLEAR with invalid physical address!"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMCLEAR_WITH_INVALID_ADDR);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-28 12:26:17 +04:00
|
|
|
|
if (pAddr == BX_CPU_THIS_PTR vmxonptr) {
|
|
|
|
|
BX_ERROR(("VMFAIL: VMLEAR with VMXON ptr !"));
|
2009-01-31 13:43:24 +03:00
|
|
|
|
VMfail(VMXERR_VMCLEAR_WITH_VMXON_VMCS_PTR);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// ensure that data for VMCS referenced by the operand is in memory
|
|
|
|
|
// initialize implementation-specific data in VMCS region
|
|
|
|
|
|
|
|
|
|
// clear VMCS launch state
|
|
|
|
|
Bit32u launch_state = VMCS_STATE_CLEAR;
|
2009-02-17 22:20:47 +03:00
|
|
|
|
access_write_physical(pAddr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4, &launch_state);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4,
|
|
|
|
|
BX_WRITE, (Bit8u*)(&launch_state));
|
|
|
|
|
|
2009-05-03 17:02:14 +04:00
|
|
|
|
if (pAddr == BX_CPU_THIS_PTR vmcsptr) {
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BX_CPU_THIS_PTR vmcsptr = BX_INVALID_VMCSPTR;
|
2009-05-03 17:02:14 +04:00
|
|
|
|
BX_CPU_THIS_PTR vmcshostptr = 0;
|
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
VMsucceed();
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
BX_INFO(("VMCLEAR: required VMX support, use --enable-vmx option"));
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
|
void BX_CPU_C::register_vmx_state(bx_param_c *parent)
|
|
|
|
|
{
|
|
|
|
|
// register VMX state for save/restore param tree
|
2009-05-28 12:26:17 +04:00
|
|
|
|
bx_list_c *vmx = new bx_list_c(parent, "VMX", 6);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmx, vmcsptr, BX_CPU_THIS_PTR vmcsptr);
|
2009-05-28 12:26:17 +04:00
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmx, vmxonptr, BX_CPU_THIS_PTR vmxonptr);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
BXRS_PARAM_BOOL(vmx, in_vmx, BX_CPU_THIS_PTR in_vmx);
|
|
|
|
|
BXRS_PARAM_BOOL(vmx, in_vmx_guest, BX_CPU_THIS_PTR in_vmx_guest);
|
2009-02-03 22:17:15 +03:00
|
|
|
|
BXRS_PARAM_BOOL(vmx, vmx_interrupt_window, BX_CPU_THIS_PTR vmx_interrupt_window);
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
|
|
bx_list_c *vmcache = new bx_list_c(vmx, "VMCS_CACHE", 5);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM-Execution Control Fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
bx_list_c *vmexec_ctrls = new bx_list_c(vmcache, "VMEXEC_CTRLS", 21);
|
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vmexec_ctrls1, BX_CPU_THIS_PTR vmcs.vmexec_ctrls1);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vmexec_ctrls2, BX_CPU_THIS_PTR vmcs.vmexec_ctrls2);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_exceptions_bitmap, BX_CPU_THIS_PTR vmcs.vm_exceptions_bitmap);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_pf_mask, BX_CPU_THIS_PTR vmcs.vm_pf_mask);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_pf_match, BX_CPU_THIS_PTR vmcs.vm_pf_match);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, io_bitmap_addr1, BX_CPU_THIS_PTR vmcs.io_bitmap_addr[0]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, io_bitmap_addr2, BX_CPU_THIS_PTR vmcs.io_bitmap_addr[1]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, tsc_offset, BX_CPU_THIS_PTR vmcs.tsc_offset);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, msr_bitmap_addr, BX_CPU_THIS_PTR vmcs.msr_bitmap_addr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr0_mask, BX_CPU_THIS_PTR vmcs.vm_cr0_mask);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr0_read_shadow, BX_CPU_THIS_PTR vmcs.vm_cr0_read_shadow);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr4_mask, BX_CPU_THIS_PTR vmcs.vm_cr4_mask);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr4_read_shadow, BX_CPU_THIS_PTR vmcs.vm_cr4_read_shadow);
|
|
|
|
|
BXRS_DEC_PARAM_FIELD(vmexec_ctrls, vm_cr3_target_cnt, BX_CPU_THIS_PTR vmcs.vm_cr3_target_cnt);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr3_target_value1, BX_CPU_THIS_PTR vmcs.vm_cr3_target_value[0]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr3_target_value2, BX_CPU_THIS_PTR vmcs.vm_cr3_target_value[1]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr3_target_value3, BX_CPU_THIS_PTR vmcs.vm_cr3_target_value[2]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_cr3_target_value4, BX_CPU_THIS_PTR vmcs.vm_cr3_target_value[3]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, virtual_apic_page_addr, BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vm_tpr_threshold, BX_CPU_THIS_PTR vmcs.vm_tpr_threshold);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, executive_vmcsptr, BX_CPU_THIS_PTR vmcs.executive_vmcsptr);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM-Exit Control Fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
bx_list_c *vmexit_ctrls = new bx_list_c(vmcache, "VMEXIT_CTRLS", 5);
|
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_ctrls, BX_CPU_THIS_PTR vmcs.vmexit_ctrls);
|
|
|
|
|
BXRS_DEC_PARAM_FIELD(vmexit_ctrls, vmexit_msr_store_cnt, BX_CPU_THIS_PTR vmcs.vmexit_msr_store_cnt);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_msr_store_addr, BX_CPU_THIS_PTR vmcs.vmexit_msr_store_addr);
|
|
|
|
|
BXRS_DEC_PARAM_FIELD(vmexit_ctrls, vmexit_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmexit_msr_load_cnt);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_msr_load_addr, BX_CPU_THIS_PTR vmcs.vmexit_msr_load_addr);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM-Entry Control Fields
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
bx_list_c *vmentry_ctrls = new bx_list_c(vmcache, "VMENTRY_CTRLS", 6);
|
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmentry_ctrls, vmentry_ctrls, BX_CPU_THIS_PTR vmcs.vmentry_ctrls);
|
|
|
|
|
BXRS_DEC_PARAM_FIELD(vmentry_ctrls, vmentry_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmentry_msr_load_cnt);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmentry_ctrls, vmentry_msr_load_addr, BX_CPU_THIS_PTR vmcs.vmentry_msr_load_addr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmentry_ctrls, vmentry_interr_info, BX_CPU_THIS_PTR vmcs.vmentry_interr_info);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmentry_ctrls, vmentry_excep_err_code, BX_CPU_THIS_PTR vmcs.vmentry_excep_err_code);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmentry_ctrls, vmentry_instr_length, BX_CPU_THIS_PTR vmcs.vmentry_instr_length);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// VM-Exit Information Fields
|
|
|
|
|
//
|
|
|
|
|
/*
|
|
|
|
|
bx_list_c *vmexit_info = new bx_list_c(vmcache, "VMEXIT_INFO", 14);
|
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_reason, BX_CPU_THIS_PTR vmcs.vmexit_reason);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_qualification, BX_CPU_THIS_PTR vmcs.vmexit_qualification);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_excep_info, BX_CPU_THIS_PTR vmcs.vmexit_excep_info);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_excep_error_code, BX_CPU_THIS_PTR vmcs.vmexit_excep_error_code);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_idt_vector_info, BX_CPU_THIS_PTR vmcs.vmexit_idt_vector_info);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_idt_vector_error_code, BX_CPU_THIS_PTR vmcs.vmexit_idt_vector_error_code);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_instr_info, BX_CPU_THIS_PTR vmcs.vmexit_instr_info);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_instr_length, BX_CPU_THIS_PTR vmcs.vmexit_instr_length);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_guest_laddr, BX_CPU_THIS_PTR vmcs.vmexit_guest_laddr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_io_rcx, BX_CPU_THIS_PTR vmcs.vmexit_io_rcx);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_io_rsi, BX_CPU_THIS_PTR vmcs.vmexit_io_rsi);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_io_rdi, BX_CPU_THIS_PTR vmcs.vmexit_io_rdi);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vmexit_io_rip, BX_CPU_THIS_PTR vmcs.vmexit_io_rip);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(vmexit_info, vm_instr_error, BX_CPU_THIS_PTR vmcs.vm_instr_error);
|
|
|
|
|
*/
|
|
|
|
|
//
|
|
|
|
|
// VMCS Host State
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
bx_list_c *host = new bx_list_c(vmcache, "HOST_STATE", 22);
|
|
|
|
|
|
|
|
|
|
#undef NEED_CPU_REG_SHORTCUTS
|
|
|
|
|
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, CR0, BX_CPU_THIS_PTR vmcs.host_state.cr0);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, CR3, BX_CPU_THIS_PTR vmcs.host_state.cr3);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, CR4, BX_CPU_THIS_PTR vmcs.host_state.cr4);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, ES, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_ES]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, CS, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_CS]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, SS, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_SS]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, DS, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_DS]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, FS, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_FS]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, FS_BASE, BX_CPU_THIS_PTR vmcs.host_state.fs_base);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, GS, BX_CPU_THIS_PTR vmcs.host_state.segreg_selector[BX_SEG_REG_GS]);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, GS_BASE, BX_CPU_THIS_PTR vmcs.host_state.gs_base);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, GDTR_BASE, BX_CPU_THIS_PTR vmcs.host_state.gdtr_base);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, IDTR_BASE, BX_CPU_THIS_PTR vmcs.host_state.idtr_base);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, TR, BX_CPU_THIS_PTR vmcs.host_state.tr_selector);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, TR_BASE, BX_CPU_THIS_PTR vmcs.host_state.tr_base);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, RSP, BX_CPU_THIS_PTR vmcs.host_state.rsp);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, RIP, BX_CPU_THIS_PTR vmcs.host_state.rip);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, sysenter_esp_msr, BX_CPU_THIS_PTR vmcs.host_state.sysenter_esp_msr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, sysenter_eip_msr, BX_CPU_THIS_PTR vmcs.host_state.sysenter_eip_msr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, sysenter_cs_msr, BX_CPU_THIS_PTR vmcs.host_state.sysenter_cs_msr);
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, pat_msr, BX_CPU_THIS_PTR vmcs.host_state.pat_msr);
|
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
BXRS_HEX_PARAM_FIELD(host, efer_msr, BX_CPU_THIS_PTR vmcs.host_state.efer_msr);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // BX_SUPPORT_VMX
|