From 70e9f4c161b7ec280eaa9b621a02135a16eaeaa8 Mon Sep 17 00:00:00 2001 From: Stanislav Shwartsman Date: Fri, 5 Dec 2008 12:48:36 +0000 Subject: [PATCH] preparing to different way of handling MSR registers --- bochs/cpu/Makefile.in | 10 + bochs/cpu/msr.cc | 508 +++++++++++++++++++++++++++++++++++++++++ bochs/cpu/proc_ctrl.cc | 483 +-------------------------------------- 3 files changed, 519 insertions(+), 482 deletions(-) create mode 100755 bochs/cpu/msr.cc diff --git a/bochs/cpu/Makefile.in b/bochs/cpu/Makefile.in index b879dc9de..94397e647 100644 --- a/bochs/cpu/Makefile.in +++ b/bochs/cpu/Makefile.in @@ -95,6 +95,7 @@ OBJS = \ exception.o \ cpuid.o \ proc_ctrl.o \ + msr.o \ smm.o \ lazy_flags.o \ flag_ctrl_pro.o \ @@ -647,6 +648,15 @@ proc_ctrl.o: proc_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ lazy_flags.h icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h \ ../config.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \ ../cpu/xmm.h stack.h +msr.o: msr.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ + ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \ + ../gui/siminterface.h ../memory/memory.h ../pc_system.h ../plugin.h \ + ../extplugin.h ../gui/gui.h ../gui/textconfig.h ../config.h \ + ../gui/keymap.h ../instrument/stubs/instrument.h cpu.h \ + ../disasm/disasm.h ../config.h crregs.h descriptor.h instr.h \ + lazy_flags.h icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h \ + ../config.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \ + ../cpu/xmm.h stack.h protect_ctrl.o: protect_ctrl.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \ ../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \ ../gui/siminterface.h ../memory/memory.h ../pc_system.h ../plugin.h \ diff --git a/bochs/cpu/msr.cc b/bochs/cpu/msr.cc new file mode 100755 index 000000000..3effd7526 --- /dev/null +++ b/bochs/cpu/msr.cc @@ -0,0 +1,508 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: msr.cc,v 1.1 2008-12-05 12:48:36 sshwarts Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2008 Stanislav Shwartsman +// Written by Stanislav Shwartsman [sshwarts at sourceforge net] +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +///////////////////////////////////////////////////////////////////////// + +#define NEED_CPU_REG_SHORTCUTS 1 +#include "bochs.h" +#include "cpu.h" +#define LOG_THIS BX_CPU_THIS_PTR + +void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i) +{ +#if BX_CPU_LEVEL >= 5 + if (!real_mode() && CPL!=0) { + BX_ERROR(("RDMSR: CPL!=0 not in real mode")); + exception(BX_GP_EXCEPTION, 0, 0); + } + + /* We have the requested MSR register in ECX */ + switch(ECX) { + +#if BX_SUPPORT_SEP + case BX_MSR_SYSENTER_CS: + RAX = BX_CPU_THIS_PTR msr.sysenter_cs_msr; + RDX = 0; + break; + + case BX_MSR_SYSENTER_ESP: + RAX = BX_CPU_THIS_PTR msr.sysenter_esp_msr; + RDX = 0; + break; + + case BX_MSR_SYSENTER_EIP: + RAX = BX_CPU_THIS_PTR msr.sysenter_eip_msr; + RDX = 0; + break; +#endif + +#if BX_SUPPORT_MTRR + case BX_MSR_MTRRCAP: // read only MSR + RAX = 0x508; + RDX = 0; + break; + + case BX_MSR_MTRRPHYSBASE0: + case BX_MSR_MTRRPHYSMASK0: + case BX_MSR_MTRRPHYSBASE1: + case BX_MSR_MTRRPHYSMASK1: + case BX_MSR_MTRRPHYSBASE2: + case BX_MSR_MTRRPHYSMASK2: + case BX_MSR_MTRRPHYSBASE3: + case BX_MSR_MTRRPHYSMASK3: + case BX_MSR_MTRRPHYSBASE4: + case BX_MSR_MTRRPHYSMASK4: + case BX_MSR_MTRRPHYSBASE5: + case BX_MSR_MTRRPHYSMASK5: + case BX_MSR_MTRRPHYSBASE6: + case BX_MSR_MTRRPHYSMASK6: + case BX_MSR_MTRRPHYSBASE7: + case BX_MSR_MTRRPHYSMASK7: + RAX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] >> 32; + break; + + case BX_MSR_MTRRFIX64K_00000: + RAX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 >> 32; + break; + case BX_MSR_MTRRFIX16K_80000: + RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 >> 32; + break; + case BX_MSR_MTRRFIX16K_A0000: + RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 >> 32; + break; + + case BX_MSR_MTRRFIX4K_C0000: + case BX_MSR_MTRRFIX4K_C8000: + case BX_MSR_MTRRFIX4K_D0000: + case BX_MSR_MTRRFIX4K_D8000: + case BX_MSR_MTRRFIX4K_E0000: + case BX_MSR_MTRRFIX4K_E8000: + case BX_MSR_MTRRFIX4K_F0000: + case BX_MSR_MTRRFIX4K_F8000: + RAX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] >> 32; + break; + + case BX_MSR_PAT: + RAX = BX_CPU_THIS_PTR msr.pat & 0xffffffff; + RDX = BX_CPU_THIS_PTR msr.pat >> 32; + break; + + case BX_MSR_MTRR_DEFTYPE: + RAX = BX_CPU_THIS_PTR msr.mtrr_deftype; + RDX = 0; + break; +#endif + +#if BX_CPU_LEVEL == 5 + /* The following registers are defined for Pentium only */ + case BX_MSR_P5_MC_ADDR: + case BX_MSR_MC_TYPE: + /* TODO */ + break; + + case BX_MSR_CESR: + /* TODO */ + break; +#else + /* These are noops on i686... */ + case BX_MSR_P5_MC_ADDR: + case BX_MSR_MC_TYPE: + /* do nothing */ + break; + + /* ... And these cause an exception on i686 */ + case BX_MSR_CESR: + case BX_MSR_CTR0: + case BX_MSR_CTR1: + exception(BX_GP_EXCEPTION, 0, 0); +#endif /* BX_CPU_LEVEL == 5 */ + + case BX_MSR_TSC: + RDTSC(i); + break; + + /* MSR_APICBASE + 0:7 Reserved + 8 This is set if its the BSP + 9:10 Reserved + 11 APIC Global Enable bit (1=enabled 0=disabled) + 12:35 APIC Base Address + 36:63 Reserved + */ +#if BX_SUPPORT_APIC + case BX_MSR_APICBASE: + RAX = BX_CPU_THIS_PTR msr.apicbase; + RDX = 0; + BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX, EAX)); + break; +#endif + +#if BX_SUPPORT_X86_64 + case BX_MSR_EFER: + RAX = BX_CPU_THIS_PTR efer.getRegister(); + RDX = 0; + break; + + case BX_MSR_STAR: + RAX = MSR_STAR & 0xffffffff; + RDX = MSR_STAR >> 32; + break; + + case BX_MSR_LSTAR: + RAX = MSR_LSTAR & 0xffffffff; + RDX = MSR_LSTAR >> 32; + break; + + case BX_MSR_CSTAR: + RAX = MSR_CSTAR & 0xffffffff; + RDX = MSR_CSTAR >> 32; + break; + + case BX_MSR_FMASK: + RAX = MSR_FMASK; + RDX = 0; + break; + + case BX_MSR_FSBASE: + RAX = MSR_FSBASE & 0xffffffff; + RDX = MSR_FSBASE >> 32; + break; + + case BX_MSR_GSBASE: + RAX = MSR_GSBASE & 0xffffffff; + RDX = MSR_GSBASE >> 32; + break; + + case BX_MSR_KERNELGSBASE: + RAX = MSR_KERNELGSBASE & 0xffffffff; + RDX = MSR_KERNELGSBASE >> 32; + break; + + case BX_MSR_TSC_AUX: + RAX = MSR_TSC_AUX; // 32 bit MSR + RDX = 0; + break; +#endif // #if BX_SUPPORT_X86_64 + + default: + BX_ERROR(("RDMSR: Unknown register %#x", ECX)); +#if BX_IGNORE_BAD_MSR + RAX = 0; + RDX = 0; +#else + exception(BX_GP_EXCEPTION, 0, 0); +#endif + } +#else + BX_INFO(("RDMSR: Pentium CPU required, use --enable-cpu-level=5")); + exception(BX_UD_EXCEPTION, 0, 0); +#endif +} + +#if BX_SUPPORT_MTRR +BX_CPP_INLINE bx_bool isMemTypeValidMTTR(Bit8u memtype) +{ + switch(memtype) { + case 0x00: // UC + case 0x01: // WC + case 0x04: // WT + case 0x05: // WP + case 0x06: // WB + return 1; + default: + return 0; + } +} + +BX_CPP_INLINE bx_bool isMemTypeValidPAT(Bit8u memtype) +{ + return (memtype == 0x07) /* UC- */ || isMemTypeValidMTTR(memtype); +} +#endif + +void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i) +{ +#if BX_CPU_LEVEL >= 5 + if (!real_mode() && CPL!=0) { + BX_ERROR(("WRMSR: CPL!=0 not in real mode")); + exception(BX_GP_EXCEPTION, 0, 0); + } + + Bit64u val64 = ((Bit64u) EDX << 32) | EAX; + + BX_INSTR_WRMSR(BX_CPU_ID, ECX, val64); + + /* ECX has the MSR to write to */ + switch(ECX) { + +#if BX_SUPPORT_SEP + case BX_MSR_SYSENTER_CS: + BX_CPU_THIS_PTR msr.sysenter_cs_msr = EAX; + break; + + case BX_MSR_SYSENTER_ESP: +#if BX_SUPPORT_X86_64 + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_ESP !")); + exception(BX_GP_EXCEPTION, 0, 0); + } +#endif + BX_CPU_THIS_PTR msr.sysenter_esp_msr = val64; + break; + + case BX_MSR_SYSENTER_EIP: +#if BX_SUPPORT_X86_64 + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_EIP !")); + exception(BX_GP_EXCEPTION, 0, 0); + } +#endif + BX_CPU_THIS_PTR msr.sysenter_eip_msr = val64; + break; +#endif + +#if BX_SUPPORT_MTRR + case BX_MSR_MTRRCAP: + BX_ERROR(("WRMSR: MTRRCAP is read only MSR")); + exception(BX_GP_EXCEPTION, 0, 0); + + case BX_MSR_MTRRPHYSBASE0: + case BX_MSR_MTRRPHYSBASE1: + case BX_MSR_MTRRPHYSBASE2: + case BX_MSR_MTRRPHYSBASE3: + case BX_MSR_MTRRPHYSBASE4: + case BX_MSR_MTRRPHYSBASE5: + case BX_MSR_MTRRPHYSBASE6: + case BX_MSR_MTRRPHYSBASE7: + if (! isMemTypeValidMTTR(AL)) { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to BX_MSR_MTRRPHYSBASE")); + exception(BX_GP_EXCEPTION, 0, 0); + } + case BX_MSR_MTRRPHYSMASK0: + case BX_MSR_MTRRPHYSMASK1: + case BX_MSR_MTRRPHYSMASK2: + case BX_MSR_MTRRPHYSMASK3: + case BX_MSR_MTRRPHYSMASK4: + case BX_MSR_MTRRPHYSMASK5: + case BX_MSR_MTRRPHYSMASK6: + case BX_MSR_MTRRPHYSMASK7: + BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] = val64; + break; + + case BX_MSR_MTRRFIX64K_00000: + if (! isMemTypeValidMTTR(AL)) { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX64K_00000")); + exception(BX_GP_EXCEPTION, 0, 0); + } + BX_CPU_THIS_PTR msr.mtrrfix64k_00000 = val64; + break; + case BX_MSR_MTRRFIX16K_80000: + if (! isMemTypeValidMTTR(AL)) { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_80000")); + exception(BX_GP_EXCEPTION, 0, 0); + } + BX_CPU_THIS_PTR msr.mtrrfix16k_80000 = val64; + break; + case BX_MSR_MTRRFIX16K_A0000: + if (! isMemTypeValidMTTR(AL)) { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_A0000")); + exception(BX_GP_EXCEPTION, 0, 0); + } + BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 = val64; + break; + + case BX_MSR_MTRRFIX4K_C0000: + case BX_MSR_MTRRFIX4K_C8000: + case BX_MSR_MTRRFIX4K_D0000: + case BX_MSR_MTRRFIX4K_D8000: + case BX_MSR_MTRRFIX4K_E0000: + case BX_MSR_MTRRFIX4K_E8000: + case BX_MSR_MTRRFIX4K_F0000: + case BX_MSR_MTRRFIX4K_F8000: + BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] = val64; + break; + + case BX_MSR_PAT: + if (! isMemTypeValidPAT(AL) || ! isMemTypeValidPAT(AH) || + ! isMemTypeValidPAT((EAX >> 16) & 0xFF) || + ! isMemTypeValidPAT(EAX >> 24) || + ! isMemTypeValidPAT(DL) || ! isMemTypeValidPAT(DH) || + ! isMemTypeValidPAT((EDX >> 16) & 0xFF) || + ! isMemTypeValidPAT(EDX >> 24)) + { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_PAT")); + exception(BX_GP_EXCEPTION, 0, 0); + } + + BX_CPU_THIS_PTR msr.pat = val64; + break; + + case BX_MSR_MTRR_DEFTYPE: + if (! isMemTypeValidMTTR(AL)) { + BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRR_DEFTYPE")); + exception(BX_GP_EXCEPTION, 0, 0); + } + BX_CPU_THIS_PTR msr.mtrr_deftype = EAX; + break; +#endif + +#if BX_CPU_LEVEL == 5 + /* The following registers are defined for Pentium only */ + case BX_MSR_P5_MC_ADDR: + case BX_MSR_MC_TYPE: + case BX_MSR_CESR: + /* TODO */ + break; +#else + /* These are noops on i686... */ + case BX_MSR_P5_MC_ADDR: + case BX_MSR_MC_TYPE: + /* do nothing */ + break; + + /* ... And these cause an exception on i686 */ + case BX_MSR_CESR: + case BX_MSR_CTR0: + case BX_MSR_CTR1: + exception(BX_GP_EXCEPTION, 0, 0); +#endif /* BX_CPU_LEVEL == 5 */ + + case BX_MSR_TSC: + BX_CPU_THIS_PTR set_TSC(val64); + BX_INFO(("WRMSR: wrote 0x%08x%08x to MSR_TSC", EDX, EAX)); + break; + + /* MSR_APICBASE + 0:7 Reserved + 8 This is set if its the BSP + 9:10 Reserved + 11 APIC Global Enable bit (1=enabled 0=disabled) + 12:35 APIC Base Address (in Bochs 12:31 because of 32-bit physical addr) + 36:63 Reserved + */ +#if BX_SUPPORT_APIC + case BX_MSR_APICBASE: + if (BX_CPU_THIS_PTR msr.apicbase & 0x800) { + BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", EDX, EAX)); + BX_CPU_THIS_PTR msr.apicbase = EAX; /* ignore the high 32bits */ +#if BX_PHY_ADDRESS_WIDTH == 32 + if (EDX != 0) { + BX_PANIC(("MSR_APICBASE: Only 32 bit physical address space is emulated !")); + } +#endif + BX_CPU_THIS_PTR local_apic.set_base(BX_CPU_THIS_PTR msr.apicbase); + // TLB flush is required for emulation correctness + TLB_flush(); // don't care about performance of apic relocation + } + else { + BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !")); + } + break; +#endif + +#if BX_SUPPORT_X86_64 + case BX_MSR_EFER: + if (val64 & ~BX_EFER_SUPPORTED_BITS) { + BX_ERROR(("WRMSR: attempt to set reserved bits of EFER MSR !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + + // #GP(0) if changing EFER.LME when cr0.pg = 1 + if ((BX_CPU_THIS_PTR efer.get_LME() != ((EAX >> 8) & 1)) && + BX_CPU_THIS_PTR cr0.get_PG()) + { + BX_ERROR(("WRMSR: attempt to change LME when CR0.PG=1")); + exception(BX_GP_EXCEPTION, 0, 0); + } + + BX_CPU_THIS_PTR efer.setRegister((EAX & BX_EFER_SUPPORTED_BITS & ~BX_EFER_LMA_MASK) + | (BX_CPU_THIS_PTR efer.val32 & BX_EFER_LMA_MASK)); // keep LMA untouched + break; + + case BX_MSR_STAR: + MSR_STAR = val64; + break; + + case BX_MSR_LSTAR: + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + MSR_LSTAR = val64; + break; + + case BX_MSR_CSTAR: + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + MSR_CSTAR = val64; + break; + + case BX_MSR_FMASK: + MSR_FMASK = (Bit32u) val64; + break; + + case BX_MSR_FSBASE: + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + MSR_FSBASE = val64; + break; + + case BX_MSR_GSBASE: + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + MSR_GSBASE = val64; + break; + + case BX_MSR_KERNELGSBASE: + if (! IsCanonical(val64)) { + BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_KERNELGSBASE !")); + exception(BX_GP_EXCEPTION, 0, 0); + } + MSR_KERNELGSBASE = val64; + break; + + case BX_MSR_TSC_AUX: + MSR_TSC_AUX = EAX; + break; +#endif // #if BX_SUPPORT_X86_64 + + default: + BX_ERROR(("WRMSR: Unknown register %#x", ECX)); +#if BX_IGNORE_BAD_MSR == 0 + exception(BX_GP_EXCEPTION, 0, 0); +#endif + } +#else + BX_INFO(("WRMSR: Pentium CPU required, use --enable-cpu-level=5")); + exception(BX_UD_EXCEPTION, 0, 0); +#endif +} diff --git a/bochs/cpu/proc_ctrl.cc b/bochs/cpu/proc_ctrl.cc index ba2d3841a..6028de9df 100644 --- a/bochs/cpu/proc_ctrl.cc +++ b/bochs/cpu/proc_ctrl.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: proc_ctrl.cc,v 1.263 2008-10-03 17:00:46 sshwarts Exp $ +// $Id: proc_ctrl.cc,v 1.264 2008-12-05 12:48:36 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001 MandrakeSoft S.A. @@ -1407,487 +1407,6 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDTSCP(bxInstruction_c *i) } #endif -void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i) -{ -#if BX_CPU_LEVEL >= 5 - if (!real_mode() && CPL!=0) { - BX_ERROR(("RDMSR: CPL!=0 not in real mode")); - exception(BX_GP_EXCEPTION, 0, 0); - } - - /* We have the requested MSR register in ECX */ - switch(ECX) { - -#if BX_SUPPORT_SEP - case BX_MSR_SYSENTER_CS: - RAX = BX_CPU_THIS_PTR msr.sysenter_cs_msr; - RDX = 0; - break; - - case BX_MSR_SYSENTER_ESP: - RAX = BX_CPU_THIS_PTR msr.sysenter_esp_msr; - RDX = 0; - break; - - case BX_MSR_SYSENTER_EIP: - RAX = BX_CPU_THIS_PTR msr.sysenter_eip_msr; - RDX = 0; - break; -#endif - -#if BX_SUPPORT_MTRR - case BX_MSR_MTRRCAP: // read only MSR - RAX = 0x508; - RDX = 0; - break; - - case BX_MSR_MTRRPHYSBASE0: - case BX_MSR_MTRRPHYSMASK0: - case BX_MSR_MTRRPHYSBASE1: - case BX_MSR_MTRRPHYSMASK1: - case BX_MSR_MTRRPHYSBASE2: - case BX_MSR_MTRRPHYSMASK2: - case BX_MSR_MTRRPHYSBASE3: - case BX_MSR_MTRRPHYSMASK3: - case BX_MSR_MTRRPHYSBASE4: - case BX_MSR_MTRRPHYSMASK4: - case BX_MSR_MTRRPHYSBASE5: - case BX_MSR_MTRRPHYSMASK5: - case BX_MSR_MTRRPHYSBASE6: - case BX_MSR_MTRRPHYSMASK6: - case BX_MSR_MTRRPHYSBASE7: - case BX_MSR_MTRRPHYSMASK7: - RAX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] >> 32; - break; - - case BX_MSR_MTRRFIX64K_00000: - RAX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 >> 32; - break; - case BX_MSR_MTRRFIX16K_80000: - RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 >> 32; - break; - case BX_MSR_MTRRFIX16K_A0000: - RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 >> 32; - break; - - case BX_MSR_MTRRFIX4K_C0000: - case BX_MSR_MTRRFIX4K_C8000: - case BX_MSR_MTRRFIX4K_D0000: - case BX_MSR_MTRRFIX4K_D8000: - case BX_MSR_MTRRFIX4K_E0000: - case BX_MSR_MTRRFIX4K_E8000: - case BX_MSR_MTRRFIX4K_F0000: - case BX_MSR_MTRRFIX4K_F8000: - RAX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] >> 32; - break; - - case BX_MSR_PAT: - RAX = BX_CPU_THIS_PTR msr.pat & 0xffffffff; - RDX = BX_CPU_THIS_PTR msr.pat >> 32; - break; - - case BX_MSR_MTRR_DEFTYPE: - RAX = BX_CPU_THIS_PTR msr.mtrr_deftype; - RDX = 0; - break; -#endif - -#if BX_CPU_LEVEL == 5 - /* The following registers are defined for Pentium only */ - case BX_MSR_P5_MC_ADDR: - case BX_MSR_MC_TYPE: - /* TODO */ - break; - - case BX_MSR_CESR: - /* TODO */ - break; -#else - /* These are noops on i686... */ - case BX_MSR_P5_MC_ADDR: - case BX_MSR_MC_TYPE: - /* do nothing */ - break; - - /* ... And these cause an exception on i686 */ - case BX_MSR_CESR: - case BX_MSR_CTR0: - case BX_MSR_CTR1: - exception(BX_GP_EXCEPTION, 0, 0); -#endif /* BX_CPU_LEVEL == 5 */ - - case BX_MSR_TSC: - RDTSC(i); - break; - - /* MSR_APICBASE - 0:7 Reserved - 8 This is set if its the BSP - 9:10 Reserved - 11 APIC Global Enable bit (1=enabled 0=disabled) - 12:35 APIC Base Address - 36:63 Reserved - */ -#if BX_SUPPORT_APIC - case BX_MSR_APICBASE: - RAX = BX_CPU_THIS_PTR msr.apicbase; - RDX = 0; - BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX, EAX)); - break; -#endif - -#if BX_SUPPORT_X86_64 - case BX_MSR_EFER: - RAX = BX_CPU_THIS_PTR efer.getRegister(); - RDX = 0; - break; - - case BX_MSR_STAR: - RAX = MSR_STAR & 0xffffffff; - RDX = MSR_STAR >> 32; - break; - - case BX_MSR_LSTAR: - RAX = MSR_LSTAR & 0xffffffff; - RDX = MSR_LSTAR >> 32; - break; - - case BX_MSR_CSTAR: - RAX = MSR_CSTAR & 0xffffffff; - RDX = MSR_CSTAR >> 32; - break; - - case BX_MSR_FMASK: - RAX = MSR_FMASK; - RDX = 0; - break; - - case BX_MSR_FSBASE: - RAX = MSR_FSBASE & 0xffffffff; - RDX = MSR_FSBASE >> 32; - break; - - case BX_MSR_GSBASE: - RAX = MSR_GSBASE & 0xffffffff; - RDX = MSR_GSBASE >> 32; - break; - - case BX_MSR_KERNELGSBASE: - RAX = MSR_KERNELGSBASE & 0xffffffff; - RDX = MSR_KERNELGSBASE >> 32; - break; - - case BX_MSR_TSC_AUX: - RAX = MSR_TSC_AUX; // 32 bit MSR - RDX = 0; - break; -#endif // #if BX_SUPPORT_X86_64 - - default: - BX_ERROR(("RDMSR: Unknown register %#x", ECX)); -#if BX_IGNORE_BAD_MSR - RAX = 0; - RDX = 0; -#else - exception(BX_GP_EXCEPTION, 0, 0); -#endif - } -#else - BX_INFO(("RDMSR: Pentium CPU required, use --enable-cpu-level=5")); - exception(BX_UD_EXCEPTION, 0, 0); -#endif -} - -#if BX_SUPPORT_MTRR -BX_CPP_INLINE bx_bool isMemTypeValidMTTR(Bit8u memtype) -{ - switch(memtype) { - case 0x00: // UC - case 0x01: // WC - case 0x04: // WT - case 0x05: // WP - case 0x06: // WB - return 1; - default: - return 0; - } -} - -BX_CPP_INLINE bx_bool isMemTypeValidPAT(Bit8u memtype) -{ - return (memtype == 0x07) /* UC- */ || isMemTypeValidMTTR(memtype); -} -#endif - -void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i) -{ -#if BX_CPU_LEVEL >= 5 - if (!real_mode() && CPL!=0) { - BX_ERROR(("WRMSR: CPL!=0 not in real mode")); - exception(BX_GP_EXCEPTION, 0, 0); - } - - Bit64u val64 = ((Bit64u) EDX << 32) | EAX; - - BX_INSTR_WRMSR(BX_CPU_ID, ECX, val64); - - /* ECX has the MSR to write to */ - switch(ECX) { - -#if BX_SUPPORT_SEP - case BX_MSR_SYSENTER_CS: - BX_CPU_THIS_PTR msr.sysenter_cs_msr = EAX; - break; - - case BX_MSR_SYSENTER_ESP: -#if BX_SUPPORT_X86_64 - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_ESP !")); - exception(BX_GP_EXCEPTION, 0, 0); - } -#endif - BX_CPU_THIS_PTR msr.sysenter_esp_msr = val64; - break; - - case BX_MSR_SYSENTER_EIP: -#if BX_SUPPORT_X86_64 - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_EIP !")); - exception(BX_GP_EXCEPTION, 0, 0); - } -#endif - BX_CPU_THIS_PTR msr.sysenter_eip_msr = val64; - break; -#endif - -#if BX_SUPPORT_MTRR - case BX_MSR_MTRRCAP: - BX_ERROR(("WRMSR: MTRRCAP is read only MSR")); - exception(BX_GP_EXCEPTION, 0, 0); - - case BX_MSR_MTRRPHYSBASE0: - case BX_MSR_MTRRPHYSBASE1: - case BX_MSR_MTRRPHYSBASE2: - case BX_MSR_MTRRPHYSBASE3: - case BX_MSR_MTRRPHYSBASE4: - case BX_MSR_MTRRPHYSBASE5: - case BX_MSR_MTRRPHYSBASE6: - case BX_MSR_MTRRPHYSBASE7: - if (! isMemTypeValidMTTR(AL)) { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to BX_MSR_MTRRPHYSBASE")); - exception(BX_GP_EXCEPTION, 0, 0); - } - case BX_MSR_MTRRPHYSMASK0: - case BX_MSR_MTRRPHYSMASK1: - case BX_MSR_MTRRPHYSMASK2: - case BX_MSR_MTRRPHYSMASK3: - case BX_MSR_MTRRPHYSMASK4: - case BX_MSR_MTRRPHYSMASK5: - case BX_MSR_MTRRPHYSMASK6: - case BX_MSR_MTRRPHYSMASK7: - BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] = val64; - break; - - case BX_MSR_MTRRFIX64K_00000: - if (! isMemTypeValidMTTR(AL)) { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX64K_00000")); - exception(BX_GP_EXCEPTION, 0, 0); - } - BX_CPU_THIS_PTR msr.mtrrfix64k_00000 = val64; - break; - case BX_MSR_MTRRFIX16K_80000: - if (! isMemTypeValidMTTR(AL)) { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_80000")); - exception(BX_GP_EXCEPTION, 0, 0); - } - BX_CPU_THIS_PTR msr.mtrrfix16k_80000 = val64; - break; - case BX_MSR_MTRRFIX16K_A0000: - if (! isMemTypeValidMTTR(AL)) { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_A0000")); - exception(BX_GP_EXCEPTION, 0, 0); - } - BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 = val64; - break; - - case BX_MSR_MTRRFIX4K_C0000: - case BX_MSR_MTRRFIX4K_C8000: - case BX_MSR_MTRRFIX4K_D0000: - case BX_MSR_MTRRFIX4K_D8000: - case BX_MSR_MTRRFIX4K_E0000: - case BX_MSR_MTRRFIX4K_E8000: - case BX_MSR_MTRRFIX4K_F0000: - case BX_MSR_MTRRFIX4K_F8000: - BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] = val64; - break; - - case BX_MSR_PAT: - if (! isMemTypeValidPAT(AL) || ! isMemTypeValidPAT(AH) || - ! isMemTypeValidPAT((EAX >> 16) & 0xFF) || - ! isMemTypeValidPAT(EAX >> 24) || - ! isMemTypeValidPAT(DL) || ! isMemTypeValidPAT(DH) || - ! isMemTypeValidPAT((EDX >> 16) & 0xFF) || - ! isMemTypeValidPAT(EDX >> 24)) - { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_PAT")); - exception(BX_GP_EXCEPTION, 0, 0); - } - - BX_CPU_THIS_PTR msr.pat = val64; - break; - - case BX_MSR_MTRR_DEFTYPE: - if (! isMemTypeValidMTTR(AL)) { - BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRR_DEFTYPE")); - exception(BX_GP_EXCEPTION, 0, 0); - } - BX_CPU_THIS_PTR msr.mtrr_deftype = EAX; - break; -#endif - -#if BX_CPU_LEVEL == 5 - /* The following registers are defined for Pentium only */ - case BX_MSR_P5_MC_ADDR: - case BX_MSR_MC_TYPE: - case BX_MSR_CESR: - /* TODO */ - break; -#else - /* These are noops on i686... */ - case BX_MSR_P5_MC_ADDR: - case BX_MSR_MC_TYPE: - /* do nothing */ - break; - - /* ... And these cause an exception on i686 */ - case BX_MSR_CESR: - case BX_MSR_CTR0: - case BX_MSR_CTR1: - exception(BX_GP_EXCEPTION, 0, 0); -#endif /* BX_CPU_LEVEL == 5 */ - - case BX_MSR_TSC: - BX_CPU_THIS_PTR set_TSC(val64); - BX_INFO(("WRMSR: wrote 0x%08x%08x to MSR_TSC", EDX, EAX)); - break; - - /* MSR_APICBASE - 0:7 Reserved - 8 This is set if its the BSP - 9:10 Reserved - 11 APIC Global Enable bit (1=enabled 0=disabled) - 12:35 APIC Base Address (in Bochs 12:31 because of 32-bit physical addr) - 36:63 Reserved - */ -#if BX_SUPPORT_APIC - case BX_MSR_APICBASE: - if (BX_CPU_THIS_PTR msr.apicbase & 0x800) { - BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", EDX, EAX)); - BX_CPU_THIS_PTR msr.apicbase = EAX; /* ignore the high 32bits */ -#if BX_PHY_ADDRESS_WIDTH == 32 - if (EDX != 0) { - BX_PANIC(("MSR_APICBASE: Only 32 bit physical address space is emulated !")); - } -#endif - BX_CPU_THIS_PTR local_apic.set_base(BX_CPU_THIS_PTR msr.apicbase); - // TLB flush is required for emulation correctness - TLB_flush(); // don't care about performance of apic relocation - } - else { - BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !")); - } - break; -#endif - -#if BX_SUPPORT_X86_64 - case BX_MSR_EFER: - if (val64 & ~BX_EFER_SUPPORTED_BITS) { - BX_ERROR(("WRMSR: attempt to set reserved bits of EFER MSR !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - - // #GP(0) if changing EFER.LME when cr0.pg = 1 - if ((BX_CPU_THIS_PTR efer.get_LME() != ((EAX >> 8) & 1)) && - BX_CPU_THIS_PTR cr0.get_PG()) - { - BX_ERROR(("WRMSR: attempt to change LME when CR0.PG=1")); - exception(BX_GP_EXCEPTION, 0, 0); - } - - BX_CPU_THIS_PTR efer.setRegister((EAX & BX_EFER_SUPPORTED_BITS & ~BX_EFER_LMA_MASK) - | (BX_CPU_THIS_PTR efer.val32 & BX_EFER_LMA_MASK)); // keep LMA untouched - break; - - case BX_MSR_STAR: - MSR_STAR = val64; - break; - - case BX_MSR_LSTAR: - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - MSR_LSTAR = val64; - break; - - case BX_MSR_CSTAR: - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - MSR_CSTAR = val64; - break; - - case BX_MSR_FMASK: - MSR_FMASK = (Bit32u) val64; - break; - - case BX_MSR_FSBASE: - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - MSR_FSBASE = val64; - break; - - case BX_MSR_GSBASE: - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - MSR_GSBASE = val64; - break; - - case BX_MSR_KERNELGSBASE: - if (! IsCanonical(val64)) { - BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_KERNELGSBASE !")); - exception(BX_GP_EXCEPTION, 0, 0); - } - MSR_KERNELGSBASE = val64; - break; - - case BX_MSR_TSC_AUX: - MSR_TSC_AUX = EAX; - break; -#endif // #if BX_SUPPORT_X86_64 - - default: - BX_ERROR(("WRMSR: Unknown register %#x", ECX)); -#if BX_IGNORE_BAD_MSR == 0 - exception(BX_GP_EXCEPTION, 0, 0); -#endif - } -#else - BX_INFO(("WRMSR: Pentium CPU required, use --enable-cpu-level=5")); - exception(BX_UD_EXCEPTION, 0, 0); -#endif -} - #if BX_SUPPORT_MONITOR_MWAIT bx_bool BX_CPU_C::is_monitor(bx_phy_address begin_addr, unsigned len) {