introducr new class for VMCS mapping so it can be customized per cpuid

This commit is contained in:
Stanislav Shwartsman 2015-07-06 18:46:57 +00:00
parent 3b87e71346
commit 5fe1423ab6
6 changed files with 177 additions and 82 deletions

View File

@ -823,7 +823,6 @@ typedef struct
} bx_regs_msr_t;
#endif
#include "cpuid.h"
#include "crregs.h"
#include "descriptor.h"
#include "instr.h"
@ -1013,6 +1012,8 @@ struct BX_SMM_State;
struct BxOpcodeInfo_t;
struct bx_cpu_statistics;
#include "cpuid.h"
class BOCHSAPI BX_CPU_C : public logfunctions {
public: // for now...
@ -1196,6 +1197,7 @@ public: // for now...
VMCS_CACHE vmcs;
VMX_CAP vmx_cap;
VMCS_Mapping *vmcs_map;
#endif
#if BX_SUPPORT_SVM

View File

@ -27,8 +27,20 @@
#include "cpuid.h"
#define LOG_THIS cpu->
bx_cpuid_t::bx_cpuid_t(BX_CPU_C *_cpu): cpu(_cpu)
{
init();
}
#if BX_SUPPORT_VMX
bx_cpuid_t::bx_cpuid_t(BX_CPU_C *_cpu, Bit32u vmcs_revision, const char *filename):
cpu(_cpu), vmcs_map(vmcs_revision, filename)
{
init();
}
#endif
void bx_cpuid_t::init()
{
#if BX_SUPPORT_SMP
nthreads = SIM->get_param_num(BXPN_CPU_NTHREADS)->get();

View File

@ -121,11 +121,18 @@ enum {
#error "ISA extensions array limit exceeded!"
#endif
class VMCS_Mapping;
class bx_cpuid_t {
public:
bx_cpuid_t(BX_CPU_C *_cpu);
#if BX_SUPPORT_VMX
bx_cpuid_t(BX_CPU_C *_cpu, Bit32u vmcs_revision, const char *filename);
#endif
virtual ~bx_cpuid_t() {}
void init();
// return CPU name
virtual const char *get_name(void) const = 0;
@ -155,10 +162,8 @@ public:
virtual int wrmsr(Bit32u index, Bit64u msr) { return -1; }
#endif
#define BX_VMX_VMCS_REVISION_ID 0x2B /* better to be unique bochs VMCS revision id */
#if BX_SUPPORT_VMX
virtual Bit32u get_vmcs_revision_id(void) const { return BX_VMX_VMCS_REVISION_ID; }
VMCS_Mapping* get_vmcs() { return &vmcs_map; }
#endif
protected:
@ -198,6 +203,10 @@ protected:
void dump_cpuid_leaf(unsigned function, unsigned subfunction = 0) const;
void dump_cpuid(unsigned max_std_leaf, unsigned max_ext_leaf) const;
#if BX_SUPPORT_VMX
VMCS_Mapping vmcs_map;
#endif
};
typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);

View File

@ -24,47 +24,47 @@
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#define LOG_THIS BX_CPU(0)->
#if BX_SUPPORT_VMX
static unsigned vmcs_map[16][1+VMX_HIGHEST_VMCS_ENCODING];
void BX_CPU_C::init_VMCS(void)
VMCS_Mapping::VMCS_Mapping(Bit32u revision): revision_id(revision)
{
static bx_bool vmcs_map_ready = 0;
unsigned type, field;
clear();
init_generic_mapping();
}
init_vmx_capabilities();
VMCS_Mapping::VMCS_Mapping(Bit32u revision, const char *filename): revision_id(revision)
{
clear();
// read mapping from file
}
if (vmcs_map_ready) return;
vmcs_map_ready = 1;
for (type=0; type<16; type++) {
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
vmcs_map[type][field] = 0xffffffff;
}
}
BX_CPP_INLINE Bit32u vmcs_encoding(Bit32u type, Bit32u field)
{
Bit32u encoding = ((type & 0xc) << 11) + ((type & 0x3) << 10) + field;
return encoding;
}
void VMCS_Mapping::init_generic_mapping()
{
#if 1
// try to build generic VMCS map
for (type=0; type<16; type++) {
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
unsigned encoding = ((type & 0xc) << 11) + ((type & 3) << 10) + field;
// 16 types, 48 encodings (0x30), 4 bytes each field => 3072 bytes
// reserve VMCS_DATA_OFFSET bytes in the beginning for special (hidden) VMCS fields
for (unsigned type=0; type<16; type++) {
for (unsigned field=0; field < VMX_HIGHEST_VMCS_ENCODING; field++) {
Bit32u encoding = vmcs_encoding(type, field);
if (vmcs_map[type][field] != 0xffffffff) {
BX_PANIC(("VMCS type %d field %d (encoding = 0x%08x) is already initialized", type, field, encoding));
}
if (vmcs_field_supported(encoding)) {
// allocate 64 fields (4 byte each) per type
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 (encoding = 0x%08x) is out of VMCS boundaries", type, field, encoding));
}
BX_DEBUG(("VMCS field 0x%08x located at 0x%08x", encoding, vmcs_map[type][field]));
}
else {
BX_DEBUG(("VMCS field 0x%08x is not supported", encoding));
// allocate 64 fields (4 byte each) per type (even more than 48 which is required now)
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 (encoding = 0x%08x) is out of VMCS boundaries", type, field, encoding));
}
BX_DEBUG(("VMCS field 0x%08x located at 0x%08x", encoding, vmcs_map[type][field]));
}
}
#else
@ -73,12 +73,37 @@ void BX_CPU_C::init_VMCS(void)
#endif
}
#define VMCS_ENCODING_RESERVED_BITS (0xffff9000)
unsigned vmcs_field_offset(Bit32u encoding)
void VMCS_Mapping::clear()
{
if (encoding & VMCS_ENCODING_RESERVED_BITS)
for (unsigned type=0; type<16; type++) {
for (unsigned field=0; field < VMX_HIGHEST_VMCS_ENCODING; field++) {
vmcs_map[type][field] = 0xffffffff;
}
}
}
void VMCS_Mapping::clear_mapping(Bit32u encoding)
{
if (is_reserved(encoding))
return;
unsigned field = VMCS_FIELD(encoding);
if (field >= VMX_HIGHEST_VMCS_ENCODING)
return;
vmcs_map[VMCS_FIELD_INDEX(encoding)][field] = 0xffffffff;
}
unsigned VMCS_Mapping::vmcs_field_offset(Bit32u encoding) const
{
if (is_reserved(encoding)) {
switch(encoding) {
case VMCS_REVISION_ID_FIELD_ENCODING: return VMCS_REVISION_ID_FIELD_ADDR;
case VMCS_VMX_ABORT_FIELD_ENCODING: return VMCS_VMX_ABORT_FIELD_ADDR;
case VMCS_LAUNCH_STATE_FIELD_ENCODING: return VMCS_LAUNCH_STATE_FIELD_ADDR;
}
return 0xffffffff;
}
unsigned field = VMCS_FIELD(encoding);
if (field >= VMX_HIGHEST_VMCS_ENCODING)
@ -87,6 +112,31 @@ unsigned vmcs_field_offset(Bit32u encoding)
return vmcs_map[VMCS_FIELD_INDEX(encoding)][field];
}
void BX_CPU_C::init_VMCS(void)
{
BX_CPU_THIS_PTR vmcs_map = BX_CPU_THIS_PTR cpuid->get_vmcs();
init_vmx_capabilities();
static bx_bool vmcs_map_ready = 0;
if (vmcs_map_ready) return;
vmcs_map_ready = 1;
// disable not supported encodings
for (unsigned type=0; type<16; type++) {
for (unsigned field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
Bit32u encoding = vmcs_encoding(type, field);
if (! vmcs_field_supported(encoding)) {
BX_CPU_THIS_PTR vmcs_map->clear_mapping(encoding);
BX_DEBUG(("VMCS field 0x%08x is not supported", encoding));
}
}
}
}
#undef LOG_THIS
#define LOG_THIS BX_CPU_THIS_PTR
bx_bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
{
switch(encoding)

View File

@ -30,7 +30,7 @@
#if BX_SUPPORT_VMX
extern unsigned vmcs_field_offset(Bit32u encoding);
extern VMCS_Mapping vmcs_map;
#if BX_SUPPORT_VMX >= 2
extern bx_bool isValidMSR_PAT(Bit64u pat_msr);
@ -136,7 +136,7 @@ Bit16u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread16(unsigned encoding)
{
Bit16u field;
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -159,7 +159,7 @@ Bit16u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread16(unsigned encoding)
// write 16-bit value into VMCS 16-bit field
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite16(unsigned encoding, Bit16u val_16)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -182,7 +182,7 @@ Bit32u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread32(unsigned encoding)
{
Bit32u field;
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -203,7 +203,7 @@ Bit32u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread32(unsigned encoding)
// write 32-bit value into VMCS field
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite32(unsigned encoding, Bit32u val_32)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -226,7 +226,7 @@ Bit64u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread64(unsigned encoding)
Bit64u field;
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -249,7 +249,7 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite64(unsigned encoding, Bit64u val_64
{
BX_ASSERT(!IS_VMCS_FIELD_HI(encoding));
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(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;
@ -296,7 +296,7 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite_natural(unsigned encoding, bx_addr
Bit16u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread16_Shadow(unsigned encoding)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMread16_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -313,7 +313,7 @@ Bit16u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread16_Shadow(unsigned encoding)
// write 16-bit value into shadow VMCS 16-bit field
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite16_Shadow(unsigned encoding, Bit16u val_16)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMwrite16_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -326,7 +326,7 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite16_Shadow(unsigned encoding, Bit16u
Bit32u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread32_Shadow(unsigned encoding)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMread32_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -341,7 +341,7 @@ Bit32u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread32_Shadow(unsigned encoding)
// write 32-bit value into shadow VMCS field
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite32_Shadow(unsigned encoding, Bit32u val_32)
{
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMwrite32_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -354,7 +354,7 @@ Bit64u BX_CPP_AttrRegparmN(1) BX_CPU_C::VMread64_Shadow(unsigned encoding)
{
BX_ASSERT(!IS_VMCS_FIELD_HI(encoding));
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMread64_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -371,7 +371,7 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMwrite64_Shadow(unsigned encoding, Bit64u
{
BX_ASSERT(!IS_VMCS_FIELD_HI(encoding));
unsigned offset = vmcs_field_offset(encoding);
unsigned offset = BX_CPU_THIS_PTR vmcs_map->vmcs_field_offset(encoding);
if(offset >= VMX_VMCS_AREA_SIZE)
BX_PANIC(("VMwrite64_Shadow: can't access encoding 0x%08x, offset=0x%x", encoding, offset));
@ -401,10 +401,7 @@ BX_CPP_INLINE void BX_CPU_C::VMfail(Bit32u error_code)
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;
access_write_physical(pAddr, 4, &abort);
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, MEMTYPE(BX_CPU_THIS_PTR vmcs_memtype), BX_WRITE, BX_VMCS_ACCESS, (Bit8u*)(&abort));
VMwrite32(VMCS_VMX_ABORT_FIELD_ENCODING, (Bit32u) error_code);
#if BX_SUPPORT_VMX >= 2
// Deactivate VMX preemtion timer
@ -1677,9 +1674,9 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
}
revision &= ~BX_VMCS_SHADOW_BIT_MASK;
}
if (revision != BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()) {
if (revision != BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()) {
*qualification = (Bit64u) VMENTER_ERR_GUEST_STATE_LINK_POINTER;
BX_ERROR(("VMFAIL: VMCS link pointer incorrect revision ID %d != %d", revision, BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()));
BX_ERROR(("VMFAIL: VMCS link pointer incorrect revision ID %d != %d", revision, BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()));
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
}
@ -2580,8 +2577,8 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMXON(bxInstruction_c *i)
// not allowed to be shadow VMCS
Bit32u revision = VMXReadRevisionID((bx_phy_address) pAddr);
if (revision != BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()) {
BX_ERROR(("VMXON: not expected (%d != %d) VMCS revision id !", revision, BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()));
if (revision != BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()) {
BX_ERROR(("VMXON: not expected (%d != %d) VMCS revision id !", revision, BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()));
VMfailInvalid();
BX_NEXT_INSTR(i);
}
@ -2687,11 +2684,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMCALL(bxInstruction_c *i)
BX_NEXT_TRACE(i);
}
Bit32u launch_state;
access_read_physical(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4, &launch_state);
BX_NOTIFY_PHY_MEMORY_ACCESS(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4,
MEMTYPE(BX_CPU_THIS_PTR vmcs_memtype), BX_READ, BX_VMCS_ACCESS, (Bit8u*)(&launch_state));
Bit32u launch_state = VMread32(VMCS_LAUNCH_STATE_FIELD_ENCODING);
if (launch_state != VMCS_STATE_CLEAR) {
BX_ERROR(("VMFAIL: VMCALL with launched VMCS"));
VMfail(VMXERR_VMCALL_NON_CLEAR_VMCS);
@ -2763,10 +2756,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
BX_NEXT_TRACE(i);
}
Bit32u launch_state;
access_read_physical(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4, &launch_state);
BX_NOTIFY_PHY_MEMORY_ACCESS(BX_CPU_THIS_PTR vmcsptr + VMCS_LAUNCH_STATE_FIELD_ADDR, 4,
MEMTYPE(BX_CPU_THIS_PTR vmcs_memtype), BX_READ, BX_VMCS_ACCESS, (Bit8u*)(&launch_state));
Bit32u launch_state = VMread32(VMCS_LAUNCH_STATE_FIELD_ENCODING);
if (vmlaunch) {
if (launch_state != VMCS_STATE_CLEAR) {
@ -2826,12 +2816,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
// 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;
access_write_physical(pAddr, 4, &launch_state);
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, MEMTYPE(BX_CPU_THIS_PTR vmcs_memtype), BX_WRITE, BX_VMCS_ACCESS, (Bit8u*)(&launch_state));
}
if (vmlaunch) VMwrite32(VMCS_LAUNCH_STATE_FIELD_ENCODING, VMCS_STATE_LAUNCHED);
/*
Check settings of VMX controls and host-state area;
@ -2952,8 +2937,8 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMPTRLD(bxInstruction_c *i)
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_VMCS_SHADOWING))
revision &= ~BX_VMCS_SHADOW_BIT_MASK; // allowed to be shadow VMCS
if (revision != BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()) {
BX_ERROR(("VMPTRLD: not expected (%d != %d) VMCS revision id !", revision, BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id()));
if (revision != BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()) {
BX_ERROR(("VMPTRLD: not expected (%d != %d) VMCS revision id !", revision, BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id()));
VMfail(VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID);
}
else {
@ -3135,7 +3120,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMREAD_EdGd(bxInstruction_c *i)
unsigned encoding = BX_READ_32BIT_REG(i->src());
if (vmcs_field_offset(encoding) == 0xffffffff) {
if (! BX_CPU_THIS_PTR vmcs_map->is_valid(encoding)) {
BX_ERROR(("VMREAD: not supported field 0x%08x", encoding));
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
BX_NEXT_INSTR(i);
@ -3200,7 +3185,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMREAD_EqGq(bxInstruction_c *i)
}
unsigned encoding = BX_READ_32BIT_REG(i->src());
if (vmcs_field_offset(encoding) == 0xffffffff) {
if (! BX_CPU_THIS_PTR vmcs_map->is_valid(encoding)) {
BX_ERROR(("VMREAD: not supported field 0x%08x", encoding));
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
BX_NEXT_INSTR(i);
@ -3270,7 +3255,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMWRITE_GdEd(bxInstruction_c *i)
Bit32u encoding = BX_READ_32BIT_REG(i->dst());
if (vmcs_field_offset(encoding) == 0xffffffff) {
if (! BX_CPU_THIS_PTR vmcs_map->is_valid(encoding)) {
BX_ERROR(("VMWRITE: not supported field 0x%08x", encoding));
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
BX_NEXT_INSTR(i);
@ -3346,7 +3331,7 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMWRITE_GqEq(bxInstruction_c *i)
Bit32u encoding = BX_READ_32BIT_REG(i->dst());
if (vmcs_field_offset(encoding) == 0xffffffff) {
if (! BX_CPU_THIS_PTR vmcs_map->is_valid(encoding)) {
BX_ERROR(("VMWRITE: not supported field 0x%08x", encoding));
VMfail(VMXERR_UNSUPPORTED_VMCS_COMPONENT_ACCESS);
BX_NEXT_INSTR(i);

View File

@ -27,7 +27,7 @@
#define VMX_VMCS_AREA_SIZE 4096
// VMCS pointer is always 64-bit variable
#define BX_INVALID_VMCSPTR BX_CONST64(0xFFFFFFFFFFFFFFFF)
const Bit64u BX_INVALID_VMCSPTR = BX_CONST64(0xFFFFFFFFFFFFFFFF);
// bits supported in IA32_FEATURE_CONTROL MSR
#define BX_IA32_FEATURE_CONTROL_LOCK_BIT 0x1
@ -450,15 +450,52 @@ enum VMFunctions {
#define VMCS_FIELD_INDEX(encoding) \
((VMCS_FIELD_WIDTH(encoding) << 2) + VMCS_FIELD_TYPE(encoding))
#define VMCS_ENCODING_RESERVED_BITS (0xffff9000)
// =============
// VMCS layout
// =============
#define BX_VMX_VMCS_REVISION_ID 0x2B /* better to be unique bochs VMCS revision id */
struct VMCS_Mapping {
private:
Bit32u revision_id;
// assume 16 VMCS field types (encoded with 4 bits: 2 bits for VMCS_FIELD_TYPE and 2 bits for VMCS_FIELD_WIDTH)
unsigned vmcs_map[16][VMX_HIGHEST_VMCS_ENCODING];
void init_generic_mapping();
public:
VMCS_Mapping(Bit32u revision_id = BX_VMX_VMCS_REVISION_ID); // default VMCS mapping
VMCS_Mapping(Bit32u revision_id, const char *filename);
void clear();
void clear_mapping(Bit32u encoding);
void set_vmcs_revision_id(Bit32u revision) { revision_id = revision; }
Bit32u get_vmcs_revision_id() const { return revision_id; }
unsigned vmcs_field_offset(Bit32u encoding) const;
bx_bool is_reserved(Bit32u encoding) const {
return (encoding & VMCS_ENCODING_RESERVED_BITS) != 0;
}
bx_bool is_valid(Bit32u encoding) const {
return ! is_reserved(encoding) && (vmcs_field_offset(encoding) != 0xffffffff);
}
};
#define VMCS_LAUNCH_STATE_FIELD_ENCODING (0xfffffffe)
#define VMCS_VMX_ABORT_FIELD_ENCODING (0xfffffffc)
#define VMCS_REVISION_ID_FIELD_ENCODING (0xfffffffa)
#define VMCS_REVISION_ID_FIELD_ADDR (0x0000)
#define VMCS_VMX_ABORT_FIELD_ADDR (0x0004)
#define VMCS_LAUNCH_STATE_FIELD_ADDR (0x0008)
// invent Bochs CPU VMCS layout - allocate 64 fields of each type
#define VMCS_DATA_OFFSET (0x0010)
#if ((VMCS_DATA_OFFSET + 4*(64*15 + VMX_HIGHEST_VMCS_ENCODING)) > VMX_VMCS_AREA_SIZE)
@ -819,7 +856,7 @@ typedef struct bx_VMCS
// 56:63 reserved, must be zero
//
#define VMX_MSR_VMX_BASIC_LO (BX_CPU_THIS_PTR cpuid->get_vmcs_revision_id())
#define VMX_MSR_VMX_BASIC_LO (BX_CPU_THIS_PTR vmcs_map->get_vmcs_revision_id())
#define VMX_MSR_VMX_BASIC_HI \
(VMX_VMCS_AREA_SIZE | ((!is_cpu_extension_supported(BX_ISA_LONG_MODE)) << 16) | \
(BX_MEMTYPE_WB << 18) | (1<<22)) | ((BX_SUPPORT_VMX >= 2) ? (1<<23) : 0)