Skip to content

Commit

Permalink
implemented WAITPKG instruction set
Browse files Browse the repository at this point in the history
still missing : UMWAIT/TPAUSE should set CF flag if it was using OS deadline and woken up after deadline (i.e. not from monitored store)
also not clear in teh spec: should UWAITX/TPAUSE always wait until deadline due to 'while(tsc<deadline)' statement ?
also include small fixes for AMD's MONITORX/MWAITX
  • Loading branch information
Stanislav Shwartsman committed Nov 25, 2023
1 parent c1c391a commit 9715b24
Show file tree
Hide file tree
Showing 20 changed files with 306 additions and 28 deletions.
4 changes: 2 additions & 2 deletions bochs/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Brief summary :
! Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest
! Implemented Linear Address Separation (LASS) extension
! Implemented recently published Intel instruction sets:
- MOVDIRI, AVX512 BF16, AVX IFMA52, VNNI-INT8, VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, SERIALIZE
- MOVDIRI, AVX512 BF16, AVX IFMA52, VNNI-INT8, VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, 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.
Expand All @@ -30,7 +30,7 @@ Detailed change log :
- Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest
- Implemented Linear Address Separation (LASS) extension
- Implemented recently published Intel instruction sets:
- MOVDIRI, AVX512 BF16, AVX IFMA52, VNNI-INT8, VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, SERIALIZE
- MOVDIRI, AVX512 BF16, AVX IFMA52, VNNI-INT8, VNNI-INT16, AVX-NE-CONVERT, CMPCCXADD, SM3, SM4, SHA512, WRMSRNS, WAITPKG, SERIALIZE

- Bochs Debugger and Instrumentation
- Updated Bochs instrumentation examples for new disassembler introduced in Bochs 2.7 release.
Expand Down
8 changes: 5 additions & 3 deletions bochs/cpu/apic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1202,9 +1202,11 @@ void bx_local_apic_c::vmx_preemption_timer_expired(void *this_ptr)
void bx_local_apic_c::set_mwaitx_timer(Bit64u value)
{
if (mwaitx_timer_active) deactivate_mwaitx_timer();
BX_DEBUG(("MWAITX timer: value = %u", value));
bx_pc_system.activate_timer_ticks(mwaitx_timer_handle, value, 0);
mwaitx_timer_active = true;
if (value) {
BX_DEBUG(("MWAITX timer: delay value = " FMT_LL "u", value));
bx_pc_system.activate_timer_ticks(mwaitx_timer_handle, value, 0);
mwaitx_timer_active = true;
}
}

void bx_local_apic_c::deactivate_mwaitx_timer(void)
Expand Down
41 changes: 36 additions & 5 deletions bochs/cpu/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,10 @@ typedef struct
Bit64u ia32_interrupt_ssp_table;
#endif

#if BX_SUPPORT_MONITOR_MWAIT
Bit32u ia32_umwait_ctrl;
#endif

Bit32u ia32_spec_ctrl; // SCA

/* TODO finish of the others */
Expand Down Expand Up @@ -783,21 +787,43 @@ typedef void (*simd_xmm_3op)(BxPackedXmmRegister *opdst, const BxPackedXmmRegist
#include "svm.h"
#endif

enum monitor_armed_by {
BX_MONITOR_NOT_ARMED = 0,
BX_MONITOR_ARMED_BY_MONITOR,
BX_MONITOR_ARMED_BY_MONITORX,
BX_MONITOR_ARMED_BY_UMONITOR
};

#if BX_SUPPORT_MONITOR_MWAIT
struct monitor_addr_t {

bx_phy_address monitor_addr;
bool armed;
unsigned armed_by;

monitor_addr_t(): monitor_addr(0xffffffff), armed(false) {}
monitor_addr_t(): monitor_addr(0xffffffff), armed_by(BX_MONITOR_NOT_ARMED) {}

BX_CPP_INLINE void arm(bx_phy_address addr) {
BX_CPP_INLINE void arm(bx_phy_address addr, monitor_armed_by by) {
// align to cache line
monitor_addr = addr & ~((bx_phy_address)(CACHE_LINE_SIZE - 1));
armed = true;
armed_by = by;
}

BX_CPP_INLINE void reset_monitor(void) { armed_by = BX_MONITOR_NOT_ARMED; }

BX_CPP_INLINE void reset_umonitor(void) {
if (armed_by == BX_MONITOR_ARMED_BY_UMONITOR)
armed_by = BX_MONITOR_NOT_ARMED;
}

BX_CPP_INLINE void reset_monitorx(void) {
if (armed_by == BX_MONITOR_ARMED_BY_MONITORX)
armed_by = BX_MONITOR_NOT_ARMED;
}

BX_CPP_INLINE void reset_monitor(void) { armed = false; }
BX_CPP_INLINE bool armed(void) const { return armed_by != BX_MONITOR_NOT_ARMED; }
BX_CPP_INLINE bool armed_by_monitor(void) const { return armed_by == BX_MONITOR_ARMED_BY_MONITOR; }
BX_CPP_INLINE bool armed_by_monitorx(void) const { return armed_by == BX_MONITOR_ARMED_BY_MONITORX; }
BX_CPP_INLINE bool armed_by_umonitor(void) const { return armed_by == BX_MONITOR_ARMED_BY_UMONITOR; }
};
#endif

Expand Down Expand Up @@ -4044,6 +4070,8 @@ class BOCHSAPI BX_CPU_C : public logfunctions {

BX_SMF void MONITOR(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
BX_SMF void MWAIT(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
BX_SMF void UMONITOR_Eq(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
BX_SMF void UMWAIT_Ed(bxInstruction_c *) BX_CPP_AttrRegparmN(1);

#if BX_SUPPORT_PKEYS
BX_SMF void RDPKRU(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
Expand Down Expand Up @@ -4680,6 +4708,9 @@ class BOCHSAPI BX_CPU_C : public logfunctions {
BX_SMF Bit64u get_TSC();
BX_SMF void set_TSC(Bit64u tsc);
BX_SMF Bit64u get_Virtual_TSC(); // takes into account VMX or SVM adjustments
#if BX_SUPPORT_VMX
BX_SMF Bit64u compute_physical_TSC_delay(Bit64u virtual_tsc_delay);
#endif
#endif

#if BX_SUPPORT_PKEYS
Expand Down
7 changes: 6 additions & 1 deletion bochs/cpu/cpuid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,12 @@ Bit32u bx_cpuid_t::get_std_cpuid_leaf_7_ecx(Bit32u extra) const
}
#endif

// [5:5] WAITPKG (TPAUSE/UMONITOR/UMWAIT) support - not supported
// [5:5] WAITPKG (TPAUSE/UMONITOR/UMWAIT) support
#if BX_SUPPORT_MONITOR_MWAIT
if (is_cpu_extension_supported(BX_ISA_WAITPKG)) {
ecx |= BX_CPUID_STD7_SUBLEAF0_ECX_WAITPKG;
}
#endif

// [6:6] AVX512 VBMI2 instructions support
#if BX_SUPPORT_EVEX
Expand Down
4 changes: 4 additions & 0 deletions bochs/cpu/ctrl_xfer16.cc
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET16(bxInstruction_c *i)
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif

#if BX_SUPPORT_MONITOR_MWAIT
BX_CPU_THIS_PTR monitor.reset_umonitor();
#endif

RSP_SPECULATIVE;

if (protected_mode()) {
Expand Down
4 changes: 4 additions & 0 deletions bochs/cpu/ctrl_xfer32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET32(bxInstruction_c *i)
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif

#if BX_SUPPORT_MONITOR_MWAIT
BX_CPU_THIS_PTR monitor.reset_umonitor();
#endif

RSP_SPECULATIVE;

if (protected_mode()) {
Expand Down
4 changes: 4 additions & 0 deletions bochs/cpu/ctrl_xfer64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,10 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET64(bxInstruction_c *i)
BX_CPU_THIS_PTR show_flag |= Flag_iret;
#endif

#if BX_SUPPORT_MONITOR_MWAIT
BX_CPU_THIS_PTR monitor.reset_umonitor();
#endif

BX_ASSERT(long_mode());

RSP_SPECULATIVE;
Expand Down
4 changes: 4 additions & 0 deletions bochs/cpu/ctrl_xfer_pro.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ BX_CPU_C::load_cs(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cp

void BX_CPU_C::branch_far(bx_selector_t *selector, bx_descriptor_t *descriptor, bx_address rip, unsigned cpl)
{
#if BX_SUPPORT_MONITOR_MWAIT
BX_CPU_THIS_PTR monitor.reset_monitorx(); // reset MONITORX after every far control transfer
#endif

#if BX_SUPPORT_X86_64
if (long_mode() && descriptor->u.segment.l) {
if (! IsCanonical(rip)) {
Expand Down
2 changes: 1 addition & 1 deletion bochs/cpu/decoder/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ x86_feature(BX_ISA_SSE4_1, "sse4_1") /* SSE4_
x86_feature(BX_ISA_SSE4_2, "sse4_2") /* SSE4_2 instruction */
x86_feature(BX_ISA_POPCNT, "popcnt") /* POPCNT instruction */
x86_feature(BX_ISA_MONITOR_MWAIT, "mwait") /* MONITOR/MWAIT instruction */
x86_feature(BX_ISA_MONITORX_MWAITX, "mwaitx") /* MONITORX/MWAITX instruction (AMD) */
x86_feature(BX_ISA_WAITPKG, "waitpkg") /* TPAUSE/UMONITOR/UMWAIT instructions */
x86_feature(BX_ISA_MONITORX_MWAITX, "mwaitx") /* MONITORX/MWAITX instruction (AMD) */
x86_feature(BX_ISA_VMX, "vmx") /* VMX instruction */
x86_feature(BX_ISA_SMX, "smx") /* SMX instruction */
x86_feature(BX_ISA_LONG_MODE, "longmode") /* Long Mode (x86-64) support */
Expand Down
7 changes: 7 additions & 0 deletions bochs/cpu/decoder/fetchdecode_opmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -2601,6 +2601,13 @@ static const Bit64u BxOpcodeTable0FAE[] = {
form_opcode(ATTR_NNN6 | ATTR_MODC0 | ATTR_SSE_NO_PREFIX, BX_IA_MFENCE),
form_opcode(ATTR_NNN7 | ATTR_MODC0 | ATTR_SSE_NO_PREFIX, BX_IA_SFENCE),

form_opcode(ATTR_NNN6 | ATTR_MODC0 | ATTR_SSE_PREFIX_66, BX_IA_TPAUSE_Ed),
form_opcode(ATTR_NNN6 | ATTR_MODC0 | ATTR_SSE_PREFIX_F2, BX_IA_UMWAIT_Ed),
#if BX_SUPPORT_X86_64
form_opcode(ATTR_NNN6 | ATTR_MODC0 | ATTR_SSE_PREFIX_F3 | ATTR_OS64, BX_IA_UMONITOR_Eq),
#endif
form_opcode(ATTR_NNN6 | ATTR_MODC0 | ATTR_SSE_PREFIX_F3, BX_IA_UMONITOR_Ed),

form_opcode(ATTR_NNN0 | ATTR_MOD_MEM | ATTR_SSE_NO_PREFIX, BX_IA_FXSAVE),
form_opcode(ATTR_NNN1 | ATTR_MOD_MEM | ATTR_SSE_NO_PREFIX, BX_IA_FXRSTOR),
form_opcode(ATTR_NNN2 | ATTR_MOD_MEM | ATTR_SSE_NO_PREFIX, BX_IA_LDMXCSR),
Expand Down
7 changes: 7 additions & 0 deletions bochs/cpu/decoder/ia_opcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,13 @@ bx_define_opcode(BX_IA_SYSEXIT, "sysexit", "sysexit", NULL, &BX_CPU_C::SYSEXIT,
bx_define_opcode(BX_IA_MONITOR, "monitor", "monitor", &BX_CPU_C::BxError, &BX_CPU_C::MONITOR, BX_ISA_MONITOR_MWAIT, OP_NONE, OP_NONE, OP_NONE, OP_NONE, 0)
bx_define_opcode(BX_IA_MWAIT, "mwait", "mwait", &BX_CPU_C::BxError, &BX_CPU_C::MWAIT, BX_ISA_MONITOR_MWAIT, OP_NONE, OP_NONE, OP_NONE, OP_NONE, BX_TRACE_END)

#if BX_SUPPORT_X86_64
bx_define_opcode(BX_IA_UMONITOR_Eq, "umonitor", "umonitor", &BX_CPU_C::BxError, &BX_CPU_C::UMONITOR_Eq, BX_ISA_WAITPKG, OP_Eq, OP_NONE, OP_NONE, OP_NONE, 0)
#endif
bx_define_opcode(BX_IA_UMONITOR_Ed, "umonitor", "umonitor", &BX_CPU_C::BxError, &BX_CPU_C::UMONITOR_Eq, BX_ISA_WAITPKG, OP_Ed, OP_NONE, OP_NONE, OP_NONE, 0)
bx_define_opcode(BX_IA_UMWAIT_Ed, "umwait", "umwait", &BX_CPU_C::BxError, &BX_CPU_C::UMWAIT_Ed, BX_ISA_WAITPKG, OP_Ed, OP_NONE, OP_NONE, OP_NONE, BX_TRACE_END)
bx_define_opcode(BX_IA_TPAUSE_Ed, "tpause", "tpause", &BX_CPU_C::BxError, &BX_CPU_C::UMWAIT_Ed, BX_ISA_WAITPKG, OP_Ed, OP_NONE, OP_NONE, OP_NONE, BX_TRACE_END)

bx_define_opcode(BX_IA_MONITORX, "monitorx", "monitorx", &BX_CPU_C::BxError, &BX_CPU_C::MONITOR, BX_ISA_MONITORX_MWAITX, OP_NONE, OP_NONE, OP_NONE, OP_NONE, 0)
bx_define_opcode(BX_IA_MWAITX, "mwaitx", "mwaitx", &BX_CPU_C::BxError, &BX_CPU_C::MWAIT, BX_ISA_MONITORX_MWAITX, OP_NONE, OP_NONE, OP_NONE, OP_NONE, BX_TRACE_END)

Expand Down
11 changes: 10 additions & 1 deletion bochs/cpu/init.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ void BX_CPU_C::register_state(void)
#if BX_SUPPORT_VMX
BXRS_HEX_PARAM_FIELD(MSR, ia32_feature_ctrl, msr.ia32_feature_ctrl);
#endif
#if BX_SUPPORT_MONITOR_MWAIT
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_WAITPKG)) {
BXRS_HEX_PARAM_FIELD(MSR, ia32_umwait_ctrl, msr.ia32_umwait_ctrl);
}
#endif

#if BX_CONFIGURE_MSRS
bx_list_c *MSRS = new bx_list_c(cpu, "USER_MSR");
Expand Down Expand Up @@ -488,7 +493,7 @@ void BX_CPU_C::register_state(void)
#if BX_SUPPORT_MONITOR_MWAIT
bx_list_c *monitor_list = new bx_list_c(cpu, "MONITOR");
BXRS_HEX_PARAM_FIELD(monitor_list, monitor_addr, monitor.monitor_addr);
BXRS_PARAM_BOOL(monitor_list, armed, monitor.armed);
BXRS_DEC_PARAM_FIELD(monitor_list, armed, monitor.armed_by);
#endif

#if BX_SUPPORT_APIC
Expand Down Expand Up @@ -886,6 +891,10 @@ void BX_CPU_C::reset(unsigned source)

BX_CPU_THIS_PTR msr.ia32_xss = 0;

#if BX_SUPPORT_MONITOR_MWAIT
BX_CPU_THIS_PTR msr.ia32_umwait_ctrl = 0;
#endif

#if BX_SUPPORT_CET
BX_CPU_THIS_PTR msr.ia32_interrupt_ssp_table = 0;
BX_CPU_THIS_PTR msr.ia32_cet_control[0] = BX_CPU_THIS_PTR msr.ia32_cet_control[1] = 0;
Expand Down
20 changes: 20 additions & 0 deletions bochs/cpu/msr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr)
val64 = BX_CPU_THIS_PTR tsc_adjust;
break;

#if BX_SUPPORT_MONITOR_MWAIT
case BX_MSR_IA32_UMWAIT_CONTROL:
if (! is_cpu_extension_supported(BX_ISA_WAITPKG)) {
BX_ERROR(("RDMSR BX_MSR_IA32_UMWAIT_CONTROL: WAITPKG is not enabled in the cpu model"));
return handle_unknown_rdmsr(index, msr);
}
val64 = BX_CPU_THIS_PTR msr.ia32_umwait_ctrl;
break;
#endif

#if BX_SUPPORT_APIC
case BX_MSR_APICBASE:
val64 = BX_CPU_THIS_PTR msr.apicbase;
Expand Down Expand Up @@ -781,6 +791,16 @@ bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
BX_CPU_THIS_PTR tsc_adjust = (Bit64s) val_64;
break;

#if BX_SUPPORT_MONITOR_MWAIT
case BX_MSR_IA32_UMWAIT_CONTROL:
if (! is_cpu_extension_supported(BX_ISA_WAITPKG)) {
BX_ERROR(("WRMSR BX_MSR_IA32_UMWAIT_CONTROL: WAITPKG is not enabled in the cpu model"));
return handle_unknown_wrmsr(index, val_64);
}
BX_CPU_THIS_PTR msr.ia32_umwait_ctrl = val32_lo;
break;
#endif

#if BX_SUPPORT_APIC
case BX_MSR_APICBASE:
return relocate_apic(val_64);
Expand Down
3 changes: 2 additions & 1 deletion bochs/cpu/msr.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ enum MSR_Register {
BX_MSR_TSC = 0x010,
BX_MSR_APICBASE = 0x01b,
BX_MSR_TSC_ADJUST = 0x03b,
BX_MSR_TSC_DEADLINE = 0x6E0,
BX_MSR_TSC_DEADLINE = 0x6e0,

BX_MSR_IA32_SPEC_CTRL = 0x048,
BX_MSR_IA32_PRED_CMD = 0x049,
BX_MSR_IA32_UMWAIT_CONTROL = 0x0e1,
BX_MSR_IA32_ARCH_CAPABILITIES = 0x10a,
BX_MSR_IA32_FLUSH_CMD = 0x10b,

Expand Down
Loading

0 comments on commit 9715b24

Please sign in to comment.