From 6e1204cb840799b53bf2b136cd53fdca9b293573 Mon Sep 17 00:00:00 2001 From: Stanislav Shwartsman Date: Thu, 8 Apr 2010 15:50:39 +0000 Subject: [PATCH] Merged X2APIC + X2APIC virtualization --- bochs/.conf.everything | 1 + bochs/CHANGES | 4 + bochs/config.h.in | 6 ++ bochs/configure | 86 ++++++++++++------- bochs/configure.in | 18 +++- bochs/cpu/apic.cc | 178 +++++++++++++++++++++++++++++++++++++- bochs/cpu/apic.h | 9 +- bochs/cpu/cpu.h | 11 ++- bochs/cpu/cpuid.cc | 190 ++++++++++++++++++++++++++++++++++------- bochs/cpu/crregs.cc | 6 +- bochs/cpu/init.cc | 5 +- bochs/cpu/msr.cc | 55 +++++++++++- bochs/cpu/paging.cc | 79 ++++++----------- bochs/cpu/vmexit.cc | 9 +- bochs/cpu/vmx.cc | 29 +++++-- bochs/cpu/vmx.h | 3 +- bochs/disasm/disasm.h | 4 +- 17 files changed, 549 insertions(+), 144 deletions(-) diff --git a/bochs/.conf.everything b/bochs/.conf.everything index 27b0def98..8391fe57d 100644 --- a/bochs/.conf.everything +++ b/bochs/.conf.everything @@ -4,6 +4,7 @@ ./configure \ --enable-smp \ + --enable-x2apic \ --enable-x86-64 \ --enable-all-optimizations \ --enable-long-phy-address \ diff --git a/bochs/CHANGES b/bochs/CHANGES index a7ba518f8..e9e582e22 100644 --- a/bochs/CHANGES +++ b/bochs/CHANGES @@ -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 X2APIC extensions (Stanislav) - Implemented Intel VMXx2 extensions (Stanislav) - Extended VMX capability MSRs, APIC Virtualization, Extended Page Tables (EPT), VPID, new VMX controls support @@ -38,6 +39,7 @@ Detailed change log : - CPU - Implemented PCLMULQDQ AES instruction + - Implemented X2APIC extensions / enable extended topology CPUID leaf (0xb) - Implemented Intel VMXx2 extensions: - Enabled extended VMX capability MSRs - Implemented VMX controls for loading/storing of MSR_PAT and MSR_EFER @@ -46,6 +48,7 @@ Detailed change log : - Implemented Extended Page Tables (EPT) mode - Implemented Descriptor Table Access VMEXIT control - Implemented RDTSCP VMEXIT control + - Implemented Virtualize X2APIC mode control - Implemented Virtual Process ID (VPID) - Implemented WBINVD VMEXIT control In order to enable emulation of VMXx2 extensions configure with @@ -70,6 +73,7 @@ Detailed change log : - Updated Bochs TESTFORM to version 0.5 - SF patches applied + [2864402] outstanding x2apic patches by Stanislav [2960379] Fix build with -Wformat -Werror=format-security by Per Oyvind Karlsen [2938273] allow instrumentation to change execute by Konrad Grochowski [2926072] Indirection operators in expressions by Derek Peschel diff --git a/bochs/config.h.in b/bochs/config.h.in index 4357f5ece..f5d436b54 100644 --- a/bochs/config.h.in +++ b/bochs/config.h.in @@ -761,6 +761,12 @@ typedef #define BX_SUPPORT_APIC 0 #endif +#define BX_SUPPORT_X2APIC 0 + +#if (BX_SUPPORT_X2APIC && !BX_SUPPORT_APIC) + #error APIC is required for X2APIC emulation ! +#endif + #define BX_HAVE_GETENV 0 #define BX_HAVE_SETENV 0 #define BX_HAVE_SELECT 0 diff --git a/bochs/configure b/bochs/configure index 88bf5de61..8c86ee409 100755 --- a/bochs/configure +++ b/bochs/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Id: configure.in,v 1.432 2010/04/03 07:30:23 sshwarts Exp . +# From configure.in Id: configure.in,v 1.433 2010/04/04 18:37:53 sshwarts Exp . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65. # @@ -951,6 +951,7 @@ enable_pcidev enable_usb enable_usb_ohci enable_pnic +enable_x2apic enable_1g_pages enable_repeat_speedups enable_trace_cache @@ -1669,6 +1670,7 @@ Optional Features: --enable-usb enable limited USB UHCI support --enable-usb-ohci enable limited USB OHCI support --enable-pnic enable PCI pseudo NIC support + --enable-x2apic support for X2APIC --enable-1g-pages support for 1G pages in long mode --enable-repeat-speedups support repeated IO and mem copy speedups --enable-trace-cache support instruction trace cache @@ -5099,7 +5101,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5102 "configure"' > conftest.$ac_ext + echo '#line 5104 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6788,11 +6790,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6791: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6793: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6795: \$? = $ac_status" >&5 + echo "$as_me:6797: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -7021,11 +7023,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7024: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7026: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7028: \$? = $ac_status" >&5 + echo "$as_me:7030: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -7088,11 +7090,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7091: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7093: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7095: \$? = $ac_status" >&5 + echo "$as_me:7097: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8878,7 +8880,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:11096: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:11098: \$? = $ac_status" >&5 + echo "$as_me:11100: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -11158,11 +11160,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:11161: $lt_compile\"" >&5) + (eval echo "\"\$as_me:11163: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:11165: \$? = $ac_status" >&5 + echo "$as_me:11167: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -12183,7 +12185,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5) + (eval echo "\"\$as_me:13109: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:13111: \$? = $ac_status" >&5 + echo "$as_me:13113: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -13171,11 +13173,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:13174: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13176: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13178: \$? = $ac_status" >&5 + echo "$as_me:13180: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -15136,11 +15138,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15139: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15141: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:15143: \$? = $ac_status" >&5 + echo "$as_me:15145: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -15369,11 +15371,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15372: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15374: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:15376: \$? = $ac_status" >&5 + echo "$as_me:15378: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings @@ -15436,11 +15438,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:15439: $lt_compile\"" >&5) + (eval echo "\"\$as_me:15441: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:15443: \$? = $ac_status" >&5 + echo "$as_me:15445: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -17226,7 +17228,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext < conftest.$ac_ext <&5 +$as_echo_n "checking for X2APIC support... " >&6; } +# Check whether --enable-x2apic was given. +if test "${enable_x2apic+set}" = set; then : + enableval=$enable_x2apic; if test "$enableval" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define BX_SUPPORT_X2APIC 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + $as_echo "#define BX_SUPPORT_X2APIC 0" >>confdefs.h + + fi +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + $as_echo "#define BX_SUPPORT_X2APIC 0" >>confdefs.h + + + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long mode 1G pages support" >&5 $as_echo_n "checking for long mode 1G pages support... " >&6; } # Check whether --enable-1g-pages was given. diff --git a/bochs/configure.in b/bochs/configure.in index 8e60f9347..7c087c871 100644 --- a/bochs/configure.in +++ b/bochs/configure.in @@ -2,7 +2,7 @@ dnl // Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) AC_INIT(bochs.h) -AC_REVISION([[$Id: configure.in,v 1.433 2010-04-04 18:37:53 sshwarts Exp $]]) +AC_REVISION([[$Id: configure.in,v 1.434 2010-04-08 15:50:39 sshwarts Exp $]]) AC_CONFIG_HEADER(config.h) AC_CONFIG_HEADER(ltdlconf.h) @@ -860,6 +860,22 @@ fi AC_SUBST(NETLOW_OBJS) +AC_MSG_CHECKING(for X2APIC support) +AC_ARG_ENABLE(x2apic, + [ --enable-x2apic support for X2APIC], + [if test "$enableval" = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(BX_SUPPORT_X2APIC, 1) + else + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_X2APIC, 0) + fi], + [ + AC_MSG_RESULT(no) + AC_DEFINE(BX_SUPPORT_X2APIC, 0) + ] + ) + AC_MSG_CHECKING(for long mode 1G pages support) AC_ARG_ENABLE(1g-pages, [ --enable-1g-pages support for 1G pages in long mode], diff --git a/bochs/cpu/apic.cc b/bochs/cpu/apic.cc index 8e91e9aef..aa678caf2 100644 --- a/bochs/cpu/apic.cc +++ b/bochs/cpu/apic.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: apic.cc,v 1.142 2010-04-05 09:36:17 sshwarts Exp $ +// $Id: apic.cc,v 1.143 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2002-2009 Zwane Mwaikambo, Stanislav Shwartsman @@ -241,6 +241,10 @@ void bx_local_apic_c::reset(unsigned type) void bx_local_apic_c::set_base(bx_phy_address newbase) { +#if BX_SUPPORT_X2APIC + if (mode == BX_APIC_X2APIC_MODE) + ldr = ((apic_id & 0xfffffff0) << 16) | (1 << (apic_id & 0xf)); +#endif mode = (newbase >> 10) & 3; newbase &= ~((bx_phy_address) 0xfff); base_addr = newbase; @@ -808,6 +812,17 @@ bx_bool bx_local_apic_c::match_logical_addr(apic_dest_t address) { bx_bool match = 0; +#if BX_SUPPORT_X2APIC + if (mode == BX_APIC_X2APIC_MODE) { + // only cluster model supported in x2apic mode + if (address == 0xffffffff) // // broadcast all + return 1; + if ((address & 0xffff0000) == (ldr & 0xffff0000)) + match = ((address & ldr & 0x0000ffff) != 0); + return match; + } +#endif + if (dest_format == 0xf) { // flat model match = ((address & ldr) != 0); @@ -962,6 +977,167 @@ void bx_local_apic_c::set_initial_timer_count(Bit32u value) } } +#if BX_SUPPORT_X2APIC +// return false when x2apic is not supported/not readable +bx_bool bx_local_apic_c::read_x2apic(unsigned index, Bit64u *val_64) +{ + index = (index - 0x800) << 4; + + switch(index) { + // return full 32-bit lapic id + case BX_LAPIC_ID: + *val_64 = apic_id; + break; + case BX_LAPIC_LDR: + *val_64 = ldr; + break; + // full 64-bit access to ICR + case BX_LAPIC_ICR_LO: + *val_64 = ((Bit64u) icr_lo) | (((Bit64u) icr_hi) << 32); + break; + // not supported/not readable in x2apic mode + case BX_LAPIC_ARBITRATION_PRIORITY: + case BX_LAPIC_DESTINATION_FORMAT: + case BX_LAPIC_ICR_HI: + case BX_LAPIC_EOI: // write only + case BX_LAPIC_SELF_IPI: // write only + return 0; + // compatible to legacy lapic mode + case BX_LAPIC_VERSION: + case BX_LAPIC_TPR: + case BX_LAPIC_PPR: + case BX_LAPIC_SPURIOUS_VECTOR: + case BX_LAPIC_ISR1: + case BX_LAPIC_ISR2: + case BX_LAPIC_ISR3: + case BX_LAPIC_ISR4: + case BX_LAPIC_ISR5: + case BX_LAPIC_ISR6: + case BX_LAPIC_ISR7: + case BX_LAPIC_ISR8: + case BX_LAPIC_TMR1: + case BX_LAPIC_TMR2: + case BX_LAPIC_TMR3: + case BX_LAPIC_TMR4: + case BX_LAPIC_TMR5: + case BX_LAPIC_TMR6: + case BX_LAPIC_TMR7: + case BX_LAPIC_TMR8: + case BX_LAPIC_IRR1: + case BX_LAPIC_IRR2: + case BX_LAPIC_IRR3: + case BX_LAPIC_IRR4: + case BX_LAPIC_IRR5: + case BX_LAPIC_IRR6: + case BX_LAPIC_IRR7: + case BX_LAPIC_IRR8: + case BX_LAPIC_ESR: + case BX_LAPIC_LVT_TIMER: + case BX_LAPIC_LVT_THERMAL: + case BX_LAPIC_LVT_PERFMON: + case BX_LAPIC_LVT_LINT0: + case BX_LAPIC_LVT_LINT1: + case BX_LAPIC_LVT_ERROR: + case BX_LAPIC_TIMER_INITIAL_COUNT: + case BX_LAPIC_TIMER_CURRENT_COUNT: + case BX_LAPIC_TIMER_DIVIDE_CFG: + *val_64 = read_aligned(index); + break; + default: + BX_DEBUG(("read_x2apic: not supported apic register 0x%08x", index)); + return 0; + } + + return 1; +} + +// return false when x2apic is not supported/not writeable +bx_bool bx_local_apic_c::write_x2apic(unsigned index, Bit64u val_64) +{ + Bit32u val32_lo = GET32L(val_64); + + index = (index - 0x800) << 4; + + switch(index) { + // read only/not available in x2apic mode + case BX_LAPIC_ID: + case BX_LAPIC_VERSION: + case BX_LAPIC_ARBITRATION_PRIORITY: + case BX_LAPIC_PPR: + case BX_LAPIC_LDR: + case BX_LAPIC_DESTINATION_FORMAT: + case BX_LAPIC_ISR1: + case BX_LAPIC_ISR2: + case BX_LAPIC_ISR3: + case BX_LAPIC_ISR4: + case BX_LAPIC_ISR5: + case BX_LAPIC_ISR6: + case BX_LAPIC_ISR7: + case BX_LAPIC_ISR8: + case BX_LAPIC_TMR1: + case BX_LAPIC_TMR2: + case BX_LAPIC_TMR3: + case BX_LAPIC_TMR4: + case BX_LAPIC_TMR5: + case BX_LAPIC_TMR6: + case BX_LAPIC_TMR7: + case BX_LAPIC_TMR8: + case BX_LAPIC_IRR1: + case BX_LAPIC_IRR2: + case BX_LAPIC_IRR3: + case BX_LAPIC_IRR4: + case BX_LAPIC_IRR5: + case BX_LAPIC_IRR6: + case BX_LAPIC_IRR7: + case BX_LAPIC_IRR8: + case BX_LAPIC_ICR_HI: + case BX_LAPIC_TIMER_CURRENT_COUNT: + return 0; + // send self ipi + case BX_LAPIC_SELF_IPI: + trigger_irq(val32_lo & 0xff, APIC_EDGE_TRIGGERED); + break; + // handle full 64-bit write + case BX_LAPIC_ICR_LO: + send_ipi(GET32H(val_64), val32_lo); + break; + case BX_LAPIC_TPR: + // handle reserved bits, only bits 0-7 are writeable + if ((val32_lo & 0xffffff00) != 0) + return 0; + break; // use legacy write + case BX_LAPIC_SPURIOUS_VECTOR: + // handle reserved bits, only bits 0-8, 12 are writeable + // we do not support directed EOI capability, so reserve bit 12 as well + if ((val32_lo & 0xfffffe00) != 0) + return 0; + break; // use legacy write + case BX_LAPIC_EOI: + case BX_LAPIC_ESR: + if (val_64 != 0) return 0; + break; // use legacy write + case BX_LAPIC_LVT_TIMER: + case BX_LAPIC_LVT_THERMAL: + case BX_LAPIC_LVT_PERFMON: + case BX_LAPIC_LVT_LINT0: + case BX_LAPIC_LVT_LINT1: + case BX_LAPIC_LVT_ERROR: + case BX_LAPIC_TIMER_INITIAL_COUNT: + case BX_LAPIC_TIMER_DIVIDE_CFG: + break; // use legacy write + default: + BX_DEBUG(("write_x2apic: not supported apic register 0x%08x", index)); + return 0; + } + + if (GET32H(val_64) != 0) // upper 32-bit are reserved for all x2apic MSRs + return 0; + + write_aligned(index, val32_lo); + return 1; +} +#endif + void bx_local_apic_c::register_state(bx_param_c *parent) { unsigned i; diff --git a/bochs/cpu/apic.h b/bochs/cpu/apic.h index d5575de43..67fb58eed 100644 --- a/bochs/cpu/apic.h +++ b/bochs/cpu/apic.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: apic.h,v 1.54 2010-03-27 09:56:30 sshwarts Exp $ +// $Id: apic.h,v 1.55 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2002-2009 Zwane Mwaikambo, Stanislav Shwartsman @@ -71,6 +71,7 @@ class BOCHSAPI bx_local_apic_c : public logfunctions #define APIC_ERR_ILLEGAL_ADDR 0x80 #define APIC_ERR_RX_ILLEGAL_VEC 0x40 #define APIC_ERR_TX_ILLEGAL_VEC 0x20 +#define X2APIC_ERR_REDIRECTIBLE_IPI 0x08 #define APIC_ERR_RX_ACCEPT_ERR 0x08 #define APIC_ERR_TX_ACCEPT_ERR 0x04 #define APIC_ERR_RX_CHECKSUM 0x02 @@ -128,7 +129,10 @@ public: void write(bx_phy_address addr, void *data, unsigned len); void write_aligned(bx_phy_address addr, Bit32u data); Bit32u read_aligned(bx_phy_address address); - void startup_msg(Bit8u vector); +#if BX_SUPPORT_X2APIC + bx_bool read_x2apic(unsigned index, Bit64u *msr); + bx_bool write_x2apic(unsigned index, Bit64u msr); +#endif // on local APIC, trigger means raise the CPU's INTR line. For now // I also have to raise pc_system.INTR but that should be replaced // with the cpu-specific INTR signals. @@ -152,6 +156,7 @@ public: void periodic(void); void set_divide_configuration(Bit32u value); void set_initial_timer_count(Bit32u value); + void startup_msg(Bit8u vector); void register_state(bx_param_c *parent); }; diff --git a/bochs/cpu/cpu.h b/bochs/cpu/cpu.h index 379d47fb4..8ba0a6c28 100644 --- a/bochs/cpu/cpu.h +++ b/bochs/cpu/cpu.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: cpu.h,v 1.666 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: cpu.h,v 1.667 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001-2010 The Bochs Project @@ -610,7 +610,7 @@ typedef struct #define BX_CPU_P6 0x00000008 /* P6 new instruction */ #define BX_CPU_MMX 0x00000010 /* MMX instruction */ #define BX_CPU_3DNOW 0x00000020 /* 3DNow! instruction */ -#define BX_CPU_FXSAVE_FXRSTOR 0x00000040 /* SYSENTER/SYSEXIT instruction */ +#define BX_CPU_FXSAVE_FXRSTOR 0x00000040 /* FXSAVE/FXRSTOR instruction */ #define BX_CPU_SYSENTER_SYSEXIT 0x00000080 /* SYSENTER/SYSEXIT instruction */ #define BX_CPU_CLFLUSH 0x00000100 /* CLFLUSH instruction */ #define BX_CPU_SSE 0x00000200 /* SSE instruction */ @@ -3122,7 +3122,6 @@ public: // for now... #endif BX_SMF void TLB_flush(void); BX_SMF void TLB_invlpg(bx_address laddr); - BX_SMF void TLB_init(void); BX_SMF void set_INTR(bx_bool value); BX_SMF const char *strseg(bx_segment_reg_t *seg); BX_SMF void interrupt(Bit8u vector, unsigned type, bx_bool push_error, @@ -3265,6 +3264,10 @@ public: // for now... BX_SMF void init_isa_features_bitmask(void); BX_SMF void init_FetchDecodeTables(void); +#if BX_SUPPORT_X2APIC + BX_SMF void bx_cpuid_extended_topology_leaf(Bit32u subfunction); +#endif + BX_SMF void bx_cpuid_xsave_leaf(Bit32u subfunction); BX_SMF BX_CPP_INLINE unsigned which_cpu(void) { return BX_CPU_THIS_PTR bx_cpuid; } BX_SMF BX_CPP_INLINE const bx_gen_reg_t *get_gen_regfile() { return BX_CPU_THIS_PTR gen_reg; } @@ -3407,7 +3410,7 @@ public: // for now... BX_SMF Bit16u VMX_Get_Current_VPID(void); #endif BX_SMF Bit32u VMX_Read_VTPR(void); - BX_SMF void VMX_Write_TPR_Shadow(Bit8u tpr_shadow); + BX_SMF void VMX_Write_VTPR(Bit8u vtpr); BX_SMF Bit64s VMX_TSC_Offset(void); // vmexit reasons BX_SMF void VMexit_Instruction(bxInstruction_c *i, Bit32u reason) BX_CPP_AttrRegparmN(2); diff --git a/bochs/cpu/cpuid.cc b/bochs/cpu/cpuid.cc index b26ce8d7b..c43aa4950 100755 --- a/bochs/cpu/cpuid.cc +++ b/bochs/cpu/cpuid.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: cpuid.cc,v 1.111 2010-04-03 05:59:07 sshwarts Exp $ +// $Id: cpuid.cc,v 1.112 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2007-2010 Stanislav Shwartsman @@ -164,47 +164,51 @@ Bit32u BX_CPU_C::get_extended_cpuid_features(void) Bit32u features = 0; // support SSE3 - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE3) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE3)) features |= (1<<0); // support for PCLMULQDQ - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_AES_PCLMULQDQ) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_AES_PCLMULQDQ)) features |= (1<<1); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_MONITOR_MWAIT) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_MONITOR_MWAIT)) features |= (1<<3); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_VMX) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_VMX)) features |= (1<<5); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSSE3) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSSE3)) features |= (1<<9); #if BX_SUPPORT_X86_64 // support CMPXCHG16B - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_X86_64) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_X86_64)) features |= (1<<13); #endif - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE4_1) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE4_1)) features |= (1<<19); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE4_2) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE4_2)) features |= (1<<20); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_MOVBE) +#if BX_SUPPORT_X2APIC + features |= (1<<21); // support X2APIC +#endif + + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_MOVBE)) features |= (1<<22); // enable POPCNT if SSE4_2 is enabled - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE4_2) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE4_2)) features |= (1<<23); // support for AES - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_AES_PCLMULQDQ) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_AES_PCLMULQDQ)) features |= (1<<25); // support XSAVE extensions - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_XSAVE) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_XSAVE)) features |= (1<<26) | (1<<27); return features; @@ -248,11 +252,11 @@ Bit32u BX_CPU_C::get_std_cpuid_features(void) Bit32u features = 0; - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_X87) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_X87)) features |= (1<<0); #if BX_CPU_LEVEL >= 5 - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_PENTIUM) { + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_PENTIUM)) { // Pentium only features features |= (1<<1); // support VME features |= (1<<3); // support PSE @@ -272,19 +276,19 @@ Bit32u BX_CPU_C::get_std_cpuid_features(void) features |= (1<<9); // APIC on chip #endif - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SYSENTER_SYSEXIT) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SYSENTER_SYSEXIT)) features |= (1<<11); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_CLFLUSH) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_CLFLUSH)) features |= (1<<19); #if BX_CPU_LEVEL >= 5 - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_MMX) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_MMX)) features |= (1<<23); #endif #if BX_CPU_LEVEL >= 6 - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_P6) { + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_P6)) { features |= (1<<6); // support PAE features |= (1<<12); // support MTRRs features |= (1<<13); // support Global pages @@ -293,13 +297,13 @@ Bit32u BX_CPU_C::get_std_cpuid_features(void) features |= (1<<17); // support PSE-36 } - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_FXSAVE_FXRSTOR) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_FXSAVE_FXRSTOR)) features |= (1<<24); // support FSAVE/FXRSTOR instructions - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE)) features |= (1<<25); - if (BX_CPU_THIS_PTR isa_extensions_bitmask & BX_CPU_SSE2) + if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_SSE2)) features |= (1<<26); #endif @@ -330,16 +334,20 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::CPUID(bxInstruction_c *i) if(function < 0x80000000) { if(function <= max_std_function) { +#if BX_SUPPORT_X2APIC + if (function == 0xb) { + bx_cpuid_extended_topology_leaf(subfunction); + return; + } +#endif + if (function == 0xd) { + bx_cpuid_xsave_leaf(subfunction); + return; + } RAX = BX_CPU_THIS_PTR cpuid_std_function[function].eax; RBX = BX_CPU_THIS_PTR cpuid_std_function[function].ebx; RCX = BX_CPU_THIS_PTR cpuid_std_function[function].ecx; RDX = BX_CPU_THIS_PTR cpuid_std_function[function].edx; - if (function == 0xD && subfunction > 0) { - RAX = 0; - RBX = 0; - RCX = 0; - RDX = 0; - } return; } } @@ -406,8 +414,11 @@ void BX_CPU_C::set_cpuid_defaults(void) if (! cpuid_limit_winnt) { if (BX_SUPPORT_MONITOR_MWAIT) cpuid->eax = 0x5; +#if BX_SUPPORT_X2APIC + cpuid->eax = 0xb; +#endif if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_XSAVE)) - cpuid->eax = 0xD; + cpuid->eax = 0xd; } #endif @@ -582,10 +593,10 @@ void BX_CPU_C::set_cpuid_defaults(void) #endif // ------------------------------------------------------ - // CPUID function 0x0000000D + // CPUID function 0x0000000d if (BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_XSAVE)) { - cpuid = &(BX_CPU_THIS_PTR cpuid_std_function[0xD]); + cpuid = &(BX_CPU_THIS_PTR cpuid_std_function[0xd]); // EAX - XCR0 lower 32 bits // EBX - Maximum size (in bytes) required by enabled features @@ -792,6 +803,123 @@ void BX_CPU_C::set_cpuid_defaults(void) #endif // BX_CPU_LEVEL >= 6 } +#if BX_SUPPORT_X2APIC + +#include + +void BX_CPU_C::bx_cpuid_extended_topology_leaf(Bit32u subfunction) +{ + static int nthreads = SIM->get_param_num(BXPN_CPU_NTHREADS)->get(); + static int ncores = SIM->get_param_num(BXPN_CPU_NCORES)->get(); + static int nprocessors = SIM->get_param_num(BXPN_CPU_NPROCESSORS)->get(); + + switch(subfunction) { + case 0: + if (nthreads > 1) { + RAX = (bx_address) ceil(log(nthreads)/log(2)); + RBX = nthreads; + RCX = subfunction | (1<<8); + } + else if (ncores > 1) { + RAX = (bx_address) ceil(log(ncores)/log(2)); + RBX = ncores; + RCX = subfunction | (2<<8); + } + else if (nprocessors > 1) { + RAX = (bx_address) ceil(log(nprocessors)/log(2)); + RBX = nprocessors; + RCX = subfunction; + } + else { + RAX = 0; + RBX = 0; + RCX = subfunction; + } + break; + + case 1: + if (nthreads > 1) { + if (ncores > 1) { + RAX = (bx_address) ceil(log(ncores)/log(2)); + RBX = ncores; + RCX = subfunction | (2<<8); + } + else if (nprocessors > 1) { + RAX = (bx_address) ceil(log(nprocessors)/log(2)); + RBX = nprocessors; + RCX = subfunction; + } + else { + RAX = 0; + RBX = 0; + RCX = subfunction; + } + } + else if (ncores > 1) { + if (nprocessors > 1) { + RAX = (bx_address) ceil(log(nprocessors)/log(2)); + RBX = nprocessors; + RCX = subfunction; + } + else { + RAX = 0; + RBX = 0; + RCX = subfunction; + } + } else { + RAX = 0; + RBX = 0; + RCX = subfunction; + } + break; + + case 2: + if (nthreads > 1) { + if (nprocessors > 1) { + RAX = (bx_address) ceil(log(nprocessors)/log(2)); + RBX = nprocessors; + } + else { + RAX = 0; + RBX = 0; + } + } + else { + RAX = 0; + RBX = 0; + } + RCX = subfunction; + break; + + default: + RAX = 0; + RBX = 0; + RCX = subfunction; + break; + } + + RDX = BX_CPU_THIS_PTR lapic.get_id(); // x2apic ID +} + +#endif + +void BX_CPU_C::bx_cpuid_xsave_leaf(Bit32u subfunction) +{ + BX_ASSERT(BX_CPU_SUPPORT_ISA_EXTENSION(BX_CPU_XSAVE)); + if (subfunction == 0) { + RAX = BX_CPU_THIS_PTR cpuid_std_function[0xd].eax; + RBX = BX_CPU_THIS_PTR cpuid_std_function[0xd].ebx; + RCX = BX_CPU_THIS_PTR cpuid_std_function[0xd].ecx; + RDX = BX_CPU_THIS_PTR cpuid_std_function[0xd].edx; + } + else { + RAX = 0; // reserved + RBX = 0; // reserved + RCX = 0; // reserved + RDX = 0; // reserved + } +} + void BX_CPU_C::init_isa_features_bitmask(void) { Bit32u features_bitmask = 0; diff --git a/bochs/cpu/crregs.cc b/bochs/cpu/crregs.cc index a4f2acb97..3704ca05d 100755 --- a/bochs/cpu/crregs.cc +++ b/bochs/cpu/crregs.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: crregs.cc,v 1.10 2010-04-06 19:26:02 sshwarts Exp $ +// $Id: crregs.cc,v 1.11 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2010 Stanislav Shwartsman @@ -575,11 +575,11 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_CqRq(bxInstruction_c *i) } #if BX_SUPPORT_VMX if (BX_CPU_THIS_PTR in_vmx_guest && VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW)) { - VMX_Write_TPR_Shadow(val_64 & 0xF); + VMX_Write_VTPR((val_64 & 0xF) << 4); break; } #endif - BX_CPU_THIS_PTR lapic.set_tpr((val_64 & 0xF) << 0x4); + BX_CPU_THIS_PTR lapic.set_tpr((val_64 & 0xF) << 4); break; #endif diff --git a/bochs/cpu/init.cc b/bochs/cpu/init.cc index 2c61df63c..ab51714ac 100644 --- a/bochs/cpu/init.cc +++ b/bochs/cpu/init.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: init.cc,v 1.238 2010-04-06 19:26:03 sshwarts Exp $ +// $Id: init.cc,v 1.239 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001-2009 The Bochs Project @@ -993,7 +993,8 @@ void BX_CPU_C::reset(unsigned source) BX_CPU_THIS_PTR EXT = 0; - TLB_init(); + TLB_flush(); + BX_CPU_THIS_PTR PDPTR_CACHE.valid = 0; // invalidate the prefetch queue BX_CPU_THIS_PTR eipPageBias = 0; diff --git a/bochs/cpu/msr.cc b/bochs/cpu/msr.cc index 0d1307aa8..b4e1f28a1 100755 --- a/bochs/cpu/msr.cc +++ b/bochs/cpu/msr.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: msr.cc,v 1.47 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: msr.cc,v 1.48 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2008-2010 Stanislav Shwartsman @@ -40,6 +40,15 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr) if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX) return 0; +#if BX_SUPPORT_X2APIC + if (index >= 0x800 && index <= 0xBFF) { + if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode + return BX_CPU_THIS_PTR lapic.read_x2apic(index, msr); + else + return 0; + } +#endif + switch(index) { #if BX_CPU_LEVEL >= 6 @@ -273,6 +282,16 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i) VMexit_MSR(i, VMX_VMEXIT_RDMSR, index); #endif +#if BX_SUPPORT_VMX >= 2 + if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) { + if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) { + RAX = VMX_Read_VTPR() & 0xff; + RDX = 0; + return; + } + } +#endif + if (!rdmsr(index, &val64)) exception(BX_GP_EXCEPTION, 0); @@ -341,6 +360,15 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64) if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX) return 0; +#if BX_SUPPORT_X2APIC + if (index >= 0x800 && index <= 0xBFF) { + if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode + return BX_CPU_THIS_PTR lapic.write_x2apic(index, val_64); + else + return 0; + } +#endif + switch(index) { #if BX_CPU_LEVEL >= 6 @@ -636,7 +664,7 @@ bx_bool BX_CPU_C::relocate_apic(Bit64u val_64) * [M:63] Reserved */ -#define BX_MSR_APICBASE_RESERVED_BITS 0x6ff +#define BX_MSR_APICBASE_RESERVED_BITS (0x2ff | (BX_SUPPORT_X2APIC ? 0 : 0x400)) if (BX_CPU_THIS_PTR msr.apicbase & 0x800) { Bit32u val32_hi = GET32H(val_64), val32_lo = GET32L(val_64); @@ -651,6 +679,20 @@ bx_bool BX_CPU_C::relocate_apic(Bit64u val_64) BX_ERROR(("relocate_apic: attempt to set reserved bits")); return 0; } + +#if BX_SUPPORT_X2APIC + unsigned apic_state = (BX_CPU_THIS_PTR msr.apicbase >> 10) & 3; + unsigned new_state = (val32_lo >> 10) & 3; + if (new_state == BX_APIC_STATE_INVALID) { + BX_ERROR(("relocate_apic: attempt to set invalid apic state")); + return 0; + } + if (apic_state == BX_APIC_X2APIC_MODE && new_state != BX_APIC_GLOBALLY_DISABLED) { + BX_ERROR(("relocate_apic: attempt to switch from x2apic -> xapic")); + return 0; + } +#endif + BX_CPU_THIS_PTR msr.apicbase = (bx_phy_address) val_64; BX_CPU_THIS_PTR lapic.set_base(BX_CPU_THIS_PTR msr.apicbase); // TLB flush is required for emulation correctness @@ -685,6 +727,15 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i) VMexit_MSR(i, VMX_VMEXIT_WRMSR, index); #endif +#if BX_SUPPORT_VMX >= 2 + if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) { + if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) { + VMX_Write_VTPR(AL); + return; + } + } +#endif + if (! wrmsr(index, val_64)) exception(BX_GP_EXCEPTION, 0); #endif diff --git a/bochs/cpu/paging.cc b/bochs/cpu/paging.cc index eec406fcd..305183e1f 100644 --- a/bochs/cpu/paging.cc +++ b/bochs/cpu/paging.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: paging.cc,v 1.216 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: paging.cc,v 1.217 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2001-2010 The Bochs Project @@ -253,7 +253,14 @@ // | +------------> u/s of current access // +---------------> Current CR0.WP value -static Bit8u priv_check[BX_PRIV_CHECK_SIZE]; +/* 0xff0bbb0b */ +static const Bit8u priv_check[BX_PRIV_CHECK_SIZE] = +{ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, +#if BX_CPU_LEVEL >= 4 + 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1 +#endif +}; #define BX_PAGING_PHY_ADDRESS_RESERVED_BITS \ (BX_PHY_ADDRESS_RESERVED_BITS & BX_CONST64(0xfffffffffffff)) @@ -360,47 +367,6 @@ static unsigned tlbNonGlobalFlushes=0; // ============================================================== -// Called to initialize the TLB upon startup. -// Unconditional initialization of all TLB entries. -void BX_CPU_C::TLB_init(void) -{ - unsigned n, wp, us_combined, rw_combined, us_current, rw_current; - - // - // Setup privilege check matrix. - // - for (n=0; n> 4; - us_current = (n & 0x08) >> 3; - us_combined = (n & 0x04) >> 2; - rw_combined = (n & 0x02) >> 1; - rw_current = (n & 0x01) >> 0; - if (wp) { // when write protect on - if (us_current > us_combined) // user access, supervisor page - priv_check[n] = 0; - else if (rw_current > rw_combined) // RW access, RO page - priv_check[n] = 0; - else - priv_check[n] = 1; - } - else { // when write protect off - if (us_current == 0) // Supervisor mode access, anything goes - priv_check[n] = 1; - else { - // user mode access - if (us_combined == 0) // user access, supervisor Page - priv_check[n] = 0; - else if (rw_current > rw_combined) // RW access, RO page - priv_check[n] = 0; - else - priv_check[n] = 1; - } - } - } - - TLB_flush(); -} - void BX_CPU_C::TLB_flush(void) { #if InstrumentTLB @@ -857,6 +823,7 @@ bx_phy_address BX_CPU_C::translate_linear_PAE(bx_address laddr, Bit32u &lpf_mask #endif if (! BX_CPU_THIS_PTR PDPTR_CACHE.valid) { + BX_ERROR(("PDPTR_CACHE not valid !")); if (! CheckPDPTR(BX_CPU_THIS_PTR cr3)) { BX_ERROR(("translate_linear_PAE(): PDPTR check failed !")); exception(BX_GP_EXCEPTION, 0); @@ -1350,12 +1317,13 @@ bx_bool BX_CPU_C::dbg_translate_guest_physical(bx_phy_address guest_paddr, bx_ph { VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs; bx_phy_address pt_address = LPFOf(vm->eptptr); - bx_phy_address offset_mask = 0xfff; + Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff); for (int level = 3; level >= 0; --level) { Bit64u pte; pt_address += ((guest_paddr >> (9 + 9*level)) & 0xff8); BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, pt_address, 8, &pte); + offset_mask >>= 9; switch(pte & 7) { case BX_EPT_ENTRY_NOT_PRESENT: @@ -1370,14 +1338,12 @@ bx_bool BX_CPU_C::dbg_translate_guest_physical(bx_phy_address guest_paddr, bx_ph if (pte & 0x80) { if (level == BX_LEVEL_PDE) { // 2M page - offset_mask = 0x1fffff; pt_address &= BX_CONST64(0x000fffffffffe000); if (pt_address & offset_mask) return 0; break; } #if BX_SUPPORT_1G_PAGES if (level == BX_LEVEL_PDPE) { // 1G page - offset_mask = 0x3fffffff; pt_address &= BX_CONST64(0x000fffffffffe000); if (pt_address & offset_mask) return 0; break; @@ -1401,7 +1367,6 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) bx_phy_address paddress; bx_phy_address pt_address = BX_CPU_THIS_PTR cr3 & BX_CR3_PAGING_MASK; - bx_address offset_mask = 0xfff; // see if page is in the TLB first bx_address lpf = LPFOf(laddr); @@ -1416,10 +1381,15 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) #if BX_CPU_LEVEL >= 6 if (BX_CPU_THIS_PTR cr4.get_PAE()) { - if (! long_mode()) pt_address &= BX_CR3_LEGACY_PAE_PAGING_MASK; + Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff); + if (! long_mode()) { + pt_address &= BX_CR3_LEGACY_PAE_PAGING_MASK; + offset_mask >>= 9; + } for (int level = 2 + long_mode(); level >= 0; --level) { Bit64u pte; pt_address += ((laddr >> (9 + 9*level)) & 0xff8); + offset_mask >>= 9; #if BX_SUPPORT_VMX >= 2 if (BX_CPU_THIS_PTR in_vmx_guest) { if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE)) { @@ -1434,9 +1404,9 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) if (pte & BX_PAGING_PHY_ADDRESS_RESERVED_BITS) goto page_fault; pt_address = bx_phy_address(pte & BX_CONST64(0x000ffffffffff000)); + if (level == BX_LEVEL_PTE) break; if (pte & 0x80) { if (level == BX_LEVEL_PDE) { // 2M page - offset_mask = 0x1fffff; pt_address &= BX_CONST64(0x000fffffffffe000); if (pt_address & offset_mask) goto page_fault; @@ -1444,15 +1414,13 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) } #if BX_SUPPORT_1G_PAGES if (level == BX_LEVEL_PDPE && long_mode()) { // 1G page - offset_mask = 0x3fffffff; pt_address &= BX_CONST64(0x000fffffffffe000); if (pt_address & offset_mask) goto page_fault; break; } #endif - if (level != BX_LEVEL_PTE) - goto page_fault; + goto page_fault; } } paddress = pt_address + (bx_phy_address)(laddr & offset_mask); @@ -1460,6 +1428,7 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) else // not PAE #endif { + Bit32u offset_mask = 0xfff; for (int level = 1; level >= 0; --level) { Bit32u pte; pt_address += ((laddr >> (10 + 10*level)) & 0xffc); @@ -1473,14 +1442,14 @@ bx_bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy) #endif BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, pt_address, 4, &pte); if (!(pte & 1)) - goto page_fault; + goto page_fault; pt_address = pte & 0xfffff000; if (level == BX_LEVEL_PDE && (pte & 0x80)) { // PSE page - offset_mask = 0x3fffff; + offset_mask = 0x3fffff; #if BX_PHY_ADDRESS_WIDTH > 32 pt_address += ((bx_phy_address)(pte & 0x003fe000)) << 19; #endif - break; + break; } } paddress = pt_address + (bx_phy_address)(laddr & offset_mask); diff --git a/bochs/cpu/vmexit.cc b/bochs/cpu/vmexit.cc index 6ba65fb74..0b51e0e6d 100755 --- a/bochs/cpu/vmexit.cc +++ b/bochs/cpu/vmexit.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: vmexit.cc,v 1.24 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: vmexit.cc,v 1.25 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2010 Stanislav Shwartsman @@ -688,15 +688,16 @@ Bit32u BX_CPU_C::VMX_Read_VTPR(void) return vtpr; } -void BX_CPU_C::VMX_Write_TPR_Shadow(Bit8u tpr_shadow) +void BX_CPU_C::VMX_Write_VTPR(Bit8u vtpr) { VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs; bx_phy_address pAddr = vm->virtual_apic_page_addr + 0x80; - Bit32u field32 = tpr_shadow << 4; + Bit32u field32 = vtpr; access_write_physical(pAddr, 4, (Bit8u*)(&field32)); BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_WRITE, (Bit8u*)(&field32)); + Bit8u tpr_shadow = vtpr >> 4; if (tpr_shadow < vm->vm_tpr_threshold) { // commit current instruction to produce trap-like VMexit BX_CPU_THIS_PTR prev_rip = RIP; // commit new RIP @@ -750,7 +751,7 @@ void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void * if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) { // VTPR access - VMX_Write_TPR_Shadow(*((Bit8u *) data)); + VMX_Write_VTPR(*((Bit8u *) data)); return; } diff --git a/bochs/cpu/vmx.cc b/bochs/cpu/vmx.cc index 00619c0a1..8f1d35865 100755 --- a/bochs/cpu/vmx.cc +++ b/bochs/cpu/vmx.cc @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: vmx.cc,v 1.59 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: vmx.cc,v 1.60 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2010 Stanislav Shwartsman @@ -447,9 +447,16 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void) return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD; } } -#endif -#if BX_SUPPORT_VMX >= 2 + if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE) { + // 'use TPR shadow' must be set and "virtualize APIC accesses" must be clear + if (!(vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_TPR_SHADOW) || + (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES)) { + BX_ERROR(("VMFAIL: VMCS EXEC CTRL: virtualize X2APIC mode misconfigured")); + return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD; + } + } + if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_EPT_ENABLE) { vm->eptptr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_EPTPTR); if (! is_eptptr_valid(vm->eptptr)) { @@ -1626,6 +1633,11 @@ Bit32u BX_CPU_C::LoadMSRs(Bit32u msr_cnt, bx_phy_address pAddr) return msr; #endif +#if BX_SUPPORT_X2APIC + if ((index & 0xfffff800) == 0x800) // X2APIC range + return msr; +#endif + if (! wrmsr(index, msr_hi)) return msr; @@ -1648,6 +1660,11 @@ Bit32u BX_CPU_C::StoreMSRs(Bit32u msr_cnt, bx_phy_address pAddr) Bit32u index = GET32L(msr_lo); +#if BX_SUPPORT_X2APIC + if ((index & 0xfffff800) == 0x800) // X2APIC range + return msr; +#endif + if (! rdmsr(index, &msr_hi)) return msr; @@ -3183,8 +3200,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::INVEPT(bxInstruction_c *i) if (i->os64L()) { type = BX_READ_64BIT_REG(i->nnn()); } - else - { + else { type = BX_READ_32BIT_REG(i->nnn()); } @@ -3245,8 +3261,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::INVVPID(bxInstruction_c *i) if (i->os64L()) { type = BX_READ_64BIT_REG(i->nnn()); } - else - { + else { type = BX_READ_32BIT_REG(i->nnn()); } diff --git a/bochs/cpu/vmx.h b/bochs/cpu/vmx.h index d5e270e8f..511c25736 100755 --- a/bochs/cpu/vmx.h +++ b/bochs/cpu/vmx.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: vmx.h,v 1.27 2010-04-07 17:12:17 sshwarts Exp $ +// $Id: vmx.h,v 1.28 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009 Stanislav Shwartsman @@ -594,6 +594,7 @@ typedef struct bx_VMCS VMX_VM_EXEC_CTRL3_EPT_ENABLE | \ VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT | \ VMX_VM_EXEC_CTRL3_RDTSCP | \ + VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE | \ VMX_VM_EXEC_CTRL3_VPID_ENABLE | \ VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT) diff --git a/bochs/disasm/disasm.h b/bochs/disasm/disasm.h index 5a5d5ac86..63c43fb03 100644 --- a/bochs/disasm/disasm.h +++ b/bochs/disasm/disasm.h @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////// -// $Id: disasm.h,v 1.61 2010-04-02 19:01:17 sshwarts Exp $ +// $Id: disasm.h,v 1.62 2010-04-08 15:50:39 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2005-2009 Stanislav Shwartsman @@ -45,7 +45,7 @@ #define IA_P6 0x00000008 /* P6 new instruction */ #define IA_MMX 0x00000010 /* MMX instruction */ #define IA_3DNOW 0x00000020 /* 3DNow! instruction */ -#define IA_FXSAVE_FXRSTOR 0x00000040 /* SYSENTER/SYSEXIT instruction */ +#define IA_FXSAVE_FXRSTOR 0x00000040 /* FXSAVE/FXRSTOR instruction */ #define IA_SYSENTER_SYSEXIT 0x00000080 /* SYSENTER/SYSEXIT instruction */ #define IA_CLFLUSH 0x00000100 /* CLFLUSH instruction */ #define IA_SSE 0x00000200 /* SSE instruction */