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.
@ -3095,7 +3095,7 @@ public: // for now...
BX_SMF void pagingCR0Changed(Bit32u oldCR0, Bit32u newCR0) BX_CPP_AttrRegparmN(2);
BX_SMF void pagingCR4Changed(Bit32u oldCR4, Bit32u newCR4) BX_CPP_AttrRegparmN(2);
#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
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.
@ -448,8 +448,7 @@ BX_CPU_C::pagingCR4Changed(Bit32u oldCR4, Bit32u newCR4)
#endif
}
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::SetCR3(bx_address val)
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR3(bx_address val)
{
// flush TLB even if value does not change
#if BX_SUPPORT_GLOBAL_PAGES
@ -478,7 +477,9 @@ BX_CPU_C::SetCR3(bx_address val)
}
else
#endif
{
BX_CPU_THIS_PTR cr3_masked = val & 0xffffffe0;
}
}
else
#endif
@ -488,26 +489,28 @@ BX_CPU_C::SetCR3(bx_address val)
}
#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++) {
Bit64u pdptr;
// read PDPE cache entry
bx_phy_address entry_pdpe_addr = (bx_phy_address) (cr3_val | (n << 3));
access_read_physical(entry_pdpe_addr, 8, (Bit8u*)(&pdptr));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, entry_pdpe_addr, 8, BX_READ, (Bit8u*)(&pdptr));
for (int n=0; n<4; n++) {
// read PDPE cache entry
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]));
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, entry_pdpe_addr, 8,
BX_READ, (Bit8u*)(&BX_CPU_THIS_PTR PDPE_CACHE.entry[n]));
if (pdptr & 0x1) {
if (pdptr & PAGING_PAE_PDPE_RESERVED_BITS)
return 0;
Bit64u pdptr = BX_CPU_THIS_PTR PDPE_CACHE.entry[n];
if (pdptr & 0x1) {
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 */
}
#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.
@ -650,7 +650,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
#if BX_SUPPORT_VMX
VMexit_CR3_Write(i, val_32);
#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);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32);
break;
@ -659,6 +664,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
#if BX_SUPPORT_VMX
val_32 = VMexit_CR4_Write(i, val_32);
#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
// any reserved bit of CR4
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
VMexit_CR3_Write(i, val_64);
#endif
// Reserved bits take on value of MOV instruction
// no PDPTR checks in long mode
SetCR3(val_64);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_64);
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);
#endif
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))
exception(BX_GP_EXCEPTION, 0, 0);
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);
}
#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) {
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
if (BX_CPU_THIS_PTR efer.get_LMA()) {
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;
}
}
@ -1482,7 +1502,7 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::SetCR4(bx_address val)
#if BX_SUPPORT_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);
}
#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
@ -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
//
@ -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))) {
BX_PANIC(("VMENTER CR0 is broken !"));
}
SetCR3(guest.cr3);
if (!SetCR4(guest.cr4)) { // improssible if CR4 checks were correct
if (!SetCR4(guest.cr4)) { // cannot fail if CR4 checks were correct
BX_PANIC(("VMENTER CR4 is broken !"));
}
SetCR3(guest.cr3);
if (vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS) {
// 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))) {
BX_PANIC(("VMEXIT CR0 is broken !"));
}
SetCR3(host_state->cr3);
if (!SetCR4(host_state->cr4)) {
BX_PANIC(("VMEXIT CR4 is broken !"));
}
SetCR3(host_state->cr3);
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);
}
#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);
if (msr) {
BX_ERROR(("VMEXIT: Error when loading guest MSR 0x%08x", msr));