implemented TSC-Deadline APIC timer mode
This commit is contained in:
parent
76b742bd93
commit
c74f590077
@ -8,7 +8,7 @@ Brief summary :
|
||||
- 10% (ST) to 50% (SMP) CPU emulation speedup !
|
||||
- Implemented support for new x86 ISA extensions, Bochs is aligned with
|
||||
latest published Intel Architecture Manual (rev 040, AVX rev 011):
|
||||
- XSAVEOPT, AVX/AVX2/FMA/F16C, BMI1/BMI2, SMEP, INVPCID
|
||||
- XSAVEOPT, AVX/AVX2/FMA/F16C, BMI1/BMI2, SMEP, INVPCID, TSC-Deadline
|
||||
- VMX: VMX Preemption Timer, Pause Loop Exiting and VM Functions
|
||||
- Implemented support for AMD SSE4A/XOP/FMA4/TBM instruction sets
|
||||
- Networking: introduced new networking module 'slirp'
|
||||
@ -64,6 +64,7 @@ Detailed change log :
|
||||
- Implemented Pause-Loop Exiting Secondary VMEXIT control.
|
||||
- Implemented VM Functions support and EPTP-Switching VM Function.
|
||||
- Added INVPCID instruction emulation support.
|
||||
- Added APIC timer TSC-Deadline mode emulation support.
|
||||
- Now you could disable x86-64 from .bochsrc so it become possible to
|
||||
emulate 32-bit CPUs using Bochs binary compiled with x86-64 support.
|
||||
- Updated/fixed instrumentation callbacks.
|
||||
|
@ -222,6 +222,7 @@ void bx_local_apic_c::reset(unsigned type)
|
||||
timer_divide_factor = 1;
|
||||
timer_initial = 0;
|
||||
timer_current = 0;
|
||||
ticksInitial = 0;
|
||||
|
||||
if(timer_active) {
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
@ -408,20 +409,8 @@ void bx_local_apic_c::write_aligned(bx_phy_address addr, Bit32u value)
|
||||
case BX_LAPIC_LVT_LINT0: // LVT LINT0 Reg
|
||||
case BX_LAPIC_LVT_LINT1: // LVT LINT1 Reg
|
||||
case BX_LAPIC_LVT_ERROR: // LVT Error Reg
|
||||
{
|
||||
static Bit32u lvt_mask[] = {
|
||||
0x000310ff, /* TIMER */
|
||||
0x000117ff, /* THERMAL */
|
||||
0x000117ff, /* PERFMON */
|
||||
0x0001f7ff, /* LINT0 */
|
||||
0x0001f7ff, /* LINT1 */
|
||||
0x000110ff /* ERROR */
|
||||
};
|
||||
unsigned lvt_entry = (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
|
||||
lvt[lvt_entry] = value & lvt_mask[lvt_entry];
|
||||
if(! software_enabled) lvt[lvt_entry] |= 0x10000;
|
||||
set_lvt_entry(apic_reg, value);
|
||||
break;
|
||||
}
|
||||
case BX_LAPIC_TIMER_INITIAL_COUNT:
|
||||
set_initial_timer_count(value);
|
||||
break;
|
||||
@ -462,6 +451,41 @@ void bx_local_apic_c::write_aligned(bx_phy_address addr, Bit32u value)
|
||||
}
|
||||
}
|
||||
|
||||
void bx_local_apic_c::set_lvt_entry(unsigned apic_reg, Bit32u value)
|
||||
{
|
||||
static Bit32u lvt_mask[] = {
|
||||
0x000710ff, /* TIMER */
|
||||
0x000117ff, /* THERMAL */
|
||||
0x000117ff, /* PERFMON */
|
||||
0x0001f7ff, /* LINT0 */
|
||||
0x0001f7ff, /* LINT1 */
|
||||
0x000110ff /* ERROR */
|
||||
};
|
||||
|
||||
unsigned lvt_entry = (apic_reg - BX_LAPIC_LVT_TIMER) >> 4;
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
if (apic_reg == BX_LAPIC_LVT_TIMER) {
|
||||
if (! cpu->bx_cpuid_support_tsc_deadline()) {
|
||||
value &= ~0x40000; // cannot enable TSC-Deadline when not supported
|
||||
}
|
||||
else {
|
||||
if ((value ^ lvt[lvt_entry]) & 0x40000) {
|
||||
// Transition between TSC-Deadline and other timer modes disarm the timer
|
||||
if(timer_active) {
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
timer_active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lvt[lvt_entry] = value & lvt_mask[lvt_entry];
|
||||
if(! software_enabled) {
|
||||
lvt[lvt_entry] |= 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
void bx_local_apic_c::send_ipi(apic_dest_t dest, Bit32u lo_cmd)
|
||||
{
|
||||
int dest_shorthand = (lo_cmd >> 18) & 3;
|
||||
@ -654,16 +678,7 @@ Bit32u bx_local_apic_c::read_aligned(bx_phy_address addr)
|
||||
data = timer_initial;
|
||||
break;
|
||||
case BX_LAPIC_TIMER_CURRENT_COUNT: // current count for timer
|
||||
if(timer_active==0) {
|
||||
data = timer_current;
|
||||
} else {
|
||||
Bit64u delta64 = (bx_pc_system.time_ticks() - ticksInitial) / timer_divide_factor;
|
||||
Bit32u delta32 = (Bit32u) delta64;
|
||||
if(delta32 > timer_initial)
|
||||
BX_PANIC(("APIC: R(curr timer count): delta < initial"));
|
||||
timer_current = timer_initial - delta32;
|
||||
data = timer_current;
|
||||
}
|
||||
data = get_current_timer_count();
|
||||
break;
|
||||
case BX_LAPIC_TIMER_DIVIDE_CFG: // timer divide configuration
|
||||
data = timer_divconf;
|
||||
@ -924,10 +939,8 @@ void bx_local_apic_c::periodic(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// timer reached zero since the last call to periodic.
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
if(timervec & 0x20000) {
|
||||
// Periodic mode.
|
||||
|
||||
// If timer is not masked, trigger interrupt.
|
||||
if((timervec & 0x10000)==0) {
|
||||
trigger_irq(timervec & 0xff, APIC_EDGE_TRIGGERED);
|
||||
@ -935,21 +948,17 @@ void bx_local_apic_c::periodic(void)
|
||||
else {
|
||||
BX_DEBUG(("local apic timer LVT masked"));
|
||||
}
|
||||
// Reload timer values.
|
||||
|
||||
// timer reached zero since the last call to periodic.
|
||||
if(timervec & 0x20000) {
|
||||
// Periodic mode - reload timer values
|
||||
timer_current = timer_initial;
|
||||
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
|
||||
ticksInitial = bx_pc_system.time_ticks(); // timer value when it started to count
|
||||
BX_DEBUG(("local apic timer(periodic) triggered int, reset counter to 0x%08x", timer_current));
|
||||
}
|
||||
else {
|
||||
// one-shot mode
|
||||
timer_current = 0;
|
||||
// If timer is not masked, trigger interrupt.
|
||||
if((timervec & 0x10000)==0) {
|
||||
trigger_irq(timervec & 0xff, APIC_EDGE_TRIGGERED);
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("local apic timer LVT masked"));
|
||||
}
|
||||
timer_active = 0;
|
||||
BX_DEBUG(("local apic timer(one-shot) triggered int"));
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
@ -968,6 +977,13 @@ void bx_local_apic_c::set_divide_configuration(Bit32u value)
|
||||
|
||||
void bx_local_apic_c::set_initial_timer_count(Bit32u value)
|
||||
{
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
// in TSC-deadline mode writes to initial time count are ignored
|
||||
if (timervec & 0x40000) return;
|
||||
#endif
|
||||
|
||||
// If active before, deactivate the current timer before changing it.
|
||||
if(timer_active) {
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
@ -984,14 +1000,70 @@ void bx_local_apic_c::set_initial_timer_count(Bit32u value)
|
||||
BX_DEBUG(("APIC: Initial Timer Count Register = %u", value));
|
||||
timer_current = timer_initial;
|
||||
timer_active = 1;
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
bx_bool continuous = (timervec & 0x20000) > 0;
|
||||
ticksInitial = bx_pc_system.time_ticks(); // Take a reading.
|
||||
ticksInitial = bx_pc_system.time_ticks(); // timer value when it started to count
|
||||
bx_pc_system.activate_timer_ticks(timer_handle,
|
||||
Bit64u(timer_initial) * Bit64u(timer_divide_factor), continuous);
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u bx_local_apic_c::get_current_timer_count(void)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
|
||||
// in TSC-deadline mode current timer count always reads 0
|
||||
if (timervec & 0x40000) return 0;
|
||||
#endif
|
||||
|
||||
if(timer_active==0) {
|
||||
return timer_current;
|
||||
} else {
|
||||
Bit64u delta64 = (bx_pc_system.time_ticks() - ticksInitial) / timer_divide_factor;
|
||||
Bit32u delta32 = (Bit32u) delta64;
|
||||
if(delta32 > timer_initial)
|
||||
BX_PANIC(("APIC: R(curr timer count): delta < initial"));
|
||||
timer_current = timer_initial - delta32;
|
||||
return timer_current;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
void bx_local_apic_c::set_tsc_deadline(Bit64u deadline)
|
||||
{
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
|
||||
if ((timervec & 0x40000) == 0) {
|
||||
BX_ERROR(("APIC: TSC-Deadline timer is disabled"));
|
||||
return;
|
||||
}
|
||||
|
||||
// If active before, deactivate the current timer before changing it.
|
||||
if(timer_active) {
|
||||
bx_pc_system.deactivate_timer(timer_handle);
|
||||
timer_active = 0;
|
||||
}
|
||||
|
||||
ticksInitial = deadline;
|
||||
if (deadline != 0) {
|
||||
BX_INFO(("APIC: TSC-Deadline is set to " FMT_LL "d", deadline));
|
||||
Bit64u currtime = bx_pc_system.time_ticks();
|
||||
timer_active = 1;
|
||||
bx_pc_system.activate_timer_ticks(timer_handle, (deadline > currtime) ? (deadline - currtime) : 1 , 0);
|
||||
}
|
||||
}
|
||||
|
||||
Bit64u bx_local_apic_c::get_tsc_deadline(void)
|
||||
{
|
||||
Bit32u timervec = lvt[APIC_LVT_TIMER];
|
||||
|
||||
// read as zero if TSC-deadline timer is disabled
|
||||
if ((timervec & 0x40000) == 0) return 0;
|
||||
|
||||
return ticksInitial; /* also holds TSC-deadline value */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
Bit32u bx_local_apic_c::read_vmx_preemption_timer(void)
|
||||
{
|
||||
|
@ -92,8 +92,9 @@ class BOCHSAPI bx_local_apic_c : public logfunctions
|
||||
#define APIC_LVT_LINT1 4
|
||||
#define APIC_LVT_ERROR 5
|
||||
|
||||
Bit32u timer_initial; // Initial timer count
|
||||
Bit32u timer_current; // current timer count
|
||||
Bit32u timer_initial; // Initial timer count (in order to reload periodic timer)
|
||||
Bit32u timer_current; // Current timer count
|
||||
Bit64u ticksInitial; // Timer value when it started to count, also holds TSC-Deadline value
|
||||
|
||||
Bit32u timer_divconf; // Timer divide configuration register
|
||||
Bit32u timer_divide_factor;
|
||||
@ -101,7 +102,6 @@ class BOCHSAPI bx_local_apic_c : public logfunctions
|
||||
// Internal timer state, not accessible from bus
|
||||
bx_bool timer_active;
|
||||
int timer_handle;
|
||||
Bit64u ticksInitial;
|
||||
|
||||
/* APIC delivery modes */
|
||||
#define APIC_DM_FIXED 0
|
||||
@ -161,10 +161,19 @@ public:
|
||||
Bit8u get_ppr(void);
|
||||
Bit8u get_apr(void);
|
||||
bx_bool is_focus(Bit8u vector);
|
||||
void set_lvt_entry(unsigned apic_reg, Bit32u val);
|
||||
|
||||
static void periodic_smf(void *);
|
||||
void periodic(void);
|
||||
void set_divide_configuration(Bit32u value);
|
||||
void set_initial_timer_count(Bit32u value);
|
||||
Bit32u get_current_timer_count(void);
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
Bit64u get_tsc_deadline(void);
|
||||
void set_tsc_deadline(Bit64u value);
|
||||
#endif
|
||||
|
||||
void startup_msg(Bit8u vector);
|
||||
void register_state(bx_param_c *parent);
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
|
@ -379,6 +379,8 @@ struct BxExceptionInfo {
|
||||
#define BX_MSR_MTRR_DEFTYPE 0x2ff
|
||||
#endif
|
||||
|
||||
#define BX_MSR_TSC_DEADLINE 0x6E0
|
||||
|
||||
#define BX_MSR_MAX_INDEX 0x1000
|
||||
|
||||
enum {
|
||||
@ -4025,6 +4027,7 @@ public: // for now...
|
||||
BX_SMF BX_CPP_INLINE int bx_cpuid_support_smx(void);
|
||||
BX_SMF BX_CPP_INLINE int bx_cpuid_support_vmx(void);
|
||||
BX_SMF BX_CPP_INLINE int bx_cpuid_support_rdtscp(void);
|
||||
BX_SMF BX_CPP_INLINE int bx_cpuid_support_tsc_deadline(void);
|
||||
|
||||
BX_SMF BX_CPP_INLINE unsigned which_cpu(void) { return BX_CPU_THIS_PTR bx_cpuid; }
|
||||
#if BX_DEBUGGER || BX_SUPPORT_HANDLERS_CHAINING_SPEEDUPS || BX_SUPPORT_SMP
|
||||
@ -4585,6 +4588,11 @@ BX_CPP_INLINE int BX_CPU_C::bx_cpuid_support_rdtscp(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
BX_CPP_INLINE int BX_CPU_C::bx_cpuid_support_tsc_deadline(void)
|
||||
{
|
||||
return (BX_CPU_THIS_PTR cpu_extensions_bitmask & BX_CPU_TSC_DEADLINE);
|
||||
}
|
||||
|
||||
IMPLEMENT_EFLAG_ACCESSOR (ID, 21)
|
||||
IMPLEMENT_EFLAG_ACCESSOR (VIP, 20)
|
||||
IMPLEMENT_EFLAG_ACCESSOR (VIF, 19)
|
||||
|
@ -44,8 +44,6 @@ corei7_sandy_bridge_2600k_t::corei7_sandy_bridge_2600k_t(BX_CPU_C *cpu): bx_cpui
|
||||
if (! BX_SUPPORT_AVX)
|
||||
BX_PANIC(("You must enable AVX for Intel Core i7 Sandy Bridge configuration"));
|
||||
|
||||
BX_INFO(("WARNING: TSC deadline is not implemented yet"));
|
||||
|
||||
if (BX_SUPPORT_VMX == 1)
|
||||
BX_INFO(("You must compile with --enable-vmx=2 for Intel Core i7 Sandy Bridge VMX configuration"));
|
||||
}
|
||||
@ -166,7 +164,8 @@ Bit32u corei7_sandy_bridge_2600k_t::get_cpu_extensions_bitmask(void) const
|
||||
/* BX_CPU_X2APIC | */
|
||||
BX_CPU_LONG_MODE |
|
||||
BX_CPU_NX |
|
||||
BX_CPU_PCID;
|
||||
BX_CPU_PCID |
|
||||
BX_CPU_TSC_DEADLINE;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
@ -322,7 +321,7 @@ void corei7_sandy_bridge_2600k_t::get_std_cpuid_leaf_1(cpuid_function_t *leaf) c
|
||||
BX_CPUID_EXT_SSE4_2 |
|
||||
/* BX_CPUID_EXT_X2APIC | */
|
||||
BX_CPUID_EXT_POPCNT |
|
||||
// BX_CPUID_EXT_TSC_DEADLINE | // not implemented yet
|
||||
BX_CPUID_EXT_TSC_DEADLINE |
|
||||
BX_CPUID_EXT_AES |
|
||||
BX_CPUID_EXT_XSAVE |
|
||||
BX_CPUID_EXT_AVX;
|
||||
|
@ -125,6 +125,7 @@ typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);
|
||||
#define BX_CPU_SMEP (1 << 14) /* SMEP support */
|
||||
#define BX_CPU_FFXSR (1 << 15) /* EFER.FFXSR support */
|
||||
#define BX_CPU_ALT_MOV_CR8 (1 << 16) /* LOCK CR0 access CR8 */
|
||||
#define BX_CPU_TSC_DEADLINE (1 << 17) /* TSC-Deadline */
|
||||
|
||||
// cpuid VMX features
|
||||
#define BX_VMX_TPR_SHADOW (1 << 0) /* TPR shadow */
|
||||
|
@ -136,6 +136,16 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr)
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_TSC_DEADLINE:
|
||||
if (! bx_cpuid_support_tsc_deadline()) {
|
||||
BX_ERROR(("RDMSR BX_MSR_TSC_DEADLINE: TSC-Deadline not enabled !"));
|
||||
return handle_unknown_rdmsr(index, msr);
|
||||
}
|
||||
val64 = BX_CPU_THIS_PTR lapic.get_tsc_deadline();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
/*
|
||||
case BX_MSR_IA32_SMM_MONITOR_CTL:
|
||||
@ -584,6 +594,16 @@ bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
|
||||
return relocate_apic(val_64);
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_TSC_DEADLINE:
|
||||
if (! bx_cpuid_support_tsc_deadline()) {
|
||||
BX_ERROR(("WRMSR BX_MSR_TSC_DEADLINE: TSC-Deadline not enabled !"));
|
||||
return handle_unknown_wrmsr(index, val_64);
|
||||
}
|
||||
BX_CPU_THIS_PTR lapic.set_tsc_deadline(val_64);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
// Support only two bits: lock bit (bit 0) and VMX enable (bit 2)
|
||||
case BX_MSR_IA32_FEATURE_CONTROL:
|
||||
|
Loading…
x
Reference in New Issue
Block a user