apic virtualization + vmx fixes

This commit is contained in:
Stanislav Shwartsman 2010-03-16 14:51:20 +00:00
parent b8dfe6d9b1
commit 79466dffe2
12 changed files with 285 additions and 119 deletions

View File

@ -4,6 +4,7 @@ Brief summary :
- Major configure/cpu rework allowing to enable/disable CPU options at runtime
through .bochsrc (Stanislav)
- Bugfixes for CPU emulation correctness and stability
- Implemented VMX Apic Virtualization
- Implemented PCLMULQDQ AES instruction
- Extended Bochs internal debugger functionality
- USB HP DeskJet 920C printer device emulation (Ben Lunt)
@ -35,6 +36,10 @@ Detailed change log :
- CPU
- Implemented PCLMULQDQ AES instruction
- VMX: Enabled secondary proc-based vmexec controls
- Implemented APIC virtualization
- Implemented WBINVD VMEXIT control
- Implemented RDTSCP VMEXIT control
- Bugfixes for CPU emulation correctness
- Fixed Bochs crash when accessing the first byte above emulated memory size
@ -61,6 +66,7 @@ Detailed change log :
[2908481] USB Printer by Ben Lunt
- these S.F. bugs were closed/fixed
[2964824] bad newline sequence in aspi-win32.h
[913419] configure options and build process needs some work
[2938398] gdbstub compile error with x86_64 enabled
[2374455] shutdown/reset type 05 should reinit the PICs

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.cc,v 1.306 2010-03-14 15:51:26 sshwarts Exp $
// $Id: cpu.cc,v 1.307 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -749,8 +749,7 @@ void BX_CPU_C::prefetch(void)
BX_CPU_THIS_PTR eipFetchPtr = fetchPtr;
}
else {
BX_CPU_THIS_PTR eipFetchPtr = BX_MEM(0)->getHostMemAddr(BX_CPU_THIS,
BX_CPU_THIS_PTR pAddrPage, BX_EXECUTE);
BX_CPU_THIS_PTR eipFetchPtr = (const Bit8u*) getHostMemAddr(BX_CPU_THIS_PTR pAddrPage, BX_EXECUTE);
// Sanity checks
if (! BX_CPU_THIS_PTR eipFetchPtr) {

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.653 2010-03-15 14:18:35 sshwarts Exp $
// $Id: cpu.h,v 1.654 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -922,6 +922,8 @@ public: // for now...
bx_bool in_event;
bx_bool in_vmx;
bx_bool in_vmx_guest;
bx_bool in_smm_vmx; // save in_vmx and in_vmx_guest flags when in SMM mode
bx_bool in_smm_vmx_guest;
bx_bool vmx_interrupt_window;
Bit64u vmcsptr;
bx_hostpageaddr_t vmcshostptr;
@ -3091,6 +3093,8 @@ public: // for now...
BX_SMF void access_read_physical(bx_phy_address paddr, unsigned len, void *data);
BX_SMF void access_write_physical(bx_phy_address paddr, unsigned len, void *data);
BX_SMF bx_hostpageaddr_t getHostMemAddr(bx_phy_address addr, unsigned rw);
// linear address for translate_linear expected to be canonical !
BX_SMF bx_phy_address translate_linear(bx_address laddr, unsigned curr_pl, unsigned rw);
#if BX_CPU_LEVEL >= 6
@ -3386,11 +3390,12 @@ public: // for now...
BX_SMF void set_VMCSPTR(Bit64u vmxptr);
BX_SMF void init_VMCS(void);
BX_SMF void register_vmx_state(bx_param_c *parent);
BX_SMF bx_bool is_virtual_apic_page(bx_phy_address paddr) BX_CPP_AttrRegparmN(1);
BX_SMF Bit64s VMX_TSC_Offset(void);
BX_SMF Bit32u VMX_Read_TPR_Shadow(void);
#if BX_SUPPORT_X86_64
BX_SMF Bit32u VMX_Read_VTPR(void);
BX_SMF void VMX_Write_TPR_Shadow(Bit8u tpr_shadow);
#endif
BX_SMF void VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data);
BX_SMF void VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data);
// vmexit reasons
BX_SMF void VMexit_Instruction(bxInstruction_c *i, Bit32u reason) BX_CPP_AttrRegparmN(2);
BX_SMF void VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector,
@ -3404,6 +3409,7 @@ public: // for now...
BX_SMF void VMexit_INVLPG(bxInstruction_c *i, bx_address laddr) BX_CPP_AttrRegparmN(2);
BX_SMF void VMexit_RDTSC(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
BX_SMF void VMexit_RDPMC(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
BX_SMF void VMexit_WBINVD(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
BX_SMF bx_bool VMexit_CLTS(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
BX_SMF void VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr) BX_CPP_AttrRegparmN(3);
BX_SMF void VMexit_IO(bxInstruction_c *i, unsigned port, unsigned len) BX_CPP_AttrRegparmN(3);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: init.cc,v 1.231 2010-03-06 16:59:05 sshwarts Exp $
// $Id: init.cc,v 1.232 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -1026,6 +1026,7 @@ void BX_CPU_C::reset(unsigned source)
#if BX_SUPPORT_VMX
BX_CPU_THIS_PTR in_vmx = BX_CPU_THIS_PTR in_vmx_guest = 0;
BX_CPU_THIS_PTR in_smm_vmx = BX_CPU_THIS_PTR in_smm_vmx_guest = 0;
BX_CPU_THIS_PTR in_event = 0;
BX_CPU_THIS_PTR vmx_interrupt_window = 0;
BX_CPU_THIS_PTR vmcsptr = BX_CPU_THIS_PTR vmxonptr = BX_INVALID_VMCSPTR;

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: paging.cc,v 1.192 2010-03-14 15:51:26 sshwarts Exp $
// $Id: paging.cc,v 1.193 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -1353,8 +1353,7 @@ bx_phy_address BX_CPU_C::translate_linear(bx_address laddr, unsigned curr_pl, un
// Attempt to get a host pointer to this physical page. Put that
// pointer in the TLB cache. Note if the request is vetoed, NULL
// will be returned, and it's OK to OR zero in anyways.
tlbEntry->hostPageAddr = (bx_hostpageaddr_t) BX_MEM(0)->getHostMemAddr(BX_CPU_THIS, ppf, rw);
tlbEntry->hostPageAddr = BX_CPU_THIS_PTR getHostMemAddr(ppf, rw);
if (tlbEntry->hostPageAddr) {
// All access allowed also via direct pointer
#if BX_X86_DEBUGGER
@ -1551,9 +1550,7 @@ void BX_CPU_C::access_write_linear(bx_address laddr, unsigned len, unsigned curr
// We haven't seen this page, or it's been bumped before.
// Request a direct write pointer so we can do either R or W.
bx_hostpageaddr_t hostPageAddr = (bx_hostpageaddr_t)
BX_MEM(0)->getHostMemAddr(BX_CPU_THIS, lpf, BX_WRITE);
bx_hostpageaddr_t hostPageAddr = BX_CPU_THIS_PTR getHostMemAddr(lpf, BX_WRITE);
if (hostPageAddr) {
tlbEntry->lpf = lpf; // Got direct write pointer OK
tlbEntry->ppf = (bx_phy_address) lpf;
@ -1714,9 +1711,7 @@ void BX_CPU_C::access_read_linear(bx_address laddr, unsigned len, unsigned curr_
// We haven't seen this page, or it's been bumped before.
// Request a direct write pointer so we can do either R or W.
bx_hostpageaddr_t hostPageAddr = (bx_hostpageaddr_t)
BX_MEM(0)->getHostMemAddr(BX_CPU_THIS, lpf, BX_READ);
bx_hostpageaddr_t hostPageAddr = BX_CPU_THIS_PTR getHostMemAddr(lpf, BX_READ);
if (hostPageAddr) {
tlbEntry->lpf = lpf; // Got direct read pointer OK.
tlbEntry->ppf = (bx_phy_address) lpf;
@ -1784,6 +1779,13 @@ void BX_CPU_C::access_read_linear(bx_address laddr, unsigned len, unsigned curr_
void BX_CPU_C::access_write_physical(bx_phy_address paddr, unsigned len, void *data)
{
#if BX_SUPPORT_VMX
if (is_virtual_apic_page(paddr)) {
VMX_Virtual_Apic_Write(paddr, len, data);
return;
}
#endif
#if BX_SUPPORT_APIC
if (BX_CPU_THIS_PTR lapic.is_selected(paddr)) {
BX_CPU_THIS_PTR lapic.write(paddr, data, len);
@ -1796,6 +1798,13 @@ void BX_CPU_C::access_write_physical(bx_phy_address paddr, unsigned len, void *d
void BX_CPU_C::access_read_physical(bx_phy_address paddr, unsigned len, void *data)
{
#if BX_SUPPORT_VMX
if (is_virtual_apic_page(paddr)) {
VMX_Virtual_Apic_Read(paddr, len, data);
return;
}
#endif
#if BX_SUPPORT_APIC
if (BX_CPU_THIS_PTR lapic.is_selected(paddr)) {
BX_CPU_THIS_PTR lapic.read(paddr, data, len);
@ -1805,3 +1814,18 @@ void BX_CPU_C::access_read_physical(bx_phy_address paddr, unsigned len, void *da
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, paddr, len, data);
}
bx_hostpageaddr_t BX_CPU_C::getHostMemAddr(bx_phy_address ppf, unsigned rw)
{
#if BX_SUPPORT_VMX
if (is_virtual_apic_page(ppf))
return 0; // Do not allow direct access to virtual apic page
#endif
#if BX_SUPPORT_APIC
if (BX_CPU_THIS_PTR lapic.is_selected(ppf))
return 0; // Vetoed! APIC address space
#endif
return (bx_hostpageaddr_t) BX_MEM(0)->getHostMemAddr(BX_CPU_THIS, ppf, rw);
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.323 2010-03-15 15:48:01 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.324 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -179,12 +179,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::WBINVD(bxInstruction_c *i)
}
#if BX_SUPPORT_VMX
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (! SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)) {
BX_ERROR(("VMEXIT: WBINVD in VMX non-root operation"));
VMexit(i, VMX_VMEXIT_WBINVD, 0);
}
}
VMexit_WBINVD(i);
#endif
invalidate_prefetch_q();
@ -853,7 +848,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RqCq(bxInstruction_c *i)
#if BX_SUPPORT_VMX
VMexit_CR8_Read(i);
if (BX_CPU_THIS_PTR in_vmx_guest && VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW)) {
val_64 = VMX_Read_TPR_Shadow();
val_64 = (VMX_Read_VTPR() >> 4) & 0xf;
break;
}
#endif
@ -1495,9 +1490,17 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR4(bx_address val)
#endif
#if BX_SUPPORT_VMX
if (!(val & (1 << 13)) && BX_CPU_THIS_PTR in_vmx) {
BX_ERROR(("SetCR4(): Attempt to clear CR4.VMXE in vmx mode"));
exception(BX_GP_EXCEPTION, 0);
if (!(val & (1 << 13))) {
if (BX_CPU_THIS_PTR in_vmx) {
BX_ERROR(("SetCR4(): Attempt to clear CR4.VMXE in vmx mode"));
return 0;
}
}
else {
if (BX_CPU_THIS_PTR in_smm) {
BX_ERROR(("SetCR4(): Attempt to set CR4.VMXE in smm mode"));
return 0;
}
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: smm.cc,v 1.64 2010-03-15 22:58:41 sshwarts Exp $
// $Id: smm.cc,v 1.65 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006-2009 Stanislav Shwartsman
@ -121,6 +121,36 @@ void BX_CPU_C::enter_system_management_mode(void)
// debug(BX_CPU_THIS_PTR prev_rip);
//
// Processors that support VMX operation perform SMI delivery as follows:
//
#if BX_SUPPORT_VMX
// Enter SMM
// save the following internal to the processor:
// * CR4.VMXE
// * an indication of whether the logical processor was in VMX operation (root or non-root)
// IF the logical processor is in VMX operation
// THEN
// leave VMX operation;
// save VMX-critical state defined below;
// preserve current VMCS pointer as noted below;
// FI;
// CR4.VMXE = 0;
BX_CPU_THIS_PTR cr4.set_VMXE(0);
BX_CPU_THIS_PTR in_smm_vmx = BX_CPU_THIS_PTR in_vmx;
BX_CPU_THIS_PTR in_smm_vmx_guest = BX_CPU_THIS_PTR in_vmx_guest;
BX_CPU_THIS_PTR in_vmx = 0;
BX_CPU_THIS_PTR in_vmx_guest = 0;
BX_INFO(("enter_system_management_mode: temporary disable VMX while in SMM mode"));
// perform ordinary SMI delivery:
// * save processor state in SMRAM;
// * set processor state to standard SMM values
#endif
BX_CPU_THIS_PTR in_smm = 1;
BX_CPU_THIS_PTR disable_NMI = 1;
@ -470,6 +500,47 @@ bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
Bit32u temp_cr0 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0);
Bit32u temp_eflags = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS);
Bit32u temp_efer = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFER);
Bit32u temp_cr4 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4);
// Processors that support VMX operation perform RSM as follows:
#if BX_SUPPORT_VMX
// IF VMXE=1 in CR4 image in SMRAM
// THEN
// fail and enter shutdown state;
if (temp_cr4 & (1 << 13)) {
BX_PANIC(("SMM restore: CR4.VMXE is set in restore image !"));
return 0;
}
// restore state normally from SMRAM;
// CR4.VMXE = value stored internally;
// IF internal storage indicates that the logical processor had been in VMX operation (root or non-root)
// THEN
// enter VMX operation (root or non-root);
// restore VMX-critical state
// set CR0.PE, CR0.NE, and CR0.PG to 1;
// IF RFLAGS.VM = 0
// THEN
// CS.RPL = SS.DPL;
// SS.RPL = SS.DPL;
// FI;
// If necessary, restore current VMCS pointer;
// Leave SMM; Deassert SMMEM on subsequent bus transactions;
// IF logical processor will be in VMX operation after RSM
// THEN
// block A20M and leave A20M mode;
// FI;
if (BX_CPU_THIS_PTR in_smm_vmx) {
BX_CPU_THIS_PTR in_vmx = 1;
BX_CPU_THIS_PTR in_vmx_guest = BX_CPU_THIS_PTR in_smm_vmx_guest;
BX_INFO(("SMM Restore: enable VMX %s mode", BX_CPU_THIS_PTR in_vmx_guest ? "guest" : "host"));
temp_cr4 |= (1<<13); /* set VMXE */
temp_cr0 |= (1<<31) /* PG */ | (1 << 5) /* NE */ | 0x1 /* PE */;
// block and disable A20M;
}
#endif
bx_bool pe = (temp_cr0 & 0x1);
bx_bool nw = (temp_cr0 >> 29) & 0x1;
@ -488,7 +559,7 @@ bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
}
// shutdown if write to reserved CR4 bits
if (! SetCR4(SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4))) {
if (! SetCR4(temp_cr4)) {
BX_PANIC(("SMM restore: incorrect CR4 state !"));
return 0;
}

View File

@ -47,8 +47,7 @@ TODO (know issues in CPU model):
[!] VMX:
- Dual-monitor treatment of SMIs and SMM not implemented yet
- NMI virtualization, APIC virtualization not implemented yet
- VMENTER to not-active state not supported yet
- No advanced features like Extended Page Tables (EPT) or VPID
[!] SSE4A, SSE5A, SMX, SVM, AVX
[!] SSE4A, SMX, SVM, AVX

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vmexit.cc,v 1.16 2010-03-13 21:06:56 sshwarts Exp $
// $Id: vmexit.cc,v 1.17 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009 Stanislav Shwartsman
@ -131,8 +131,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_HLT(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT)) {
BX_ERROR(("VMEXIT: HLT"));
VMexit(i, VMX_VMEXIT_HLT, 0);
}
@ -142,8 +141,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_PAUSE(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT)) {
BX_ERROR(("VMEXIT: PAUSE"));
VMexit(i, VMX_VMEXIT_PAUSE, 0);
}
@ -153,8 +151,7 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_INVLPG(bxInstruction_c *i, bx_addre
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT)) {
BX_ERROR(("VMEXIT: INVLPG 0x" FMT_ADDRX, laddr));
VMexit(i, VMX_VMEXIT_INVLPG, laddr);
}
@ -175,8 +172,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDTSC(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT)) {
BX_ERROR(("VMEXIT: RDTSC"));
VMexit(i, VMX_VMEXIT_RDTSC, 0);
}
@ -186,8 +182,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDPMC(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT)) {
BX_ERROR(("VMEXIT: RDPMC"));
VMexit(i, VMX_VMEXIT_RDPMC, 0);
}
@ -198,8 +193,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MONITOR(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT)) {
BX_ERROR(("VMEXIT: MONITOR"));
VMexit(i, VMX_VMEXIT_MONITOR, 0);
}
@ -209,10 +203,9 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MWAIT(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT))
{
if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT)) {
BX_ERROR(("VMEXIT: MWAIT"));
VMexit(i, VMX_VMEXIT_MWAIT, 0);
VMexit(i, VMX_VMEXIT_MWAIT, BX_CPU_THIS_PTR monitor.armed);
}
}
#endif
@ -673,27 +666,23 @@ void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_DR_Access(bxInstruction_c *i, unsig
}
}
Bit32u BX_CPU_C::VMX_Read_TPR_Shadow(void)
Bit32u BX_CPU_C::VMX_Read_VTPR(void)
{
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr + 0x80;
Bit8u tpr_shadow;
access_read_physical(pAddr, 1, &tpr_shadow);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_READ, &tpr_shadow);
return (tpr_shadow >> 4) & 0xF;
Bit32u vtpr;
access_read_physical(pAddr, 4, &vtpr);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_READ, &vtpr);
return vtpr;
}
#if BX_SUPPORT_X86_64
void BX_CPU_C::VMX_Write_TPR_Shadow(Bit8u tpr_shadow)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_phy_address pAddr = vm->virtual_apic_page_addr + 0x80;
Bit8u field = tpr_shadow << 4;
Bit32u field32 = tpr_shadow << 4;
access_write_physical(pAddr, 1, &field);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_WRITE, &field);
access_write_physical(pAddr, 4, &field32);
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_WRITE, &field32);
if (tpr_shadow < vm->vm_tpr_threshold) {
// commit current instruction to produce trap-like VMexit
@ -702,6 +691,68 @@ void BX_CPU_C::VMX_Write_TPR_Shadow(Bit8u tpr_shadow)
}
}
#endif
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::is_virtual_apic_page(bx_phy_address paddr)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES))
if (LPFOf(paddr) == LPFOf(vm->apic_access_page)) return 1;
}
return 0;
}
void BX_CPU_C::VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
// access is not instruction fetch because cpu::prefetch will crash them
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
Bit32u vtpr = VMX_Read_VTPR();
if (len == 1)
*((Bit8u *) data) = vtpr & 0xff;
else if (len == 2)
*((Bit16u *) data) = vtpr & 0xffff;
else if (len == 4)
*((Bit32u *) data) = vtpr;
else
BX_PANIC(("PANIC: Unsupported Virtual APIC access len = 3 !"));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_READ_INSTRUCTION_EXECUTION;
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
}
void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
VMX_Write_TPR_Shadow(*((Bit8u *) data));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_WRITE_INSTRUCTION_EXECUTION;
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_WBINVD(bxInstruction_c *i)
{
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)) {
BX_ERROR(("VMEXIT: WBINVD in VMX non-root operation"));
VMexit(i, VMX_VMEXIT_WBINVD, 0);
}
}
#endif // BX_SUPPORT_VMX

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vmx.cc,v 1.39 2010-03-15 22:58:41 sshwarts Exp $
// $Id: vmx.cc,v 1.40 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009 Stanislav Shwartsman
@ -81,7 +81,7 @@ 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);
BX_CPU_THIS_PTR vmcshostptr = BX_CPU_THIS_PTR getHostMemAddr(vmxptr, BX_WRITE);
else
BX_CPU_THIS_PTR vmcshostptr = 0;
}
@ -305,6 +305,7 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
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);
vm->executive_vmcsptr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR);
vm->apic_access_page = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_APIC_ACCESS_ADDR);
//
// Check VM-execution control fields
@ -385,41 +386,21 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
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;
if (! (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES)) {
Bit8u tpr_shadow = (VMX_Read_VTPR() >> 4) & 0xf;
if (vm->vm_tpr_threshold > tpr_shadow) {
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: TPR threshold > TPR shadow"));
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
}
}
}
/*
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.
*/
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES) {
if ((vm->apic_access_page & 0xfff) != 0 || ! IsValidPhyAddr(vm->apic_access_page)) {
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: apic access page phy addr malformed"));
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
}
}
//
// Load VM-exit control fields to VMCS Cache
@ -1300,6 +1281,9 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
}
SetCR3(guest.cr3);
// flush TLB to invalidate possible APIC ACCESS PAGE caching by host
TLB_flush();
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;
@ -1892,8 +1876,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMXON(bxInstruction_c *i)
}
else {
// in VMX root operation mode
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMXON with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
VMfail(VMXERR_VMXON_IN_VMX_ROOT_OPERATION);
}
@ -1914,8 +1900,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMXOFF(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMXOFF);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMXOFF with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
/*
if dual-monitor treatment of SMIs and SMM is active
@ -1952,8 +1940,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMCALL(bxInstruction_c *i)
if (BX_CPU_THIS_PTR get_VM() || BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_COMPAT)
exception(BX_UD_EXCEPTION, 0);
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMCALL with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
if (BX_CPU_THIS_PTR in_smm /*||
(the logical processor does not support the dual-monitor treatment of SMIs and SMM) ||
@ -2032,8 +2022,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
VMexit_Instruction(i, vmlaunch ? VMX_VMEXIT_VMLAUNCH : VMX_VMEXIT_VMRESUME);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMLAUNCH/VMRESUME with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
if (! VMCSPTR_VALID()) {
BX_ERROR(("VMFAIL: VMLAUNCH with invalid VMCS ptr !"));
@ -2183,8 +2175,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMPTRLD(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMPTRLD);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMPTRLD with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u pAddr = read_virtual_qword(i->seg(), eaddr); // keep 64-bit
@ -2226,8 +2220,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMPTRST(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMPTRST);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMPTRST with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_qword(i->seg(), eaddr, BX_CPU_THIS_PTR vmcsptr);
@ -2249,8 +2245,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMREAD(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMREAD);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMREAD with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
if (! VMCSPTR_VALID()) {
BX_ERROR(("VMFAIL: VMREAD with invalid VMCS ptr !"));
@ -2529,8 +2527,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMWRITE(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMWRITE);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMWRITE with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
if (! VMCSPTR_VALID()) {
BX_ERROR(("VMFAIL: VMWRITE with invalid VMCS ptr !"));
@ -2821,8 +2821,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMCLEAR(bxInstruction_c *i)
VMexit_Instruction(i, VMX_VMEXIT_VMCLEAR);
}
if (CPL != 0)
if (CPL != 0) {
BX_ERROR(("VMCLEAR with CPL!=0 will cause #GP(0)"));
exception(BX_GP_EXCEPTION, 0);
}
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64u pAddr = read_virtual_qword(i->seg(), eaddr); // keep 64-bit
@ -2863,12 +2865,14 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMCLEAR(bxInstruction_c *i)
void BX_CPU_C::register_vmx_state(bx_param_c *parent)
{
// register VMX state for save/restore param tree
bx_list_c *vmx = new bx_list_c(parent, "VMX", 6);
bx_list_c *vmx = new bx_list_c(parent, "VMX", 8);
BXRS_HEX_PARAM_FIELD(vmx, vmcsptr, BX_CPU_THIS_PTR vmcsptr);
BXRS_HEX_PARAM_FIELD(vmx, vmxonptr, BX_CPU_THIS_PTR vmxonptr);
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);
BXRS_PARAM_BOOL(vmx, in_smm_vmx, BX_CPU_THIS_PTR in_smm_vmx);
BXRS_PARAM_BOOL(vmx, in_smm_vmx_guest, BX_CPU_THIS_PTR in_smm_vmx_guest);
BXRS_PARAM_BOOL(vmx, vmx_interrupt_window, BX_CPU_THIS_PTR vmx_interrupt_window);
bx_list_c *vmcache = new bx_list_c(vmx, "VMCS_CACHE", 5);
@ -2877,7 +2881,7 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
// VM-Execution Control Fields
//
bx_list_c *vmexec_ctrls = new bx_list_c(vmcache, "VMEXEC_CTRLS", 22);
bx_list_c *vmexec_ctrls = new bx_list_c(vmcache, "VMEXEC_CTRLS", 23);
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);
@ -2900,6 +2904,7 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
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, apic_access_page, BX_CPU_THIS_PTR vmcs.apic_access_page);
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, executive_vmcsptr, BX_CPU_THIS_PTR vmcs.executive_vmcsptr);
//

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: vmx.h,v 1.14 2010-03-15 15:49:55 sshwarts Exp $
// $Id: vmx.h,v 1.15 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2009 Stanislav Shwartsman
@ -153,6 +153,12 @@ enum VMX_vmabort_code {
VMABORT_VMEXIT_MACHINE_CHECK_ERROR
};
// VMX APIC ACCESS VMEXIT qualification
#define VMX_APIC_READ_INSTRUCTION_EXECUTION 0x0000
#define VMX_APIC_WRITE_INSTRUCTION_EXECUTION 0x1000
#define VMX_APIC_INSTRUCTION_FETCH 0x2000 /* won't happen because cpu::prefetch will crash */
#define VMX_APIC_ACCESS_DURING_EVENT_DELIVERY 0x3000
// =============
// VMCS fields
// =============
@ -573,7 +579,8 @@ typedef struct bx_VMCS
#else // only really supported features
#define VMX_VM_EXEC_CTRL3_SUPPORTED_BITS \
(VMX_VM_EXEC_CTRL3_RDTSCP | \
(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES | \
VMX_VM_EXEC_CTRL3_RDTSCP | \
VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)
#endif
@ -599,6 +606,7 @@ typedef struct bx_VMCS
bx_phy_address virtual_apic_page_addr;
Bit32u vm_tpr_threshold;
bx_phy_address apic_access_page;
Bit64u executive_vmcsptr;
@ -889,7 +897,7 @@ enum VMX_Activity_State {
// 63:10 reserved, must be zero
//
#define VMX_HIGHEST_VMCS_ENCODING 0x2A
#define VMX_HIGHEST_VMCS_ENCODING 0x2C
#define VMX_MSR_VMCS_ENUM_LO (VMX_HIGHEST_VMCS_ENCODING)
#define VMX_MSR_VMCS_ENUM_HI (0x00000000)

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: misc_mem.cc,v 1.143 2010-03-07 09:16:24 sshwarts Exp $
// $Id: misc_mem.cc,v 1.144 2010-03-16 14:51:20 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001-2009 The Bochs Project
@ -73,7 +73,7 @@ void BX_MEM_C::init_memory(Bit64u guest, Bit64u host)
{
unsigned idx;
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.143 2010-03-07 09:16:24 sshwarts Exp $"));
BX_DEBUG(("Init $Id: misc_mem.cc,v 1.144 2010-03-16 14:51:20 sshwarts Exp $"));
// accept only memory size which is multiply of 1M
BX_ASSERT((host & 0xfffff) == 0);
@ -572,13 +572,6 @@ Bit8u *BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, bx_phy_address addr, unsigned rw)
if (a20addr > BX_CONST64(0xffffffff)) is_bios = 0;
#endif
#if BX_SUPPORT_APIC
if (cpu != NULL) {
if (cpu->lapic.is_selected(a20addr))
return(NULL); // Vetoed! APIC address space
}
#endif
bx_bool write = rw & 1;
// allow direct access to SMRAM memory space for code and veto data
@ -592,7 +585,7 @@ Bit8u *BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, bx_phy_address addr, unsigned rw)
}
#if BX_SUPPORT_MONITOR_MWAIT
if (write && BX_MEM_THIS is_monitor(a20addr & ~0xfff, 0x1000)) {
if (write && BX_MEM_THIS is_monitor(a20addr & ~((bx_phy_address)(0xfff)), 0xfff)) {
// Vetoed! Write monitored page !
return(NULL);
}