@@ -28,6 +28,7 @@
#define APIC_TIMER_MODE_MASK (0x3<<17)
#define APIC_TIMER_MODE_ONESHOT (0x0<<17)
#define APIC_TIMER_MODE_PERIODIC (0x1<<17)
+#define APIC_TIMER_MODE_TSC_DEADLINE (0x2<<17)
#define APIC_TMICT 0x380
#define APIC_TMCCT 0x390
@@ -77,6 +77,7 @@ static inline bool cpu_has(unsigned int feature)
#define cpu_has_smx cpu_has(X86_FEATURE_SMX)
#define cpu_has_pcid cpu_has(X86_FEATURE_PCID)
#define cpu_has_x2apic cpu_has(X86_FEATURE_X2APIC)
+#define cpu_has_tsc_deadline cpu_has(X86_FEATURE_TSC_DEADLINE)
#define cpu_has_xsave cpu_has(X86_FEATURE_XSAVE)
#define cpu_has_avx cpu_has(X86_FEATURE_AVX)
@@ -425,6 +425,15 @@ static inline void write_xcr0(uint64_t xcr0)
xsetbv(0, xcr0);
}
+static inline uint64_t rdtsc(void)
+{
+ uint32_t lo, hi;
+
+ asm volatile("rdtsc": "=a" (lo), "=d" (hi));
+
+ return (((uint64_t)hi) << 32) | lo;
+}
+
#endif /* XTF_X86_LIB_H */
/*
@@ -37,6 +37,7 @@
#define MSR_A_PMC(n) (0x000004c1 + (n))
+#define MSR_TSC_DEADLINE 0x000006e0
#define MSR_X2APIC_REGS 0x00000800
#define MSR_EFER 0xc0000080 /* Extended Feature register. */
@@ -16,9 +16,22 @@
*/
#include <xtf.h>
#include <arch/apic.h>
+#include <arch/msr-index.h>
const char test_title[] = "Test vlapic-timer";
+static inline uint64_t rdtscdeadline(void)
+{
+ uint64_t v = 0;
+ rdmsr_safe(MSR_TSC_DEADLINE, &v);
+ return v;
+}
+
+static inline void wrtscdeadline(uint64_t tsc)
+{
+ wrmsr_safe(MSR_TSC_DEADLINE, tsc);
+}
+
static inline void change_mode(unsigned long new_mode)
{
uint32_t lvtt;
@@ -168,6 +181,58 @@ void testing_divide_configuration(void)
xtf_failure("Fail: TMCCT should not be 0\n");
}
+/*
+ * Testing TSC-Deadline Mode Timer
+ */
+void testing_tsc_deadline_mode(void)
+{
+ uint64_t tsc_diff;
+ uint32_t tmict = 0x19999999;
+
+ if ( !cpu_has_tsc_deadline )
+ return;
+
+ /* find a short time in TSC */
+ change_mode(APIC_TIMER_MODE_ONESHOT);
+ apic_write(APIC_TMICT, tmict);
+ tsc_diff = rdtsc();
+ wait_until_tmcct_is_zero(tmict);
+ tsc_diff = rdtsc() - tsc_diff;
+
+ printk("Testing TSC Deadline Timer\n");
+
+ /* Before changing mode, test writes to TDT */
+ wrtscdeadline(rdtsc() + tsc_diff);
+ if ( rdtscdeadline() )
+ xtf_failure("Fail: TSC Deadline should be 0 when not in TDT mode\n");
+
+ /*
+ * Switching to TSC-Deadline mode should disarm the timer.
+ * Observation show that TMICT also reads 0.
+ */
+ change_mode(APIC_TIMER_MODE_TSC_DEADLINE);
+ if ( apic_read(APIC_TMCCT) )
+ xtf_failure("Fail: TMCCT should be 0\n");
+ if ( apic_read(APIC_TMICT) )
+ xtf_failure("Fail: TMICT should be 0\n");
+
+ /* Testing write to TMICT while in TSC-Deadline mode */
+ apic_write(APIC_TMICT, tmict);
+ if ( apic_read(APIC_TMICT) )
+ xtf_failure("Fail: Write to TMICT should be ignored\n");
+
+ /* Setting the timer */
+ wrtscdeadline(rdtsc() + tsc_diff);
+ if ( !rdtscdeadline() )
+ xtf_failure("Fail: TSC-Deadline should have a value when set\n");
+
+ /* Check that switching to other modes disarm TSC-Deadline timer. */
+ change_mode(APIC_TIMER_MODE_ONESHOT);
+ if ( rdtscdeadline() )
+ xtf_failure("Fail: TSC-Deadline should be disarmed when changing mode"
+ " TDT -> one-shot\n");
+}
+
void test_main(void)
{
if ( apic_init(APIC_MODE_XAPIC) )
@@ -177,6 +242,8 @@ void test_main(void)
testing_divide_configuration();
+ testing_tsc_deadline_mode();
+
xtf_success(NULL);
}
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> --- arch/x86/include/arch/apic.h | 1 + arch/x86/include/arch/cpuid.h | 1 + arch/x86/include/arch/lib.h | 9 ++++++ arch/x86/include/arch/msr-index.h | 1 + tests/vlapic-timer/main.c | 67 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+)