diff --git a/bochs/CHANGES b/bochs/CHANGES index 0a9da4ee4..bf4702a45 100644 --- a/bochs/CHANGES +++ b/bochs/CHANGES @@ -8,9 +8,10 @@ Brief summary : ! Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest ! Implemented Posted-Interrupt Processing VMX extension emulation ! Implemented Linear Address Separation (LASS) extension + ! Implemented 57-bit Linear Address and 5-Level Paging support ! Implemented User-Level Interrupt (UINTR) extension ! Implemented recently published Intel instruction sets: - - MOVDIRI/MOVDIR64B, AVX512 BF16, AVX IFMA52, VNNI-INT8/VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, MSRLIST, WAITPKG, SERIALIZE + - MOVDIRI/MOVDIR64B, AVX512 BF16, AVX IFMA52, VNNI-INT8/VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3/SM4, SHA512, WRMSRNS, MSRLIST, WAITPKG, SERIALIZE - Improved 64-bit guest support in Bochs internal debugger, added new internal debugger commands - Bochs debugger enhanced with new commands (setpmem, loadmem, deref, ...) Enhanced magic breakpoint capabilities. Refer to user documentation for more details. @@ -35,9 +36,10 @@ Detailed change log : - Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest - Implemented Posted-Interrupt Processing VMX extension emulation - Implemented Linear Address Separation (LASS) extension + - Implemented 57-bit Linear Address and 5-Level Paging support - Implemented User-Level Interrupt (UINTR) extension - Implemented recently published Intel instruction sets: - - MOVDIRI/MOVDIR64B, AVX512 BF16, AVX IFMA52, VNNI-INT8/VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, MSRLIST, WAITPKG, SERIALIZE + - MOVDIRI/MOVDIR64B, AVX512 BF16, AVX IFMA52, VNNI-INT8/VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3/SM4, SHA512, WRMSRNS, MSRLIST, WAITPKG, SERIALIZE - Bochs Debugger and Instrumentation - Updated Bochs instrumentation examples for new disassembler introduced in Bochs 2.7 release. diff --git a/bochs/bx_debug/dbg_main.cc b/bochs/bx_debug/dbg_main.cc index 7cd0a3783..a2aaf5ef4 100644 --- a/bochs/bx_debug/dbg_main.cc +++ b/bochs/bx_debug/dbg_main.cc @@ -717,10 +717,12 @@ void bx_dbg_phy_memory_access(unsigned cpu, bx_phy_address phy, unsigned len, un "PDE", "PDPTE", "PML4E", + "PML5E", "EPT PTE", "EPT PDE", "EPT PDPTE", "EPT PML4E", + "EPT PML5E", // place holder "EPT SPP PTE", "EPT SPP PDE", "EPT SPP PDPTE", diff --git a/bochs/config.h.in b/bochs/config.h.in index 413f9d487..a3f4554c2 100644 --- a/bochs/config.h.in +++ b/bochs/config.h.in @@ -475,12 +475,6 @@ typedef Bit32u bx_address; // define physical and linear address types typedef bx_address bx_lin_address; -#if BX_SUPPORT_X86_64 -#define BX_LIN_ADDRESS_WIDTH 48 -#else -#define BX_LIN_ADDRESS_WIDTH 32 -#endif - #if BX_PHY_ADDRESS_LONG typedef Bit64u bx_phy_address; #if BX_CPU_LEVEL == 5 diff --git a/bochs/cpu/cpu.h b/bochs/cpu/cpu.h index e44f42c4f..86d111b90 100644 --- a/bochs/cpu/cpu.h +++ b/bochs/cpu/cpu.h @@ -284,10 +284,12 @@ enum AccessReason { BX_PDE_ACCESS, BX_PDTE_ACCESS, BX_PML4E_ACCESS, + BX_PML5E_ACCESS, BX_EPT_PTE_ACCESS, BX_EPT_PDE_ACCESS, BX_EPT_PDTE_ACCESS, BX_EPT_PML4E_ACCESS, + BX_EPT_PML5E_ACCESS, // place holder BX_EPT_SPP_PTE_ACCESS, BX_EPT_SPP_PDE_ACCESS, BX_EPT_SPP_PDTE_ACCESS, @@ -357,10 +359,13 @@ const unsigned BX_MSR_MAX_INDEX = 0x1000; extern const char* cpu_mode_string(unsigned cpu_mode); #if BX_SUPPORT_X86_64 -BX_CPP_INLINE bool IsCanonical(bx_address offset) +BX_CPP_INLINE bool IsCanonicalToWidth(bx_address addr, unsigned LIN_ADDRESS_WIDTH) { - return ((Bit64u)((((Bit64s)(offset)) >> (BX_LIN_ADDRESS_WIDTH-1)) + 1) < 2); + return ((Bit64u)((((Bit64s)(addr)) >> (LIN_ADDRESS_WIDTH-1)) + 1) < 2); } + +BX_CPP_INLINE bool IsCanonical48(bx_address addr) { return IsCanonicalToWidth(addr, 48); } +BX_CPP_INLINE bool IsCanonical57(bx_address addr) { return IsCanonicalToWidth(addr, 57); } #endif BX_CPP_INLINE bool IsValidPhyAddr(bx_phy_address addr) @@ -944,6 +949,9 @@ public: // for now... #if BX_CPU_LEVEL >= 5 bx_cr4_t cr4; Bit32u cr4_suppmask; +#if BX_SUPPORT_X86_64 + unsigned linaddr_width; +#endif bx_efer_t efer; Bit32u efer_suppmask; @@ -4147,6 +4155,10 @@ public: // for now... BX_CPU_THIS_PTR espPageWindowSize = 0; } +#if BX_SUPPORT_X86_64 + BX_SMF BX_CPP_INLINE bool IsCanonical(bx_address addr) { return IsCanonicalToWidth(addr, BX_CPU_THIS_PTR linaddr_width); } +#endif + BX_SMF bool write_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned len, bool align = false) BX_CPP_AttrRegparmN(4); BX_SMF bool read_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned len, bool align = false) BX_CPP_AttrRegparmN(4); BX_SMF bool execute_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned len) BX_CPP_AttrRegparmN(3); diff --git a/bochs/cpu/cpuid.cc b/bochs/cpu/cpuid.cc index 6ed7828bb..fd53edde6 100644 --- a/bochs/cpu/cpuid.cc +++ b/bochs/cpu/cpuid.cc @@ -927,7 +927,13 @@ Bit32u bx_cpuid_t::get_std_cpuid_leaf_7_ecx(Bit32u extra) const #endif // [15:15] reserved - // [16:16] LA57: LA57 and 5-level paging - not supported + + // [16:16] LA57: LA57 and 5-level paging +#if BX_SUPPORT_X86_64 + if (is_cpu_extension_supported(BX_ISA_LA57)) + ecx |= BX_CPUID_STD7_SUBLEAF0_ECX_LA57; +#endif + // [17:17] reserved // [18:18] reserved // [19:19] reserved @@ -1152,7 +1158,8 @@ void bx_cpuid_t::get_ext_cpuid_leaf_8(cpuid_function_t *leaf) const // virtual & phys address size in low 2 bytes of EAX. // TODO: physical address width should be 32-bit when no PSE-36 is supported Bit32u phy_addr_width = BX_PHY_ADDRESS_WIDTH; - Bit32u lin_addr_width = is_cpu_extension_supported(BX_ISA_LONG_MODE) ? BX_LIN_ADDRESS_WIDTH : 32; + Bit32u lin_addr_width = is_cpu_extension_supported(BX_ISA_LONG_MODE) ? + (is_cpu_extension_supported(BX_ISA_LA57) ? 57 : 48) : 32; leaf->eax = phy_addr_width | (lin_addr_width << 8); diff --git a/bochs/cpu/crregs.cc b/bochs/cpu/crregs.cc index a100b28a3..baea19d8d 100644 --- a/bochs/cpu/crregs.cc +++ b/bochs/cpu/crregs.cc @@ -1152,6 +1152,10 @@ bool BX_CPU_C::SetCR0(bxInstruction_c *i, bx_address val) #endif } +#if BX_SUPPORT_X86_64 + BX_CPU_THIS_PTR linaddr_width = BX_CPU_THIS_PTR cr4.get_LA57() ? 57 : 48; +#endif + return true; } @@ -1177,7 +1181,7 @@ Bit32u BX_CPU_C::get_cr4_allow_mask(void) // [15] Reserved, Must be Zero // [14] SMXE: SMX Extensions R/W // [13] VMXE: VMX Extensions R/W - // [12] Reserved, Must be Zero + // [12] LA57, 57-bit Linear Address and 5-level paging // [11] UMIP: User Mode Instruction Prevention R/W // [10] OSXMMEXCPT: Operating System Unmasked Exception Support R/W // [9] OSFXSR: Operating System FXSAVE/FXRSTOR Support R/W @@ -1260,6 +1264,11 @@ Bit32u BX_CPU_C::get_cr4_allow_mask(void) if (is_cpu_extension_supported(BX_ISA_UMIP)) allowMask |= BX_CR4_UMIP_MASK; +#if BX_SUPPORT_X86_64 + if (is_cpu_extension_supported(BX_ISA_LA57)) + allowMask |= BX_CR4_LA57_MASK; +#endif + #if BX_SUPPORT_CET if (is_cpu_extension_supported(BX_ISA_CET)) allowMask |= BX_CR4_CET_MASK; @@ -1299,6 +1308,11 @@ bool BX_CPP_AttrRegparmN(1) BX_CPU_C::check_CR4(bx_address cr4_val) BX_ERROR(("check_CR4(): attempt to clear CR4.PAE when EFER.LMA=1")); return false; } + + if(! temp_cr4.get_LA57()) { + BX_ERROR(("check_CR4(): attempt to clear CR4.LA57 when EFER.LMA=1")); + return false; + } } else { if (temp_cr4.get_PCIDE()) { @@ -1388,6 +1402,10 @@ bool BX_CPU_C::SetCR4(bxInstruction_c *i, bx_address val) set_PKeys(BX_CPU_THIS_PTR pkru, BX_CPU_THIS_PTR pkrs); #endif +#if BX_SUPPORT_X86_64 + BX_CPU_THIS_PTR linaddr_width = BX_CPU_THIS_PTR cr4.get_LA57() ? 57 : 48; +#endif + return true; } #endif // BX_CPU_LEVEL >= 5 diff --git a/bochs/cpu/crregs.h b/bochs/cpu/crregs.h index b11a354fc..493a3096a 100644 --- a/bochs/cpu/crregs.h +++ b/bochs/cpu/crregs.h @@ -153,7 +153,7 @@ struct bx_cr4_t { BX_CPP_INLINE void set32(Bit32u val) { val32 = val; } }; -const Bit32u BX_CR4_FLUSH_TLB_MASK = (BX_CR4_PSE_MASK | BX_CR4_PAE_MASK | BX_CR4_PGE_MASK | BX_CR4_PCIDE_MASK | BX_CR4_SMEP_MASK | BX_CR4_SMAP_MASK | BX_CR4_PKE_MASK | BX_CR4_CET_MASK | BX_CR4_PKS_MASK | BX_CR4_LASS_MASK); +const Bit32u BX_CR4_FLUSH_TLB_MASK = (BX_CR4_PSE_MASK | BX_CR4_PAE_MASK | BX_CR4_PGE_MASK | BX_CR4_LA57_MASK | BX_CR4_PCIDE_MASK | BX_CR4_SMEP_MASK | BX_CR4_SMAP_MASK | BX_CR4_PKE_MASK | BX_CR4_CET_MASK | BX_CR4_PKS_MASK | BX_CR4_LASS_MASK); #endif // #if BX_CPU_LEVEL >= 5 @@ -398,7 +398,7 @@ typedef struct msr { switch(type) { #if BX_SUPPORT_X86_64 case BX_LIN_ADDRESS_MSR: - if (! IsCanonical(new_val)) return 0; + if (! IsCanonical48(new_val)) return 0; break; #endif case BX_PHY_ADDRESS_MSR: diff --git a/bochs/cpu/decoder/features.h b/bochs/cpu/decoder/features.h index aded10a9b..72c746c2c 100644 --- a/bochs/cpu/decoder/features.h +++ b/bochs/cpu/decoder/features.h @@ -140,6 +140,7 @@ x86_feature(BX_ISA_WRMSRNS, "wrmsrns") /* Non-S x86_feature(BX_ISA_CMPCCXADD, "cmpccxadd") /* CMPccXADD instructions */ x86_feature(BX_ISA_SERIALIZE, "serialize") /* SERIALIZE instruction */ x86_feature(BX_ISA_LASS, "lass") /* Linear Address Space Separation support */ +x86_feature(BX_ISA_LA57, "la57") /* 57-bit Virtual Address and 5-level paging support */ x86_feature(BX_ISA_UINTR, "uintr") /* User Level Interrupts support */ x86_feature(BX_ISA_MOVDIRI, "movdiri") /* MOVDIRI instruction support */ x86_feature(BX_ISA_MOVDIR64B, "movdir64b") /* MOVDIR64B instruction support */ diff --git a/bochs/cpu/init.cc b/bochs/cpu/init.cc index 9a6882251..c58b46178 100644 --- a/bochs/cpu/init.cc +++ b/bochs/cpu/init.cc @@ -688,6 +688,10 @@ void BX_CPU_C::after_restore_state(void) set_PKeys(BX_CPU_THIS_PTR pkru, BX_CPU_THIS_PTR pkrs); #endif +#if BX_SUPPORT_X86_64 + BX_CPU_THIS_PTR linaddr_width = BX_CPU_THIS_PTR cr4.get_LA57() ? 57 : 48; +#endif + handleCpuContextChange(); assert_checks(); @@ -895,6 +899,9 @@ void BX_CPU_C::reset(unsigned source) #if BX_CPU_LEVEL >= 5 BX_CPU_THIS_PTR cr4.set32(0); BX_CPU_THIS_PTR cr4_suppmask = get_cr4_allow_mask(); +#if BX_SUPPORT_X86_64 + BX_CPU_THIS_PTR linaddr_width = 48; +#endif #endif #if BX_CPU_LEVEL >= 6 diff --git a/bochs/cpu/paging.cc b/bochs/cpu/paging.cc index 1a5f0a055..2388f1ac3 100644 --- a/bochs/cpu/paging.cc +++ b/bochs/cpu/paging.cc @@ -533,13 +533,14 @@ void BX_CPU_C::page_fault(unsigned fault, bx_address laddr, unsigned user, unsig } enum { + BX_LEVEL_PML5 = 4, BX_LEVEL_PML4 = 3, BX_LEVEL_PDPTE = 2, BX_LEVEL_PDE = 1, BX_LEVEL_PTE = 0 }; -static const char *bx_paging_level[4] = { "PTE", "PDE", "PDPE", "PML4" }; // keep it 4 letters +static const char *bx_paging_level[5] = { "PTE", "PDE", "PDPE", "PML4", "PML5" }; // keep it 4 letters // combined_access legend: // ----------------------- @@ -697,9 +698,8 @@ bx_phy_address BX_CPU_C::translate_linear_long_mode(bx_address laddr, Bit32u &lp BxMemtype entry_memtype[4] = { 0 }; bool nx_fault = false; - int leaf; - Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff); + Bit64u offset_mask = ((BX_CONST64(1) << BX_CPU_THIS_PTR linaddr_width) - 1); lpf_mask = 0xfff; Bit32u combined_access = (BX_COMBINED_ACCESS_WRITE | BX_COMBINED_ACCESS_USER); Bit64u curr_entry = BX_CPU_THIS_PTR cr3; @@ -708,7 +708,9 @@ bx_phy_address BX_CPU_C::translate_linear_long_mode(bx_address laddr, Bit32u &lp if (! BX_CPU_THIS_PTR efer.get_NXE()) reserved |= PAGE_DIRECTORY_NX_BIT; - for (leaf = BX_LEVEL_PML4;; --leaf) { + int start_leaf = BX_CPU_THIS_PTR cr4.get_LA57() ? BX_LEVEL_PML5 : BX_LEVEL_PML4, leaf = start_leaf; + + for (;; --leaf) { entry_addr[leaf] = ppf + ((laddr >> (9 + 9*leaf)) & 0xff8); #if BX_SUPPORT_VMX >= 2 if (BX_CPU_THIS_PTR in_vmx_guest) { @@ -854,7 +856,7 @@ bx_phy_address BX_CPU_C::translate_linear_long_mode(bx_address laddr, Bit32u &lp #endif // Update A/D bits if needed - update_access_dirty_PAE(entry_addr, entry, entry_memtype, BX_LEVEL_PML4, leaf, isWrite); + update_access_dirty_PAE(entry_addr, entry, entry_memtype, start_leaf, leaf, isWrite); return (ppf | combined_access); } @@ -1654,19 +1656,20 @@ bx_phy_address BX_CPU_C::nested_walk_long_mode(bx_phy_address guest_paddr, unsig Bit64u entry[4]; BxMemtype entry_memtype[4] = { BX_MEMTYPE_INVALID }; bool nx_fault = false; - int leaf; SVM_CONTROLS *ctrls = &BX_CPU_THIS_PTR vmcb.ctrls; SVM_HOST_STATE *host_state = &BX_CPU_THIS_PTR vmcb.host_state; bx_phy_address ppf = ctrls->ncr3 & BX_CR3_PAGING_MASK; - Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff); + Bit64u offset_mask = ((BX_CONST64(1) << BX_CPU_THIS_PTR linaddr_width) - 1); unsigned combined_access = BX_COMBINED_ACCESS_WRITE | BX_COMBINED_ACCESS_USER; Bit64u reserved = PAGING_PAE_RESERVED_BITS; if (! host_state->efer.get_NXE()) reserved |= PAGE_DIRECTORY_NX_BIT; - for (leaf = BX_LEVEL_PML4;; --leaf) { + int start_leaf = BX_CPU_THIS_PTR cr4.get_LA57() ? BX_LEVEL_PML5 : BX_LEVEL_PML4, leaf = start_leaf; + + for (;; --leaf) { entry_addr[leaf] = ppf + ((guest_paddr >> (9 + 9*leaf)) & 0xff8); entry[leaf] = read_physical_qword(entry_addr[leaf], BX_MEMTYPE_INVALID, AccessReason(BX_PTE_ACCESS + leaf)); offset_mask >>= 9; @@ -1705,7 +1708,7 @@ bx_phy_address BX_CPU_C::nested_walk_long_mode(bx_phy_address guest_paddr, unsig nested_page_fault(ERROR_PROTECTION, guest_paddr, rw, is_page_walk); // Update A/D bits if needed - update_access_dirty_PAE(entry_addr, entry, entry_memtype, BX_LEVEL_PML4, leaf, isWrite); + update_access_dirty_PAE(entry_addr, entry, entry_memtype, start_leaf, leaf, isWrite); // Make up the physical page frame address return ppf | (bx_phy_address)(guest_paddr & offset_mask); @@ -2268,7 +2271,7 @@ bool BX_CPU_C::dbg_translate_guest_physical_ept(bx_phy_address guest_paddr, bx_p bx_phy_address pt_address = LPFOf(vm->eptptr); Bit64u offset_mask = BX_CONST64(0x0000ffffffffffff); - for (int level = 3; level >= 0; --level) { + for (int level = BX_LEVEL_PML4; level >= 0; --level) { Bit64u pte; pt_address += ((guest_paddr >> (9 + 9*level)) & 0xff8); offset_mask >>= 9; @@ -2335,9 +2338,8 @@ bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy, bx_ad #if BX_CPU_LEVEL >= 6 if (BX_CPU_THIS_PTR cr4.get_PAE()) { - offset_mask = BX_CONST64(0x0000ffffffffffff); - - int level = 3; + int level = BX_CPU_THIS_PTR cr4.get_LA57() ? BX_LEVEL_PML5 : BX_LEVEL_PML4; + offset_mask = ((BX_CONST64(1) << BX_CPU_THIS_PTR linaddr_width) - 1); if (! long_mode()) { pt_address = BX_CPU_THIS_PTR PDPTR_CACHE.entry[(laddr >> 30) & 3]; if (! (pt_address & 0x1)) { @@ -2346,7 +2348,7 @@ bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy, bx_ad } offset_mask >>= 18; pt_address &= BX_CONST64(0x000ffffffffff000); - level = 1; + level = BX_LEVEL_PDE; } for (; level >= 0; --level) { @@ -2394,7 +2396,7 @@ bool BX_CPU_C::dbg_xlate_linear2phy(bx_address laddr, bx_phy_address *phy, bx_ad #endif { offset_mask = 0xfff; - for (int level = 1; level >= 0; --level) { + for (int level = BX_LEVEL_PDE; level >= 0; --level) { Bit32u pte; pt_address += ((laddr >> (10 + 10*level)) & 0xffc); #if BX_SUPPORT_VMX >= 2