This commit is contained in:
Stanislav Shwartsman 2022-07-30 15:43:25 +03:00
commit 0f9aec0e1a
11 changed files with 67 additions and 23 deletions

View File

@ -1,5 +1,10 @@
Changes after 2.7:
The Bochs source tree is transitioning from SVN to GIT hosted on github.
We welcome every new contributor !
- Bugfixes for CPU emulation correctness (MONITOR/MWAIT, VMX/SVM fixes)
! Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest
- Fixed Voodoo device compilation for big endian architectures
- Fixed memory handling in volatile BIOS write support
- Fixed APIC MWAIT timer activation

View File

@ -4532,7 +4532,7 @@ public: // for now...
BX_SMF bx_phy_address translate_linear_long_mode(bx_address laddr, Bit32u &lpf_mask, Bit32u &pkey, unsigned user, unsigned rw);
#endif
#if BX_SUPPORT_VMX >= 2
BX_SMF bx_phy_address translate_guest_physical(bx_phy_address guest_paddr, bx_address guest_laddr, bool guest_laddr_valid, bool is_page_walk, unsigned rw, bool supervisor_shadow_stack = false);
BX_SMF bx_phy_address translate_guest_physical(bx_phy_address guest_paddr, bx_address guest_laddr, bool guest_laddr_valid, bool is_page_walk, unsigned user_page, unsigned rw, bool supervisor_shadow_stack = false);
BX_SMF void update_ept_access_dirty(bx_phy_address *entry_addr, Bit64u *entry, BxMemtype eptptr_memtype, unsigned leaf, unsigned write);
BX_SMF bool is_eptptr_valid(Bit64u eptptr);
BX_SMF bool spp_walk(bx_phy_address guest_paddr, bx_address guest_laddr, BxMemtype memtype);

View File

@ -252,7 +252,7 @@ Bit32u corei3_cnl_t::get_vmx_extensions_bitmask(void) const
BX_VMX_VMCS_SHADOWING |
BX_VMX_EPT_EXCEPTION |
BX_VMX_SW_INTERRUPT_INJECTION_ILEN_0 |
/* BX_VMX_MBE_CONTROL - not implemeted yet */
BX_VMX_MBE_CONTROL |
BX_VMX_TSC_SCALING;
}

View File

@ -261,7 +261,7 @@ Bit32u corei7_icelake_t::get_vmx_extensions_bitmask(void) const
BX_VMX_PML |
BX_VMX_SW_INTERRUPT_INJECTION_ILEN_0 |
/* BX_VMX_POSTED_INSTERRUPTS - not implemented yet */
/* BX_VMX_MBE_CONTROL - not implemeted yet */
BX_VMX_MBE_CONTROL |
BX_VMX_SPP |
BX_VMX_TSC_SCALING;
}

View File

@ -249,7 +249,7 @@ Bit32u corei7_skylake_x_t::get_vmx_extensions_bitmask(void) const
BX_VMX_SW_INTERRUPT_INJECTION_ILEN_0 |
BX_VMX_PML |
/* BX_VMX_POSTED_INSTERRUPTS - not implemented yet */
/* BX_VMX_MBE_CONTROL - not implemeted yet */
BX_VMX_MBE_CONTROL |
BX_VMX_TSC_SCALING;
}

View File

@ -265,7 +265,7 @@ Bit32u tigerlake_t::get_vmx_extensions_bitmask(void) const
BX_VMX_PML |
BX_VMX_SW_INTERRUPT_INJECTION_ILEN_0 |
/* BX_VMX_POSTED_INSTERRUPTS - not implemented yet */
/* BX_VMX_MBE_CONTROL - not implemeted yet */
BX_VMX_MBE_CONTROL |
BX_VMX_SPP |
BX_VMX_TSC_SCALING;
}

View File

@ -173,6 +173,7 @@ typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);
#define BX_VMX_SPP (1 << 23) /* Sub Page Protection */
#define BX_VMX_TSC_SCALING (1 << 24) /* TSC Scaling */
#define BX_VMX_SW_INTERRUPT_INJECTION_ILEN_0 (1 << 25) /* Allow software interrupt injection with instruction length 0 */
#define BX_VMX_MBE_CONTROL (1 << 26) /* Mode-Based Execution Control (XU/XS) */
// CPUID defines - STD features CPUID[0x00000001].EDX
// ----------------------------

View File

@ -554,6 +554,8 @@ enum {
BX_COMBINED_GLOBAL_PAGE = 0x100,
};
#define IS_USER_PAGE(combined_access) !!((combined_access) & BX_COMBINED_ACCESS_USER)
#if BX_CPU_LEVEL >= 6
// Format of a Long Mode Non-Leaf Entry
@ -648,7 +650,7 @@ int BX_CPU_C::check_entry_PAE(const char *s, Bit64u entry, Bit64u reserved, unsi
}
if (entry & reserved) {
BX_DEBUG(("PAE %s: reserved bit is set 0x" FMT_ADDRX64, s, entry));
BX_DEBUG(("PAE %s: reserved bit is set 0x" FMT_ADDRX64 "(reserved: " FMT_ADDRX64 ")", s, entry, entry & reserved));
return ERROR_RESERVED | ERROR_PROTECTION;
}
@ -707,7 +709,7 @@ bx_phy_address BX_CPU_C::translate_linear_long_mode(bx_address laddr, Bit32u &lp
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE))
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, 1, 1, BX_READ);
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, true /* laddr_valid */, true /* page walk */, IS_USER_PAGE(combined_access), BX_READ);
}
#endif
#if BX_SUPPORT_SVM
@ -904,7 +906,7 @@ bool BX_CPP_AttrRegparmN(1) BX_CPU_C::CheckPDPTR(bx_phy_address cr3_val)
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE))
cr3_val = translate_guest_physical(cr3_val, 0, 0, 1, BX_READ);
cr3_val = translate_guest_physical(cr3_val, 0, false /* laddr_valid */, true /* page walk */, 0, BX_READ);
}
#endif
@ -1003,7 +1005,7 @@ bx_phy_address BX_CPU_C::translate_linear_PAE(bx_address laddr, Bit32u &lpf_mask
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE))
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, 1, 1, BX_READ);
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, true /* laddr_valid */, true /* page walk */, IS_USER_PAGE(combined_access), BX_READ);
}
#endif
#if BX_SUPPORT_SVM
@ -1144,7 +1146,7 @@ bx_phy_address BX_CPU_C::translate_linear_legacy(bx_address laddr, Bit32u &lpf_m
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE))
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, 1, 1, BX_READ);
entry_addr[leaf] = translate_guest_physical(entry_addr[leaf], laddr, true /* laddr_valid */, true /* page walk */, IS_USER_PAGE(combined_access), BX_READ);
}
#endif
#if BX_SUPPORT_SVM
@ -1375,7 +1377,7 @@ bx_phy_address BX_CPU_C::translate_linear(bx_TLB_entry *tlbEntry, bx_address lad
#if BX_SUPPORT_VMX >= 2
if (BX_CPU_THIS_PTR in_vmx_guest) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_ENABLE)) {
paddress = translate_guest_physical(paddress, laddr, 1, 0, rw, isShadowStack & !user);
paddress = translate_guest_physical(paddress, laddr, true /* laddr_valid */, false /* page walk */, IS_USER_PAGE(combined_access), rw, isShadowStack & !user);
}
}
#endif
@ -1857,7 +1859,10 @@ bx_phy_address BX_CPU_C::nested_walk(bx_phy_address guest_paddr, unsigned rw, bo
enum {
BX_EPT_READ = 0x01,
BX_EPT_WRITE = 0x02,
BX_EPT_EXECUTE = 0x04
BX_EPT_EXECUTE = 0x04,
BX_EPT_MBE_SUPERVISOR_EXECUTE = BX_EPT_EXECUTE,
BX_EPT_MBE_USER_EXECUTE = 0x400
};
/* EPT access mask */
@ -1900,7 +1905,7 @@ const Bit64u BX_SUPERVISOR_SHADOW_STACK_PAGE = (BX_CONST64(1) << 60);
const Bit64u PAGING_EPT_RESERVED_BITS = BX_PAGING_PHY_ADDRESS_RESERVED_BITS;
bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx_address guest_laddr, bool guest_laddr_valid, bool is_page_walk, unsigned rw, bool supervisor_shadow_stack)
bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx_address guest_laddr, bool guest_laddr_valid, bool is_page_walk, unsigned user_page, unsigned rw, bool supervisor_shadow_stack)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_phy_address entry_addr[4], ppf = LPFOf(vm->eptptr);
@ -1912,8 +1917,10 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
BxMemtype eptptr_memtype = BX_CPU_THIS_PTR cr0.get_CD() ? (BX_MEMTYPE_UC) : BxMemtype(vm->eptptr & 0x7);
#endif
Bit32u combined_access = 0x7, access_mask = 0;
Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff);
Bit32u combined_access = 0x7, access_mask = 0;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_MBE_CTRL))
combined_access |= BX_EPT_MBE_USER_EXECUTE;
BX_DEBUG(("EPT walk for guest paddr 0x" FMT_PHY_ADDRX, guest_paddr));
@ -1921,7 +1928,14 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
if (BX_VMX_EPT_ACCESS_DIRTY_ENABLED && is_page_walk && guest_laddr_valid)
rw = BX_WRITE;
if (rw == BX_EXECUTE) access_mask |= BX_EPT_EXECUTE;
if (rw == BX_EXECUTE) {
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_MBE_CTRL)) {
access_mask |= user_page ? BX_EPT_MBE_USER_EXECUTE : BX_EPT_MBE_SUPERVISOR_EXECUTE;
}
else {
access_mask |= BX_EPT_EXECUTE;
}
}
if (rw & 1) access_mask |= BX_EPT_WRITE; // write or r-m-w
if ((rw & 3) == BX_READ) access_mask |= BX_EPT_READ; // handle correctly shadow stack reads
@ -1935,6 +1949,9 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
offset_mask >>= 9;
Bit64u curr_entry = entry[leaf];
Bit32u curr_access_mask = curr_entry & 0x7;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_MBE_CTRL)) {
curr_access_mask |= (curr_entry & BX_EPT_MBE_USER_EXECUTE);
}
if (curr_access_mask == BX_EPT_ENTRY_NOT_PRESENT) {
BX_DEBUG(("EPT %s: not present", bx_paging_level[leaf]));
@ -1942,8 +1959,8 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
break;
}
if (curr_access_mask == BX_EPT_ENTRY_WRITE_ONLY || curr_access_mask == BX_EPT_ENTRY_WRITE_EXECUTE) {
BX_DEBUG(("EPT %s: EPT misconfiguration mask=%d", bx_paging_level[leaf], curr_access_mask));
if ((curr_access_mask & (BX_EPT_READ | BX_EPT_WRITE)) == BX_EPT_ENTRY_WRITE_ONLY) {
BX_DEBUG(("EPT %s: EPT misconfiguration access_mask=%x", bx_paging_level[leaf], curr_access_mask));
vmexit_reason = VMX_VMEXIT_EPT_MISCONFIGURATION;
break;
}
@ -1957,7 +1974,7 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
}
if (curr_entry & PAGING_EPT_RESERVED_BITS) {
BX_DEBUG(("EPT %s: reserved bit is set 0x" FMT_ADDRX64, bx_paging_level[leaf], curr_entry));
BX_DEBUG(("EPT %s: reserved bit is set 0x" FMT_ADDRX64 "(reserved: " FMT_ADDRX64 ")", bx_paging_level[leaf], curr_entry, curr_entry & PAGING_EPT_RESERVED_BITS));
vmexit_reason = VMX_VMEXIT_EPT_MISCONFIGURATION;
break;
}
@ -2038,6 +2055,12 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
if (vmexit_reason == VMX_VMEXIT_EPT_VIOLATION) {
combined_access &= entry[leaf];
vmexit_qualification = access_mask | (combined_access << 3);
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_MBE_CTRL) && (rw == BX_EXECUTE)) {
vmexit_qualification &= (0x3f); // reset all bit bits beyond [5:0]
vmexit_qualification |= (1<<2); // bit2 indicate the operation was instruction fetch
if (combined_access & BX_EPT_MBE_USER_EXECUTE)
vmexit_qualification |= (1<<6);
}
if (guest_laddr_valid) {
vmexit_qualification |= (1<<7);
if (! is_page_walk) vmexit_qualification |= (1<<8);
@ -2193,7 +2216,7 @@ void dbg_print_paging_pte(int level, Bit64u entry)
}
#if BX_SUPPORT_VMX >= 2
void dbg_print_ept_paging_pte(int level, Bit64u entry)
void dbg_print_ept_paging_pte(int level, Bit64u entry, bool mbe)
{
dbg_printf("EPT %4s: 0x%08x%08x", bx_paging_level[level], GET32H(entry), GET32L(entry));
@ -2202,8 +2225,11 @@ void dbg_print_ept_paging_pte(int level, Bit64u entry)
else
dbg_printf(" ");
if (mbe)
dbg_printf(" %s", (entry & 0x400) ? "XU" : "xu");
dbg_printf(" %s %s %s",
(entry & 0x04) ? "E" : "e",
(entry & 0x04) ? "X" : "x",
(entry & 0x02) ? "W" : "w",
(entry & 0x01) ? "R" : "r");
@ -2234,7 +2260,7 @@ bool BX_CPU_C::dbg_translate_guest_physical(bx_phy_address guest_paddr, bx_phy_a
BX_MEM(0)->readPhysicalPage(BX_CPU_THIS, pt_address, 8, &pte);
#if BX_DEBUGGER
if (verbose)
dbg_print_ept_paging_pte(level, pte);
dbg_print_ept_paging_pte(level, pte, SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_MBE_CTRL));
#endif
switch(pte & 7) {
case BX_EPT_ENTRY_NOT_PRESENT:

View File

@ -712,7 +712,7 @@ void BX_CPU_C::init_secondary_proc_based_vmexec_ctrls(void)
// [19] Reserved (must be '0)
// [20] XSAVES Exiting
// [21] Reserved (must be '0)
// [22] Mode Based Execution Control (MBE) (not implemented yet)
// [22] Mode Based Execution Control (MBE)
// [23] Sub Page Protection
// [24] Reserved (must be '0)
// [25] Enable TSC Scaling
@ -775,6 +775,11 @@ void BX_CPU_C::init_secondary_proc_based_vmexec_ctrls(void)
}
#endif
#if BX_SUPPORT_VMX >= 2
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_MBE_CONTROL)) {
if (! BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPT))
BX_PANIC(("VMX MBE feature requires EPT support !"));
cap->vmx_vmexec_ctrl2_supported_bits |= VMX_VM_EXEC_CTRL3_MBE_CTRL;
}
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_SPP)) {
if (! BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPT))
BX_PANIC(("VMX SPP feature requires EPT support !"));

View File

@ -827,6 +827,13 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
}
}
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_MBE_CTRL) {
if ((vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_EPT_ENABLE) == 0) {
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: MBE is enabled without EPT"));
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
}
}
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_XSAVES_XRSTORS)
vm->xss_exiting_bitmap = VMread64(VMCS_64BIT_CONTROL_XSS_EXITING_BITMAP);
else

View File

@ -746,7 +746,7 @@ typedef struct bx_VMCS
#define VMX_VM_EXEC_CTRL3_EPT_VIOLATION_EXCEPTION (1 << 18) /* #VE Exception */
#define VMX_VM_EXEC_CTRL3_SUPPRESS_GUEST_VMX_TRACE (1 << 19) /* Processor Trace (not implemented) */
#define VMX_VM_EXEC_CTRL3_XSAVES_XRSTORS (1 << 20) /* XSAVES */
#define VMX_VM_EXEC_CTRL3_MBE_CTRL (1 << 22) /* Mode Based Execution Control (not implemented yet) */
#define VMX_VM_EXEC_CTRL3_MBE_CTRL (1 << 22) /* Mode Based Execution Control */
#define VMX_VM_EXEC_CTRL3_SUBPAGE_WR_PROTECT_CTRL (1 << 23) /* Sub-Page Write Protection Control */
#define VMX_VM_EXEC_CTRL3_PROCESSOR_TRACE_USE_GPA (1 << 24) /* Processor Trace (not implemented) */
#define VMX_VM_EXEC_CTRL3_TSC_SCALING (1 << 25) /* TSC Scaling */