implement pdptr checks in legacy PAE mode

This commit is contained in:
Stanislav Shwartsman 2009-05-31 07:49:04 +00:00
parent 222129db4b
commit 03ba2ec988
4 changed files with 61 additions and 34 deletions

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.600 2009-05-30 15:09:38 sshwarts Exp $ // $Id: cpu.h,v 1.601 2009-05-31 07:49:03 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2001 MandrakeSoft S.A. // Copyright (C) 2001 MandrakeSoft S.A.
@ -3095,7 +3095,7 @@ public: // for now...
BX_SMF void pagingCR0Changed(Bit32u oldCR0, Bit32u newCR0) BX_CPP_AttrRegparmN(2); BX_SMF void pagingCR0Changed(Bit32u oldCR0, Bit32u newCR0) BX_CPP_AttrRegparmN(2);
BX_SMF void pagingCR4Changed(Bit32u oldCR4, Bit32u newCR4) BX_CPP_AttrRegparmN(2); BX_SMF void pagingCR4Changed(Bit32u oldCR4, Bit32u newCR4) BX_CPP_AttrRegparmN(2);
#if BX_SUPPORT_PAE #if BX_SUPPORT_PAE
BX_SMF bx_bool CheckPDPTR(bx_bool pg, bx_bool pae, bx_address cr3_val); BX_SMF bx_bool CheckPDPTR(Bit32u cr3_val) BX_CPP_AttrRegparmN(1);
#endif #endif
BX_SMF void reset(unsigned source); BX_SMF void reset(unsigned source);

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: paging.cc,v 1.175 2009-05-30 15:09:38 sshwarts Exp $ // $Id: paging.cc,v 1.176 2009-05-31 07:49:04 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2001 MandrakeSoft S.A. // Copyright (C) 2001 MandrakeSoft S.A.
@ -448,8 +448,7 @@ BX_CPU_C::pagingCR4Changed(Bit32u oldCR4, Bit32u newCR4)
#endif #endif
} }
void BX_CPP_AttrRegparmN(1) void BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR3(bx_address val)
BX_CPU_C::SetCR3(bx_address val)
{ {
// flush TLB even if value does not change // flush TLB even if value does not change
#if BX_SUPPORT_GLOBAL_PAGES #if BX_SUPPORT_GLOBAL_PAGES
@ -478,7 +477,9 @@ BX_CPU_C::SetCR3(bx_address val)
} }
else else
#endif #endif
{
BX_CPU_THIS_PTR cr3_masked = val & 0xffffffe0; BX_CPU_THIS_PTR cr3_masked = val & 0xffffffe0;
}
} }
else else
#endif #endif
@ -488,26 +489,28 @@ BX_CPU_C::SetCR3(bx_address val)
} }
#if BX_SUPPORT_PAE #if BX_SUPPORT_PAE
bx_bool BX_CPU_C::CheckPDPTR(bx_bool pg, bx_bool pae, bx_address cr3_val) bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::CheckPDPTR(Bit32u cr3_val)
{ {
if (pg && pae && !long_mode()) cr3_val &= 0xffffffe0;
{
cr3_val &= 0xffffffe0;
for (int n=0; n<4; n++) { for (int n=0; n<4; n++) {
Bit64u pdptr; // read PDPE cache entry
// read PDPE cache entry bx_phy_address entry_pdpe_addr = (bx_phy_address) (cr3_val | (n << 3));
bx_phy_address entry_pdpe_addr = (bx_phy_address) (cr3_val | (n << 3)); access_read_physical(entry_pdpe_addr, 8, &(BX_CPU_THIS_PTR PDPE_CACHE.entry[n]));
access_read_physical(entry_pdpe_addr, 8, (Bit8u*)(&pdptr)); BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, entry_pdpe_addr, 8,
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, entry_pdpe_addr, 8, BX_READ, (Bit8u*)(&pdptr)); BX_READ, (Bit8u*)(&BX_CPU_THIS_PTR PDPE_CACHE.entry[n]));
if (pdptr & 0x1) { Bit64u pdptr = BX_CPU_THIS_PTR PDPE_CACHE.entry[n];
if (pdptr & PAGING_PAE_PDPE_RESERVED_BITS) if (pdptr & 0x1) {
return 0; if (pdptr & PAGING_PAE_PDPE_RESERVED_BITS) {
BX_CPU_THIS_PTR PDPE_CACHE.valid = 0;
return 0;
} }
} }
} }
BX_CPU_THIS_PTR PDPE_CACHE.valid = 1;
return 1; /* PDPTRs are fine */ return 1; /* PDPTRs are fine */
} }
#endif #endif

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.297 2009-05-30 15:09:38 sshwarts Exp $ // $Id: proc_ctrl.cc,v 1.298 2009-05-31 07:49:04 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (C) 2001 MandrakeSoft S.A. // Copyright (C) 2001 MandrakeSoft S.A.
@ -650,7 +650,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
#if BX_SUPPORT_VMX #if BX_SUPPORT_VMX
VMexit_CR3_Write(i, val_32); VMexit_CR3_Write(i, val_32);
#endif #endif
// Reserved bits take on value of MOV instruction if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE() && !long_mode()) {
if (! CheckPDPTR(val_32)) {
BX_ERROR(("SetCR3(): PDPTR check failed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
SetCR3(val_32); SetCR3(val_32);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32); BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32);
break; break;
@ -659,6 +664,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
#if BX_SUPPORT_VMX #if BX_SUPPORT_VMX
val_32 = VMexit_CR4_Write(i, val_32); val_32 = VMexit_CR4_Write(i, val_32);
#endif #endif
if (BX_CPU_THIS_PTR cr0.get_PG() && (val_32 & (1<<5)) != 0 /* PAE */ && !long_mode()) {
if (! CheckPDPTR(BX_CPU_THIS_PTR cr3)) {
BX_ERROR(("SetCR4(): PDPTR check failed !"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
// Protected mode: #GP(0) if attempt to write a 1 to // Protected mode: #GP(0) if attempt to write a 1 to
// any reserved bit of CR4 // any reserved bit of CR4
if (! SetCR4(val_32)) if (! SetCR4(val_32))
@ -759,7 +770,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
#if BX_SUPPORT_VMX #if BX_SUPPORT_VMX
VMexit_CR3_Write(i, val_64); VMexit_CR3_Write(i, val_64);
#endif #endif
// Reserved bits take on value of MOV instruction // no PDPTR checks in long mode
SetCR3(val_64); SetCR3(val_64);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_64); BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_64);
break; break;
@ -768,6 +779,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
val_64 = VMexit_CR4_Write(i, val_64); val_64 = VMexit_CR4_Write(i, val_64);
#endif #endif
BX_DEBUG(("MOV_CqRq: write to CR4 of %08x:%08x", GET32H(val_64), GET32L(val_64))); BX_DEBUG(("MOV_CqRq: write to CR4 of %08x:%08x", GET32H(val_64), GET32L(val_64)));
// no PDPTR checks in long mode
if (! SetCR4(val_64)) if (! SetCR4(val_64))
exception(BX_GP_EXCEPTION, 0, 0); exception(BX_GP_EXCEPTION, 0, 0);
break; break;
@ -1352,6 +1364,14 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR0(bx_address val)
} }
BX_CPU_THIS_PTR efer.set_LMA(1); BX_CPU_THIS_PTR efer.set_LMA(1);
} }
#if BX_SUPPORT_PAE
if (BX_CPU_THIS_PTR cr4.get_PAE() && !long_mode()) {
if (! CheckPDPTR(BX_CPU_THIS_PTR cr3)) {
BX_ERROR(("SetCR0(): PDPTR check failed !"));
return 0;
}
}
#endif
} }
else if (prev_pg==1 && ! pg) { else if (prev_pg==1 && ! pg) {
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) { if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
@ -1474,7 +1494,7 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR4(bx_address val)
// need to GP(0) if LMA=1 and PAE=1->0 // need to GP(0) if LMA=1 and PAE=1->0
if (BX_CPU_THIS_PTR efer.get_LMA()) { if (BX_CPU_THIS_PTR efer.get_LMA()) {
if(!(val & (1<<5)) && BX_CPU_THIS_PTR cr4.get_PAE()) { if(!(val & (1<<5)) && BX_CPU_THIS_PTR cr4.get_PAE()) {
BX_ERROR(("SetCR4: attempt to change PAE when EFER.LMA=1")); BX_ERROR(("SetCR4(): attempt to change PAE when EFER.LMA=1"));
return 0; return 0;
} }
} }
@ -1482,7 +1502,7 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR4(bx_address val)
#if BX_SUPPORT_VMX #if BX_SUPPORT_VMX
if (!(val & (1 << 13)) && BX_CPU_THIS_PTR in_vmx) { if (!(val & (1 << 13)) && BX_CPU_THIS_PTR in_vmx) {
BX_ERROR(("Attempt to clear CR4.VMXE in vmx mode")); BX_ERROR(("SetCR4(): Attempt to clear CR4.VMXE in vmx mode"));
exception(BX_GP_EXCEPTION, 0, 0); exception(BX_GP_EXCEPTION, 0, 0);
} }
#endif #endif

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// $Id: vmx.cc,v 1.18 2009-05-30 15:09:38 sshwarts Exp $ // $Id: vmx.cc,v 1.19 2009-05-31 07:49:04 sshwarts Exp $
///////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2009 Stanislav Shwartsman // Copyright (c) 2009 Stanislav Shwartsman
@ -1165,6 +1165,17 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
} }
} }
#if BX_SUPPORT_PAE
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
// //
// Load Guest State -> VMENTER // Load Guest State -> VMENTER
// //
@ -1185,10 +1196,10 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (guest.cr0 & ~VMX_KEEP_CR0_BITS))) { if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (guest.cr0 & ~VMX_KEEP_CR0_BITS))) {
BX_PANIC(("VMENTER CR0 is broken !")); BX_PANIC(("VMENTER CR0 is broken !"));
} }
SetCR3(guest.cr3); if (!SetCR4(guest.cr4)) { // cannot fail if CR4 checks were correct
if (!SetCR4(guest.cr4)) { // improssible if CR4 checks were correct
BX_PANIC(("VMENTER CR4 is broken !")); BX_PANIC(("VMENTER CR4 is broken !"));
} }
SetCR3(guest.cr3);
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS) { if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS) {
// always clear bits 15:14 and set bit 10 // always clear bits 15:14 and set bit 10
@ -1487,10 +1498,10 @@ void BX_CPU_C::VMexitLoadHostState(void)
if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (host_state->cr0 & ~VMX_KEEP_CR0_BITS))) { if (!SetCR0((old_cr0 & VMX_KEEP_CR0_BITS) | (host_state->cr0 & ~VMX_KEEP_CR0_BITS))) {
BX_PANIC(("VMEXIT CR0 is broken !")); BX_PANIC(("VMEXIT CR0 is broken !"));
} }
SetCR3(host_state->cr3);
if (!SetCR4(host_state->cr4)) { if (!SetCR4(host_state->cr4)) {
BX_PANIC(("VMEXIT CR4 is broken !")); BX_PANIC(("VMEXIT CR4 is broken !"));
} }
SetCR3(host_state->cr3);
BX_CPU_THIS_PTR dr7 = 0x00000400; BX_CPU_THIS_PTR dr7 = 0x00000400;
@ -1960,13 +1971,6 @@ void BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
VMexit(0, state_load_error | (1 << 31), qualification); VMexit(0, state_load_error | (1 << 31), qualification);
} }
#if BX_SUPPORT_PAE
if (! CheckPDPTR(BX_CPU_THIS_PTR cr0.get_PG(), BX_CPU_THIS_PTR cr4.get_PAE(), BX_CPU_THIS_PTR cr3)) {
BX_ERROR(("VMEXIT: Guest State PDPTRs Checks Failed"));
VMexit(0, VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE | (1 << 31), VMENTER_ERR_GUEST_STATE_PDPTR_LOADING);
}
#endif
Bit32u msr = LoadMSRs(BX_CPU_THIS_PTR vmcs.vmentry_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmentry_msr_load_addr); Bit32u msr = LoadMSRs(BX_CPU_THIS_PTR vmcs.vmentry_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmentry_msr_load_addr);
if (msr) { if (msr) {
BX_ERROR(("VMEXIT: Error when loading guest MSR 0x%08x", msr)); BX_ERROR(("VMEXIT: Error when loading guest MSR 0x%08x", msr));