diff --git a/arch/x86/include/arch/apic.h b/arch/x86/include/arch/apic.h
index 1389f70..4cb262d 100644
--- a/arch/x86/include/arch/apic.h
+++ b/arch/x86/include/arch/apic.h
@@ -24,6 +24,14 @@
 #define   APIC_DEST_SELF          0x40000
 
 #define APIC_ICR2       0x310
+#define APIC_LVTT       0x320
+#define   APIC_TIMER_MODE_MASK          (0x3<<17)
+#define   APIC_TIMER_MODE_ONESHOT       (0x0<<17)
+#define   APIC_TIMER_MODE_PERIODIC      (0x1<<17)
+
+#define APIC_TMICT      0x380
+#define APIC_TMCCT      0x390
+
 
 #define APIC_DEFAULT_BASE 0xfee00000ul
 
diff --git a/tests/vlapic-timer/Makefile b/tests/vlapic-timer/Makefile
new file mode 100644
index 0000000..f2a61cb
--- /dev/null
+++ b/tests/vlapic-timer/Makefile
@@ -0,0 +1,9 @@
+include $(ROOT)/build/common.mk
+
+NAME      := vlapic-timer
+CATEGORY  := functional
+TEST-ENVS := hvm64
+
+obj-perenv += main.o
+
+include $(ROOT)/build/gen.mk
diff --git a/tests/vlapic-timer/main.c b/tests/vlapic-timer/main.c
new file mode 100644
index 0000000..47836a8
--- /dev/null
+++ b/tests/vlapic-timer/main.c
@@ -0,0 +1,151 @@
+/**
+ * @file tests/vlapic-timer/main.c
+ * @ref test-vlapic-timer - LAPIC Timer Emulation
+ *
+ * @page test-vlapic-timer LAPIC Timer Emulation
+ *
+ * Tests the behavior of the vlapic timer emulation by Xen.
+ *
+ * These tests are mostly base on observation made on baremetal, Intel SDM does
+ * not describe everything.
+ *
+ * It is testing switch between different mode, one-shot and periodic, as well
+ * a the TSC-Deadline mode.
+ *
+ * @see tests/vlapic-timer/main.c
+ */
+#include <xtf.h>
+#include <arch/apic.h>
+
+const char test_title[] = "Test vlapic-timer";
+
+static inline void change_mode(unsigned long new_mode)
+{
+    uint32_t lvtt;
+
+    lvtt = apic_read(APIC_LVTT);
+    apic_write(APIC_LVTT, (lvtt & ~APIC_TIMER_MODE_MASK) | new_mode);
+}
+
+void wait_tmcct_count_down(uint32_t initial_count, bool stop_when_half)
+{
+    uint32_t tmcct = apic_read(APIC_TMCCT);
+
+    if ( tmcct )
+    {
+        while ( tmcct > (initial_count / 2) )
+            tmcct = apic_read(APIC_TMCCT);
+
+        if ( stop_when_half )
+            return;
+
+        /* Wait until the counter reach 0 or wrap-around */
+        while ( tmcct <= (initial_count / 2) && tmcct > 0 )
+            tmcct = apic_read(APIC_TMCCT);
+    }
+}
+
+static inline void wait_until_tmcct_is_zero(uint32_t initial_count)
+{
+    wait_tmcct_count_down(initial_count, false);
+}
+static inline void wait_until_tmcct_is_half_down(uint32_t initial_count)
+{
+    wait_tmcct_count_down(initial_count, true);
+}
+
+void testing_oneshot_and_periodic_mode(void)
+{
+    uint32_t tmict = 0x9999999;
+
+    /* Start in one-shot mode */
+    change_mode(APIC_TIMER_MODE_ONESHOT);
+
+    apic_write(APIC_TMICT, tmict);
+
+    /* On mode change one-shot -> periodic, TMICT is not reset on baremetal */
+    change_mode(APIC_TIMER_MODE_PERIODIC);
+    if ( apic_read(APIC_TMICT) != tmict )
+        xtf_failure("Fail: TMICT value reset\n");
+
+    /*
+     * Testing one-shot
+     */
+    printk("Testing one-shot mode\n");
+    change_mode(APIC_TIMER_MODE_ONESHOT);
+
+    /* Testing TMCCT after setting TMICT */
+    apic_write(APIC_TMICT, tmict);
+    if ( !apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should have a non-zero value\n");
+
+    wait_until_tmcct_is_zero(tmict);
+    if ( apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should have reached 0\n");
+
+    /*
+     * Testing periodic timer mode
+     *
+     * Write TMICT before changing mode one-shot -> periodic,
+     * check that TMCCT keeps counting down after this mode change
+     */
+    apic_write(APIC_TMICT, tmict);
+    wait_until_tmcct_is_half_down(tmict);
+
+    printk("Testing periodic mode\n");
+    change_mode(APIC_TIMER_MODE_PERIODIC);
+
+    if ( !apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should have a non-zero value\n");
+
+    if ( apic_read(APIC_TMCCT) > (tmict / 2) )
+        xtf_failure("Fail: TMCCT should not be reset to TMICT value\n");
+
+    /* Check that the TMCCT is reset to TMICT */
+    wait_until_tmcct_is_zero(tmict);
+    if ( apic_read(APIC_TMCCT) < (tmict / 2) )
+        xtf_failure("Fail: TMCCT should be reset to TMICT periodically\n");
+
+    wait_until_tmcct_is_half_down(tmict);
+
+    /*
+     * Keep the same TMICT and change timer mode periodic -> one-shot
+     * Check that TMCCT keeps counting down and is not reset.
+     */
+    printk("Testing one-shot after periodic (with same tmict)\n");
+    change_mode(APIC_TIMER_MODE_ONESHOT);
+
+    if ( !apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should have a non-zero value\n");
+    if ( apic_read(APIC_TMCCT) > (tmict / 2) )
+        xtf_failure("Fail: TMCCT should not be reset to init\n");
+
+    wait_until_tmcct_is_zero(tmict);
+    if ( apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should have reach zero\n");
+
+    /* Now TMCCT == 0 and TMICT != 0 */
+    change_mode(APIC_TIMER_MODE_PERIODIC);
+    if ( apic_read(APIC_TMCCT) )
+        xtf_failure("Fail: TMCCT should stay at zero\n");
+}
+
+void test_main(void)
+{
+    if ( apic_init(APIC_MODE_XAPIC) )
+        return xtf_skip("No APIC support");
+
+    testing_oneshot_and_periodic_mode();
+
+    xtf_success(NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
