From 03ba2ec98890a4631a5ca4e0c0b9a294a6d767fd Mon Sep 17 00:00:00 2001 From: Stanislav Shwartsman Date: Sun, 31 May 2009 07:49:04 +0000 Subject: [PATCH] implement pdptr checks in legacy PAE mode --- bochs/cpu/cpu.h | 4 ++-- bochs/cpu/paging.cc | 35 +++++++++++++++++++---------------- bochs/cpu/proc_ctrl.cc | 30 +++++++++++++++++++++++++----- bochs/cpu/vmx.cc | 26 +++++++++++++++----------- 4 files changed, 61 insertions(+), 34 deletions(-) diff --git a/bochs/cpu/cpu.h b/bochs/cpu/cpu.h index 234b99ff0..fbf33c8f8 100644 --- a/bochs/cpu/cpu.h +++ b/bochs/cpu/cpu.h @@ -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); diff --git a/bochs/cpu/paging.cc b/bochs/cpu/paging.cc index 7e88c5b05..9d19b394e 100644 --- a/bochs/cpu/paging.cc +++ b/bochs/cpu/paging.cc @@ -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 diff --git a/bochs/cpu/proc_ctrl.cc b/bochs/cpu/proc_ctrl.cc index 6f89ac821..a60038ff3 100644 --- a/bochs/cpu/proc_ctrl.cc +++ b/bochs/cpu/proc_ctrl.cc @@ -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 diff --git a/bochs/cpu/vmx.cc b/bochs/cpu/vmx.cc index e6b86ec06..8c5aa4c18 100755 --- a/bochs/cpu/vmx.cc +++ b/bochs/cpu/vmx.cc @@ -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));