WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [HVM] Fix HPET timer to support 8-byte ac

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [HVM] Fix HPET timer to support 8-byte accesses, erroneous updates
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Fri, 29 Dec 2006 14:20:26 -0800
Delivery-date: Fri, 29 Dec 2006 14:56:59 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxxx
# Date 1167401575 0
# Node ID a8b2738a6f7ff22022e0b49e14c3142409f8681a
# Parent  98271ea55d94cc9eebadafdac435794582b642df
[HVM] Fix HPET timer to support 8-byte accesses, erroneous updates
to read-only bits, etc.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/hpet.c       |  472 +++++++++++++++---------------------------
 xen/include/asm-x86/hvm/vpt.h |   13 -
 2 files changed, 172 insertions(+), 313 deletions(-)

diff -r 98271ea55d94 -r a8b2738a6f7f xen/arch/x86/hvm/hpet.c
--- a/xen/arch/x86/hvm/hpet.c   Fri Dec 29 13:02:19 2006 +0000
+++ b/xen/arch/x86/hvm/hpet.c   Fri Dec 29 14:12:55 2006 +0000
@@ -1,6 +1,7 @@
 /*
- * hpet.c: emulating HPET in Xen
+ * hpet.c: HPET emulation for HVM guests.
  * Copyright (c) 2006, Intel Corporation.
+ * Copyright (c) 2006, Keir Fraser <keir@xxxxxxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -42,19 +43,7 @@
 #define HPET_T2_CFG     0x140
 #define HPET_T2_CMP     0x148
 #define HPET_T2_ROUTE   0x150
-#define HPET_T3_CFG     0x158 /* not supported now*/
-
-#define HPET_REV                0x01ULL
-#define HPET_NUMBER            0x200ULL /* 3 timers */
-#define HPET_COUNTER_SIZE_CAP 0x2000ULL
-#define HPET_LEG_RT_CAP       0x8000ULL
-#define HPET_VENDOR_8086  0x80860000ULL
-
-/* 64bit main counter; 3 timers supported now;
-   LegacyReplacemen Route supported.           */
-#define HPET_CAP_ID_REG \
-    (HPET_REV | HPET_NUMBER | HPET_COUNTER_SIZE_CAP | \
-     HPET_LEG_RT_CAP | HPET_VENDOR_8086)
+#define HPET_T3_CFG     0x160
 
 #define HPET_CFG_ENABLE          0x001
 #define HPET_CFG_LEGACY          0x002
@@ -65,6 +54,7 @@
 #define HPET_TN_PERIODIC_CAP     0x010
 #define HPET_TN_SETVAL           0x040
 #define HPET_TN_32BIT            0x100
+#define HPET_TN_SIZE_CAP         0x200
 #define HPET_TN_INT_ROUTE_MASK  0x3e00
 #define HPET_TN_INT_ROUTE_SHIFT      9
 #define HPET_TN_INT_ROUTE_CAP_SHIFT 32
@@ -76,17 +66,12 @@
 
 #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
                     << HPET_TN_INT_ROUTE_CAP_SHIFT)
-
-#define HPET_TIMER_CMP32_DEFAULT 0xffffffffULL
-#define HPET_TIMER_CMP64_DEFAULT 0xffffffffffffffffULL
-#define HPET_TN_SIZE_CAP         (1 << 5)
 
 #define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq)
 #define timer_config(h, n)       (h->hpet.timers[n].config)
 #define timer_enabled(h, n)      (timer_config(h, n) & HPET_TN_ENABLE)
 #define timer_is_periodic(h, n)  (timer_config(h, n) & HPET_TN_PERIODIC)
 #define timer_is_32bit(h, n)     (timer_config(h, n) & HPET_TN_32BIT)
-#define timer_period_cap(h, n)   (timer_config(h, n) & HPET_TN_PERIODIC_CAP)
 #define hpet_enabled(h)          (h->hpet.config & HPET_CFG_ENABLE)
 #define timer_level(h, n)        (timer_config(h, n) & HPET_TN_INT_TYPE_LEVEL)
 
@@ -97,72 +82,26 @@
     ((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
         >> HPET_TN_INT_ROUTE_CAP_SHIFT)
 
-#define hpet_time_after(a, b)   ((int32_t)(b) -(int32_t)(a) < 0)
-#define hpet_time_after64(a, b)   ((int64_t)(b) -(int64_t)(a) < 0)
-
-static inline uint32_t hpet_read32(HPETState *h, unsigned long addr)
-{
-    unsigned long p = ((unsigned long)&h->hpet) + addr;
-    return  *((uint32_t*)p);
-}
-
-static inline void hpet_write32(HPETState *h, unsigned long addr, uint32_t val)
-{
-    unsigned long p = ((unsigned long)&h->hpet) + addr;
-    *((uint32_t*)p) = val;
+#define hpet_time_after(a, b)   ((int32_t)(b) - (int32_t)(a) < 0)
+#define hpet_time_after64(a, b) ((int64_t)(b) - (int64_t)(a) < 0)
+
+static inline uint64_t hpet_read64(HPETState *h, unsigned long addr)
+{
+    uint64_t *p = (uint64_t *)(((unsigned long)&h->hpet) + addr);
+    return (addr >= HPET_T3_CFG) ? 0 : *p;
 }
 
 static int hpet_check_access_length(unsigned long addr, unsigned long len)
 {
-    if ( (len != 4) && (len != 8) )
-    {
-        gdprintk(XENLOG_ERR, "HPET: access with len=%lu\n", len);
-        goto fail;
-    }
-
-    if ( addr & (len-1) )
-    {
-        gdprintk(XENLOG_ERR, "HPET: access across register boundary\n");
-        goto fail;
+    if ( (addr & (len - 1)) || (len > 8) )
+    {
+        gdprintk(XENLOG_ERR, "HPET: access across register boundary: "
+                 "%lx %lx\n", addr, len);
+        domain_crash(current->domain);
+        return -EINVAL;
     }
 
     return 0;
-
- fail:
-    domain_crash(current->domain);
-    return -EINVAL;
-}
-
-static int hpet_check_access_offset(unsigned long addr)
-{
-    if ( addr >= HPET_T3_CFG )
-    {
-        gdprintk(XENLOG_ERR, "HPET: only 3 timers supported now\n");
-        goto fail;
-    }
-
-    if ( (addr == HPET_T0_ROUTE) || (addr == HPET_T0_ROUTE+4) ||
-         (addr == HPET_T1_ROUTE) || (addr == HPET_T1_ROUTE+4) ||
-         (addr == HPET_T2_ROUTE) || (addr == HPET_T2_ROUTE+4) )
-    {
-        gdprintk(XENLOG_ERR, "HPET: FSB interrupt route not supported now\n");
-        goto fail;
-    }
-
-    return 0;
-
- fail:
-    domain_crash(current->domain);
-    return -EINVAL;
-}
-
-static void hpet_level_triggered_interrupt_not_supported(void)
-{
-    /* It's hard to support level triggered interrupt in HPET. */
-    /* Now we haven't found any OS uses this kind of interrupt of HPET. */
-    gdprintk(XENLOG_ERR,
-             "HPET: level triggered interrupt not supported now\n");
-    domain_crash(current->domain);
 }
 
 static uint64_t hpet_update_maincounter(HPETState *h)
@@ -177,104 +116,68 @@ static unsigned long hpet_read(
     struct vcpu *v, unsigned long addr, unsigned long length)
 {
     HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
-    uint64_t mc, result;
+    unsigned long result;
+    uint64_t val;
 
     addr &= HPET_MMAP_SIZE-1;
 
     if ( hpet_check_access_length(addr, length) != 0 )
-        goto fail;
-
-    if ( length == 8 )
-    {
-        /* TODO: no OS is found to use length=8 now. 
-         * Windows 2000/XP/2003 doesn't use HPET; all of Linux 
-         * and 32bit/64bit Vista use 4-byte-length access.
-         * Besides, section 2.4.7 of HPET spec gives a note saying
-         * 64bit read may be inaccurate in some platforms. */
-        gdprintk(XENLOG_ERR, "HPET: hpet_read with len=8 not implementated\n");
-        domain_crash(v->domain);
-        goto fail;
-    }
-
-    switch ( addr )
-    {
-    case HPET_COUNTER:
-        mc = hpet_update_maincounter(h);
-        result = mc & 0xffffffffU;
-        break;
-    case HPET_COUNTER + 4:
-        mc = hpet_update_maincounter(h);
-        result = (mc >> 32);
-        break;
-    case HPET_T0_CMP:
-        result = hpet_read32(h, addr);
-        break;
-    case HPET_T0_CMP + 4:
-        result = timer_is_32bit(h, 0) ? 0 : hpet_read32(h, addr);
-        break;
-    default:
-        if ( hpet_check_access_offset(addr) != 0 )
-            goto fail;
-        result = hpet_read32(h, addr);
-        break;
-    }
+        return ~0UL;
+
+    val = hpet_read64(h, addr & ~7);
+    if ( (addr & ~7) == HPET_COUNTER )
+        val = hpet_update_maincounter(h);
+
+    result = val;
+    if ( length != 8 )
+        result = (val >> ((addr & 7) * 8)) & ((1UL << (length * 8)) - 1);
 
     return result;
-
- fail:
-    return ~0UL;
 }
 
 static void hpet_stop_timer(HPETState *h, unsigned int tn)
 {
-    ASSERT( tn < HPET_TIMER_NUM );
+    ASSERT(tn < HPET_TIMER_NUM);
     stop_timer(&h->timers[tn]);
 }
 
 static void hpet_set_timer(HPETState *h, unsigned int tn)
 {
-    uint64_t tn_cmp;
-    uint32_t cur_tick;
+    uint64_t tn_cmp, cur_tick;
 
     ASSERT(tn < HPET_TIMER_NUM);
     
     if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
         return;
 
-    switch ( tn )
-    {
-    case 0:
-        if ( !(h->hpet.config & HPET_CFG_LEGACY) )
-        {
-            gdprintk(XENLOG_INFO,
-                     "HPET: LegacyReplacementRoute not set for timer0\n");
-        }
-        else
-        {
-            /* HPET specification requires PIT shouldn't generate
-             * interrupts if LegacyReplacementRoute is set for timer0 */
-            PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
-            pit_stop_channel0_irq(pit);
-        }
-        if ( timer_is_32bit(h, 0) )
-            h->t0_period = hpet_tick_to_ns(h, (uint32_t)h->t0_initial_cnt);
-        else
-            h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
-        h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
-        set_timer(&h->timers[0], NOW() + h->t0_period);
-        break;
-    case 1:
-    case 2: /* only support 32bit timer1 & timer 2 now */
-        tn_cmp = h->hpet.timers[tn].c64 & 0xffffffffULL;
-        cur_tick = hpet_update_maincounter(h);
-        if ( tn_cmp > cur_tick )
-            set_timer(&h->timers[tn], NOW() +
-                      hpet_tick_to_ns(h, tn_cmp-cur_tick));
-        else /* handle the overflow case */
-            set_timer(&h->timers[tn], NOW() +
-                      hpet_tick_to_ns(h, 0xffffffff-cur_tick+tn_cmp));
-        break;
-    }
+    if ( (tn == 0) && (h->hpet.config & HPET_CFG_LEGACY) )
+    {
+        /* HPET specification requires PIT shouldn't generate
+         * interrupts if LegacyReplacementRoute is set for timer0 */
+        PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
+        pit_stop_channel0_irq(pit);
+    }
+
+    tn_cmp   = h->hpet.timers[tn].cmp;
+    cur_tick = hpet_update_maincounter(h);
+    if ( timer_is_32bit(h, tn) )
+    {
+        tn_cmp   = (uint32_t)tn_cmp;
+        cur_tick = (uint32_t)cur_tick;
+    }
+
+    if ( (int64_t)(tn_cmp - cur_tick) > 0 )
+        set_timer(&h->timers[tn], NOW() +
+                  hpet_tick_to_ns(h, tn_cmp-cur_tick));
+    else
+        set_timer(&h->timers[tn], NOW());
+}
+
+static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
+{
+    new &= mask;
+    new |= old & ~mask;
+    return new;
 }
 
 static void hpet_write(
@@ -282,7 +185,7 @@ static void hpet_write(
     unsigned long length, unsigned long val)
 {
     HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
-    unsigned long old_val;
+    uint64_t old_val, new_val;
     int tn, i;
 
     addr &= HPET_MMAP_SIZE-1;
@@ -290,106 +193,93 @@ static void hpet_write(
     if ( hpet_check_access_length(addr, length) != 0 )
         return;
 
-    if ( length == 8 )
-    {
-        gdprintk(XENLOG_ERR, "HPET: hpet_write with len=8 not implemented\n");
-        domain_crash(v->domain);
-        return;
-    }
-
-    switch ( addr )
-    {
-    case HPET_ID: 
-    case HPET_ID + 4: 
-        gdprintk(XENLOG_WARNING,
-                 "HPET: Capabilities and ID register is readonly\n");
-        break;
-    case HPET_CFG: 
-        old_val = h->hpet.config;
-        h->hpet.config = val;
-
-        if ( !(old_val & HPET_CFG_ENABLE) && (val & HPET_CFG_ENABLE) )
-        {
-            /* enable main counter & interrupt generating */
+    old_val = hpet_read64(h, addr & ~7);
+    if ( (addr & ~7) == HPET_COUNTER )
+        old_val = hpet_update_maincounter(h);
+
+    new_val = val;
+    if ( length != 8 )
+        new_val = hpet_fixup_reg(
+            new_val << (addr & 7) * 8, old_val,
+            ((1ULL << (length*8)) - 1) << ((addr & 7) * 8));
+
+    switch ( addr & ~7 )
+    {
+    case HPET_CFG:
+        h->hpet.config = hpet_fixup_reg(new_val, old_val, 0x3);
+
+        if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) )
+        {
+            /* Enable main counter and interrupt generation. */
             h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu);
             for ( i = 0; i < HPET_TIMER_NUM; i++ )
                 hpet_set_timer(h, i); 
         }
-        else if ( (old_val & HPET_CFG_ENABLE) && !(val & HPET_CFG_ENABLE) )
-        {
-            /* halt main counter & disable interrupt generating */
+        else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
+        {
+            /* Halt main counter and disable interrupt generation. */
             h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu);
             for ( i = 0; i < HPET_TIMER_NUM; i++ )
                 hpet_stop_timer(h, i);
         }
         break;
-    case HPET_STATUS:
-        hpet_level_triggered_interrupt_not_supported();
-        break;
+
     case HPET_COUNTER:
-    case HPET_COUNTER + 4:
         if ( hpet_enabled(h) )
             gdprintk(XENLOG_WARNING, 
                      "HPET: writing main counter but it's not halted!\n");
-        hpet_write32(h, addr, val);
-        break;
+        h->hpet.mc64 = new_val;
+        break;
+
+    case HPET_T0_CFG:
+    case HPET_T1_CFG:
+    case HPET_T2_CFG:
+        tn = (addr - HPET_T0_CFG) >> 5;
+
+        h->hpet.timers[tn].config = hpet_fixup_reg(new_val, old_val, 0x3f4e);
+
+        if ( timer_level(h, tn) )
+        {
+            gdprintk(XENLOG_ERR,
+                     "HPET: level triggered interrupt not supported now\n");
+            domain_crash(current->domain);
+            break;
+        }
+
+        if ( new_val & HPET_TN_32BIT )
+            h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;
+
+        if ( !(old_val & HPET_TN_ENABLE) && (new_val & HPET_TN_ENABLE) )
+            hpet_set_timer(h, tn);
+        else if ( (old_val & HPET_TN_ENABLE) && !(new_val & HPET_TN_ENABLE) )
+            hpet_stop_timer(h, tn);
+        break;
+
+    case HPET_T0_CMP:
+    case HPET_T1_CMP:
+    case HPET_T2_CMP:
+        tn = (addr - HPET_T0_CMP) >> 5;
+        if ( timer_is_32bit(h, tn) )
+            new_val = (uint32_t)new_val;
+        if ( !timer_is_periodic(h, tn) ||
+             (h->hpet.timers[tn].config & HPET_TN_SETVAL) )
+            h->hpet.timers[tn].cmp = new_val;
+        else
+            h->period[tn] = new_val;
+        h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
+        if ( hpet_enabled(h) && timer_enabled(h, tn) )
+            hpet_set_timer(h, tn);
+        break;
+
+    case HPET_T0_ROUTE:
+    case HPET_T1_ROUTE:
+    case HPET_T2_ROUTE:
+        tn = (addr - HPET_T0_ROUTE) >> 5;
+        h->hpet.timers[tn].hpet_fsb[0] = new_val;
+        break;
+
     default:
-        if ( hpet_check_access_offset(addr) != 0 )
-            break;
-
-        if ( (addr < HPET_T0_CFG) || (addr >= HPET_T2_ROUTE) )
-        {
-            gdprintk(XENLOG_WARNING,
-                     "HPET: writing reserved addr=0x%lx, ignored\n", addr);
-            break;
-        }
-
-        tn = (addr - HPET_T0_CFG) / 0x20;
-        if ( (addr == HPET_T0_CMP + 0x20*tn) || 
-             (addr == HPET_T0_CMP + 0x20*tn+4) )
-        {
-            hpet_write32(h, addr, val);
-            if ( addr == HPET_T0_CMP )
-                *((uint32_t*)&(h->t0_initial_cnt)) = val;
-            else if ( addr == HPET_T0_CMP + 4 )
-                *(((uint32_t*)&(h->t0_initial_cnt))+1) = val;
-            if( hpet_enabled(h) && timer_enabled(h, tn) )
-                hpet_set_timer(h, tn);
-        }
-        else /* HPET_Tn_CFG or HPET_Tn_CFG+4 */
-        {
-            if ( addr == (HPET_T0_CFG + 0x20*tn + 4) )
-            {
-                gdprintk(XENLOG_WARNING,
-                         "HPET:  Timer%d_CFG[63..32] is readonly\n", tn);
-            }
-            else
-            {
-                old_val = timer_config(h, tn);
-                if( (old_val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) !=
-                    (val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) )
-                {
-                    gdprintk(XENLOG_ERR,
-                             "HPET: TN_CFG writing incorrect value\n");
-                    domain_crash(v->domain);
-                    break;
-                }
-                hpet_write32(h, addr, val);
-
-                if ( timer_level(h, tn) )
-                {
-                    hpet_level_triggered_interrupt_not_supported();
-                    break;
-                }
-
-                if ( !(old_val & HPET_TN_ENABLE) &&
-                     (val & HPET_TN_ENABLE) )
-                    hpet_set_timer(h, tn);
-                else if ( (old_val & HPET_TN_ENABLE) &&
-                          !(val & HPET_TN_ENABLE) )
-                    hpet_stop_timer(h, tn); 
-            }
-        }
+        /* Ignore writes to unsupported and reserved registers. */
         break;
     }
 }
@@ -402,25 +292,26 @@ static int hpet_range(struct vcpu *v, un
 
 struct hvm_mmio_handler hpet_mmio_handler = {
     .check_handler = hpet_range,
-    .read_handler = hpet_read,
+    .read_handler  = hpet_read,
     .write_handler = hpet_write
 };
-
-static void hpet_set_irq(struct domain *d, int hpet_tn)
-{
-    /* if LegacyReplacementRoute bit is set, HPET specification requires
-       timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
-       timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
-    int isa_irq = (hpet_tn == 0) ? 0 : 8;
-    hvm_isa_irq_deassert(d, isa_irq);
-    hvm_isa_irq_assert(d, isa_irq);
-}
 
 static void hpet_route_interrupt(HPETState *h, unsigned int tn)
 {
     unsigned int tn_int_route = timer_int_route(h, tn);
     struct domain *d = h->vcpu->domain;
     struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+    if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
+    {
+        /* if LegacyReplacementRoute bit is set, HPET specification requires
+           timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
+           timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
+        int isa_irq = (tn == 0) ? 0 : 8;
+        hvm_isa_irq_deassert(d, isa_irq);
+        hvm_isa_irq_assert(d, isa_irq);
+        return;
+    }
 
     if ( !(timer_int_route_cap(h, tn) & (1U << tn_int_route)) )
     {
@@ -444,45 +335,24 @@ static void hpet_timer_fn(void *opaque)
 
     if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
         return;
-    
-    if ( timer_level(h, tn) )
-    {
-        hpet_level_triggered_interrupt_not_supported();
-        return;
-    }
-
-    switch ( tn )
-    {
-        case 0:
-        case 1:
-            if ( h->hpet.config & HPET_CFG_LEGACY )
-                hpet_set_irq(h->vcpu->domain, tn);
-            else
-                hpet_route_interrupt(h, tn);
-
-            if ( (tn == 0) && timer_is_periodic(h, tn) )
-            {
-                uint64_t mc = hpet_update_maincounter(h);
-                if ( timer_is_32bit(h, 0) )
-                {
-                    while ( hpet_time_after(mc, h->hpet.timers[0].c32) )
-                        h->hpet.timers[0].c32 += h->t0_initial_cnt;
-                }
-                else
-                {
-                    while ( hpet_time_after64(mc, h->hpet.timers[0].c64) )
-                        h->hpet.timers[0].c64 += h->t0_initial_cnt;
-                }
-                set_timer(&h->timers[tn], NOW() + h->t0_period);
-            }
-            break;
-        case 2:
-            hpet_route_interrupt(h, tn);
-            break;
-        default:
-            gdprintk(XENLOG_WARNING,
-                     "HPET: timer%u is not supported now\n", tn);
-            break;
+
+    hpet_route_interrupt(h, tn);
+
+    if ( timer_is_periodic(h, tn) && (h->period[tn] != 0) )
+    {
+        uint64_t mc = hpet_update_maincounter(h);
+        if ( timer_is_32bit(h, tn) )
+        {
+            while ( hpet_time_after(mc, h->hpet.timers[tn].cmp) )
+                h->hpet.timers[tn].cmp = (uint32_t)(
+                    h->hpet.timers[tn].cmp + h->period[tn]);
+        }
+        else
+        {
+            while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) )
+                h->hpet.timers[tn].cmp += h->period[tn];
+        }
+        set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, h->period[tn]));
     }
 
     vcpu_kick(h->vcpu);    
@@ -506,23 +376,19 @@ void hpet_init(struct vcpu *v)
 
     h->vcpu = v;
     h->tsc_freq = ticks_per_sec(v);
-    h->hpet.capability = HPET_CAP_ID_REG;
+
+    /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
+    h->hpet.capability = 0x8086A201ULL;
 
     /* This is the number of femptoseconds per HPET tick. */
-    /* Here we define HPET's frequency as tsc's. */
+    /* Here we define HPET's frequency to be the same as the TSC's. */
     h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32);
 
-    h->hpet.timers[0].config = HPET_TN_INT_ROUTE_CAP | 
-                        HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
-    h->hpet.timers[0].c64 = HPET_TIMER_CMP64_DEFAULT;
-
-    h->hpet.timers[1].config = HPET_TN_INT_ROUTE_CAP;
-    h->hpet.timers[1].c32 = HPET_TIMER_CMP32_DEFAULT;
-    h->hpet.timers[2].config = HPET_TN_INT_ROUTE_CAP;
-    h->hpet.timers[2].c32 = HPET_TIMER_CMP32_DEFAULT;
-
     for ( i = 0; i < HPET_TIMER_NUM; i++ )
     {
+        h->hpet.timers[i].config = 
+            HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
+        h->hpet.timers[i].cmp = ~0ULL;
         h->timer_fn_info[i].hs = h;
         h->timer_fn_info[i].tn = i;
         init_timer(&h->timers[i], hpet_timer_fn, &h->timer_fn_info[i],
diff -r 98271ea55d94 -r a8b2738a6f7f xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Fri Dec 29 13:02:19 2006 +0000
+++ b/xen/include/asm-x86/hvm/vpt.h     Fri Dec 29 14:12:55 2006 +0000
@@ -39,17 +39,11 @@ struct HPET {
     uint64_t res1;              /* reserved */
     uint64_t isr;               /* interrupt status reg */
     uint64_t res2[25];          /* reserved */
-    union {                     /* main counter */
-        uint64_t mc64;
-        uint32_t mc32;
-    };
+    uint64_t mc64;              /* main counter */
     uint64_t res3;              /* reserved */
     struct {                    /* timers */
         uint64_t config;        /* configuration/cap */
-        union {                 /* timer compare register */
-            uint64_t c64;
-            uint32_t c32;
-        };
+        uint64_t cmp;           /* comparator */
         uint64_t hpet_fsb[2];   /* FSB route, not supported now */
     } timers[HPET_TIMER_NUM];
 };
@@ -65,8 +59,7 @@ typedef struct HPETState {
     struct vcpu     *vcpu;
     uint64_t        tsc_freq;
     uint64_t        mc_offset;
-    uint64_t        t0_initial_cnt;
-    uint64_t        t0_period;
+    uint64_t        period[HPET_TIMER_NUM];
     struct timer timers[HPET_TIMER_NUM];
     struct HPET_timer_fn_info timer_fn_info[HPET_TIMER_NUM]; 
 } HPETState;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [HVM] Fix HPET timer to support 8-byte accesses, erroneous updates, Xen patchbot-unstable <=