Implemented VMX preemption timer VMEXIT control (patch by Jianan Hao)
This commit is contained in:
parent
4699840aaf
commit
909e750549
@ -12,6 +12,7 @@ Bochs repository moved to the SVN version control !
|
||||
When compiled in, AVX still has to be enabled using .bochsrc CPUID option.
|
||||
- Added emulation of AVX float16 convert instructions, the feature can be
|
||||
enabled using .bochsrc CPUID option.
|
||||
- Implemented VMX preemption timer VMEXIT control (patch by Jianan Hao)
|
||||
- Redefined/Updated/Fixed instrumentation callbacks.
|
||||
- Bugfixes for CPU emulation correctness and stability.
|
||||
|
||||
@ -65,6 +66,7 @@ Bochs repository moved to the SVN version control !
|
||||
from the "clock" setting)
|
||||
|
||||
- SF patches applied
|
||||
[3302668] VMX preemption timer by Jianan Hao
|
||||
[3327510] Fix wrong address translation in debugger by Jianan Hao
|
||||
[3323758] Ctrl-Break support for the Win32 gui by Nikolay Nikolov
|
||||
[3316785] Ctrl-Break support for the X11 gui by Nikolay Nikolov
|
||||
|
@ -184,8 +184,17 @@ bx_local_apic_c::bx_local_apic_c(BX_CPU_C *mycpu, unsigned id)
|
||||
|
||||
// Register a non-active timer for use when the timer is started.
|
||||
timer_handle = bx_pc_system.register_timer_ticks(this,
|
||||
BX_CPU(0)->lapic.periodic_smf, 0, 0, 0, "lapic");
|
||||
bx_local_apic_c::periodic_smf, 0, 0, 0, "lapic");
|
||||
timer_active = 0;
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
// Register a non-active timer for VMX preemption timer.
|
||||
vmx_timer_handle = bx_pc_system.register_timer_ticks(this,
|
||||
bx_local_apic_c::vmx_preemption_timer_expired, 0, 0, 0, "vmx_preemtion");
|
||||
BX_DEBUG(("vmx_timer is = %d", vmx_timer_handle));
|
||||
vmx_preemption_timer_rate = VMX_MISC_PREEMPTION_TIMER_RATE;
|
||||
vmx_timer_active = 0;
|
||||
#endif
|
||||
|
||||
xapic = simulate_xapic; // xAPIC or legacy APIC
|
||||
|
||||
@ -219,6 +228,13 @@ void bx_local_apic_c::reset(unsigned type)
|
||||
timer_active = 0;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if(vmx_timer_active) {
|
||||
bx_pc_system.deactivate_timer(vmx_timer_handle);
|
||||
vmx_timer_active = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
for(i=0; i<APIC_LVT_ENTRIES; i++) {
|
||||
lvt[i] = 0x10000; // all LVT are masked
|
||||
}
|
||||
@ -952,7 +968,7 @@ void bx_local_apic_c::set_divide_configuration(Bit32u value)
|
||||
|
||||
void bx_local_apic_c::set_initial_timer_count(Bit32u value)
|
||||
{
|
||||
// If active before, deactive the current timer before changing it.
|
||||
// If active before, deactivate the current timer before changing it.
|
||||
if(timer_active) {
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
timer_active = 0;
|
||||
@ -976,6 +992,43 @@ void bx_local_apic_c::set_initial_timer_count(Bit32u value)
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
Bit32u bx_local_apic_c::read_vmx_preemption_timer(void)
|
||||
{
|
||||
Bit32u diff = (bx_pc_system.time_ticks() >> vmx_preemption_timer_rate) - (vmx_preemption_timer_initial >> vmx_preemption_timer_rate);
|
||||
if (vmx_preemption_timer_value < diff)
|
||||
return 0;
|
||||
else
|
||||
return vmx_preemption_timer_value - diff;
|
||||
}
|
||||
|
||||
void bx_local_apic_c::set_vmx_preemption_timer(Bit32u value)
|
||||
{
|
||||
vmx_preemption_timer_value = value;
|
||||
vmx_preemption_timer_initial = bx_pc_system.time_ticks();
|
||||
vmx_preemption_timer_fire = ((vmx_preemption_timer_initial >> vmx_preemption_timer_rate) + value) << vmx_preemption_timer_rate;
|
||||
BX_DEBUG(("VMX Preemption timer. value = %u, rate = %u, init = %u, fire = %u", value, vmx_preemption_timer_rate, vmx_preemption_timer_initial, vmx_preemption_timer_fire));
|
||||
bx_pc_system.activate_timer_ticks(vmx_timer_handle, vmx_preemption_timer_fire - vmx_preemption_timer_initial, 0);
|
||||
vmx_timer_active = 1;
|
||||
}
|
||||
|
||||
void bx_local_apic_c::deactivate_vmx_preemption_timer(void)
|
||||
{
|
||||
if (! vmx_timer_active) return;
|
||||
bx_pc_system.deactivate_timer(vmx_timer_handle);
|
||||
vmx_timer_active = 0;
|
||||
}
|
||||
|
||||
// Invoked when VMX preemption timer expired
|
||||
void bx_local_apic_c::vmx_preemption_timer_expired(void *this_ptr)
|
||||
{
|
||||
bx_local_apic_c *class_ptr = (bx_local_apic_c *) this_ptr;
|
||||
class_ptr->cpu->pending_vmx_timer_expired = 1;
|
||||
class_ptr->cpu->async_event = 1;
|
||||
class_ptr->deactivate_vmx_preemption_timer();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
// return false when x2apic is not supported/not readable
|
||||
bx_bool bx_local_apic_c::read_x2apic(unsigned index, Bit64u *val_64)
|
||||
@ -1142,7 +1195,7 @@ void bx_local_apic_c::register_state(bx_param_c *parent)
|
||||
unsigned i;
|
||||
char name[6];
|
||||
|
||||
bx_list_c *lapic = new bx_list_c(parent, "local_apic", 25);
|
||||
bx_list_c *lapic = new bx_list_c(parent, "local_apic", 31);
|
||||
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, base_addr);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, apic_id);
|
||||
@ -1183,6 +1236,15 @@ void bx_local_apic_c::register_state(bx_param_c *parent)
|
||||
BXRS_PARAM_BOOL(lapic, timer_active, timer_active);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, ticksInitial);
|
||||
BXRS_PARAM_BOOL(lapic, INTR, INTR);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BXRS_DEC_PARAM_SIMPLE(lapic, vmx_timer_handle);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_initial);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_fire);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_value);
|
||||
BXRS_HEX_PARAM_SIMPLE(lapic, vmx_preemption_timer_rate);
|
||||
BXRS_PARAM_BOOL(lapic, vmx_timer_active, vmx_timer_active);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_APIC */
|
||||
|
@ -113,6 +113,15 @@ class BOCHSAPI bx_local_apic_c : public logfunctions
|
||||
#define APIC_DM_SIPI 6
|
||||
#define APIC_DM_EXTINT 7
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
int vmx_timer_handle;
|
||||
Bit32u vmx_preemption_timer_value;
|
||||
Bit64u vmx_preemption_timer_initial; //The value of system tick when set the timer (absolute value)
|
||||
Bit64u vmx_preemption_timer_fire; //The value of system tick when fire the exception (absolute value)
|
||||
Bit32u vmx_preemption_timer_rate; //rate stated in MSR_VMX_MISC
|
||||
bx_bool vmx_timer_active;
|
||||
#endif
|
||||
|
||||
BX_CPU_C *cpu;
|
||||
|
||||
public:
|
||||
@ -158,6 +167,12 @@ public:
|
||||
void set_initial_timer_count(Bit32u value);
|
||||
void startup_msg(Bit8u vector);
|
||||
void register_state(bx_param_c *parent);
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
Bit32u read_vmx_preemption_timer(void);
|
||||
void set_vmx_preemption_timer(Bit32u value);
|
||||
void deactivate_vmx_preemption_timer(void);
|
||||
static void vmx_preemption_timer_expired(void *);
|
||||
#endif
|
||||
};
|
||||
|
||||
int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast);
|
||||
|
@ -421,8 +421,10 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
|
||||
// an interrupt wakes up the CPU.
|
||||
while (1)
|
||||
{
|
||||
if ((BX_CPU_INTR && (BX_CPU_THIS_PTR get_IF() ||
|
||||
(BX_CPU_THIS_PTR activity_state == BX_ACTIVITY_STATE_MWAIT_IF))) ||
|
||||
if ((BX_CPU_INTR && (BX_CPU_THIS_PTR get_IF() || BX_CPU_THIS_PTR activity_state == BX_ACTIVITY_STATE_MWAIT_IF)) ||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired ||
|
||||
#endif
|
||||
BX_CPU_THIS_PTR pending_NMI || BX_CPU_THIS_PTR pending_SMI || BX_CPU_THIS_PTR pending_INIT)
|
||||
{
|
||||
// interrupt ends the HALT condition
|
||||
@ -521,6 +523,16 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
|
||||
if (BX_CPU_THIS_PTR debug_trap)
|
||||
exception(BX_DB_EXCEPTION, 0); // no error, not interrupt
|
||||
}
|
||||
|
||||
// Priority 4.5: VMX Preemption Timer Expired. FIXME: is it a kind of external interrupt?
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
||||
if (BX_CPU_THIS_PTR pending_vmx_timer_expired) {
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired = 0;
|
||||
VMexit_PreemptionTimerExpired();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Priority 5: External Interrupts
|
||||
// NMI Interrupts
|
||||
@ -637,6 +649,9 @@ unsigned BX_CPU_C::handleAsyncEvent(void)
|
||||
#if BX_SUPPORT_VMX
|
||||
|| BX_CPU_THIS_PTR vmx_interrupt_window || BX_CPU_THIS_PTR inhibit_mask
|
||||
#endif
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
|| BX_CPU_THIS_PTR pending_vmx_timer_expired
|
||||
#endif
|
||||
#if BX_X86_DEBUGGER
|
||||
// a debug code breakpoint is set in current page
|
||||
|| BX_CPU_THIS_PTR codebp
|
||||
|
@ -980,6 +980,9 @@ public: // for now...
|
||||
bx_bool in_smm_vmx; // save in_vmx and in_vmx_guest flags when in SMM mode
|
||||
bx_bool in_smm_vmx_guest;
|
||||
bx_bool vmx_interrupt_window;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
bx_bool pending_vmx_timer_expired;
|
||||
#endif
|
||||
Bit64u vmcsptr;
|
||||
bx_hostpageaddr_t vmcshostptr;
|
||||
Bit64u vmxonptr;
|
||||
@ -3673,6 +3676,7 @@ public: // for now...
|
||||
BX_SMF void VMexit_RDPMC(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BX_SMF void VMexit_WBINVD(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
|
||||
BX_SMF void VMexit_PreemptionTimerExpired(void);
|
||||
#endif
|
||||
BX_SMF bx_bool VMexit_CLTS(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
|
||||
BX_SMF void VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr) BX_CPP_AttrRegparmN(3);
|
||||
|
@ -30,6 +30,38 @@
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
#undef BX_INSTRUMENTATION
|
||||
#define BX_INSTRUMENTATION 1
|
||||
|
||||
void update_branch_stats(Bit32s offset, bx_bool taken)
|
||||
{
|
||||
static Bit32u counts = 0;
|
||||
static Bit32u taken_pos = 0, taken_neg = 0;
|
||||
static Bit32u not_taken_pos = 0, not_taken_neg = 0;
|
||||
|
||||
counts++;
|
||||
|
||||
if (offset < 0) {
|
||||
if (taken) taken_neg++;
|
||||
else not_taken_neg++;
|
||||
}
|
||||
else {
|
||||
if (taken) taken_pos++;
|
||||
else not_taken_pos++;
|
||||
}
|
||||
|
||||
if (counts > 10000000) {
|
||||
printf("======================\n");
|
||||
printf("negative: taken %f, not taken %f\n", taken_neg / 100000.0, not_taken_neg / 100000.0);
|
||||
printf("positive: taken %f, not taken %f\n", taken_pos / 100000.0, not_taken_pos / 100000.0);
|
||||
counts = 0;
|
||||
taken_neg = 0;
|
||||
not_taken_neg = 0;
|
||||
taken_pos = 0;
|
||||
not_taken_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near32(Bit32u new_EIP)
|
||||
@ -284,10 +316,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jd(bxInstruction_c *i)
|
||||
if (get_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -298,10 +332,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jd(bxInstruction_c *i)
|
||||
if (! get_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -312,10 +348,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jd(bxInstruction_c *i)
|
||||
if (get_CF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -326,10 +364,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jd(bxInstruction_c *i)
|
||||
if (! get_CF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -340,10 +380,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jd(bxInstruction_c *i)
|
||||
if (get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -354,10 +396,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jd(bxInstruction_c *i)
|
||||
if (! get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -368,10 +412,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jd(bxInstruction_c *i)
|
||||
if (get_CF() || get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -382,10 +428,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jd(bxInstruction_c *i)
|
||||
if (! (get_CF() || get_ZF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -396,10 +444,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jd(bxInstruction_c *i)
|
||||
if (get_SF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -410,10 +460,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jd(bxInstruction_c *i)
|
||||
if (! get_SF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -424,10 +476,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jd(bxInstruction_c *i)
|
||||
if (get_PF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -438,10 +492,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jd(bxInstruction_c *i)
|
||||
if (! get_PF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -452,10 +508,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jd(bxInstruction_c *i)
|
||||
if (getB_SF() != getB_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -466,10 +524,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jd(bxInstruction_c *i)
|
||||
if (getB_SF() == getB_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -480,10 +540,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jd(bxInstruction_c *i)
|
||||
if (get_ZF() || (getB_SF() != getB_OF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -494,10 +556,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jd(bxInstruction_c *i)
|
||||
if (! get_ZF() && (getB_SF() == getB_OF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -646,10 +710,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::JECXZ_Jb(bxInstruction_c *i)
|
||||
if (temp_ECX == 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -677,10 +743,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE32_Jb(bxInstruction_c *i)
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -694,10 +762,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE32_Jb(bxInstruction_c *i)
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -718,10 +788,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE32_Jb(bxInstruction_c *i)
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -735,10 +807,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE32_Jb(bxInstruction_c *i)
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -759,10 +833,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP32_Jb(bxInstruction_c *i)
|
||||
if (count != 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
@ -776,10 +852,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP32_Jb(bxInstruction_c *i)
|
||||
if (count != 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
update_branch_stats((Bit32s) i->Id(), 1);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
update_branch_stats((Bit32s) i->Id(), 0);
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
@ -1035,6 +1035,9 @@ void BX_CPU_C::reset(unsigned source)
|
||||
BX_CPU_THIS_PTR in_smm_vmx = BX_CPU_THIS_PTR in_smm_vmx_guest = 0;
|
||||
BX_CPU_THIS_PTR in_event = 0;
|
||||
BX_CPU_THIS_PTR vmx_interrupt_window = 0;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired = 0;
|
||||
#endif
|
||||
BX_CPU_THIS_PTR vmcsptr = BX_CPU_THIS_PTR vmxonptr = BX_INVALID_VMCSPTR;
|
||||
BX_CPU_THIS_PTR vmcshostptr = 0;
|
||||
/* enable VMX, should be done in BIOS instead */
|
||||
|
@ -175,6 +175,9 @@ bx_bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
|
||||
case VMCS_32BIT_GUEST_ACTIVITY_STATE:
|
||||
case VMCS_32BIT_GUEST_SMBASE:
|
||||
case VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR:
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
/* VMCS 32-bit host-state fields */
|
||||
|
@ -240,6 +240,18 @@ void BX_CPU_C::VMexit_ExtInterrupt(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
void BX_CPU_C::VMexit_PreemptionTimerExpired(void)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT)) {
|
||||
BX_DEBUG(("VMEXIT: VMX Preemption Timer Expired"));
|
||||
VMexit(0, VMX_VMEXIT_VMX_PREEMPTION_TIMER_EXPIRED, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPU_C::VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector, Bit16u errcode, bx_bool errcode_valid, Bit64u qualification)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
@ -222,6 +222,12 @@ void BX_CPU_C::VMabort(VMX_vmabort_code error_code)
|
||||
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcsptr + VMCS_VMX_ABORT_FIELD_ADDR;
|
||||
access_write_physical(pAddr, 4, &abort);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMCS_ACCESS | BX_WRITE, (Bit8u*)(&abort));
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
// Deactivate VMX preemtion timer
|
||||
BX_CPU_THIS_PTR lapic.deactivate_vmx_preemption_timer();
|
||||
#endif
|
||||
|
||||
shutdown();
|
||||
}
|
||||
|
||||
@ -470,6 +476,13 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if ((~vm->vmexec_ctrls1 & VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT) && (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)) {
|
||||
BX_ERROR(("VMFAIL: save_VMX_preemption_timer VMEXIT control is set but VMX_preemption_timer VMEXEC control is clear"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vm->vmexit_msr_store_cnt > 0) {
|
||||
vm->vmexit_msr_store_addr = VMread64(VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR);
|
||||
if ((vm->vmexit_msr_store_addr & 0xf) != 0 || ! IsValidPhyAddr(vm->vmexit_msr_store_addr)) {
|
||||
@ -1852,6 +1865,13 @@ void BX_CPU_C::VMexitSaveGuestState(void)
|
||||
|
||||
VMwrite32(VMCS_32BIT_CONTROL_VMENTRY_CONTROLS, vm->vmentry_ctrls);
|
||||
}
|
||||
|
||||
// Deactivate VMX preemtion timer
|
||||
BX_CPU_THIS_PTR lapic.deactivate_vmx_preemption_timer();
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired = 0;
|
||||
// Store back to VMCS
|
||||
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)
|
||||
VMwrite32(VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE, BX_CPU_THIS_PTR lapic.read_vmx_preemption_timer());
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2461,6 +2481,22 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMLAUNCH(bxInstruction_c *i)
|
||||
BX_CPU_THIS_PTR in_vmx_guest = 1;
|
||||
BX_CPU_THIS_PTR disable_INIT = 0;
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT)) {
|
||||
Bit32u timer_value = VMread32(VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE);
|
||||
if (timer_value == 0) {
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired = 1;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
else {
|
||||
// activate VMX preemption timer
|
||||
BX_INFO(("VMX preemption timer active"));
|
||||
BX_CPU_THIS_PTR pending_vmx_timer_expired = 0;
|
||||
BX_CPU_THIS_PTR lapic.set_vmx_preemption_timer(timer_value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// STEP 7: Inject events to the guest
|
||||
///////////////////////////////////////////////////////
|
||||
@ -2920,7 +2956,7 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::INVVPID(bxInstruction_c *i)
|
||||
void BX_CPU_C::register_vmx_state(bx_param_c *parent)
|
||||
{
|
||||
// register VMX state for save/restore param tree
|
||||
bx_list_c *vmx = new bx_list_c(parent, "VMX", 8);
|
||||
bx_list_c *vmx = new bx_list_c(parent, "VMX", 9);
|
||||
|
||||
BXRS_HEX_PARAM_FIELD(vmx, vmcsptr, BX_CPU_THIS_PTR vmcsptr);
|
||||
BXRS_HEX_PARAM_FIELD(vmx, vmxonptr, BX_CPU_THIS_PTR vmxonptr);
|
||||
@ -2929,6 +2965,9 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
|
||||
BXRS_PARAM_BOOL(vmx, in_smm_vmx, BX_CPU_THIS_PTR in_smm_vmx);
|
||||
BXRS_PARAM_BOOL(vmx, in_smm_vmx_guest, BX_CPU_THIS_PTR in_smm_vmx_guest);
|
||||
BXRS_PARAM_BOOL(vmx, vmx_interrupt_window, BX_CPU_THIS_PTR vmx_interrupt_window);
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BXRS_PARAM_BOOL(vmx, pending_vmx_timer_expired, BX_CPU_THIS_PTR pending_vmx_timer_expired);
|
||||
#endif
|
||||
|
||||
bx_list_c *vmcache = new bx_list_c(vmx, "VMCS_CACHE", 5);
|
||||
|
||||
|
@ -123,7 +123,7 @@ enum VMX_vmexit_reason {
|
||||
VMX_VMEXIT_EPT_MISCONFIGURATION = 49,
|
||||
VMX_VMEXIT_INVEPT = 50,
|
||||
VMX_VMEXIT_RDTSCP = 51,
|
||||
VMX_VMEXIT_VMX_PREEMTION_TIMER_FIRED = 52,
|
||||
VMX_VMEXIT_VMX_PREEMPTION_TIMER_EXPIRED = 52,
|
||||
VMX_VMEXIT_INVVPID = 53,
|
||||
VMX_VMEXIT_WBINVD = 54,
|
||||
VMX_VMEXIT_XSETBV = 55,
|
||||
@ -305,6 +305,7 @@ enum VMX_vmabort_code {
|
||||
#define VMCS_32BIT_GUEST_ACTIVITY_STATE 0x00004826
|
||||
#define VMCS_32BIT_GUEST_SMBASE 0x00004828
|
||||
#define VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR 0x0000482A
|
||||
#define VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE 0x0000482E
|
||||
|
||||
/* VMCS 32-bit host-state fields */
|
||||
/* binary 0100_11xx_xxxx_xxx0 */
|
||||
@ -368,7 +369,7 @@ enum VMX_vmabort_code {
|
||||
#define VMCS_HOST_RSP 0x00006C14
|
||||
#define VMCS_HOST_RIP 0x00006C16
|
||||
|
||||
#define VMX_HIGHEST_VMCS_ENCODING (0x2C)
|
||||
#define VMX_HIGHEST_VMCS_ENCODING (0x2F)
|
||||
|
||||
// ===============================
|
||||
// VMCS fields encoding/decoding
|
||||
@ -504,10 +505,10 @@ typedef struct bx_VMCS
|
||||
// VM-Execution Control Fields
|
||||
//
|
||||
|
||||
#define VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT (1 << 0)
|
||||
#define VMX_VM_EXEC_CTRL1_NMI_VMEXIT (1 << 3)
|
||||
#define VMX_VM_EXEC_CTRL1_VIRTUAL_NMI (1 << 5)
|
||||
#define VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER (1 << 6)
|
||||
#define VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT (1 << 0)
|
||||
#define VMX_VM_EXEC_CTRL1_NMI_VMEXIT (1 << 3)
|
||||
#define VMX_VM_EXEC_CTRL1_VIRTUAL_NMI (1 << 5)
|
||||
#define VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT (1 << 6)
|
||||
|
||||
#ifdef BX_VMX_ENABLE_ALL
|
||||
|
||||
@ -517,7 +518,8 @@ typedef struct bx_VMCS
|
||||
|
||||
#define VMX_VM_EXEC_CTRL1_SUPPORTED_BITS \
|
||||
(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT | \
|
||||
VMX_VM_EXEC_CTRL1_NMI_VMEXIT)
|
||||
VMX_VM_EXEC_CTRL1_NMI_VMEXIT | \
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VM_EXEC_CTRL1_VMX_PREEMPTION_TIMER_VMEXIT : 0))
|
||||
|
||||
#endif
|
||||
|
||||
@ -662,7 +664,8 @@ typedef struct bx_VMCS
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_STORE_PAT_MSR : 0) | \
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_LOAD_PAT_MSR : 0) | \
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_STORE_EFER_MSR : 0) | \
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_LOAD_EFER_MSR : 0))
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_LOAD_EFER_MSR : 0) | \
|
||||
((BX_SUPPORT_VMX >= 2) ? VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER : 0))
|
||||
|
||||
#endif
|
||||
|
||||
@ -930,8 +933,12 @@ enum VMX_Activity_State {
|
||||
#define VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL (0)
|
||||
#endif
|
||||
|
||||
//Rate to increase VMX preemtion timer
|
||||
#define VMX_MISC_PREEMPTION_TIMER_RATE (0)
|
||||
|
||||
#define VMX_MSR_MISC ((VMX_CR3_TARGET_MAX_CNT << 16) | \
|
||||
VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL)
|
||||
VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL | \
|
||||
VMX_MISC_PREEMPTION_TIMER_RATE)
|
||||
|
||||
//
|
||||
// IA32_VMX_CR0_FIXED0 MSR (0x486) IA32_VMX_CR0_FIXED1 MSR (0x487)
|
||||
|
Loading…
Reference in New Issue
Block a user