- IO intercept is not implemented yet
 - MSR intercept is not implemented yet

VMX:
 Fixed Bochs PANIC crash when doing I/O access crossing VMX I/O permission bitmaps.
 This can happen because access_physical_read and access_physical_write cannot access memory cross 4K boundary.
This commit is contained in:
Stanislav Shwartsman 2011-12-25 22:09:31 +00:00
parent ea6dfe3dc0
commit bfcbb81602
7 changed files with 185 additions and 28 deletions

View File

@ -444,8 +444,8 @@ BOCHSAPI extern Bit32u apic_id_mask;
#define BX_EPT_PDPTE_ACCESS 0x0b0
#define BX_EPT_PML4E_ACCESS 0x0c0
#define BX_VMCS_ACCESS 0x0d0
#define BX_VMX_MSR_BITMAP_ACCESS 0x0e0
#define BX_VMX_IO_BITMAP_ACCESS 0x0f0
#define BX_MSR_BITMAP_ACCESS 0x0e0
#define BX_IO_BITMAP_ACCESS 0x0f0
#define BX_VMX_LOAD_MSR_ACCESS 0x100
#define BX_VMX_STORE_MSR_ACCESS 0x110
#define BX_VMX_VTPR_ACCESS 0x120

View File

@ -644,8 +644,8 @@ void bx_dbg_phy_memory_access(unsigned cpu, bx_phy_address phy, unsigned len, un
"EPT PDPTE",
"EPT PML4E",
"VMCS",
"VMX MSR BITMAP",
"VMX I/O BITMAP",
"MSR BITMAP",
"I/O BITMAP",
"VMX LDMSR",
"VMX STMSR",
"VMX VTPR",

View File

@ -4265,8 +4265,8 @@ public: // for now...
BX_SMF void SvmInjectEvents(bx_phy_address vmcbaddr);
BX_SMF void SvmInterceptException(bxInstruction_c *i, unsigned vector,
Bit16u errcode, bx_bool errcode_valid, Bit64u qualification = 0);
BX_SMF void SvmInterceptIO(bxInstruction_c *i, unsigned op, Bit32u msr);
BX_SMF void SvmInterceptMSR(bxInstruction_c *i, unsigned port, unsigned len);
BX_SMF void SvmInterceptIO(bxInstruction_c *i, unsigned port, unsigned len);
BX_SMF void SvmInterceptMSR(bxInstruction_c *i, unsigned op, Bit32u msr);
BX_SMF void register_svm_state(bx_param_c *parent);
#endif

View File

@ -1004,6 +1004,9 @@ void BX_CPU_C::reset(unsigned source)
}
#endif
#if BX_SUPPORT_VMX || BX_SUPPORT_SVM
BX_CPU_THIS_PTR tsc_offset = 0;
#endif
if (source == BX_RESET_HARDWARE) {
BX_CPU_THIS_PTR set_TSC(0); // do not change TSC on INIT
}

View File

@ -44,49 +44,65 @@ BX_CPP_INLINE Bit64u CanonicalizeAddress(Bit64u laddr)
BX_CPP_INLINE Bit8u BX_CPU_C::vmcb_read8(bx_phy_address vmcbaddr, unsigned offset)
{
Bit32u val_8;
access_read_physical(vmcbaddr + offset, 1, (Bit8u*)(&val_8));
bx_phy_address pAddr = vmcbaddr + offset;
access_read_physical(pAddr, 1, (Bit8u*)(&val_8));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMCS_ACCESS | BX_READ, (Bit8u*)(&val_8));
return val_8;
}
BX_CPP_INLINE Bit16u BX_CPU_C::vmcb_read16(bx_phy_address vmcbaddr, unsigned offset)
{
Bit32u val_16;
access_read_physical(vmcbaddr + offset, 2, (Bit8u*)(&val_16));
bx_phy_address pAddr = vmcbaddr + offset;
access_read_physical(pAddr, 2, (Bit8u*)(&val_16));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_VMCS_ACCESS | BX_READ, (Bit8u*)(&val_16));
return val_16;
}
BX_CPP_INLINE Bit32u BX_CPU_C::vmcb_read32(bx_phy_address vmcbaddr, unsigned offset)
{
Bit32u val_32;
access_read_physical(vmcbaddr + offset, 4, (Bit8u*)(&val_32));
bx_phy_address pAddr = vmcbaddr + offset;
access_read_physical(pAddr, 4, (Bit8u*)(&val_32));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMCS_ACCESS | BX_READ, (Bit8u*)(&val_32));
return val_32;
}
BX_CPP_INLINE Bit64u BX_CPU_C::vmcb_read64(bx_phy_address vmcbaddr, unsigned offset)
{
Bit64u val_64;
access_read_physical(vmcbaddr + offset, 8, (Bit8u*)(&val_64));
bx_phy_address pAddr = vmcbaddr + offset;
access_read_physical(pAddr, 8, (Bit8u*)(&val_64));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_VMCS_ACCESS | BX_READ, (Bit8u*)(&val_64));
return val_64;
}
BX_CPP_INLINE void BX_CPU_C::vmcb_write8(bx_phy_address vmcbaddr, unsigned offset, Bit8u val_8)
{
access_write_physical(vmcbaddr + offset, 1, (Bit8u*)(&val_8));
bx_phy_address pAddr = vmcbaddr + offset;
access_write_physical(pAddr, 1, (Bit8u*)(&val_8));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMCS_ACCESS | BX_WRITE, (Bit8u*)(&val_8));
}
BX_CPP_INLINE void BX_CPU_C::vmcb_write16(bx_phy_address vmcbaddr, unsigned offset, Bit16u val_16)
{
access_write_physical(vmcbaddr + offset, 2, (Bit8u*)(&val_16));
bx_phy_address pAddr = vmcbaddr + offset;
access_write_physical(pAddr, 2, (Bit8u*)(&val_16));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_VMCS_ACCESS | BX_WRITE, (Bit8u*)(&val_16));
}
BX_CPP_INLINE void BX_CPU_C::vmcb_write32(bx_phy_address vmcbaddr, unsigned offset, Bit32u val_32)
{
access_write_physical(vmcbaddr + offset, 4, (Bit8u*)(&val_32));
bx_phy_address pAddr = vmcbaddr + offset;
access_write_physical(pAddr, 4, (Bit8u*)(&val_32));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMCS_ACCESS | BX_WRITE, (Bit8u*)(&val_32));
}
BX_CPP_INLINE void BX_CPU_C::vmcb_write64(bx_phy_address vmcbaddr, unsigned offset, Bit64u val_64)
{
access_write_physical(vmcbaddr + offset, 8, (Bit8u*)(&val_64));
bx_phy_address pAddr = vmcbaddr + offset;
access_write_physical(pAddr, 8, (Bit8u*)(&val_64));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 8, BX_VMCS_ACCESS | BX_WRITE, (Bit8u*)(&val_64));
}
BX_CPP_INLINE void BX_CPU_C::svm_segment_read(bx_phy_address vmcbaddr, bx_segment_reg_t *seg, unsigned offset)
@ -537,12 +553,128 @@ void BX_CPU_C::SvmInterceptException(bxInstruction_c *i, unsigned vector, Bit16u
{
}
void BX_CPU_C::SvmInterceptIO(bxInstruction_c *i, unsigned op, Bit32u msr)
#define SVM_VMEXIT_IO_PORTIN (1 << 0)
#define SVM_VMEXIT_IO_INSTR_STRING (1 << 2)
#define SVM_VMEXIT_IO_INSTR_REP (1 << 3)
#define SVM_VMEXIT_IO_INSTR_LEN8 (1 << 4)
#define SVM_VMEXIT_IO_INSTR_LEN16 (1 << 5)
#define SVM_VMEXIT_IO_INSTR_LEN32 (1 << 6)
void BX_CPU_C::SvmInterceptIO(bxInstruction_c *i, unsigned port, unsigned len)
{
if (! BX_CPU_THIS_PTR in_svm_guest) return;
if (! SVM_INTERCEPT(0, SVM_INTERCEPT0_IO)) return;
Bit8u bitmap[2];
bx_phy_address pAddr;
// access_read_physical cannot read 2 bytes cross 4K boundary :(
pAddr = BX_CPU_THIS_PTR vmcb.ctrls.iopm_base + (port / 8);
access_read_physical(pAddr, 1, &bitmap[0]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[0]);
pAddr++;
access_read_physical(pAddr, 1, &bitmap[1]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[1]);
Bit16u combined_bitmap = bitmap[1];
combined_bitmap = (combined_bitmap << 8) | bitmap[0];
unsigned mask = ((1 << len) - 1) << (port & 7);
if (combined_bitmap & mask) {
BX_ERROR(("SVM VMEXIT: I/O port 0x%04x", port));
Bit32u qualification = 0;
switch(i->getIaOpcode()) {
case BX_IA_IN_ALIb:
case BX_IA_IN_AXIb:
case BX_IA_IN_EAXIb:
case BX_IA_IN_ALDX:
case BX_IA_IN_AXDX:
case BX_IA_IN_EAXDX:
qualification = SVM_VMEXIT_IO_PORTIN;
break;
case BX_IA_OUT_IbAL:
case BX_IA_OUT_IbAX:
case BX_IA_OUT_IbEAX:
case BX_IA_OUT_DXAL:
case BX_IA_OUT_DXAX:
case BX_IA_OUT_DXEAX:
qualification = 0; // PORTOUT
break;
case BX_IA_REP_INSB_YbDX:
case BX_IA_REP_INSW_YwDX:
case BX_IA_REP_INSD_YdDX:
qualification = SVM_VMEXIT_IO_PORTIN | SVM_VMEXIT_IO_INSTR_STRING;
if (i->repUsedL())
qualification |= SVM_VMEXIT_IO_INSTR_REP;
break;
case BX_IA_REP_OUTSB_DXXb:
case BX_IA_REP_OUTSW_DXXw:
case BX_IA_REP_OUTSD_DXXd:
qualification = SVM_VMEXIT_IO_INSTR_STRING; // PORTOUT
if (i->repUsedL())
qualification |= SVM_VMEXIT_IO_INSTR_REP;
break;
default:
BX_PANIC(("VMexit_IO: I/O instruction %s unknown", i->getIaOpcodeName()));
}
qualification |= (port << 16);
if (len == 1)
qualification |= SVM_VMEXIT_IO_INSTR_LEN8;
else if (len == 2)
qualification |= SVM_VMEXIT_IO_INSTR_LEN16;
else if (len == 4)
qualification |= SVM_VMEXIT_IO_INSTR_LEN32;
vmcb_write64(BX_CPU_THIS_PTR vmcbptr, SVM_CONTROL_EXITINFO1, qualification);
Svm_Vmexit(SVM_VMEXIT_IO);
}
}
void BX_CPU_C::SvmInterceptMSR(bxInstruction_c *i, unsigned port, unsigned len)
void BX_CPU_C::SvmInterceptMSR(bxInstruction_c *i, unsigned op, Bit32u msr)
{
if (! BX_CPU_THIS_PTR in_svm_guest) return;
if (! SVM_INTERCEPT(0, SVM_INTERCEPT0_MSR)) return;
BX_ASSERT(op == BX_READ || op == BX_WRITE);
bx_bool vmexit = 1;
int msr_map_offset = -1;
if (msr <= 0x1fff) {
msr_map_offset = 0;
}
else if (msr <= 0xc0001fff) {
msr_map_offset = 2048;
}
else if (msr <= 0xc0011fff) {
msr_map_offset = 4096;
}
if (msr_map_offset >= 0) {
bx_phy_address msr_bitmap_addr = BX_CPU_THIS_PTR vmcb.ctrls.msrpm_base + msr_map_offset;
Bit32u msr_offset = (msr & 0x1fff) * 2 + op;
Bit8u msr_bitmap;
access_read_physical(msr_bitmap_addr + (msr_offset / 8), 1, (Bit8u*)(&msr_bitmap));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, msr_bitmap_addr + (msr_offset / 8), 1, BX_MSR_BITMAP_ACCESS | BX_READ, &msr_bitmap);
vmexit = (msr_bitmap >> (msr_offset & 7)) & 0x1;
}
if (vmexit) {
vmcb_write64(BX_CPU_THIS_PTR vmcbptr, SVM_CONTROL_EXITINFO1, op); // 0 - RDMSR, 1 - WRMSR
Svm_Vmexit(SVM_VMEXIT_MSR);
}
}
#endif

View File

@ -389,7 +389,7 @@ void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op
// check MSR-HI bitmaps
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + 1024 + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
access_read_physical(pAddr, 1, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_MSR_BITMAP_ACCESS | BX_READ, &field);
if (field & (1 << (msr & 7)))
vmexit = 1;
}
@ -400,7 +400,7 @@ void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op
// check MSR-LO bitmaps
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
access_read_physical(pAddr, 1, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_MSR_BITMAP_ACCESS | BX_READ, &field);
if (field & (1 << (msr & 7)))
vmexit = 1;
}
@ -429,13 +429,35 @@ void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_IO(bxInstruction_c *i, unsigned por
// always VMEXIT on port "wrap around" case
if ((port + len) > 0x10000) vmexit = 1;
else {
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) >> 3);
Bit16u bitmap;
access_read_physical(pAddr, 2, (Bit8u*) &bitmap);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_VMX_IO_BITMAP_ACCESS | BX_READ, (Bit8u*) &bitmap);
Bit8u bitmap[2];
bx_phy_address pAddr;
if ((port & 0x7fff) + len > 0x8000) {
// special case - the IO access split cross both I/O bitmaps
pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[0] + 0xfff;
access_read_physical(pAddr, 1, &bitmap[0]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[0]);
pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[1];
access_read_physical(pAddr, 1, &bitmap[1]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[1]);
}
else {
// access_read_physical cannot read 2 bytes cross 4K boundary :(
pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) / 8);
access_read_physical(pAddr, 1, &bitmap[0]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[0]);
pAddr++;
access_read_physical(pAddr, 1, &bitmap[1]);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_IO_BITMAP_ACCESS | BX_READ, &bitmap[1]);
}
Bit16u combined_bitmap = bitmap[1];
combined_bitmap = (combined_bitmap << 8) | bitmap[0];
unsigned mask = ((1 << len) - 1) << (port & 7);
if (bitmap & mask) vmexit = 1;
if (combined_bitmap & mask) vmexit = 1;
}
}
else if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_VMEXIT)) vmexit = 1;

View File

@ -1492,11 +1492,6 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
// Load Guest State -> VMENTER
//
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_TSC_OFFSET)
BX_CPU_THIS_PTR tsc_offset = VMread64(VMCS_64BIT_CONTROL_TSC_OFFSET);
else
BX_CPU_THIS_PTR tsc_offset = 0;
#if BX_SUPPORT_X86_64
#if BX_SUPPORT_VMX >= 2
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_EFER_MSR) {
@ -2541,6 +2536,11 @@ BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
BX_CPU_THIS_PTR in_vmx_guest = 1;
BX_CPU_THIS_PTR disable_INIT = 0;
if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET))
BX_CPU_THIS_PTR tsc_offset = VMread64(VMCS_64BIT_CONTROL_TSC_OFFSET);
else
BX_CPU_THIS_PTR tsc_offset = 0;
#if BX_SUPPORT_VMX >= 2
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT)) {
Bit32u timer_value = VMread32(VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE);