Implemented VMX preemption timer VMEXIT control (patch by Jianan Hao)

This commit is contained in:
Stanislav Shwartsman 2011-07-03 15:59:48 +00:00
parent 4699840aaf
commit 909e750549
11 changed files with 255 additions and 15 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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)